Merge "msm: mdss: Provide generic io access mechanism to all mdss modules"
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index 843da69..3684a3f 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -11,7 +11,7 @@
 KERNEL_MODULES_OUT := $(TARGET_OUT)/lib/modules
 KERNEL_IMG=$(KERNEL_OUT)/arch/arm/boot/Image
 
-DTS_NAMES ?= $(shell $(PERL) -e 'while (<>) {$$a = $$1 if /CONFIG_ARCH_((?:MSM|QSD)[a-zA-Z0-9]+)=y/; $$r = $$1 if /CONFIG_MSM_SOC_REV_(?!NONE)(\w+)=y/; $$arch = $$arch.lc("$$a$$r ") if /CONFIG_ARCH_((?:MSM|QSD)[a-zA-Z0-9]+)=y/} print $$arch;' $(KERNEL_CONFIG))
+DTS_NAMES ?= $(shell $(PERL) -e 'while (<>) {$$a = $$1 if /CONFIG_ARCH_((?:MSM|QSD|MPQ)[a-zA-Z0-9]+)=y/; $$r = $$1 if /CONFIG_MSM_SOC_REV_(?!NONE)(\w+)=y/; $$arch = $$arch.lc("$$a$$r ") if /CONFIG_ARCH_((?:MSM|QSD|MPQ)[a-zA-Z0-9]+)=y/} print $$arch;' $(KERNEL_CONFIG))
 KERNEL_USE_OF ?= $(shell $(PERL) -e '$$of = "n"; while (<>) { if (/CONFIG_USE_OF=y/) { $$of = "y"; break; } } print $$of;' kernel/arch/arm/configs/$(KERNEL_DEFCONFIG))
 
 ifeq "$(KERNEL_USE_OF)" "y"
diff --git a/Documentation/devicetree/bindings/pil/pil-mba.txt b/Documentation/devicetree/bindings/pil/pil-mba.txt
index 7aafd219..9692059 100644
--- a/Documentation/devicetree/bindings/pil/pil-mba.txt
+++ b/Documentation/devicetree/bindings/pil/pil-mba.txt
@@ -10,6 +10,8 @@
 		      first corresponds to the Relay Message Buffer (RMB)
 		      register base. The second specifies the address at which
 		      the primary modem image metadata should be stored.
+- reg-names:	      Names for the above base addresses. "rmb_base" and
+	              "metadata_base" are expected.
 - qcom,firmware-name: Base name of the firmware image. Ex. "modem"
 
 Optional properties:
@@ -21,6 +23,7 @@
 		compatible = "qcom,pil-mba";
 		reg = <0xfc820000 0x0020>,
 		      <0x0d1f0000 0x4000>;
+		reg-names = "rmb_base", "metadata_base";
 
 		qcom,firmware-name = "modem";
 		qcom,depends-on    = "mba";
diff --git a/Documentation/devicetree/bindings/pil/pil-pronto.txt b/Documentation/devicetree/bindings/pil/pil-pronto.txt
index 6193b68..e123bdb 100644
--- a/Documentation/devicetree/bindings/pil/pil-pronto.txt
+++ b/Documentation/devicetree/bindings/pil/pil-pronto.txt
@@ -7,9 +7,9 @@
 
 Required properties:
 - compatible: "pil-pronto"
-- reg: offset and length of the register set for the device. The first pair
-       corresponds to PRONTO_PMU, the second pair corresponds to CLK_CTL_WCNSS
-       the third pair corresponds to WCNSS_HALTREQ.
+- reg: offset and length of the register set for the device.
+- reg-names: names of the bases for the above registers. "pmu_base", "clk_base",
+             and "halt_base" are expected.
 - vdd_pronto_pll-supply: regulator to supply pronto pll.
 - qcom,firmware-name: Base name of the firmware image. Ex. "wcnss"
 
@@ -19,6 +19,7 @@
 		reg = <0xfb21b000 0x3000>,
 		      <0xfc401700 0x4>,
 		      <0xfd485300 0xc>;
+		reg-names = "pmu_base", "clk_base", "halt_base";
 		vdd_pronto_pll-supply = <&pm8941_l12>;
 
 		qcom,firmware-name = "wcnss";
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
index 308f992..d39c98c 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -7,9 +7,10 @@
 
 Required properties:
 - compatible:	      Must be "qcom,pil-q6v5-lpass"
-- reg:		      Two pairs of physical base addresses and region sizes
-		      of memory mapped registers. The first region corresponds
-		      to QDSP6SS_PUB, and the second to LPASS_HALTREQ.
+- reg:		      Pairs of physical base addresses and region sizes of
+		      memory mapped registers.
+- reg-names:	      Names of the bases for the above registers. "qdsp6_base"
+		      and "halt_base" are expected.
 - qcom,firmware-name: Base name of the firmware image. Ex. "lpass"
 
 Example:
@@ -17,6 +18,7 @@
 	        compatible = "qcom,pil-q6v5-lpass";
 	        reg = <0xfe200000 0x00100>,
 	              <0xfd485100 0x00010>;
+		reg-names = "qdsp6_base", "halt_base";
 
 	        qcom,firmware-name = "lpass";
 	};
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 32c9c35..41ffd8a 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -7,12 +7,11 @@
 
 Required properties:
 - compatible:	      Must be "qcom,pil-q6v5-mss"
-- reg:		      Five pairs of physical base addresses and region sizes of
-		      memory mapped registers. The first region corresponds to
-		      QDSP6SS_PUB, the second to the bus port halt register
-		      base, the third to the MSS_RELAY_MSG_BUFFER base, the
-		      fourth to the MSS_RESTART register, and the fifth to the
-		      MSS_CLAMP_IO register.
+- reg:		      Pairs of physical base addresses and region sizes of
+		      memory mapped registers.
+- reg-names:	      Names of the bases for the above registers. "qdsp6_base",
+		      "halt_base", "rmb_base", "restart_reg" and "clamp_reg"
+		      are expected.
 - vdd_mss-supply:     Reference to the regulator that supplies the processor.
 - qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
 - qcom,pil-self-auth: <0> if the hardware does not require self-authenticating
@@ -27,6 +26,8 @@
 		      <0xfc820000 0x020>,
 		      <0xfc401680 0x004>,
 		      <0xfc980008 0x004>;
+		reg-names = "qdsp6_base", "halt_base", "rmb_base",
+			    "restart_reg", "clamp_reg";
 		vdd_mss-supply = <&pm8841_s3>;
 
 		qcom,firmware-name = "mba";
diff --git a/Documentation/devicetree/bindings/pil/pil-venus.txt b/Documentation/devicetree/bindings/pil/pil-venus.txt
index 93cba32..4b87f17 100644
--- a/Documentation/devicetree/bindings/pil/pil-venus.txt
+++ b/Documentation/devicetree/bindings/pil/pil-venus.txt
@@ -7,8 +7,9 @@
 
 Required properties:
 - compatible: "pil-venus"
-- reg: offset and length of the register set for the device. The first pair
-       corresponds to VENUS_WRAPPER, the second pair corresponds to VENUS_VBIF.
+- reg: offset and length of the register set for the device.
+- reg-names: names of the bases for the above registers. "wrapper_base" and
+             "vbif_base" are expected.
 - vdd-supply: regulator to supply venus.
 - qcom,firmware-name: Base name of the firmware image. Ex. "venus"
 - qcom,firmware-min-paddr: The lowest addr boundary for firmware image in DDR
@@ -19,6 +20,7 @@
                 compatible = "qcom,pil-venus";
                 reg = <0xfdce0000 0x4000>,
                       <0xfdc80208 0x8>;
+		reg-names = "wrapper_base", "vbif_base";
                 vdd-supply = <&gdsc_venus>;
 
                 qcom,firmware-name = "venus";
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
new file mode 100644
index 0000000..244e622
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -0,0 +1,209 @@
+Qualcomm QPNP Charger
+
+The charger supports the switch mode battery charger and boost (SMBB)
+peripherals on Qualcomm PMIC chips.
+
+There are seven different peripherals adding the following functionality.
+Each of these peripherals are implemented as subnodes in the example at the
+end of this file.
+
+- qcom,chg-chgr:	Supports charging control and status
+			reporting.
+- qcom,chg-bat-if:	Battery status reporting such as presence,
+			temperature reporting and voltage collapse
+			protection.
+- qcom,chg-buck:	Charger buck configuration and status
+			reporting with regards to several regulation
+			loops such as vdd, ibat etc.
+- qcom,usb-chgpth:	USB charge path detection and input current
+			limiting configuration.
+- qcom,dc-chgpth:	DC charge path detection and input current
+			limiting configuration.
+- qcom,chg-misc:	Miscellaneous features such as buck frequency
+			settings, comparator override features etc.
+
+Parent node required properties:
+- qcom,chg-vddmax-mv:	Target voltage of battery in mV
+- qcom,chg-vddsafe-mv:	Maximum Vdd voltage in mV
+- qcom,chg-vinmin-mv:	Minimum input voltage in mV
+- qcom,chg-ibatmax-ma:	Maximum battery charge current in mA
+- qcom,chg-ibatterm-ma:	Current at which charging is terminated in mA.
+
+Sub node required structure:
+- A qcom,chg node must be a child of an SPMI node that has specified
+	the spmi-dev-container property. Each subnode reflects
+	a hardware peripheral which adds a unique set of features
+	to the collective charging device. For example USB detection
+	and the battery interface are each seperate peripherals and
+	each should be their own subnode.
+
+Sub node required properties:
+- compatible:		Must be "qcom,charger".
+- reg:			Specifies the SPMI address and size for this peripheral.
+- interrupts:		Specifies the interrupt associated with the peripheral.
+- interrupt-names:	Specifies the interrupt names for the peripheral. Every
+			available interrupt needs to have an associated name
+			with it to indentify its purpose.
+
+			The following lists each subnode and their corresponding
+			required interrupt names:
+
+			qcom,usb-chgpth:
+			 - usbin-valid
+			qcom,chg-chgr:
+			 - chg-done
+			 - chg-failed
+
+			The following interrupts are available:
+
+			qcom,chg-chgr:
+			 - chg-done:		Triggers on charge completion.
+			 - chg-failed:		Notifies of charge failures.
+			 - fast-chg-on:		Notifies of fast charging state.
+			 - trkl-chg-on:		Indicates trickle charging.
+			 - state-change:	Notifies of a state change in
+						the charger state machine.
+			 - chgwdog:		Charger watchdog interrupt.
+			 - vbat-det-hi:		Triggers on vbat-det-hi voltage
+						setting,can be used as
+						battery alarm.
+			 - vbat-det-hi:		Triggers on vbat-det-low voltage
+						setting, can be used as
+						battery alarm.
+
+			qcom,chg-buck:
+			 - vdd-loop:		VDD loop change interrupt.
+			 - ibat-loop:		Ibat loop change interrupt.
+			 - ichg-loop:		Charge current loop change.
+			 - vchg-loop:		Charge voltage loop change.
+			 - overtemp:		Overtemperature interrupt.
+			 - vref-ov:		Reference overvoltage interrupt.
+			 - vbat-ov:		Battery overvoltage interrupt.
+
+			qcom,chg-bat-if:
+			 - psi:			PMIC serial interface interrupt.
+			 - vcp-on:		Voltage collapse protection
+						status interrupt.
+			 - bat-fet-on:		BATFET status interrupt.
+			 - bat-temp-ok:		Battery temperature status
+						interrupt.
+			 - batt-pres:		Battery presence status
+						interrupt.
+
+			qcom,usb-chgpth:
+			 - usbin-valid:		Indicates valid USB connection.
+			 - coarse-det-usb:	Coarse detect interrupt triggers
+						at low voltage on USB_IN.
+			 - chg-gone:		Triggers on VCHG line.
+
+			qcom,dc-chgpth:
+			 - dcin-valid:		Indicates a valid DC charger
+						connection.
+			 - coarse-det-dc:	Coarse detect interrupt triggers
+						at low voltage on DC_IN.
+
+			qcom,boost:
+			 - limit-error:		Limiting error on SMBB boost.
+			 - boost-pwr-ok:	Status of boost power.
+
+Example:
+	pm8941-chg {
+		spmi-dev-container;
+		compatible = "qcom,charger";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		qcom,chg-vddmax-mv = <4200>;
+		qcom,chg-vddsafe-mv = <4200>;
+		qcom,chg-vinmin-mv = <4200>;
+		qcom,chg-ibatmax-mv = <1500>;
+		qcom,chg-ibatterm-mv = <200>;
+
+		qcom,chg-chgr@1000 {
+			reg = <0x1000 0x100>;
+			interrupts =	<0x0 0x10 0x0>,
+				<0x0 0x10 0x1>,
+					<0x0 0x10 0x2>,
+					<0x0 0x10 0x3>,
+					<0x0 0x10 0x4>,
+					<0x0 0x10 0x5>,
+					<0x0 0x10 0x6>,
+					<0x0 0x10 0x7>;
+
+			interrupt-names =	"chg-done",
+						"chg-failed",
+						"fast-chg-on",
+						"trkl-chg-on",
+						"state-change",
+						"chgwdog",
+						"vbat-det-hi",
+						"vbat-det-lo";
+		};
+
+		qcom,chg-buck@1100 {
+			reg = <0x1100 0x100>;
+			interrupts =	<0x0 0x11 0x0>,
+					<0x0 0x11 0x1>,
+					<0x0 0x11 0x2>,
+					<0x0 0x11 0x3>,
+					<0x0 0x11 0x4>,
+					<0x0 0x11 0x5>,
+					<0x0 0x11 0x6>;
+
+			interrupt-names =	"vdd-loop",
+						"ibat-loop",
+						"ichg-loop",
+						"vchg-loop",
+						"overtemp",
+						"vref-ov",
+						"vbat-ov";
+		};
+
+		qcom,chg-bat-if@1200 {
+			reg = <0x1200 0x100>;
+			interrupts =	<0x0 0x12 0x0>,
+					<0x0 0x12 0x1>,
+					<0x0 0x12 0x2>,
+					<0x0 0x12 0x3>,
+					<0x0 0x12 0x4>;
+
+			interrupt-names =	"psi",
+						"vcp-on",
+						"bat-fet-on",
+						"bat-temp-ok",
+						"batt-pres";
+		};
+
+		qcom,chg-usb-chgpth@1300 {
+			reg = <0x1300 0x100>;
+			interrupts =	<0 0x13 0x0>,
+					<0 0x13 0x1>,
+					<0x0 0x13 0x2>;
+
+			interrupt-names =	"usbin-valid",
+						"coarse-det-usb",
+						"chg-gone";
+		};
+
+		qcom,chg-dc-chgpth@1400 {
+			reg = <0x1400 0x100>;
+			interrupts =	<0x0 0x14 0x0>,
+					<0x0 0x14 0x1>;
+
+			interrupt-names =	"dcin-valid",
+						"coarse-det-dc";
+		};
+
+		qcom,chg-boost@1500 {
+			reg = <0x1500 0x100>;
+			interrupts =	<0x0 0x15 0x0>,
+					<0x0 0x15 0x1>;
+
+			interrupt-names =	"limit-error",
+						"boost-pwr-ok";
+		};
+
+		qcom,chg-misc@1600 {
+			reg = <0x1600 0x100>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt b/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt
index b5ca08e..63c1e87 100644
--- a/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt
+++ b/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt
@@ -10,6 +10,10 @@
 - qcom,pmic-arb-channel : the assigned channel number for channel registers.
 - qcom,pmic-arb-ppid-map : an array used to map a 12-bit PPID to 8-bit APID.
 
+Optional properties:
+- qcom,not-wakeup : boolean property which indicates that SPMI PMIC interrupts
+	should not be treated as wakeup sources
+
 Peripherals on the SPMI bus are identified with a 12-bit identifier (PPID)
 which is composed of a 4-bit slave address and an 8-bit peripheral identifier.
 The PMIC Arbiter hardware uses an 8-bit APID (Arbiter Peripheral Identifier)
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index 08f7312..22ae844 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -8,23 +8,6 @@
 
 	force_ro		Enforce read-only access even if write protect switch is off.
 
-	num_wr_reqs_to_start_packing 	This attribute is used to determine
-	the trigger for activating the write packing, in case the write
-	packing control feature is enabled.
-
-	When the MMC manages to reach a point where num_wr_reqs_to_start_packing
-	write requests could be packed, it enables the write packing feature.
-	This allows us to start the write packing only when it is beneficial
-	and has minimum affect on the read latency.
-
-	The number of potential packed requests that will trigger the packing
-	can be configured via sysfs by writing the required value to:
-	/sys/block/<block_dev_name>/num_wr_reqs_to_start_packing.
-
-	The default value of num_wr_reqs_to_start_packing was determined by
-	running parallel lmdd write and lmdd read operations and calculating
-	the max number of packed writes requests.
-
 SD and MMC Device Attributes
 ============================
 
diff --git a/arch/arm/boot/dts/mpq8092-iommu.dtsi b/arch/arm/boot/dts/mpq8092-iommu.dtsi
new file mode 100755
index 0000000..6a88992
--- /dev/null
+++ b/arch/arm/boot/dts/mpq8092-iommu.dtsi
@@ -0,0 +1,33 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "msm-iommu.dtsi"
+
+&jpeg_iommu {
+	status = "ok";
+};
+
+&mdp_iommu {
+	status = "ok";
+};
+
+&venus_iommu {
+	status = "ok";
+};
+
+&kgsl_iommu {
+	status = "ok";
+};
+
+&vfe_iommu {
+	status = "ok";
+};
diff --git a/arch/arm/boot/dts/mpq8092-sim.dts b/arch/arm/boot/dts/mpq8092-sim.dts
index f73abe7..ac984a1 100644
--- a/arch/arm/boot/dts/mpq8092-sim.dts
+++ b/arch/arm/boot/dts/mpq8092-sim.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,37 +12,19 @@
 
 /dts-v1/;
 
-/include/ "skeleton.dtsi"
+/include/ "mpq8092.dtsi"
 
 / {
 	model = "Qualcomm MPQ8092 Simulator";
 	compatible = "qcom,mpq8092-sim", "qcom,mpq8092";
-	interrupt-parent = <&intc>;
-
-	intc: interrupt-controller@f9000000 {
-		compatible = "qcom,msm-qgic2";
-		interrupt-controller;
-		#interrupt-cells = <3>;
-		reg = <0xf9000000 0x1000>,
-		<0xf9002000 0x1000>;
-	};
-
-	timer {
-		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
-		interrupts = <1 2 0>, <1 3 0>;
-		clock-frequency = <19200000>;
-	};
+	qcom,msm-id = <126 16 0>;
 
 	serial@f991f000 {
-		compatible = "qcom,msm-lsuart-v14";
-		reg = <0xf991f000 0x1000>;
-		interrupts = <0 109 0>;
+		status = "ok";
 	};
 
 	serial@f995e000 {
-		compatible = "qcom,msm-lsuart-v14";
-		reg = <0xf995e000 0x1000>;
-		interrupts = <0 114 0>;
+		status = "ok";
 	};
 
 };
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
new file mode 100644
index 0000000..9b51ceb
--- /dev/null
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -0,0 +1,58 @@
+/* Copyright (c) 2012, The Linux Foundation. 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/ "skeleton.dtsi"
+/include/ "mpq8092-iommu.dtsi"
+/include/ "msm-gdsc.dtsi"
+
+/ {
+	model = "Qualcomm MPQ8092";
+	compatible = "qcom,mpq8092";
+	interrupt-parent = <&intc>;
+
+	intc: interrupt-controller@f9000000 {
+		compatible = "qcom,msm-qgic2";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		reg = <0xf9000000 0x1000>,
+		<0xf9002000 0x1000>;
+	};
+
+	msmgpio: gpio@fd510000 {
+		compatible = "qcom,msm-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		reg = <0xfd510000 0x4000>;
+	};
+
+	timer {
+		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+		interrupts = <1 2 0>, <1 3 0>;
+		clock-frequency = <19200000>;
+	};
+
+	serial@f991f000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf991f000 0x1000>;
+		interrupts = <0 109 0>;
+		status = "disabled";
+	};
+
+	serial@f995e000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf995e000 0x1000>;
+		interrupts = <0 114 0>;
+		status = "disabled";
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8019-rpm-regulator.dtsi b/arch/arm/boot/dts/msm-pm8019-rpm-regulator.dtsi
new file mode 100644
index 0000000..c48f67d
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8019-rpm-regulator.dtsi
@@ -0,0 +1,301 @@
+/* Copyright (c) 2012, Linux Foundation. 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.
+ */
+
+&rpm_bus {
+	rpm-regulator-smpa1 {
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <1>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-s1 {
+			regulator-name = "8019_s1";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-smpa2 {
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <2>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-s2 {
+			regulator-name = "8019_s2";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-smpa3 {
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <3>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-s3 {
+			regulator-name = "8019_s3";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-smpa4 {
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <4>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-s4 {
+			regulator-name = "8019_s4";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa1 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <1>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l1 {
+			regulator-name = "8019_l1";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa2 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <2>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l2 {
+			regulator-name = "8019_l2";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa3 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <3>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l3 {
+			regulator-name = "8019_l3";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa4 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <4>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l4 {
+			regulator-name = "8019_l4";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa5 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <5>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l5 {
+			regulator-name = "8019_l5";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa6 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <6>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l6 {
+			regulator-name = "8019_l6";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa7 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <7>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l7 {
+			regulator-name = "8019_l7";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa8 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <8>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l8 {
+			regulator-name = "8019_l8";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa9 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <9>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l9 {
+			regulator-name = "8019_l9";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa10 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <10>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l10 {
+			regulator-name = "8019_l10";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa11 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <11>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l11 {
+			regulator-name = "8019_l11";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa12 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <12>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l12 {
+			regulator-name = "8019_l12";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa13 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <13>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l13 {
+			regulator-name = "8019_l13";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa14 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <14>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l14 {
+			regulator-name = "8019_l14";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8019.dtsi b/arch/arm/boot/dts/msm-pm8019.dtsi
new file mode 100755
index 0000000..3b06450
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8019.dtsi
@@ -0,0 +1,340 @@
+/* Copyright (c) 2012, Linux Foundation. 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.
+ */
+
+&spmi_bus {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	interrupt-controller;
+	#interrupt-cells = <3>;
+
+	qcom,pm8019@0 {
+		spmi-slave-container;
+		reg = <0x0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		clkdiv@5b00 {
+			reg = <0x5b00 0x100>;
+			compatible = "qcom,qpnp-clkdiv";
+			qcom,cxo-freq = <19200000>;
+		};
+
+		clkdiv@5c00 {
+			reg = <0x5c00 0x100>;
+			compatible = "qcom,qpnp-clkdiv";
+			qcom,cxo-freq = <19200000>;
+		};
+
+		clkdiv@5d00 {
+			reg = <0x5d00 0x100>;
+			compatible = "qcom,qpnp-clkdiv";
+			qcom,cxo-freq = <19200000>;
+		};
+
+		rtc {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-rtc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			qcom,qpnp-rtc-write = <0>;
+			qcom,qpnp-rtc-alarm-pwrup = <0>;
+
+			qcom,pm8019_rtc_rw@6000 {
+				reg = <0x6000 0x100>;
+			};
+
+			qcom,pm8019_rtc_alarm@6100 {
+				reg = <0x6100 0x100>;
+				interrupts = <0x0 0x61 0x1>;
+			};
+		};
+
+		pm8019_gpios: gpios {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-pin";
+			gpio-controller;
+			#gpio-cells = <2>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			label = "pm8019-gpio";
+
+			gpio@c000 {
+				reg = <0xc000 0x100>;
+				qcom,pin-num = <1>;
+			};
+
+			gpio@c100 {
+				reg = <0xc100 0x100>;
+				qcom,pin-num = <2>;
+			};
+
+			gpio@c200 {
+				reg = <0xc200 0x100>;
+				qcom,pin-num = <3>;
+			};
+
+			gpio@c300 {
+				reg = <0xc300 0x100>;
+				qcom,pin-num = <4>;
+			};
+
+			gpio@c400 {
+				reg = <0xc400 0x100>;
+				qcom,pin-num = <5>;
+			};
+
+			gpio@c500 {
+				reg = <0xc500 0x100>;
+				qcom,pin-num = <6>;
+			};
+		};
+
+		pm8019_mpps: mpps {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-pin";
+			gpio-controller;
+			#gpio-cells = <2>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			label = "pm8019-mpp";
+
+			mpp@a000 {
+				reg = <0xa000 0x100>;
+				qcom,pin-num = <1>;
+			};
+
+			mpp@a100 {
+				reg = <0xa100 0x100>;
+				qcom,pin-num = <2>;
+			};
+
+			mpp@a200 {
+				reg = <0xa200 0x100>;
+				qcom,pin-num = <3>;
+			};
+
+			mpp@a300 {
+				reg = <0xa300 0x100>;
+				qcom,pin-num = <4>;
+			};
+
+			mpp@a400 {
+				reg = <0xa400 0x100>;
+				qcom,pin-num = <5>;
+			};
+
+			mpp@a500 {
+				reg = <0xa500 0x100>;
+				qcom,pin-num = <6>;
+			};
+		};
+	};
+
+	qcom,pm8019@1 {
+		spmi-slave-container;
+		reg = <0x1>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		regulator@1400 {
+			regulator-name = "8019_s1";
+			spmi-dev-container;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qpnp-regulator";
+			reg = <0x1400 0x300>;
+			status = "disabled";
+
+			qcom,ctl@1400 {
+				reg = <0x1400 0x100>;
+			};
+			qcom,ps@1500 {
+				reg = <0x1500 0x100>;
+			};
+			qcom,freq@1600 {
+				reg = <0x1600 0x100>;
+			};
+		};
+
+		regulator@1700 {
+			regulator-name = "8019_s2";
+			spmi-dev-container;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qpnp-regulator";
+			reg = <0x1700 0x300>;
+			status = "disabled";
+
+			qcom,ctl@1700 {
+				reg = <0x1700 0x100>;
+			};
+			qcom,ps@1800 {
+				reg = <0x1800 0x100>;
+			};
+			qcom,freq@1900 {
+				reg = <0x1900 0x100>;
+			};
+		};
+
+		regulator@1a00 {
+			regulator-name = "8019_s3";
+			spmi-dev-container;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qpnp-regulator";
+			reg = <0x1a00 0x300>;
+			status = "disabled";
+
+			qcom,ctl@1a00 {
+				reg = <0x1a00 0x100>;
+			};
+			qcom,ps@1b00 {
+				reg = <0x1b00 0x100>;
+			};
+			qcom,freq@1c00 {
+				reg = <0x1c00 0x100>;
+			};
+		};
+
+		regulator@1d00 {
+			regulator-name = "8019_s4";
+			spmi-dev-container;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qpnp-regulator";
+			reg = <0x1d00 0x300>;
+			status = "disabled";
+
+			qcom,ctl@1d00 {
+				reg = <0x1d00 0x100>;
+			};
+			qcom,ps@1e00 {
+				reg = <0x1e00 0x100>;
+			};
+			qcom,freq@1f00 {
+				reg = <0x1f00 0x100>;
+			};
+		};
+
+		regulator@4000 {
+			regulator-name = "8019_l1";
+			reg = <0x4000 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4100 {
+			regulator-name = "8019_l2";
+			reg = <0x4100 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4200 {
+			regulator-name = "8019_l3";
+			reg = <0x4200 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4300 {
+			regulator-name = "8019_l4";
+			reg = <0x4300 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4400 {
+			regulator-name = "8019_l5";
+			reg = <0x4400 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4500 {
+			regulator-name = "8019_l6";
+			reg = <0x4500 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4600 {
+			regulator-name = "8019_l7";
+			reg = <0x4600 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4700 {
+			regulator-name = "8019_l8";
+			reg = <0x4700 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4800 {
+			regulator-name = "8019_l9";
+			reg = <0x4800 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4900 {
+			regulator-name = "8019_l10";
+			reg = <0x4900 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4a00 {
+			regulator-name = "8019_l11";
+			reg = <0x4a00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4b00 {
+			regulator-name = "8019_l12";
+			reg = <0x4b00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4c00 {
+			regulator-name = "8019_l13";
+			reg = <0x4c00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4d00 {
+			regulator-name = "8019_l14";
+			reg = <0x4d00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4e00 {
+			regulator-name = "8019_ldo_xo";
+			reg = <0x4e00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4f00 {
+			regulator-name = "8019_ldo_rfclk";
+			reg = <0x4f00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 869a357..8560f9f 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -49,6 +49,41 @@
 			};
 		};
 
+		bms@4000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			compatible = "qcom,qpnp-bms";
+			reg = <0x4000 0x100>;
+
+			interrupts =	<0x0 0x40 0x0>,
+					<0x0 0x40 0x1>,
+					<0x0 0x40 0x2>,
+					<0x0 0x40 0x3>,
+					<0x0 0x40 0x4>,
+					<0x0 0x40 0x5>,
+					<0x0 0x40 0x6>,
+					<0x0 0x40 0x7>;
+
+			interrupt-names = "vsense_for_r",
+					  "vsense_avg",
+					  "sw_cc_thr",
+					  "ocv_thr",
+					  "charge_begin",
+					  "good_ocv",
+					  "ocv_for_r",
+					  "cc_thr";
+
+			qcom,bms-r-sense-mohm = <10>;
+			qcom,bms-v-cutoff-uv = <3400000>;
+			qcom,bms-max-voltage-uv = <4200000>;
+			qcom,bms-r-conn-mohm = <18>;
+			qcom,bms-shutdown-soc-valid-limit = <20>;
+			qcom,bms-adjust-soc-low-threshold = <25>;
+			qcom,bms-adjust-soc-high-threshold = <45>;
+			qcom,bms-chg-term-ua = <100000>;
+		};
+
 		clkdiv@5b00 {
 			reg = <0x5b00 0x100>;
 			compatible = "qcom,qpnp-clkdiv";
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index c92188a..fd652a0 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, The Linux Foundation. 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
@@ -181,7 +181,6 @@
 			reg = <0x6e 0x0>;
 			qcom,csi-if = <1>;
 			qcom,csid-core = <0>;
-			qcom,is-vpe = <1>;
 			qcom,flash-type = <0>;
 			qcom,mount-angle = <90>;
 			qcom,sensor-name = "s5k3l1yx";
@@ -222,8 +221,7 @@
 			compatible = "qcom,ov2720";
 			reg = <0x6c 0x0>;
 			qcom,csi-if = <1>;
-			qcom,csid-core = <1>;
-			qcom,is-vpe = <1>;
+			qcom,csid-core = <0>;
 			qcom,flash-type = <0>;
 			qcom,mount-angle = <0>;
 			qcom,sensor-name = "ov2720";
@@ -257,5 +255,40 @@
 			qcom,camera-type = <1>;
 			qcom,sensor-type = <0>;
 		};
+
+		qcom,camera@90 {
+			compatible = "qcom,mt9m114";
+			reg = <0x90 0x0>;
+			qcom,csi-if = <1>;
+			qcom,csid-core = <0>;
+			qcom,flash-type = <0>;
+			qcom,mount-angle = <0>;
+			qcom,sensor-name = "mt9m114";
+			cam_vdig-supply = <&pm8941_l3>;
+			cam_vana-supply = <&pm8941_l17>;
+			cam_vio-supply = <&pm8941_lvs3>;
+			qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+			qcom,cam-vreg-type = <0 0 1>;
+			qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+			qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+			qcom,cam-vreg-op-mode = <105000 80000 0>;
+			qcom,gpio-no-mux = <0>;
+			gpios = <&msmgpio 16 0>,
+				<&msmgpio 92 0>;
+			qcom,gpio-common-tbl-num = <0>;
+			qcom,gpio-common-tbl-flags = <1>;
+			qcom,gpio-common-tbl-label = "CAMIF_MCLK";
+			qcom,gpio-req-tbl-num = <1>;
+			qcom,gpio-req-tbl-flags = <0>;
+			qcom,gpio-req-tbl-label = "CAM_RESET1";
+			qcom,gpio-set-tbl-num = <1 1>;
+			qcom,gpio-set-tbl-flags = <0 2>;
+			qcom,gpio-set-tbl-delay = <1000 4000>;
+			qcom,csi-lane-assign = <0x4320>;
+			qcom,csi-lane-mask = <0x3>;
+			qcom,csi-phy-sel = <1>;
+			qcom,camera-type = <1>;
+			qcom,sensor-type = <1>;
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-mtp.dts
index d3e0bc3..ed89368 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-mtp.dts
@@ -18,7 +18,7 @@
 / {
 	model = "Qualcomm MSM 8974 MTP";
 	compatible = "qcom,msm8974-mtp", "qcom,msm8974";
-	qcom,msm-id = <126 8 0>;
+	qcom,msm-id = <126 8 0>, <126 3 0>;
 
 	serial@f991e000 {
 		status = "ok";
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index da0e1e5..c3c0d56 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -306,7 +306,6 @@
 		qcom,audio-routing =
 			"RX_BIAS", "MCLK",
 			"LDO_H", "MCLK",
-			"HEADPHONE", "LDO_H",
 			"Ext Spk Bottom Pos", "LINEOUT1",
 			"Ext Spk Bottom Neg", "LINEOUT3",
 			"Ext Spk Top Pos", "LINEOUT2",
@@ -633,6 +632,7 @@
 		compatible = "qcom,pil-q6v5-lpass";
 		reg = <0xfe200000 0x00100>,
 		      <0xfd485100 0x00010>;
+		reg-names = "qdsp6_base", "halt_base";
 
 		qcom,firmware-name = "adsp";
 	};
@@ -727,6 +727,9 @@
 		      <0xfc820000 0x020>,
 		      <0xfc401680 0x004>,
 		      <0xfc980008 0x004>;
+		reg-names = "qdsp6_base", "halt_base", "rmb_base",
+			    "restart_reg", "clamp_reg";
+
 		vdd_mss-supply = <&pm8841_s3>;
 
 		qcom,firmware-name = "mba";
@@ -737,6 +740,7 @@
 		compatible = "qcom,pil-mba";
 		reg = <0xfc820000 0x0020>,
 		      <0x0d1fc000 0x4000>;
+		reg-names = "rmb_base", "metadata_base";
 
 		qcom,firmware-name = "modem";
 		qcom,depends-on    = "mba";
@@ -747,6 +751,7 @@
 		reg = <0xfb21b000 0x3000>,
 		      <0xfc401700 0x4>,
 		      <0xfd485300 0xc>;
+		reg-names = "pmu_base", "clk_base", "halt_base";
 		vdd_pronto_pll-supply = <&pm8941_l12>;
 
 		qcom,firmware-name = "wcnss";
@@ -851,6 +856,7 @@
 		compatible = "qcom,pil-venus";
 		reg = <0xfdce0000 0x4000>,
 		      <0xfdc80208 0x8>;
+		reg-names = "wrapper_base", "vbif_base";
 		vdd-supply = <&gdsc_venus>;
 
 		qcom,firmware-name = "venus";
diff --git a/arch/arm/boot/dts/msm8974_pm.dtsi b/arch/arm/boot/dts/msm8974_pm.dtsi
index 8e3f4b8..77f2532 100644
--- a/arch/arm/boot/dts/msm8974_pm.dtsi
+++ b/arch/arm/boot/dts/msm8974_pm.dtsi
@@ -385,8 +385,8 @@
 			<40  95>;
 	};
 
-	qcom,pc-cntr@fe800000 {
+	qcom,pc-cntr@fe805664 {
 		compatible = "qcom,pc-cntr";
-		reg = <0xfe800664 0x40>;
+		reg = <0xfe805664 0x40>;
 	};
 };
diff --git a/arch/arm/boot/dts/msm9625-cdp.dts b/arch/arm/boot/dts/msm9625-cdp.dts
index 6733f59..aa1ec92 100644
--- a/arch/arm/boot/dts/msm9625-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-cdp.dts
@@ -19,3 +19,44 @@
 	compatible = "qcom,msm9625-cdp", "qcom,msm9625";
 	qcom,msm-id = <134 1 0>;
 };
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+};
+
+&pm8019_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+	};
+
+	mpp@a500 { /* MPP 6 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm9625-mtp.dts b/arch/arm/boot/dts/msm9625-mtp.dts
index 32185dc..3ec949f 100644
--- a/arch/arm/boot/dts/msm9625-mtp.dts
+++ b/arch/arm/boot/dts/msm9625-mtp.dts
@@ -19,3 +19,44 @@
 	compatible = "qcom,msm9625-mtp", "qcom,msm9625";
 	qcom,msm-id = <134 8 0>;
 };
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+};
+
+&pm8019_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+	};
+
+	mpp@a500 { /* MPP 6 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm9625-regulator.dtsi b/arch/arm/boot/dts/msm9625-regulator.dtsi
new file mode 100644
index 0000000..c42af2c
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-regulator.dtsi
@@ -0,0 +1,164 @@
+/* Copyright (c) 2012, Linux Foundation. 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.
+ */
+
+&spmi_bus {
+	qcom,pm8019@1 {
+		pm8019_s1: regulator@1400 {
+			regulator-min-microvolt = <800000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,enable-time = <500>;
+			status = "okay";
+		};
+
+		pm8019_s2: regulator@1700 {
+			regulator-min-microvolt = <1250000>;
+			regulator-max-microvolt = <1250000>;
+			qcom,system-load = <100000>;
+			qcom,enable-time = <500>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pm8019_s3: regulator@1a00 {
+			regulator-min-microvolt = <1100000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,system-load = <100000>;
+			qcom,enable-time = <500>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pm8019_s4: regulator@1d00 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2075000>;
+			qcom,system-load = <100000>;
+			qcom,enable-time = <500>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pm8019_l1: regulator@4000 {
+			parent-supply = <&pm8019_s2>;
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l2: regulator@4100 {
+			parent-supply = <&pm8019_s4>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l3: regulator@4200 {
+			parent-supply = <&pm8019_s4>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l4: regulator@4300 {
+			regulator-min-microvolt = <3075000>;
+			regulator-max-microvolt = <3075000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l5: regulator@4400 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l6: regulator@4500 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l7: regulator@4600 {
+			parent-supply = <&pm8019_s4>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l8: regulator@4700 {
+			parent-supply = <&pm8019_s4>;
+			regulator-min-microvolt = <2050000>;
+			regulator-max-microvolt = <2050000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l9: regulator@4800 {
+			parent-supply = <&pm8019_s2>;
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			qcom,system-load = <10000>;
+			qcom,enable-time = <200>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pm8019_l10: regulator@4900 {
+			parent-supply = <&pm8019_s3>;
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,system-load = <10000>;
+			qcom,enable-time = <200>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pm8019_l11: regulator@4a00 {
+			parent-supply = <&pm8019_s4>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,system-load = <10000>;
+			qcom,enable-time = <200>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pm8019_l12: regulator@4b00 {
+			parent-supply = <&pm8019_s3>;
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,system-load = <10000>;
+			qcom,enable-time = <200>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pm8019_l13: regulator@4c00 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l14: regulator@4d00 {
+			regulator-min-microvolt = <2700000>;
+			regulator-max-microvolt = <2700000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm9625-rumi.dts b/arch/arm/boot/dts/msm9625-rumi.dts
index e4fa000..dadb3f7 100644
--- a/arch/arm/boot/dts/msm9625-rumi.dts
+++ b/arch/arm/boot/dts/msm9625-rumi.dts
@@ -18,4 +18,9 @@
 	model = "Qualcomm MSM 9625 RUMI";
 	compatible = "qcom,msm9625-rumi", "qcom,msm9625";
 	qcom,msm-id = <134 15 0>;
+
+	chosen{
+		bootargs = "root=/dev/ram rw init=/init console=ttyHSL0,115200n8 initrd=0x00000000,0x00000000 mem=29M@0x00200000 mem=10M@0x07600000";
+
+	};
 };
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 8ad3b66..767f385 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -106,4 +106,41 @@
 		qcom,pet-time = <10000>;
 		qcom,ipi-ping = <0>;
 	};
+
+	rpm_bus: qcom,rpm-smd {
+		compatible = "qcom,rpm-smd";
+		rpm-channel-name = "rpm_requests";
+		rpm-channel-type = <15>; /* SMD_APPS_RPM */
+	};
+
+	spmi_bus: qcom,spmi@fc4c0000 {
+		cell-index = <0>;
+		compatible = "qcom,spmi-pmic-arb";
+		reg = <0xfc4cf000 0x1000>,
+		      <0Xfc4cb000 0x1000>;
+		/* 190,ee0_krait_hlos_spmi_periph_irq */
+		/* 187,channel_0_krait_hlos_trans_done_irq */
+		interrupts = <0 190 0 0 187 0>;
+		qcom,not-wakeup;
+		qcom,pmic-arb-ee = <0>;
+		qcom,pmic-arb-channel = <0>;
+		qcom,pmic-arb-ppid-map = <0x02400000>, /* TEMP_ALARM */
+					 <0x03100001>, /* VADC1_USR */
+					 <0x06100002>, /* RTC_ALARM */
+					 <0x06200003>, /* RTC_TIMER */
+					 <0x0a000004>, /* MPP1 */
+					 <0x0a100005>, /* MPP2 */
+					 <0x0a200006>, /* MPP3 */
+					 <0x0a300007>, /* MPP4 */
+					 <0x0a400008>, /* MPP5 */
+					 <0x0a500009>, /* MPP6 */
+					 <0x0c20000a>, /* GPIO3 */
+					 <0x0c30000b>, /* GPIO4 */
+					 <0x0c50000c>, /* GPIO6 */
+					 <0x0080000d>; /* PON */
+	};
 };
+
+/include/ "msm-pm8019-rpm-regulator.dtsi"
+/include/ "msm-pm8019.dtsi"
+/include/ "msm9625-regulator.dtsi"
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 4ba55de..93e84e9 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -39,6 +39,9 @@
 # CONFIG_QSD_AUDIO is not set
 # CONFIG_SURF_FFA_GPIO_KEYPAD is not set
 CONFIG_MSM_WATCHDOG=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_VMSPLIT_2G=y
diff --git a/arch/arm/configs/fsm9xxx_defconfig b/arch/arm/configs/fsm9xxx_defconfig
index ad1b6a6..c45063f 100644
--- a/arch/arm/configs/fsm9xxx_defconfig
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -38,6 +38,9 @@
 # CONFIG_QSD_AUDIO is not set
 # CONFIG_SURF_FFA_GPIO_KEYPAD is not set
 CONFIG_MSM_WATCHDOG=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_VMSPLIT_2G=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 7f10641..9a0bfba 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -55,6 +55,9 @@
 CONFIG_MSM_MULTIMEDIA_USE_ION=y
 CONFIG_MSM_CPR=y
 CONFIG_MSM_VP_REGULATOR=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
 CONFIG_ARM_THUMBEE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 0e0653f..60a2d72 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -57,6 +57,9 @@
 CONFIG_MSM_RTB_SEPARATE_CPUS=y
 CONFIG_MSM_CPR=y
 CONFIG_MSM_VP_REGULATOR=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
 CONFIG_ARM_THUMBEE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index 188ee03..401654d 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -44,6 +44,9 @@
 CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
 CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
 CONFIG_MSM_MULTIMEDIA_USE_ION=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index 5c5a152..0e066d9 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -44,6 +44,9 @@
 CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
 CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
 CONFIG_MSM_MULTIMEDIA_USE_ION=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index afe528d..3fdc804 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -347,6 +347,7 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_MSM_WFD=y
 CONFIG_USER_RC_INPUT=y
 CONFIG_IR_GPIO_CIR=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 4c9383d..4daaa12 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -351,6 +351,7 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_MSM_WFD=y
 CONFIG_USER_RC_INPUT=y
 CONFIG_IR_GPIO_CIR=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
@@ -513,6 +514,7 @@
 CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
 CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_USER=y
 CONFIG_PID_IN_CONTEXTIDR=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 392e062..b318c30 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -57,6 +57,7 @@
 CONFIG_MSM_PIL_PRONTO=y
 CONFIG_MSM_MODEM_SSR_8974=y
 CONFIG_MSM_ADSP_SSR_8974=y
+CONFIG_MSM_WCNSS_SSR_8974=y
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_BUS_SCALING=y
@@ -297,6 +298,7 @@
 CONFIG_MSM_CSI2_REGISTER=y
 CONFIG_MSM_ISPIF=y
 CONFIG_S5K3L1YX=y
+CONFIG_MT9M114=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_ION=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 7e3aad7..914547f 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -56,6 +56,7 @@
 CONFIG_MSM_PIL_PRONTO=y
 CONFIG_MSM_MODEM_SSR_8974=y
 CONFIG_MSM_ADSP_SSR_8974=y
+CONFIG_MSM_WCNSS_SSR_8974=y
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_BUS_SCALING=y
@@ -73,6 +74,8 @@
 CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
 CONFIG_MSM_L2_ERP_1BIT_PANIC=y
 CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_MSM_CACHE_DUMP=y
+CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -272,6 +275,7 @@
 CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_SUPPLY=y
 # CONFIG_BATTERY_MSM is not set
+CONFIG_QPNP_BMS=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_SENSORS_QPNP_ADC_CURRENT=y
 CONFIG_THERMAL=y
@@ -287,7 +291,7 @@
 CONFIG_VIDEOBUF2_MSM_MEM=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_MSM_CAMERA_V4L2=y
-CONFIG_MSM_WFD=y
+CONFIG_MT9M114=y
 CONFIG_OV2720=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_ACTUATOR=y
@@ -299,6 +303,7 @@
 CONFIG_MSM_CSI2_REGISTER=y
 CONFIG_MSM_ISPIF=y
 CONFIG_S5K3L1YX=y
+CONFIG_MSM_WFD=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_ION=y
@@ -404,6 +409,7 @@
 CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
 CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_USER=y
 CONFIG_PID_IN_CONTEXTIDR=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 0057062..d2e37e0 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -45,8 +45,6 @@
 CONFIG_HIGHMEM=y
 CONFIG_VMALLOC_RESERVE=0x19000000
 CONFIG_USE_OF=y
-CONFIG_ARM_APPENDED_DTB=y
-CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_VFP=y
 CONFIG_NEON=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
@@ -93,11 +91,21 @@
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_GPIO_QPNP_PIN_DEBUG=y
 # CONFIG_HWMON is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_QPNP=y
 # CONFIG_HID_SUPPORT is not set
 # CONFIG_USB_SUPPORT is not set
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
diff --git a/arch/arm/mach-msm/cp14.h b/arch/arm/include/asm/hardware/cp14.h
similarity index 99%
rename from arch/arm/mach-msm/cp14.h
rename to arch/arm/include/asm/hardware/cp14.h
index d640412..8acf0c7 100644
--- a/arch/arm/mach-msm/cp14.h
+++ b/arch/arm/include/asm/hardware/cp14.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. 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
@@ -10,8 +10,8 @@
  * GNU General Public License for more details.
  */
 
-#ifndef _ARCH_ARM_MACH_MSM_CP14_H_
-#define _ARCH_ARM_MACH_MSM_CP14_H_
+#ifndef __ASM_HARDWARE_CP14_H
+#define __ASM_HARDWARE_CP14_H
 
 #include <linux/types.h>
 
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index c9b786c..e59fb5b 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -357,6 +357,8 @@
 	select MSM_GPIOMUX
 	select MULTI_IRQ_HANDLER
 	select GPIO_MSM_V3
+	select MAY_HAVE_SPARSE_IRQ
+	select SPARSE_IRQ
 endmenu
 
 choice
@@ -927,7 +929,7 @@
 	default "0x00000000" if ARCH_MPQ8092
 	default "0x00000000" if ARCH_MSM8226
 	default "0x10000000" if ARCH_FSM9XXX
-	default "0x20200000" if ARCH_MSM9625
+	default "0x00200000" if ARCH_MSM9625
 	default "0x00200000" if !MSM_STACKED_MEMORY
 	default "0x00000000" if ARCH_QSD8X50 && MSM_SOC_REV_A
 	default "0x20000000" if ARCH_QSD8X50
@@ -2052,6 +2054,15 @@
 	 restarts the adsp or the 8974 when the adsp encounters a fatal error,
 	 depending on the restart level selected in the subsystem restart driver.
 
+config MSM_WCNSS_SSR_8974
+	tristate "MSM 8974 WCNSS restart module"
+	depends on (ARCH_MSM8974)
+	help
+	 This option enables the WCNSS restart module for MSM8974. It monitors
+	 WCNSS SMSM status bits and WCNSS hardware watchdog interrupt line; and
+	 depending on the restart level, it will restart WCNSS when a fatal error
+	 occurs at WCNSS.
+
 config SCORPION_Uni_45nm_BUG
 	bool "Scorpion Uni 45nm(SC45U): Workaround for ICIMVAU and BPIMVA"
 	depends on ARCH_MSM7X30 || (ARCH_QSD8X50 && MSM_SOC_REV_A)
@@ -2607,4 +2618,31 @@
 	  can be read and written to send character data to the sysmon port of
 	  the modem over USB.
 
+config MSM_RPC_PMIC
+	tristate "MSM RPC PMIC driver"
+	depends on MSM_ONCRPCROUTER
+	help
+	 This driver supports the PMIC functionality over RPC for those MSM's
+	 which do not have a direct access to PMIC. It supports ability to
+	 configure MPP, GPIO and all the other supported peripherals of the
+	 PMIC.
+
+config MSM_RPC_USB
+	tristate "MSM RPC USB driver"
+	depends on MSM_ONCRPCROUTER
+	help
+	 This driver supports the USB configuration support over the RPC
+	 interface. It support the HS USB module connected to the MSM
+	 and FS USB which is connected over the PMIC. This support is
+	 required for MSMs on which the APPS does not have a direct access
+	 to the PMIC.
+
+config MSM_RPC_PMAPP
+	tristate "MSM RPC PMIC APP driver"
+	depends on MSM_ONCRPCROUTER
+	help
+	 This driver supports the configuration of various PMIC APP modules
+	 such as display backlight, vreg pin-ctrl, smps clock over the RPC
+	 interface. This support is required for MSMs on which the APPS
+	 does not have a direct access to the PMIC.
 endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index d8e625a..d00acc9 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -98,20 +98,6 @@
 endif
 obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o
 obj-y += socinfo.o
-ifndef CONFIG_ARCH_MSM9615
-ifndef CONFIG_ARCH_APQ8064
-ifndef CONFIG_ARCH_MSM8960
-ifndef CONFIG_ARCH_MSM8X60
-ifndef CONFIG_ARCH_MSM8974
-ifndef CONFIG_ARCH_MPQ8092
-	obj-$(CONFIG_MSM_SMD) += pmic.o
-	obj-$(CONFIG_MSM_ONCRPCROUTER) += rpc_hsusb.o rpc_pmapp.o rpc_fsusb.o
-endif
-endif
-endif
-endif
-endif
-endif
 ifndef CONFIG_ARCH_MSM8960
 ifndef CONFIG_ARCH_MSM8X60
 ifndef CONFIG_ARCH_APQ8064
@@ -288,7 +274,7 @@
 obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
 obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
 obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
-obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o
+obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.o
 obj-$(CONFIG_MACH_APQ8064_CDP) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_MACH_APQ8064_MTP) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_MACH_APQ8064_LIQUID) += board-8064-all.o board-8064-regulator.o
@@ -393,6 +379,10 @@
 obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o
 obj-$(CONFIG_MSM_CPR) += msm_cpr.o
 obj-$(CONFIG_MSM_VP_REGULATOR) += msm_vp.o
+obj-$(CONFIG_MSM_RPC_PMIC) += pmic.o
+obj-$(CONFIG_MSM_RPC_USB) += rpc_hsusb.o rpc_fsusb.o
+obj-$(CONFIG_MSM_RPC_PMAPP) += rpc_pmapp.o
+
 
 ifdef CONFIG_MSM_CPR
 obj-$(CONFIG_DEBUG_FS) += msm_cpr-debug.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 526616a..9234b2c 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -52,7 +52,7 @@
    zreladdr-$(CONFIG_ARCH_MSM9615)	:= 0x40808000
 
 # MSM9625
-   zreladdr-$(CONFIG_ARCH_MSM9625)	:= 0x20208000
+   zreladdr-$(CONFIG_ARCH_MSM9625)	:= 0x00208000
 
 # MSM8226
    zreladdr-$(CONFIG_ARCH_MSM8226)	:= 0x00008000
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index 6788cbe..5c4a923 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -719,6 +719,7 @@
 				 */
 				clk_enable(pll_clk[backup_s->pll].clk);
 				acpuclk_set_div(backup_s);
+				update_jiffies(cpu, backup_s->lpj);
 			}
 			/* Make sure PLL4 is off before reprogramming */
 			if ((plls_enabled & (1 << tgt_s->pll))) {
@@ -736,6 +737,7 @@
 				 */
 				clk_enable(pll_clk[backup_s->pll].clk);
 				acpuclk_set_div(backup_s);
+				update_jiffies(cpu, backup_s->lpj);
 			}
 		}
 
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index ee2ca45..e384d1a 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -36,8 +36,8 @@
 	.has_user_reg = true,
 	.user_offset = 0x10,
 	.config_offset = 0x14,
-	/* TODO: Verify magic numbers when final values are available. */
 	.user_val = 0x8,
+	.user_vco_mask = BIT(20),
 	.config_val = 0x04D0405D,
 	.low_vco_l_max = 65,
 	.low_vdd_l_max = 52,
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index 2951c1a..f4050f2 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -45,6 +45,8 @@
 #define SEC_SRC_SEL_L2PLL	1
 #define SEC_SRC_SEL_AUX		2
 
+#define SECCLKAGD		BIT(4)
+
 static DEFINE_MUTEX(driver_lock);
 static DEFINE_SPINLOCK(l2_lock);
 
@@ -83,10 +85,20 @@
 {
 	u32 regval;
 
+	/* 8064 Errata: disable sec_src clock gating during switch. */
 	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+	regval |= SECCLKAGD;
+	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+
+	/* Program the MUX */
 	regval &= ~(0x3 << 2);
 	regval |= ((sec_src_sel & 0x3) << 2);
 	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+
+	/* 8064 Errata: re-enabled sec_src clock gating. */
+	regval &= ~SECCLKAGD;
+	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+
 	/* Wait for switch to complete. */
 	mb();
 	udelay(1);
diff --git a/arch/arm/mach-msm/adsp-8974.c b/arch/arm/mach-msm/adsp-8974.c
index 050a24b..fa7d9d4 100644
--- a/arch/arm/mach-msm/adsp-8974.c
+++ b/arch/arm/mach-msm/adsp-8974.c
@@ -119,12 +119,17 @@
 	wmb();
 }
 
+static void restart_adsp(void)
+{
+	adsp_log_failure_reason();
+	subsystem_restart("adsp");
+}
+
 static void adsp_fatal_fn(struct work_struct *work)
 {
 	pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME,
 		__func__);
-	adsp_log_failure_reason();
-	panic(MODULE_NAME ": Resetting the SoC");
+	restart_adsp();
 }
 
 static void adsp_smsm_state_cb(void *data, uint32_t old_state,
@@ -137,8 +142,7 @@
 	if (new_state & SMSM_RESET) {
 		pr_debug("%s: ADSP SMSM state changed to SMSM_RESET, new_state= 0x%x, old_state = 0x%x\n",
 			 __func__, new_state, old_state);
-		adsp_log_failure_reason();
-		panic(MODULE_NAME ": Resetting the SoC");
+		restart_adsp();
 	}
 }
 
@@ -156,7 +160,7 @@
 	/* The write needs to go through before the q6 is shutdown. */
 	mb();
 
-	pil_force_shutdown("q6");
+	pil_force_shutdown("adsp");
 	disable_irq_nosync(ADSP_Q6SS_WDOG_EXPIRED);
 
 	return 0;
@@ -171,7 +175,7 @@
 		msleep(10000);
 	}
 
-	ret = pil_force_boot("q6");
+	ret = pil_force_boot("adsp");
 	enable_irq(ADSP_Q6SS_WDOG_EXPIRED);
 	return ret;
 }
diff --git a/arch/arm/mach-msm/batterydata-lib.c b/arch/arm/mach-msm/batterydata-lib.c
new file mode 100644
index 0000000..2be591c
--- /dev/null
+++ b/arch/arm/mach-msm/batterydata-lib.c
@@ -0,0 +1,338 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
+
+int linear_interpolate(int y0, int x0, int y1, int x1, int x)
+{
+	if (y0 == y1 || x == x0)
+		return y0;
+	if (x1 == x0 || x == x1)
+		return y1;
+
+	return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
+}
+
+int is_between(int left, int right, int value)
+{
+	if (left >= right && left >= value && value >= right)
+		return 1;
+	if (left <= right && left <= value && value <= right)
+		return 1;
+	return 0;
+}
+
+static int interpolate_single_lut(struct single_row_lut *lut, int x)
+{
+	int i, result;
+
+	if (x < lut->x[0]) {
+		pr_debug("x %d less than known range return y = %d lut = %pS\n",
+							x, lut->y[0], lut);
+		return lut->y[0];
+	}
+	if (x > lut->x[lut->cols - 1]) {
+		pr_debug("x %d more than known range return y = %d lut = %pS\n",
+						x, lut->y[lut->cols - 1], lut);
+		return lut->y[lut->cols - 1];
+	}
+
+	for (i = 0; i < lut->cols; i++)
+		if (x <= lut->x[i])
+			break;
+	if (x == lut->x[i]) {
+		result = lut->y[i];
+	} else {
+		result = linear_interpolate(
+			lut->y[i - 1],
+			lut->x[i - 1],
+			lut->y[i],
+			lut->x[i],
+			x);
+	}
+	return result;
+}
+
+int interpolate_fcc(struct single_row_lut *fcc_temp_lut, int batt_temp)
+{
+	/* batt_temp is in tenths of degC - convert it to degC for lookups */
+	batt_temp = batt_temp/10;
+	return interpolate_single_lut(fcc_temp_lut, batt_temp);
+}
+
+int interpolate_scalingfactor_fcc(struct single_row_lut *fcc_sf_lut,
+		int cycles)
+{
+	/*
+	 * sf table could be null when no battery aging data is available, in
+	 * that case return 100%
+	 */
+	if (fcc_sf_lut)
+		return interpolate_single_lut(fcc_sf_lut, cycles);
+	else
+		return 100;
+}
+
+int interpolate_scalingfactor(struct sf_lut *sf_lut, int row_entry, int pc)
+{
+	int i, scalefactorrow1, scalefactorrow2, scalefactor, rows, cols;
+	int row1 = 0;
+	int row2 = 0;
+
+	/*
+	 * sf table could be null when no battery aging data is available, in
+	 * that case return 100%
+	 */
+	if (!sf_lut)
+		return 100;
+
+	rows = sf_lut->rows;
+	cols = sf_lut->cols;
+	if (pc > sf_lut->percent[0]) {
+		pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
+		row1 = 0;
+		row2 = 0;
+	}
+	if (pc < sf_lut->percent[rows - 1]) {
+		pr_debug("pc %d less than known pc ranges for sf\n", pc);
+		row1 = rows - 1;
+		row2 = rows - 1;
+	}
+	for (i = 0; i < rows; i++) {
+		if (pc == sf_lut->percent[i]) {
+			row1 = i;
+			row2 = i;
+			break;
+		}
+		if (pc > sf_lut->percent[i]) {
+			row1 = i - 1;
+			row2 = i;
+			break;
+		}
+	}
+
+	if (row_entry < sf_lut->row_entries[0])
+		row_entry = sf_lut->row_entries[0];
+	if (row_entry > sf_lut->row_entries[cols - 1])
+		row_entry = sf_lut->row_entries[cols - 1];
+
+	for (i = 0; i < cols; i++)
+		if (row_entry <= sf_lut->row_entries[i])
+			break;
+	if (row_entry == sf_lut->row_entries[i]) {
+		scalefactor = linear_interpolate(
+				sf_lut->sf[row1][i],
+				sf_lut->percent[row1],
+				sf_lut->sf[row2][i],
+				sf_lut->percent[row2],
+				pc);
+		return scalefactor;
+	}
+
+	scalefactorrow1 = linear_interpolate(
+				sf_lut->sf[row1][i - 1],
+				sf_lut->row_entries[i - 1],
+				sf_lut->sf[row1][i],
+				sf_lut->row_entries[i],
+				row_entry);
+
+	scalefactorrow2 = linear_interpolate(
+				sf_lut->sf[row2][i - 1],
+				sf_lut->row_entries[i - 1],
+				sf_lut->sf[row2][i],
+				sf_lut->row_entries[i],
+				row_entry);
+
+	scalefactor = linear_interpolate(
+				scalefactorrow1,
+				sf_lut->percent[row1],
+				scalefactorrow2,
+				sf_lut->percent[row2],
+				pc);
+
+	return scalefactor;
+}
+
+/* get ocv given a soc  -- reverse lookup */
+int interpolate_ocv(struct pc_temp_ocv_lut *pc_temp_ocv,
+				int batt_temp_degc, int pc)
+{
+	int i, ocvrow1, ocvrow2, ocv, rows, cols;
+	int row1 = 0;
+	int row2 = 0;
+
+	rows = pc_temp_ocv->rows;
+	cols = pc_temp_ocv->cols;
+	if (pc > pc_temp_ocv->percent[0]) {
+		pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
+		row1 = 0;
+		row2 = 0;
+	}
+	if (pc < pc_temp_ocv->percent[rows - 1]) {
+		pr_debug("pc %d less than known pc ranges for sf\n", pc);
+		row1 = rows - 1;
+		row2 = rows - 1;
+	}
+	for (i = 0; i < rows; i++) {
+		if (pc == pc_temp_ocv->percent[i]) {
+			row1 = i;
+			row2 = i;
+			break;
+		}
+		if (pc > pc_temp_ocv->percent[i]) {
+			row1 = i - 1;
+			row2 = i;
+			break;
+		}
+	}
+
+	if (batt_temp_degc < pc_temp_ocv->temp[0])
+		batt_temp_degc = pc_temp_ocv->temp[0];
+	if (batt_temp_degc > pc_temp_ocv->temp[cols - 1])
+		batt_temp_degc = pc_temp_ocv->temp[cols - 1];
+
+	for (i = 0; i < cols; i++)
+		if (batt_temp_degc <= pc_temp_ocv->temp[i])
+			break;
+	if (batt_temp_degc == pc_temp_ocv->temp[i]) {
+		ocv = linear_interpolate(
+				pc_temp_ocv->ocv[row1][i],
+				pc_temp_ocv->percent[row1],
+				pc_temp_ocv->ocv[row2][i],
+				pc_temp_ocv->percent[row2],
+				pc);
+		return ocv;
+	}
+
+	ocvrow1 = linear_interpolate(
+				pc_temp_ocv->ocv[row1][i - 1],
+				pc_temp_ocv->temp[i - 1],
+				pc_temp_ocv->ocv[row1][i],
+				pc_temp_ocv->temp[i],
+				batt_temp_degc);
+
+	ocvrow2 = linear_interpolate(
+				pc_temp_ocv->ocv[row2][i - 1],
+				pc_temp_ocv->temp[i - 1],
+				pc_temp_ocv->ocv[row2][i],
+				pc_temp_ocv->temp[i],
+				batt_temp_degc);
+
+	ocv = linear_interpolate(
+				ocvrow1,
+				pc_temp_ocv->percent[row1],
+				ocvrow2,
+				pc_temp_ocv->percent[row2],
+				pc);
+
+	return ocv;
+}
+
+int interpolate_pc(struct pc_temp_ocv_lut *pc_temp_ocv,
+				int batt_temp_degc, int ocv)
+{
+	int i, j, pcj, pcj_minus_one, pc;
+	int rows = pc_temp_ocv->rows;
+	int cols = pc_temp_ocv->cols;
+
+	if (batt_temp_degc < pc_temp_ocv->temp[0]) {
+		pr_debug("batt_temp %d < known temp range\n", batt_temp_degc);
+		batt_temp_degc = pc_temp_ocv->temp[0];
+	}
+
+	if (batt_temp_degc > pc_temp_ocv->temp[cols - 1]) {
+		pr_debug("batt_temp %d > known temp range\n", batt_temp_degc);
+		batt_temp_degc = pc_temp_ocv->temp[cols - 1];
+	}
+
+	for (j = 0; j < cols; j++)
+		if (batt_temp_degc <= pc_temp_ocv->temp[j])
+			break;
+	if (batt_temp_degc == pc_temp_ocv->temp[j]) {
+		/* found an exact match for temp in the table */
+		if (ocv >= pc_temp_ocv->ocv[0][j])
+			return pc_temp_ocv->percent[0];
+		if (ocv <= pc_temp_ocv->ocv[rows - 1][j])
+			return pc_temp_ocv->percent[rows - 1];
+		for (i = 0; i < rows; i++) {
+			if (ocv >= pc_temp_ocv->ocv[i][j]) {
+				if (ocv == pc_temp_ocv->ocv[i][j])
+					return pc_temp_ocv->percent[i];
+				pc = linear_interpolate(
+					pc_temp_ocv->percent[i],
+					pc_temp_ocv->ocv[i][j],
+					pc_temp_ocv->percent[i - 1],
+					pc_temp_ocv->ocv[i - 1][j],
+					ocv);
+				return pc;
+			}
+		}
+	}
+
+	/*
+	 * batt_temp_degc is within temperature for
+	 * column j-1 and j
+	 */
+	if (ocv >= pc_temp_ocv->ocv[0][j])
+		return pc_temp_ocv->percent[0];
+	if (ocv <= pc_temp_ocv->ocv[rows - 1][j - 1])
+		return pc_temp_ocv->percent[rows - 1];
+
+	pcj_minus_one = 0;
+	pcj = 0;
+	for (i = 0; i < rows-1; i++) {
+		if (pcj == 0
+			&& is_between(pc_temp_ocv->ocv[i][j],
+				pc_temp_ocv->ocv[i+1][j], ocv)) {
+			pcj = linear_interpolate(
+				pc_temp_ocv->percent[i],
+				pc_temp_ocv->ocv[i][j],
+				pc_temp_ocv->percent[i + 1],
+				pc_temp_ocv->ocv[i+1][j],
+				ocv);
+		}
+
+		if (pcj_minus_one == 0
+			&& is_between(pc_temp_ocv->ocv[i][j-1],
+				pc_temp_ocv->ocv[i+1][j-1], ocv)) {
+			pcj_minus_one = linear_interpolate(
+				pc_temp_ocv->percent[i],
+				pc_temp_ocv->ocv[i][j-1],
+				pc_temp_ocv->percent[i + 1],
+				pc_temp_ocv->ocv[i+1][j-1],
+				ocv);
+		}
+
+		if (pcj && pcj_minus_one) {
+			pc = linear_interpolate(
+				pcj_minus_one,
+				pc_temp_ocv->temp[j-1],
+				pcj,
+				pc_temp_ocv->temp[j],
+				batt_temp_degc);
+			return pc;
+		}
+	}
+
+	if (pcj)
+		return pcj;
+
+	if (pcj_minus_one)
+		return pcj_minus_one;
+
+	pr_debug("%d ocv wasn't found for temp %d in the LUT returning 100%%\n",
+							ocv, batt_temp_degc);
+	return 100;
+}
diff --git a/arch/arm/mach-msm/bms-batterydata-desay.c b/arch/arm/mach-msm/bms-batterydata-desay.c
index f362a72..d9fa061 100644
--- a/arch/arm/mach-msm/bms-batterydata-desay.c
+++ b/arch/arm/mach-msm/bms-batterydata-desay.c
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/mfd/pm8xxx/pm8921-bms.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
 
 static struct single_row_lut desay_5200_fcc_temp = {
 	.x		= {-20, 0, 25, 40},
@@ -76,7 +76,7 @@
 	},
 };
 
-struct pm8921_bms_battery_data desay_5200_data = {
+struct bms_battery_data desay_5200_data = {
 	.fcc			= 5200,
 	.fcc_temp_lut		= &desay_5200_fcc_temp,
 	.fcc_sf_lut		= &desay_5200_fcc_sf,
diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
index 81ab121..fb4f967 100644
--- a/arch/arm/mach-msm/bms-batterydata.c
+++ b/arch/arm/mach-msm/bms-batterydata.c
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/mfd/pm8xxx/pm8921-bms.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
 
 static struct single_row_lut fcc_temp = {
 	.x		= {-20, 0, 25, 40, 65},
@@ -99,7 +99,7 @@
 	}
 };
 
-struct pm8921_bms_battery_data palladium_1500_data = {
+struct bms_battery_data palladium_1500_data = {
 	.fcc			= 1500,
 	.fcc_temp_lut		= &fcc_temp,
 	.pc_temp_ocv_lut	= &pc_temp_ocv,
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 07acac6..1bac198 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -1930,6 +1930,7 @@
 	.ramdump_delay_ms = 2000,
 	.early_power_on = 1,
 	.sfr_query = 1,
+	.send_shdn = 1,
 	.vddmin_resource = &mdm_vddmin_rscs,
 	.peripheral_platform_device = &apq8064_device_hsic_host,
 	.ramdump_timeout_ms = 120000,
@@ -2575,6 +2576,7 @@
 #ifdef CONFIG_MSM_ROTATOR
 	&msm_rotator_device,
 #endif
+	&msm8064_pc_cntr,
 };
 
 static struct platform_device
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index ab35948..05592c2 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -2398,6 +2398,7 @@
 	&msm8930_iommu_domain_device,
 	&msm_tsens_device,
 	&msm8930_cache_dump_device,
+	&msm8930_pc_cntr,
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 8ed9666..710b10f 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -2744,6 +2744,7 @@
 	&msm8960_cache_dump_device,
 	&msm8960_iommu_domain_device,
 	&msm_tsens_device,
+	&msm8960_pc_cntr,
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
@@ -3158,13 +3159,22 @@
 #endif
 }
 
+static void __init msm8960_tsens_init(void)
+{
+	if (cpu_is_msm8960())
+		if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1)
+			return;
+
+	msm_tsens_early_init(&msm_tsens_pdata);
+}
+
 static void __init msm8960_cdp_init(void)
 {
 	if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
 		pr_err("meminfo_init() failed!\n");
 
 	platform_device_register(&msm_gpio_device);
-	msm_tsens_early_init(&msm_tsens_pdata);
+	msm8960_tsens_init();
 	msm_thermal_init(&msm_thermal_pdata);
 	BUG_ON(msm_rpm_init(&msm8960_rpm_data));
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 479dec6..1577a2b 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -290,22 +290,34 @@
 
 static struct gpiomux_setting cam_settings[] = {
 	{
-		.func = GPIOMUX_FUNC_1, /*active 1*/
+		.func = GPIOMUX_FUNC_1, /*active 1*/ /* 0 */
 		.drv = GPIOMUX_DRV_2MA,
 		.pull = GPIOMUX_PULL_NONE,
 	},
 
 	{
-		.func = GPIOMUX_FUNC_1, /*suspend*/
+		.func = GPIOMUX_FUNC_1, /*suspend*/ /* 1 */
 		.drv = GPIOMUX_DRV_2MA,
 		.pull = GPIOMUX_PULL_DOWN,
 	},
 
 	{
-		.func = GPIOMUX_FUNC_1, /*i2c suspend*/
+		.func = GPIOMUX_FUNC_1, /*i2c suspend*/ /* 2 */
 		.drv = GPIOMUX_DRV_2MA,
 		.pull = GPIOMUX_PULL_KEEPER,
 	},
+
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*active 0*/ /* 3 */
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*suspend 0*/ /* 4 */
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
 };
 
 static struct msm_gpiomux_config msm_sensor_configs[] __initdata = {
@@ -333,8 +345,8 @@
 	{
 		.gpio = 18, /* WEBCAM1_RESET_N / CAM_MCLK3 */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[0],
-			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[4],
 		},
 	},
 	{
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 99b9f16..797f5f1 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -30,6 +30,7 @@
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/clk-provider.h>
+#include <mach/qpnp-int.h>
 #include "clock.h"
 
 #define L2CC_AUX_CTRL	((0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | \
@@ -62,6 +63,7 @@
 static struct of_device_id irq_match[] __initdata  = {
 	{ .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
 	{ .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
+	{ .compatible = "qcom,spmi-pmic-arb", .data = qpnpint_of_init, },
 	{}
 };
 
@@ -75,6 +77,8 @@
 			"msm_serial_hsl.0", NULL),
 	OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9928000, \
 			"spi_qsd.1", NULL),
+	OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
+			"spmi-pmic-arb.0", NULL),
 	{}
 };
 
@@ -111,5 +115,4 @@
 	.handle_irq = gic_handle_irq,
 	.timer = &msm_dt_timer,
 	.dt_compat = msm9625_dt_match,
-	.nr_irqs = -1,
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index f6b0c4f..ed1fafc 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -276,6 +276,7 @@
 
 static struct msm_hsusb_gadget_platform_data msm_gadget_pdata = {
 	.is_phy_status_timer_on = 1,
+	.prop_chg = 0,
 };
 
 #ifdef CONFIG_SERIAL_MSM_HS
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 9ff039f0..b60f693 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5450,6 +5450,10 @@
 	CLK_LOOKUP("osr_clk",		spare_i2s_mic_osr_clk.c,
 			   "msm-dai-q6.5"),
 	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
 			   "msm-dai-q6.16384"),
 	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
 			   "msm-dai-q6.16384"),
@@ -5793,6 +5797,10 @@
 	CLK_LOOKUP("osr_clk",		spare_i2s_mic_osr_clk.c,
 			   "msm-dai-q6.5"),
 	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
 			   "msm-dai-q6.16384"),
 	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
 			   "msm-dai-q6.16384"),
@@ -6125,6 +6133,10 @@
 	CLK_LOOKUP("osr_clk",		spare_i2s_mic_osr_clk.c,
 			   "msm-dai-q6.5"),
 	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
 			   "msm-dai-q6.16384"),
 	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
 			   "msm-dai-q6.16384"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index ca0dd20..e9b4867 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. 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
@@ -2366,9 +2366,12 @@
 
 static struct clk_freq_tbl ftbl_mmss_axi_clk[] = {
 	F_MM( 19200000,    cxo,     1,   0,   0),
+	F_MM( 37500000,  gpll0,    16,   0,   0),
+	F_MM( 50000000,  gpll0,    12,   0,   0),
+	F_MM( 75000000,  gpll0,     8,   0,   0),
+	F_MM(100000000,  gpll0,     6,   0,   0),
 	F_MM(150000000,  gpll0,     4,   0,   0),
 	F_MM(282000000, mmpll1,     3,   0,   0),
-	F_MM(320000000, mmpll0,   2.5,   0,   0),
 	F_MM(400000000, mmpll0,     2,   0,   0),
 	F_END
 };
@@ -2390,6 +2393,10 @@
 
 static struct clk_freq_tbl ftbl_ocmemnoc_clk[] = {
 	F_MM( 19200000,    cxo,   1,   0,   0),
+	F_MM( 37500000,  gpll0,  16,   0,   0),
+	F_MM( 50000000,  gpll0,  12,   0,   0),
+	F_MM( 75000000,  gpll0,   8,   0,   0),
+	F_MM(100000000,  gpll0,   6,   0,   0),
 	F_MM(150000000,  gpll0,   4,   0,   0),
 	F_MM(282000000, mmpll1,   3,   0,   0),
 	F_MM(400000000, mmpll0,   2,   0,   0),
@@ -5132,8 +5139,10 @@
 	/* MM sensor clocks */
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, ""),
 	CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, ""),
 	CLK_LOOKUP("cam_clk", camss_mclk3_clk.c, ""),
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index e66881b..6be8b7ff 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -99,6 +99,23 @@
 /* Address of PCIE20 */
 #define PCIE20_PHYS   0x1b500000
 #define PCIE20_SIZE   SZ_4K
+#define MSM8064_PC_CNTR_PHYS	(APQ8064_IMEM_PHYS + 0x664)
+#define MSM8064_PC_CNTR_SIZE		0x40
+
+static struct resource msm8064_resources_pccntr[] = {
+	{
+		.start	= MSM8064_PC_CNTR_PHYS,
+		.end	= MSM8064_PC_CNTR_PHYS + MSM8064_PC_CNTR_SIZE,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm8064_pc_cntr = {
+	.name		= "pc-cntr",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(msm8064_resources_pccntr),
+	.resource	= msm8064_resources_pccntr,
+};
 
 static struct msm_watchdog_pdata msm_watchdog_pdata = {
 	.pet_time = 10000,
@@ -2350,17 +2367,18 @@
 
 /* Sensors DSPS platform data */
 
-#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
-#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
-#define PPSS_DSPS_TCM_BUF_BASE  0x12040000
-#define PPSS_DSPS_TCM_BUF_SIZE  0x4000
-#define PPSS_DSPS_PIPE_BASE     0x12800000
-#define PPSS_DSPS_PIPE_SIZE     0x4000
-#define PPSS_DSPS_DDR_BASE      0x8fe00000
-#define PPSS_DSPS_DDR_SIZE      0x100000
-#define PPSS_SMEM_BASE          0x80000000
-#define PPSS_SMEM_SIZE          0x200000
-#define PPSS_REG_PHYS_BASE	0x12080000
+#define PPSS_DSPS_TCM_CODE_BASE   0x12000000
+#define PPSS_DSPS_TCM_CODE_SIZE   0x28000
+#define PPSS_DSPS_TCM_BUF_BASE    0x12040000
+#define PPSS_DSPS_TCM_BUF_SIZE    0x4000
+#define PPSS_DSPS_PIPE_BASE       0x12800000
+#define PPSS_DSPS_PIPE_SIZE       0x4000
+#define PPSS_DSPS_DDR_BASE        0x8fe00000
+#define PPSS_DSPS_DDR_SIZE        0x100000
+#define PPSS_SMEM_BASE            0x80000000
+#define PPSS_SMEM_SIZE            0x200000
+#define PPSS_REG_PHYS_BASE        0x12080000
+#define PPSS_WDOG_UNMASKED_INT_EN 0x1808
 
 static struct dsps_clk_info dsps_clks[] = {};
 static struct dsps_regulator_info dsps_regs[] = {};
@@ -2388,6 +2406,7 @@
 	.ddr_size = PPSS_DSPS_DDR_SIZE,
 	.smem_start = PPSS_SMEM_BASE,
 	.smem_size  = PPSS_SMEM_SIZE,
+	.ppss_wdog_unmasked_int_en_reg = PPSS_WDOG_UNMASKED_INT_EN,
 	.signature = DSPS_SIGNATURE,
 };
 
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index ad89a86..f52ee18 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -37,6 +37,23 @@
 #ifdef CONFIG_MSM_MPM
 #include <mach/mpm.h>
 #endif
+#define MSM8930_PC_CNTR_PHYS	(MSM8930_IMEM_PHYS + 0x664)
+#define MSM8930_PC_CNTR_SIZE		0x40
+
+static struct resource msm8930_resources_pccntr[] = {
+	{
+		.start	= MSM8930_PC_CNTR_PHYS,
+		.end	= MSM8930_PC_CNTR_PHYS + MSM8930_PC_CNTR_SIZE,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm8930_pc_cntr = {
+	.name		= "pc-cntr",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(msm8930_resources_pccntr),
+	.resource	= msm8930_resources_pccntr,
+};
 
 struct msm_rpm_platform_data msm8930_rpm_data __initdata = {
 	.reg_base_addrs = {
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 64b901f..5cbfb5b 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -103,6 +103,24 @@
 #define MSM8960_HSUSB_PHYS		0x12500000
 #define MSM8960_HSUSB_SIZE		SZ_4K
 
+#define MSM8960_PC_CNTR_PHYS	(MSM8960_IMEM_PHYS + 0x664)
+#define MSM8960_PC_CNTR_SIZE		0x40
+
+static struct resource msm8960_resources_pccntr[] = {
+	{
+		.start	= MSM8960_PC_CNTR_PHYS,
+		.end	= MSM8960_PC_CNTR_PHYS + MSM8960_PC_CNTR_SIZE,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm8960_pc_cntr = {
+	.name		= "pc-cntr",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(msm8960_resources_pccntr),
+	.resource	= msm8960_resources_pccntr,
+};
+
 static struct resource resources_otg[] = {
 	{
 		.start	= MSM8960_HSUSB_PHYS,
@@ -3705,17 +3723,18 @@
 /* Sensors DSPS platform data */
 #ifdef CONFIG_MSM_DSPS
 
-#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
-#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
-#define PPSS_DSPS_TCM_BUF_BASE  0x12040000
-#define PPSS_DSPS_TCM_BUF_SIZE  0x4000
-#define PPSS_DSPS_PIPE_BASE     0x12800000
-#define PPSS_DSPS_PIPE_SIZE     0x4000
-#define PPSS_DSPS_DDR_BASE      0x8fe00000
-#define PPSS_DSPS_DDR_SIZE      0x100000
-#define PPSS_SMEM_BASE          0x80000000
-#define PPSS_SMEM_SIZE          0x200000
-#define PPSS_REG_PHYS_BASE	0x12080000
+#define PPSS_DSPS_TCM_CODE_BASE   0x12000000
+#define PPSS_DSPS_TCM_CODE_SIZE   0x28000
+#define PPSS_DSPS_TCM_BUF_BASE    0x12040000
+#define PPSS_DSPS_TCM_BUF_SIZE    0x4000
+#define PPSS_DSPS_PIPE_BASE       0x12800000
+#define PPSS_DSPS_PIPE_SIZE       0x4000
+#define PPSS_DSPS_DDR_BASE        0x8fe00000
+#define PPSS_DSPS_DDR_SIZE        0x100000
+#define PPSS_SMEM_BASE            0x80000000
+#define PPSS_SMEM_SIZE            0x200000
+#define PPSS_REG_PHYS_BASE        0x12080000
+#define PPSS_WDOG_UNMASKED_INT_EN 0x1808
 
 static struct dsps_clk_info dsps_clks[] = {};
 static struct dsps_regulator_info dsps_regs[] = {};
@@ -3743,6 +3762,7 @@
 	.ddr_size = PPSS_DSPS_DDR_SIZE,
 	.smem_start = PPSS_SMEM_BASE,
 	.smem_size  = PPSS_SMEM_SIZE,
+	.ppss_wdog_unmasked_int_en_reg = PPSS_WDOG_UNMASKED_INT_EN,
 	.signature = DSPS_SIGNATURE,
 };
 
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 343ea76..65dfc31 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -2022,6 +2022,7 @@
 
 static struct notifier_block panic_handler = {
 	.notifier_call = msm7627a_panic_handler,
+	.priority = INT_MAX,
 };
 
 static int __init panic_register(void)
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index e66bf27..0506217 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -109,6 +109,10 @@
 extern struct platform_device msm_device_sdc3;
 extern struct platform_device msm_device_sdc4;
 
+extern struct platform_device msm8960_pc_cntr;
+extern struct platform_device msm8064_pc_cntr;
+extern struct platform_device msm8930_pc_cntr;
+
 extern struct platform_device msm_device_gadget_peripheral;
 extern struct platform_device msm_device_hsusb_host;
 extern struct platform_device msm_device_hsusb_host2;
diff --git a/arch/arm/mach-msm/etm.c b/arch/arm/mach-msm/etm.c
index 6cceff2..ae42733 100644
--- a/arch/arm/mach-msm/etm.c
+++ b/arch/arm/mach-msm/etm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. 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
@@ -24,8 +24,7 @@
 #include <linux/pm_qos.h>
 
 #include <asm/atomic.h>
-
-#include "cp14.h"
+#include <asm/hardware/cp14.h>
 
 #define LOG_BUF_LEN			32768
 /* each slot is 4 bytes, 8kb total */
diff --git a/arch/arm/mach-msm/include/mach/irqs-8974.h b/arch/arm/mach-msm/include/mach/irqs-8974.h
index d10b537..8152eca 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8974.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8974.h
@@ -24,9 +24,7 @@
 #define GIC_PPI_START 16
 #define GIC_SPI_START 32
 
-#define AVS_SVICINT				(GIC_PPI_START + 6)
-#define AVS_SVICINTSWDONE			(GIC_PPI_START + 7)
-#define INT_ARMQC_PERFMON			(GIC_PPI_START + 10)
+#define INT_ARMQC_PERFMON			(GIC_PPI_START + 7)
 /* PPI 15 is unused */
 
 #define APCC_QGICL2PERFMONIRPTREQ	(GIC_SPI_START + 1)
diff --git a/arch/arm/mach-msm/include/mach/mdm2.h b/arch/arm/mach-msm/include/mach/mdm2.h
index 6ec12c1..fd63fd2 100644
--- a/arch/arm/mach-msm/include/mach/mdm2.h
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -33,6 +33,7 @@
 	const unsigned int ramdump_timeout_ms;
 	int image_upgrade_supported;
 	struct gpiomux_setting *mdm2ap_status_gpio_run_cfg;
+	int send_shdn;
 };
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_dsps.h b/arch/arm/mach-msm/include/mach/msm_dsps.h
index 0f9dba6..a876798 100644
--- a/arch/arm/mach-msm/include/mach/msm_dsps.h
+++ b/arch/arm/mach-msm/include/mach/msm_dsps.h
@@ -86,6 +86,7 @@
  * @smem_start - start of the smem region as physical address
  * @smem_size - size of the smem region in bytes
  * @ppss_pause_reg - Offset to the PPSS_PAUSE register
+ * @ppss_wdog_unmasked_int_en_reg - Offset to PPSS_WDOG_UNMASKED_INT_EN register
  * @signature - signature for validity check.
  */
 struct msm_dsps_platform_data {
@@ -109,6 +110,7 @@
 	int smem_start;
 	int smem_size;
 	int ppss_pause_reg;
+	int ppss_wdog_unmasked_int_en_reg;
 	u32 signature;
 };
 
diff --git a/arch/arm/mach-msm/include/mach/msm_hsusb.h b/arch/arm/mach-msm/include/mach/msm_hsusb.h
index 4e22b0f..c6eb527 100644
--- a/arch/arm/mach-msm/include/mach/msm_hsusb.h
+++ b/arch/arm/mach-msm/include/mach/msm_hsusb.h
@@ -138,6 +138,7 @@
 
 	int self_powered;
 	int is_phy_status_timer_on;
+	bool prop_chg;
 };
 
 struct msm_otg_platform_data {
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8092.h b/arch/arm/mach-msm/include/mach/msm_iomap-8092.h
index dec8a58..732aaff 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8092.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8092.h
@@ -23,7 +23,7 @@
  *
  */
 
-#define MPQ8092_SHARED_RAM_PHYS	0x0FA00000
+#define MPQ8092_MSM_SHARED_RAM_PHYS	0x0FA00000
 
 #define MPQ8092_QGIC_DIST_PHYS	0xF9000000
 #define MPQ8092_QGIC_DIST_SIZE	SZ_4K
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 133a1b3..be8f6c1 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -97,47 +97,6 @@
 
 #define SMSM_SUBSYS2AP_STATUS         0x00008000
 
-#ifdef CONFIG_MSM_SMD
-void *smem_alloc(unsigned id, unsigned size);
-#else
-void *smem_alloc(unsigned id, unsigned size)
-{
-	return NULL;
-}
-#endif
-void *smem_alloc2(unsigned id, unsigned size_in);
-void *smem_get_entry(unsigned id, unsigned *size);
-int smsm_change_state(uint32_t smsm_entry,
-		      uint32_t clear_mask, uint32_t set_mask);
-
-/*
- * Changes the global interrupt mask.  The set and clear masks are re-applied
- * every time the global interrupt mask is updated for callback registration
- * and de-registration.
- *
- * The clear mask is applied first, so if a bit is set to 1 in both the clear
- * mask and the set mask, the result will be that the interrupt is set.
- *
- * @smsm_entry  SMSM entry to change
- * @clear_mask  1 = clear bit, 0 = no-op
- * @set_mask    1 = set bit, 0 = no-op
- *
- * @returns 0 for success, < 0 for error
- */
-int smsm_change_intr_mask(uint32_t smsm_entry,
-			  uint32_t clear_mask, uint32_t set_mask);
-int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask);
-uint32_t smsm_get_state(uint32_t smsm_entry);
-int smsm_state_cb_register(uint32_t smsm_entry, uint32_t mask,
-	void (*notify)(void *, uint32_t old_state, uint32_t new_state),
-	void *data);
-int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
-	void (*notify)(void *, uint32_t, uint32_t), void *data);
-void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
-	uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
-void smsm_reset_modem(unsigned mode);
-void smsm_reset_modem_cont(void);
-void smd_sleep_exit(void);
 
 #define SMEM_NUM_SMD_STREAM_CHANNELS        64
 #define SMEM_NUM_SMD_BLOCK_CHANNELS         64
@@ -250,8 +209,128 @@
 	SMSM_NUM_INTR_MUX = 8,
 };
 
+#ifdef CONFIG_MSM_SMD
+void *smem_alloc(unsigned id, unsigned size);
+void *smem_alloc2(unsigned id, unsigned size_in);
+void *smem_get_entry(unsigned id, unsigned *size);
+int smsm_change_state(uint32_t smsm_entry,
+		      uint32_t clear_mask, uint32_t set_mask);
+
+/*
+ * Changes the global interrupt mask.  The set and clear masks are re-applied
+ * every time the global interrupt mask is updated for callback registration
+ * and de-registration.
+ *
+ * The clear mask is applied first, so if a bit is set to 1 in both the clear
+ * mask and the set mask, the result will be that the interrupt is set.
+ *
+ * @smsm_entry  SMSM entry to change
+ * @clear_mask  1 = clear bit, 0 = no-op
+ * @set_mask    1 = set bit, 0 = no-op
+ *
+ * @returns 0 for success, < 0 for error
+ */
+int smsm_change_intr_mask(uint32_t smsm_entry,
+			  uint32_t clear_mask, uint32_t set_mask);
+int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask);
+uint32_t smsm_get_state(uint32_t smsm_entry);
+int smsm_state_cb_register(uint32_t smsm_entry, uint32_t mask,
+	void (*notify)(void *, uint32_t old_state, uint32_t new_state),
+	void *data);
+int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
+	void (*notify)(void *, uint32_t, uint32_t), void *data);
+void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
+	uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
+void smsm_reset_modem(unsigned mode);
+void smsm_reset_modem_cont(void);
+void smd_sleep_exit(void);
+
+
 int smsm_check_for_modem_crash(void);
 void *smem_find(unsigned id, unsigned size);
 void *smem_get_entry(unsigned id, unsigned *size);
+#else
+static inline void *smem_alloc(unsigned id, unsigned size)
+{
+	return NULL;
+}
 
+static inline void *smem_alloc2(unsigned id, unsigned size_in)
+{
+	return NULL;
+}
+
+static inline void *smem_get_entry(unsigned id, unsigned *size)
+{
+	return NULL;
+}
+
+static inline int smsm_change_state(uint32_t smsm_entry,
+		      uint32_t clear_mask, uint32_t set_mask)
+{
+	return -ENODEV;
+}
+
+/*
+ * Changes the global interrupt mask.  The set and clear masks are re-applied
+ * every time the global interrupt mask is updated for callback registration
+ * and de-registration.
+ *
+ * The clear mask is applied first, so if a bit is set to 1 in both the clear
+ * mask and the set mask, the result will be that the interrupt is set.
+ *
+ * @smsm_entry  SMSM entry to change
+ * @clear_mask  1 = clear bit, 0 = no-op
+ * @set_mask    1 = set bit, 0 = no-op
+ *
+ * @returns 0 for success, < 0 for error
+ */
+static inline int smsm_change_intr_mask(uint32_t smsm_entry,
+			  uint32_t clear_mask, uint32_t set_mask)
+{
+	return -ENODEV;
+}
+
+static inline int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask)
+{
+	return -ENODEV;
+}
+static inline uint32_t smsm_get_state(uint32_t smsm_entry)
+{
+	return 0;
+}
+static inline int smsm_state_cb_register(uint32_t smsm_entry, uint32_t mask,
+	void (*notify)(void *, uint32_t old_state, uint32_t new_state),
+	void *data)
+{
+	return -ENODEV;
+}
+static inline int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
+	void (*notify)(void *, uint32_t, uint32_t), void *data)
+{
+	return -ENODEV;
+}
+static inline void smsm_print_sleep_info(uint32_t sleep_delay,
+	uint32_t sleep_limit, uint32_t irq_mask, uint32_t wakeup_reason,
+	uint32_t pending_irqs)
+{
+}
+static inline void smsm_reset_modem(unsigned mode)
+{
+}
+static inline void smsm_reset_modem_cont(void)
+{
+}
+static inline void smd_sleep_exit(void)
+{
+}
+static inline int smsm_check_for_modem_crash(void)
+{
+	return -ENODEV;
+}
+static inline void *smem_find(unsigned id, unsigned size)
+{
+	return NULL;
+}
+#endif
 #endif
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.h b/arch/arm/mach-msm/include/mach/qdsp6v2/q6core.h
similarity index 81%
rename from arch/arm/mach-msm/qdsp6v2/q6core.h
rename to arch/arm/mach-msm/include/mach/qdsp6v2/q6core.h
index cb25d6b..ea345fb 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6core.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/q6core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. 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
@@ -45,8 +45,18 @@
 	uint32_t power_collapse;
 };
 
+#define ADSP_CMD_SET_DTS_MODEL_ID 0x00012917
+
+struct adsp_dts_modelid {
+	struct apr_hdr hdr;
+	uint32_t  model_ID_size;
+	uint8_t   model_ID[128];
+};
+
 int core_req_bus_bandwith(u16 bus_id, u32 ab_bps, u32 ib_bps);
 
 uint32_t core_get_adsp_version(void);
 
+uint32_t core_set_dts_model_id(uint32_t id_size, uint8_t *id);
+
 #endif /* __Q6CORE_H__ */
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index e0fec65..5ee7068 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -497,7 +497,7 @@
 
 void __init msm_map_mpq8092_io(void)
 {
-	msm_shared_ram_phys = MSM8092_MSM_SHARED_RAM_PHYS;
+	msm_shared_ram_phys = MPQ8092_MSM_SHARED_RAM_PHYS;
 	msm_map_io(mpq8092_io_desc, ARRAY_SIZE(mpq8092_io_desc));
 }
 #endif /* CONFIG_ARCH_MPQ8092 */
diff --git a/arch/arm/mach-msm/jtag.c b/arch/arm/mach-msm/jtag.c
index 4f14b19..24e1c41 100644
--- a/arch/arm/mach-msm/jtag.c
+++ b/arch/arm/mach-msm/jtag.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. 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,11 +20,10 @@
 #include <linux/printk.h>
 #include <linux/ratelimit.h>
 #include <linux/coresight.h>
+#include <asm/hardware/cp14.h>
 #include <mach/scm.h>
 #include <mach/jtag.h>
 
-#include "cp14.h"
-
 /* DBGv7 with baseline CP14 registers implemented */
 #define ARM_DEBUG_ARCH_V7B	(0x3)
 /* DBGv7 with all CP14 registers implemented */
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index f548417..77eeb53 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -110,8 +110,12 @@
 
 	/* Wait for the modem to complete its power down actions. */
 	for (i = 20; i > 0; i--) {
-		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
+		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0) {
+			if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG)
+				pr_info("%s: mdm2ap_status went low, i = %d\n",
+					__func__, i);
 			break;
+		}
 		msleep(100);
 	}
 	if (i == 0) {
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index ea15a17..58b26f2 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -290,6 +290,17 @@
 		} else
 			pr_debug("%s Image upgrade not supported\n", __func__);
 		break;
+	case SHUTDOWN_CHARM:
+		if (!mdm_drv->pdata->send_shdn)
+			break;
+		mdm_drv->mdm_ready = 0;
+		if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG)
+			pr_info("Sending shutdown request to mdm\n");
+		ret = sysmon_send_shutdown(SYSMON_SS_EXT_MODEM);
+		if (ret)
+			pr_err("%s: Graceful shutdown of the external modem failed, ret = %d\n",
+				   __func__, ret);
+		break;
 	default:
 		pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
 		ret = -EINVAL;
@@ -382,6 +393,9 @@
 {
 	int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
 
+	if ((mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG) && (value == 0))
+		pr_info("%s: mdm2ap_status went low\n", __func__);
+
 	pr_debug("%s: mdm sent status change interrupt\n", __func__);
 	if (value == 0 && mdm_drv->mdm_ready == 1) {
 		pr_info("%s: unexpected reset external modem\n", __func__);
diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h
index c406b89a..9e865c5 100644
--- a/arch/arm/mach-msm/mdm_private.h
+++ b/arch/arm/mach-msm/mdm_private.h
@@ -14,6 +14,7 @@
 #define _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H
 
 #define MDM_DEBUG_MASK_VDDMIN_SETUP (0x00000002)
+#define MDM_DEBUG_MASK_SHDN_LOG     (0x00000004)
 #define GPIO_IS_VALID(gpio) \
 	(gpio != -1)
 struct mdm_modem_drv;
diff --git a/arch/arm/mach-msm/modem-ssr-8974.c b/arch/arm/mach-msm/modem-ssr-8974.c
index fec578f..942eca5 100644
--- a/arch/arm/mach-msm/modem-ssr-8974.c
+++ b/arch/arm/mach-msm/modem-ssr-8974.c
@@ -15,10 +15,14 @@
 #include <linux/module.h>
 #include <linux/err.h>
 
+#include <mach/peripheral-loader.h>
 #include <mach/subsystem_restart.h>
 #include <mach/msm_smsm.h>
 
+#include "ramdump.h"
+
 static int crash_shutdown;
+static int modem_ssr_ignore_errors;
 static struct subsys_device *modem_ssr_dev;
 
 #define MAX_SSR_REASON_LEN 81U
@@ -50,6 +54,7 @@
 static void restart_modem(void)
 {
 	log_modem_sfr();
+	modem_ssr_ignore_errors = 1;
 	subsystem_restart("modem");
 }
 
@@ -67,11 +72,21 @@
 
 static int modem_shutdown(const struct subsys_desc *subsys)
 {
+	pil_force_shutdown("modem");
+	pil_force_shutdown("mba");
 	return 0;
 }
 
 static int modem_powerup(const struct subsys_desc *subsys)
 {
+	/*
+	 * At this time, the modem is shutdown. Therefore this function cannot
+	 * run concurrently with either the watchdog bite error handler or the
+	 * SMSM callback, making it safe to unset the flag below.
+	 */
+	modem_ssr_ignore_errors = 0;
+	pil_force_boot("mba");
+	pil_force_boot("modem");
 	return 0;
 }
 
@@ -81,15 +96,53 @@
 	smsm_reset_modem(SMSM_RESET);
 }
 
-static int modem_ramdump(int enable,
-				const struct subsys_desc *crashed_subsys)
+static struct ramdump_segment modem_segments[] = {
+	{0x08400000, 0x0D100000 - 0x08400000},
+};
+
+static struct ramdump_segment smem_segments[] = {
+	{0x0FA00000, 0x0FC00000 - 0x0FA00000},
+};
+
+static void *modem_ramdump_dev;
+static void *smem_ramdump_dev;
+
+static int modem_ramdump(int enable, const struct subsys_desc *crashed_subsys)
 {
-	return 0;
+	int ret = 0;
+
+	if (!enable)
+		return ret;
+
+	pil_force_boot("mba");
+
+	ret = do_ramdump(modem_ramdump_dev, modem_segments,
+				ARRAY_SIZE(modem_segments));
+
+	if (ret < 0) {
+		pr_err("Unable to dump modem fw memory (rc = %d).\n",
+			ret);
+		goto out;
+	}
+
+	ret = do_ramdump(smem_ramdump_dev, smem_segments,
+		ARRAY_SIZE(smem_segments));
+
+	if (ret < 0) {
+		pr_err("Unable to dump smem memory (rc = %d).\n", ret);
+		goto out;
+	}
+
+out:
+	pil_force_shutdown("mba");
+	return ret;
 }
 
 static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
 {
-	pr_err("Watchdog bite received from modem software!\n");
+	if (modem_ssr_ignore_errors)
+		return IRQ_HANDLED;
+	pr_err("Watchdog bite received from the modem!\n");
 	restart_modem();
 	return IRQ_HANDLED;
 }
@@ -133,9 +186,27 @@
 		goto out;
 	}
 
+	modem_ramdump_dev = create_ramdump_device("modem");
+
+	if (!modem_ramdump_dev) {
+		pr_err("%s: Unable to create a modem ramdump device.\n",
+			__func__);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	smem_ramdump_dev = create_ramdump_device("smem-modem");
+
+	if (!smem_ramdump_dev) {
+		pr_err("%s: Unable to create an smem ramdump device.\n",
+			__func__);
+		ret = -ENOMEM;
+		goto out;
+	}
+
 	pr_info("%s: modem subsystem restart driver init'ed.\n", __func__);
 out:
 	return ret;
 }
 
-arch_initcall(modem_8974_init);
+module_init(modem_8974_init);
diff --git a/arch/arm/mach-msm/mpm.c b/arch/arm/mach-msm/mpm.c
index 1c39415..5127607 100644
--- a/arch/arm/mach-msm/mpm.c
+++ b/arch/arm/mach-msm/mpm.c
@@ -388,6 +388,7 @@
 {
 	unsigned long *apps_irq_bitmap;
 	int debug_mask;
+	int i = 0;
 
 	if (from_idle) {
 		apps_irq_bitmap = msm_mpm_enabled_apps_irqs;
@@ -400,15 +401,17 @@
 	}
 
 	if (debug_mask) {
-		static char buf[DIV_ROUND_UP(MSM_MPM_NR_APPS_IRQS, 32)*9+1];
+		i = find_first_bit(apps_irq_bitmap, MSM_MPM_NR_APPS_IRQS);
+		while (i < MSM_MPM_NR_APPS_IRQS) {
+			struct irq_desc *desc = i ?
+				irq_to_desc(i) : NULL;
+			pr_info("%s: cannot monitor irq=%d %s\n",
+			__func__, i, desc->name);
+			i = find_next_bit(apps_irq_bitmap,
+				MSM_MPM_NR_APPS_IRQS, i + 1);
+		}
 
-		bitmap_scnprintf(buf, sizeof(buf), apps_irq_bitmap,
-				MSM_MPM_NR_APPS_IRQS);
-		buf[sizeof(buf) - 1] = '\0';
-
-		pr_info("%s: cannot monitor %s", __func__, buf);
 	}
-
 	return (bool)__bitmap_empty(apps_irq_bitmap, MSM_MPM_NR_APPS_IRQS);
 }
 
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index 6dde576..c39829b 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -45,7 +45,7 @@
 #include "timer.h"
 
 #define DRV_NAME	"msm_dsps"
-#define DRV_VERSION	"4.02"
+#define DRV_VERSION	"4.03"
 
 
 #define PPSS_TIMER0_32KHZ_REG	0x1004
@@ -771,6 +771,11 @@
 {
 	pr_debug("%s\n", __func__);
 	disable_irq_nosync(drv->wdog_irq);
+	if (drv->pdata->ppss_wdog_unmasked_int_en_reg) {
+		writel_relaxed(0, (drv->ppss_base+
+			drv->pdata->ppss_wdog_unmasked_int_en_reg));
+		mb(); /* Make sure wdog is disabled before shutting down */
+	}
 	pil_force_shutdown(drv->pdata->pil_name);
 	dsps_power_off_handler();
 	return 0;
@@ -799,6 +804,7 @@
 static void dsps_crash_shutdown(const struct subsys_desc *subsys)
 {
 	pr_debug("%s\n", __func__);
+	disable_irq_nosync(drv->wdog_irq);
 	dsps_crash_shutdown_g = 1;
 	smsm_change_state(SMSM_DSPS_STATE, SMSM_RESET, SMSM_RESET);
 }
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index 5a85eec..9a85a17 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -856,7 +856,7 @@
 /* Interfaces invoked from the scheduler */
 int ocmem_memory_off(int id, unsigned long offset, unsigned long len)
 {
-	return switch_power_state(id, offset, len, REGION_DEFAULT_OFF);
+	return switch_power_state(id, offset, len, REGION_DEFAULT_ON);
 }
 
 int ocmem_memory_on(int id, unsigned long offset, unsigned long len)
@@ -866,7 +866,7 @@
 
 int ocmem_memory_retain(int id, unsigned long offset, unsigned long len)
 {
-	return switch_power_state(id, offset, len, REGION_DEFAULT_RETENTION);
+	return switch_power_state(id, offset, len, REGION_DEFAULT_ON);
 }
 
 static int ocmem_power_show_sw_state(struct seq_file *f, void *dummy)
diff --git a/arch/arm/mach-msm/pil-mba.c b/arch/arm/mach-msm/pil-mba.c
index 5e67d4f..0207f0b 100644
--- a/arch/arm/mach-msm/pil-mba.c
+++ b/arch/arm/mach-msm/pil-mba.c
@@ -172,7 +172,7 @@
 		return -ENOMEM;
 	platform_set_drvdata(pdev, drv);
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb_base");
 	if (!res)
 		return -EINVAL;
 	drv->reg_base = devm_ioremap(&pdev->dev, res->start,
@@ -180,7 +180,8 @@
 	if (!drv->reg_base)
 		return -ENOMEM;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					    "metadata_base");
 	if (res) {
 		drv->metadata_base = devm_ioremap(&pdev->dev, res->start,
 						  resource_size(res));
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 01cdb0b..1e39043 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -233,7 +233,7 @@
 	int ret;
 	uint32_t regval;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmu_base");
 	if (!res)
 		return -EINVAL;
 
@@ -246,14 +246,14 @@
 	if (!drv->base)
 		return -ENOMEM;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clk_base");
 	if (!res)
 		return -EINVAL;
 
 	drv->reset_base = devm_ioremap(&pdev->dev, res->start,
 					resource_size(res));
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_base");
 	if (!res)
 		return -EINVAL;
 
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 1fdd342..7b45a0e 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -266,20 +266,21 @@
 	of_property_read_u32(pdev->dev.of_node, "qcom,pil-self-auth",
 			     &drv->self_auth);
 	if (drv->self_auth) {
-		res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						    "rmb_base");
 		drv->rmb_base = devm_ioremap(&pdev->dev, res->start,
 					     resource_size(res));
 		if (!drv->rmb_base)
 			return -ENOMEM;
 	}
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "restart_reg");
 	drv->restart_reg = devm_ioremap(&pdev->dev, res->start,
 					resource_size(res));
 	if (!drv->restart_reg)
 		return -ENOMEM;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clamp_reg");
 	drv->io_clamp_reg = devm_ioremap(&pdev->dev, res->start,
 					resource_size(res));
 	if (!drv->io_clamp_reg)
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index 772031b..f4e8844 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -205,14 +205,14 @@
 		return ERR_PTR(-ENOMEM);
 	platform_set_drvdata(pdev, drv);
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6_base");
 	if (!res)
 		return ERR_PTR(-EINVAL);
 	drv->reg_base = devm_ioremap(&pdev->dev, res->start,
 				     resource_size(res));
 	if (!drv->reg_base)
 		return ERR_PTR(-ENOMEM);
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_base");
 	drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
 					  resource_size(res));
 	if (!drv->axi_halt_base)
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
index 1ccde72..e331296 100644
--- a/arch/arm/mach-msm/pil-venus.c
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -388,7 +388,8 @@
 	struct pil_desc *desc;
 	int rc;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					    "wrapper_base");
 	if (!res)
 		return -EINVAL;
 
@@ -402,7 +403,7 @@
 	if (!drv->venus_wrapper_base)
 		return -ENOMEM;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vbif_base");
 	if (!res)
 		return -EINVAL;
 
diff --git a/arch/arm/mach-msm/qdsp5/adsp_driver.c b/arch/arm/mach-msm/qdsp5/adsp_driver.c
index 9d261ae..6419bd0 100644
--- a/arch/arm/mach-msm/qdsp5/adsp_driver.c
+++ b/arch/arm/mach-msm/qdsp5/adsp_driver.c
@@ -139,7 +139,7 @@
 		pr_err("%s: could not get flags for the handle\n", __func__);
 		goto flag_error;
 	}
-	temp_ptr = ion_map_kernel(region->client, region->handle, ionflag);
+	temp_ptr = ion_map_kernel(region->client, region->handle);
 	if (IS_ERR_OR_NULL(temp_ptr)) {
 		pr_err("%s: could not get virtual address\n", __func__);
 		goto map_error;
@@ -267,7 +267,7 @@
 			module->name, vaddr, len);
 		return ret;
 	}
-	if ((region->ion_flag == CACHED) && region->handle) {
+	if ((region->ion_flag == ION_FLAG_CACHED) && region->handle) {
 		len = ((((len) + 31) & (~31)) + 32);
 		ret = msm_ion_do_cache_op(region->client, region->handle,
 				(void *)paddr, len, cmd);
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c
index ac7cca3..46a80d7 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac.c
@@ -1716,7 +1716,7 @@
 
 	MM_DBG("allocating mem sz = %d\n", mem_sz);
 	handle = ion_alloc(client, mem_sz, SZ_4K,
-		ION_HEAP(ION_AUDIO_HEAP_ID));
+		ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		rc = -ENOMEM;
@@ -1742,7 +1742,7 @@
 		goto output_buff_get_flags_error;
 	}
 
-	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	audio->map_v_write = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_write)) {
 		MM_ERR("could not map write buffers,freeing instance 0x%08x\n",
 				(int)audio);
@@ -1758,7 +1758,7 @@
 	mem_sz = (PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT);
 	MM_DBG("allocating mem sz = %d\n", mem_sz);
 	handle = ion_alloc(client, mem_sz,
-			SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+			SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate I/P buffers\n");
 		rc = -ENOMEM;
@@ -1785,8 +1785,7 @@
 		goto input_buff_get_flags_error;
 	}
 
-	audio->map_v_read = ion_map_kernel(client,
-		handle, ionflag);
+	audio->map_v_read = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_read)) {
 		MM_ERR("could not map read buffers, freeing instance \
 				0x%08x\n", (int)audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac_in.c b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
index 2e64a09..c86c1dd 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
@@ -1370,7 +1370,7 @@
 
 	MM_DBG("allocating mem sz = %d\n", dma_size);
 	handle = ion_alloc(client, dma_size, SZ_4K,
-		ION_HEAP(ION_AUDIO_HEAP_ID));
+		ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		rc = -ENOMEM;
@@ -1398,7 +1398,7 @@
 		goto output_buff_get_flags_error;
 	}
 
-	audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+	audio->map_v_read = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_read)) {
 		MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
 				(int)audio);
@@ -1414,7 +1414,7 @@
 
 		MM_DBG("allocating BUFFER_SIZE  %d\n", BUFFER_SIZE);
 		handle = ion_alloc(client, BUFFER_SIZE,
-				SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+				SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 		if (IS_ERR_OR_NULL(handle)) {
 			MM_ERR("Unable to create allocate I/P buffers\n");
 			rc = -ENOMEM;
@@ -1444,8 +1444,7 @@
 			goto input_buff_get_flags_error;
 		}
 
-		audio->map_v_write = ion_map_kernel(client,
-			handle, ionflag);
+		audio->map_v_write = ion_map_kernel(client, handle);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could not map write buffers\n");
 			rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_ac3.c b/arch/arm/mach-msm/qdsp5/audio_ac3.c
index 63904fb..e453ec5 100644
--- a/arch/arm/mach-msm/qdsp5/audio_ac3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_ac3.c
@@ -1029,7 +1029,7 @@
 				handle = ion_alloc(audio->client,
 					(config.buffer_size *
 					config.buffer_count),
-					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 				if (IS_ERR_OR_NULL(handle)) {
 					MM_ERR("Unable to alloc I/P buffs\n");
 					audio->input_buff_handle = NULL;
@@ -1067,8 +1067,7 @@
 				}
 
 				audio->map_v_read = ion_map_kernel(
-					audio->client,
-					handle, ionflag);
+					audio->client, handle);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("map of read buf failed\n");
 					ion_free(audio->client, handle);
@@ -1588,7 +1587,7 @@
 	audio->client = client;
 
 	handle = ion_alloc(client, DMASZ, SZ_4K,
-			ION_HEAP(ION_AUDIO_HEAP_ID));
+			ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		rc = -ENOMEM;
@@ -1614,7 +1613,7 @@
 		goto output_buff_get_flags_error;
 	}
 
-	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	audio->map_v_write = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_write)) {
 		MM_ERR("could not map write buffers,freeing instance 0x%08x\n",
 				(int)audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index 8aa102a..0792e3f 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -981,7 +981,7 @@
 				handle = ion_alloc(audio->client,
 					(config.buffer_size *
 					config.buffer_count),
-					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 				if (IS_ERR_OR_NULL(handle)) {
 					MM_ERR("Unable to alloc I/P buffs\n");
 					audio->input_buff_handle = NULL;
@@ -1018,8 +1018,7 @@
 					break;
 				}
 				audio->map_v_read = ion_map_kernel(
-					audio->client,
-					handle, ionflag);
+					audio->client, handle);
 			if (IS_ERR(audio->map_v_read)) {
 				MM_ERR("failed to map read buf\n");
 				ion_free(audio->client, handle);
@@ -1536,7 +1535,7 @@
 	audio->client = client;
 
 	handle = ion_alloc(client, mem_sz, SZ_4K,
-		ION_HEAP(ION_AUDIO_HEAP_ID));
+		ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		rc = -ENOMEM;
@@ -1562,7 +1561,7 @@
 		goto output_buff_get_flags_error;
 	}
 
-	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	audio->map_v_write = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_write)) {
 		MM_ERR("could not map write buffers\n");
 		rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
index 4effc8e..0742686 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
@@ -1336,7 +1336,7 @@
 	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
 		MM_DBG("allocating BUFFER_SIZE  %d\n", BUFFER_SIZE);
 		handle = ion_alloc(client, BUFFER_SIZE,
-				SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+				SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 		if (IS_ERR_OR_NULL(handle)) {
 			MM_ERR("Unable to create allocate write buffers\n");
 			rc = -ENOMEM;
@@ -1366,8 +1366,7 @@
 			goto input_buff_get_flags_error;
 		}
 
-		audio->map_v_write = ion_map_kernel(client,
-			handle, ionflag);
+		audio->map_v_write = ion_map_kernel(client, handle);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could not map write buffers\n");
 			rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrwb.c b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
index 83320f3..7d37cea 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
@@ -977,7 +977,7 @@
 				handle = ion_alloc(audio->client,
 					(config.buffer_size *
 					config.buffer_count),
-					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 				if (IS_ERR_OR_NULL(handle)) {
 					MM_ERR("Unable to alloc I/P buffs\n");
 					audio->input_buff_handle = NULL;
@@ -1014,8 +1014,7 @@
 					break;
 				}
 				audio->map_v_read = ion_map_kernel(
-					audio->client,
-					handle, ionflag);
+					audio->client, handle);
 			if (IS_ERR(audio->map_v_read)) {
 				MM_ERR("failed to map mem for read buf\n");
 				ion_free(audio->client, handle);
@@ -1600,7 +1599,7 @@
 	audio->client = client;
 
 	handle = ion_alloc(client, mem_sz, SZ_4K,
-		ION_HEAP(ION_AUDIO_HEAP_ID));
+		ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		goto output_buff_alloc_error;
@@ -1625,7 +1624,7 @@
 		goto output_buff_get_flags_error;
 	}
 
-	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	audio->map_v_write = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_write)) {
 		MM_ERR("could not map write buffers\n");
 		rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c
index c0486db..155b0e1 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c
@@ -966,7 +966,7 @@
 				handle = ion_alloc(audio->client,
 					(config.buffer_size *
 					config.buffer_count),
-					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 				if (IS_ERR_OR_NULL(handle)) {
 					MM_ERR("Unable to alloc I/P buffs\n");
 					audio->input_buff_handle = NULL;
@@ -1003,8 +1003,7 @@
 					break;
 				}
 				audio->map_v_read = ion_map_kernel(
-					audio->client,
-					handle, ionflag);
+					audio->client, handle);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("failed to map mem"
 							" for read buf\n");
@@ -1527,7 +1526,7 @@
 	audio->client = client;
 
 	handle = ion_alloc(client, mem_sz, SZ_4K,
-		ION_HEAP(ION_AUDIO_HEAP_ID));
+		ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		rc = -ENOMEM;
@@ -1553,7 +1552,7 @@
 		goto output_buff_get_flags_error;
 	}
 
-	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	audio->map_v_write = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_write)) {
 		MM_ERR("could not map write buffers\n");
 		rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
index 9bf0e83..89ad974 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
@@ -1310,7 +1310,7 @@
 
 	MM_DBG("allocating mem sz = %d\n", dma_size);
 	handle = ion_alloc(client, dma_size, SZ_4K,
-		ION_HEAP(ION_AUDIO_HEAP_ID));
+		ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		rc = -ENOMEM;
@@ -1338,7 +1338,7 @@
 		goto output_buff_get_flags_error;
 	}
 
-	audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+	audio->map_v_read = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_read)) {
 		MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
 				(int)audio);
@@ -1353,7 +1353,7 @@
 	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
 		MM_DBG("allocating BUFFER_SIZE  %d\n", BUFFER_SIZE);
 		handle = ion_alloc(client, BUFFER_SIZE,
-				SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+				SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 		if (IS_ERR_OR_NULL(handle)) {
 			MM_ERR("Unable to create allocate I/P buffers\n");
 			rc = -ENOMEM;
@@ -1383,8 +1383,7 @@
 			goto input_buff_alloc_error;
 		}
 
-		audio->map_v_write = ion_map_kernel(client,
-			handle, ionflag);
+		audio->map_v_write = ion_map_kernel(client, handle);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could not map write buffers\n");
 			rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_lpa.c b/arch/arm/mach-msm/qdsp5/audio_lpa.c
index a067b83..8120d7b 100644
--- a/arch/arm/mach-msm/qdsp5/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp5/audio_lpa.c
@@ -741,7 +741,7 @@
 		pr_err("%s: could not get flags for the handle\n", __func__);
 		goto flag_error;
 	}
-	kvaddr = (unsigned long)ion_map_kernel(audio->client, handle, ionflag);
+	kvaddr = (unsigned long)ion_map_kernel(audio->client, handle);
 	if (IS_ERR_OR_NULL((void *)kvaddr)) {
 		pr_err("%s: could not get virtual address\n", __func__);
 		goto map_error;
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
index cef3d99..b8c64be 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c
@@ -1095,7 +1095,7 @@
 		goto flag_error;
 	}
 
-	temp_ptr = ion_map_kernel(audio->client, handle, ionflag);
+	temp_ptr = ion_map_kernel(audio->client, handle);
 	if (IS_ERR_OR_NULL(temp_ptr)) {
 		pr_err("%s: could not get virtual address\n", __func__);
 		goto map_error;
@@ -1525,7 +1525,7 @@
 				handle = ion_alloc(audio->client,
 					(config.buffer_size *
 					config.buffer_count),
-					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 				if (IS_ERR_OR_NULL(handle)) {
 					MM_ERR("Unable to alloc I/P buffs\n");
 					rc = -ENOMEM;
@@ -1558,8 +1558,7 @@
 				}
 
 				audio->map_v_read = ion_map_kernel(
-					audio->client,
-					handle, ionflag);
+					audio->client, handle);
 
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("map of read buf failed\n");
@@ -2254,7 +2253,7 @@
 		MM_DBG("memsz = %d\n", mem_sz);
 
 		handle = ion_alloc(client, mem_sz, SZ_4K,
-			ION_HEAP(ION_AUDIO_HEAP_ID));
+			ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 		if (IS_ERR_OR_NULL(handle)) {
 			MM_ERR("Unable to create allocate O/P buffers\n");
 			rc = -ENOMEM;
@@ -2280,7 +2279,7 @@
 			goto output_buff_get_flags_error;
 		}
 
-		audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+		audio->map_v_write = ion_map_kernel(client, handle);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could not map write buffers\n");
 			rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_mvs.c b/arch/arm/mach-msm/qdsp5/audio_mvs.c
index 158dd46..c0e670c 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mvs.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mvs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. 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
@@ -1187,6 +1187,9 @@
 			       rpc_hdr_len);
 
 			break;
+		} else if ((rpc_hdr_len == 0) &&
+				(audio->state == AUDIO_MVS_CLOSED)) {
+			break;
 		} else if (rpc_hdr_len < RPC_COMMON_HDR_SZ) {
 			continue;
 		} else {
@@ -1353,8 +1356,11 @@
 	mutex_lock(&audio->lock);
 	if (audio->state == AUDIO_MVS_STARTED)
 		audio_mvs_stop(audio);
-	audio_mvs_free_buf(audio);
 	audio->state = AUDIO_MVS_CLOSED;
+	msm_rpc_read_wakeup(audio->rpc_endpt);
+	msm_rpc_close(audio->rpc_endpt);
+	audio->task = NULL;
+	audio_mvs_free_buf(audio);
 	mutex_unlock(&audio->lock);
 
 	MM_DBG("Release done\n");
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c
index 340bcc6..3eb72c8 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c
@@ -823,7 +823,7 @@
 		pr_err("%s: could not get flags for the handle\n", __func__);
 		goto flag_error;
 	}
-	kvaddr = (unsigned long)ion_map_kernel(audio->client, handle, ionflag);
+	kvaddr = (unsigned long)ion_map_kernel(audio->client, handle);
 	if (IS_ERR_OR_NULL((void *)kvaddr)) {
 		pr_err("%s: could not get virtual address\n", __func__);
 		goto map_error;
@@ -1576,7 +1576,7 @@
 		MM_DBG("memsz = %d\n", mem_sz);
 
 		handle = ion_alloc(client, mem_sz, SZ_4K,
-			ION_HEAP(ION_AUDIO_HEAP_ID));
+			ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 		if (IS_ERR_OR_NULL(handle)) {
 			MM_ERR("Unable to create allocate O/P buffers\n");
 			rc = -ENOMEM;
@@ -1602,7 +1602,7 @@
 			goto output_buff_get_flags_error;
 		}
 
-		audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+		audio->map_v_write = ion_map_kernel(client, handle);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could not map write buffers\n");
 			rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
index 2da1f19..68ffcfef 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
@@ -843,7 +843,7 @@
 
 	MM_DBG("allocating mem sz = %d\n", DMASZ);
 	handle = ion_alloc(client, DMASZ, SZ_4K,
-		ION_HEAP(ION_AUDIO_HEAP_ID));
+		ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		rc = -ENOMEM;
@@ -871,7 +871,7 @@
 		goto output_buff_get_flags_error;
 	}
 
-	audio->data = ion_map_kernel(client, handle, ionflag);
+	audio->data = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->data)) {
 		MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
 				(int)audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
index 1a0c333..876c909 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
@@ -967,7 +967,7 @@
 				handle = ion_alloc(audio->client,
 					(config.buffer_size *
 					config.buffer_count),
-					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 				if (IS_ERR_OR_NULL(handle)) {
 					MM_ERR("Unable to alloc I/P buffs\n");
 					audio->input_buff_handle = NULL;
@@ -1004,8 +1004,7 @@
 					break;
 				}
 				audio->map_v_read = ion_map_kernel(
-					audio->client,
-					handle, ionflag);
+					audio->client, handle);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("failed to map read buf\n");
 					ion_free(audio->client, handle);
@@ -1525,7 +1524,7 @@
 	audio->client = client;
 
 	handle = ion_alloc(client, mem_sz, SZ_4K,
-		ION_HEAP(ION_AUDIO_HEAP_ID));
+		ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		rc = -ENOMEM;
@@ -1551,7 +1550,7 @@
 		goto output_buff_get_flags_error;
 	}
 
-	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	audio->map_v_write = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_write)) {
 		MM_ERR("could not map write buffers\n");
 		rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
index ee079bc..6ca3382 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -1312,7 +1312,7 @@
 
 	MM_DBG("allocating mem sz = %d\n", dma_size);
 	handle = ion_alloc(client, dma_size, SZ_4K,
-		ION_HEAP(ION_AUDIO_HEAP_ID));
+		ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		rc = -ENOMEM;
@@ -1340,7 +1340,7 @@
 		goto output_buff_get_flags_error;
 	}
 
-	audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+	audio->map_v_read = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_read)) {
 		MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
 				(int)audio);
@@ -1355,7 +1355,7 @@
 	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
 		MM_DBG("allocating BUFFER_SIZE  %d\n", BUFFER_SIZE);
 		handle = ion_alloc(client, BUFFER_SIZE,
-				SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+				SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 		if (IS_ERR_OR_NULL(handle)) {
 			MM_ERR("Unable to create allocate I/P buffers\n");
 			rc = -ENOMEM;
@@ -1385,8 +1385,7 @@
 			goto input_buff_get_flags_error;
 		}
 
-		audio->map_v_write = ion_map_kernel(client,
-			handle, ionflag);
+		audio->map_v_write = ion_map_kernel(client, handle);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could not map write buffers\n");
 			rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_wma.c b/arch/arm/mach-msm/qdsp5/audio_wma.c
index 0a77b58..6d520b4 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wma.c
@@ -1045,7 +1045,7 @@
 				handle = ion_alloc(audio->client,
 					(config.buffer_size *
 					config.buffer_count),
-					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 				if (IS_ERR_OR_NULL(handle)) {
 					MM_ERR("Unable to alloc I/P buffs\n");
 					audio->input_buff_handle = NULL;
@@ -1083,8 +1083,7 @@
 				}
 
 				audio->map_v_read = ion_map_kernel(
-					audio->client,
-					handle, ionflag);
+					audio->client, handle);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("map of read buf failed\n");
 					ion_free(audio->client, handle);
@@ -1678,7 +1677,7 @@
 	audio->client = client;
 
 	handle = ion_alloc(client, mem_sz, SZ_4K,
-		ION_HEAP(ION_AUDIO_HEAP_ID));
+		ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		rc = -ENOMEM;
@@ -1704,7 +1703,7 @@
 		goto output_buff_get_flags_error;
 	}
 
-	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	audio->map_v_write = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_write)) {
 		MM_ERR("could not map write buffers\n");
 		rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_wmapro.c b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
index 82fc3f9..a08f3c9 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
@@ -1042,7 +1042,7 @@
 				handle = ion_alloc(audio->client,
 					(config.buffer_size *
 					config.buffer_count),
-					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 				if (IS_ERR_OR_NULL(handle)) {
 					MM_ERR("Unable to alloc I/P buffs\n");
 					audio->input_buff_handle = NULL;
@@ -1080,8 +1080,7 @@
 				}
 
 				audio->map_v_read = ion_map_kernel(
-					audio->client,
-					handle, ionflag);
+					audio->client, handle);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("map of read buf failed\n");
 					ion_free(audio->client, handle);
@@ -1673,7 +1672,7 @@
 	audio->client = client;
 
 	handle = ion_alloc(client, mem_sz, SZ_4K,
-		ION_HEAP(ION_AUDIO_HEAP_ID));
+		ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		rc = -ENOMEM;
@@ -1699,7 +1698,7 @@
 		goto output_buff_get_flags_error;
 	}
 
-	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	audio->map_v_write = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_write)) {
 		MM_ERR("could not map write buffers\n");
 		rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
index 2f03cd0..f1951f7 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
@@ -803,7 +803,7 @@
 	audio->client = client;
 
 	handle = ion_alloc(client, DMASZ, SZ_4K,
-		ION_HEAP(ION_AUDIO_HEAP_ID));
+		ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		rc = -ENOMEM;
@@ -828,7 +828,7 @@
 		goto buff_get_flags_error;
 	}
 
-	audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+	audio->map_v_read = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_read)) {
 		MM_ERR("could not map write buffers\n");
 		rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
index 1180e8d..6e95dc5 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
@@ -1363,7 +1363,7 @@
 
 	MM_DBG("allocating mem sz = %d\n", DMASZ);
 	handle = ion_alloc(client, DMASZ, SZ_4K,
-		ION_HEAP(ION_AUDIO_HEAP_ID));
+		ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		rc = -ENOMEM;
@@ -1391,7 +1391,7 @@
 		goto output_buff_get_flags_error;
 	}
 
-	audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+	audio->map_v_read = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_read)) {
 		MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
 				(int)audio);
@@ -1458,7 +1458,7 @@
 
 	MM_DBG("allocating BUFFER_SIZE  %d\n", BUFFER_SIZE);
 	handle = ion_alloc(client, BUFFER_SIZE,
-			SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+			SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate I/P buffers\n");
 		rc = -ENOMEM;
@@ -1488,8 +1488,7 @@
 		goto input_buff_alloc_error;
 	}
 
-	audio->map_v_write = ion_map_kernel(client,
-		handle, ionflag);
+	audio->map_v_write = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_write)) {
 		MM_ERR("could not map write buffers\n");
 		rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
index 7fac2ea..8ad738e 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
@@ -1368,7 +1368,7 @@
 
 	MM_DBG("allocating mem sz = %d\n", DMASZ);
 	handle = ion_alloc(client, DMASZ, SZ_4K,
-		ION_HEAP(ION_AUDIO_HEAP_ID));
+		ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		rc = -ENOMEM;
@@ -1396,7 +1396,7 @@
 		goto output_buff_get_flags_error;
 	}
 
-	audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+	audio->map_v_read = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_read)) {
 		MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
 				(int)audio);
@@ -1465,7 +1465,7 @@
 
 	MM_DBG("allocating BUFFER_SIZE  %d\n", BUFFER_SIZE);
 	handle = ion_alloc(client, BUFFER_SIZE,
-			SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+			SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate I/P buffers\n");
 		rc = -ENOMEM;
@@ -1495,8 +1495,7 @@
 		goto input_buff_alloc_error;
 	}
 
-	audio->map_v_write = ion_map_kernel(client,
-		handle, ionflag);
+	audio->map_v_write = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_write)) {
 		MM_ERR("could not map write buffers\n");
 		rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_wma.c b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
index 4ba5821..8562020 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
@@ -1061,7 +1061,7 @@
 				handle = ion_alloc(audio->client,
 					(config.buffer_size *
 					config.buffer_count),
-					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 				if (IS_ERR_OR_NULL(handle)) {
 					MM_ERR("Unable to alloc I/P buffs\n");
 					audio->input_buff_handle = NULL;
@@ -1099,8 +1099,7 @@
 				}
 
 				audio->map_v_read = ion_map_kernel(
-					audio->client,
-					handle, ionflag);
+					audio->client, handle);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("map of read buf failed\n");
 					ion_free(audio->client, handle);
@@ -1696,7 +1695,7 @@
 	audio->client = client;
 
 	handle = ion_alloc(client, mem_sz, SZ_4K,
-		ION_HEAP(ION_AUDIO_HEAP_ID));
+		ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		MM_ERR("Unable to create allocate O/P buffers\n");
 		rc = -ENOMEM;
@@ -1722,7 +1721,7 @@
 		goto output_buff_get_flags_error;
 	}
 
-	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	audio->map_v_write = ion_map_kernel(client, handle);
 	if (IS_ERR(audio->map_v_write)) {
 		MM_ERR("could not map write buffers\n");
 		rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc.c b/arch/arm/mach-msm/qdsp6v2/adsprpc.c
index 6e6f8e8..49008de 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsprpc.c
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc.c
@@ -73,11 +73,10 @@
 	int err = 0;
 
 	buf->handle = ion_alloc(clnt, buf->size, SZ_4K,
-				ION_HEAP(ION_AUDIO_HEAP_ID));
+				ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	VERIFY(0 == IS_ERR_OR_NULL(buf->handle));
 	buf->virt = 0;
-	VERIFY(0 != (buf->virt = ion_map_kernel(clnt, buf->handle,
-						ION_SET_CACHE(CACHED))));
+	VERIFY(0 != (buf->virt = ion_map_kernel(clnt, buf->handle)));
 	VERIFY(0 == ion_phys(clnt, buf->handle, &buf->phys, &buf->size));
  bail:
 	if (err && !IS_ERR_OR_NULL(buf->handle))
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index 7298fa1..7272f97 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -662,7 +662,7 @@
 	}
 
 	kvptr = ion_map_kernel(acdb_data.ion_client,
-		acdb_data.ion_handle, 0);
+		acdb_data.ion_handle);
 	if (IS_ERR_OR_NULL(kvptr)) {
 		pr_err("%s: Could not get kernel virt addr!!!\n", __func__);
 		result = PTR_ERR(kvptr);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
index b5a382e..176f364 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
@@ -486,7 +486,7 @@
 		goto flag_error;
 	}
 
-	temp_ptr = ion_map_kernel(audio->client, handle, ionflag);
+	temp_ptr = ion_map_kernel(audio->client, handle);
 	if (IS_ERR_OR_NULL(temp_ptr)) {
 		pr_err("%s: could not get virtual address\n", __func__);
 		goto map_error;
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 84a79cd..28bf5c6 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -676,7 +676,7 @@
 		goto flag_error;
 	}
 
-	temp_ptr = ion_map_kernel(audio->client, handle, ionflag);
+	temp_ptr = ion_map_kernel(audio->client, handle);
 	if (IS_ERR_OR_NULL(temp_ptr)) {
 		pr_err("%s: could not get virtual address\n", __func__);
 		goto map_error;
diff --git a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
index c19fd85..63b3064 100644
--- a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
+++ b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
@@ -26,7 +26,7 @@
 #include <mach/msm_hdmi_audio.h>
 #include <mach/audio_dma_msm8k.h>
 #include <sound/dai.h>
-#include "q6core.h"
+#include <mach/qdsp6v2/q6core.h>
 
 #define DMA_ALLOC_BUF_SZ		(SZ_4K * 16)
 
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.c b/arch/arm/mach-msm/qdsp6v2/q6core.c
index d7de50e..9dd66e1 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6core.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6core.c
@@ -26,7 +26,7 @@
 #include <linux/delay.h>
 #include <mach/msm_smd.h>
 #include <mach/qdsp6v2/apr.h>
-#include "q6core.h"
+#include <mach/qdsp6v2/q6core.h>
 
 #define TIMEOUT_MS 1000
 
@@ -79,6 +79,10 @@
 			bus_bw_resp_received = 1;
 			wake_up(&bus_bw_req_wait);
 			break;
+		case ADSP_CMD_SET_DTS_MODEL_ID:
+			pr_debug("ADSP_CMD_SET_DTS_MODEL_ID status[0x%x]\n",
+					payload1[1]);
+			break;
 		default:
 			pr_err("Invalid cmd rsp[0x%x][0x%x]\n",
 					payload1[0], payload1[1]);
@@ -382,6 +386,35 @@
 	return count;
 }
 
+uint32_t core_set_dts_model_id(uint32_t id_size, uint8_t *id)
+{
+	struct adsp_dts_modelid payload;
+	int rc = 0;
+	pr_debug("core_set_dts_model_id(): Enter\n");
+	core_open();
+	if (core_handle_q) {
+		payload.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		payload.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(uint32_t)+id_size);
+		payload.hdr.src_port = 0;
+		payload.hdr.dest_port = 0;
+		payload.hdr.token = 0;
+		payload.hdr.opcode = ADSP_CMD_SET_DTS_MODEL_ID;
+		payload.model_ID_size = id_size;
+		memcpy(payload.model_ID, id, id_size+1);
+		pr_debug("Send DTS sec opcode=%x modelID = %s, size=%d\n",
+			payload.hdr.opcode, (char *)payload.model_ID,
+			payload.model_ID_size);
+		rc = apr_send_pkt(core_handle_q, (uint32_t *)&payload);
+		if (rc < 0)
+			pr_err("%s: SET_DTS_DTS_MODEL_ID failed op[0x%x]rc[%d]\n",
+				__func__, payload.hdr.opcode, rc);
+	}
+	pr_debug("core_set_dts_model_id(): Exit\n");
+	return rc;
+}
+
 static const struct file_operations apr_debug_fops = {
 	.write = apr_debug_write,
 	.open = apr_debug_open,
diff --git a/arch/arm/mach-msm/qdsp6v2/q6voice.c b/arch/arm/mach-msm/qdsp6v2/q6voice.c
index 12a02c5..7464ed7 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6voice.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6voice.c
@@ -30,7 +30,7 @@
 #include <mach/qdsp6v2/rtac.h>
 #include <mach/qdsp6v2/audio_acdb.h>
 
-#include "q6core.h"
+#include <mach/qdsp6v2/q6core.h>
 
 
 #define TIMEOUT_MS 3000
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index e33f87b..b228147 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -3516,6 +3516,7 @@
 	{SMD_WCNSS, "riva", .nb.notifier_call = restart_notifier_cb},
 	{SMD_DSPS, "dsps", .nb.notifier_call = restart_notifier_cb},
 	{SMD_MODEM, "gss", .nb.notifier_call = restart_notifier_cb},
+	{SMD_Q6, "adsp", .nb.notifier_call = restart_notifier_cb},
 };
 
 static int restart_notifier_cb(struct notifier_block *this,
diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c
index 983d0c1..68c3dd3 100644
--- a/arch/arm/mach-msm/smd_rpcrouter.c
+++ b/arch/arm/mach-msm/smd_rpcrouter.c
@@ -2421,6 +2421,7 @@
 {
 	struct rpcrouter_xprt_info *xprt_info;
 	struct rpcrouter_xprt_work *xprt_work;
+	unsigned long flags;
 
 	/* Workqueue is created in init function which works for all existing
 	 * clients.  If this fails in the future, then it will need to be
@@ -2452,11 +2453,13 @@
 
 	xprt_info = xprt->priv;
 	if (xprt_info) {
+		spin_lock_irqsave(&xprt_info->lock, flags);
 		/* Check read_avail even for OPEN event to handle missed
 		   DATA events while processing the OPEN event*/
 		if (xprt->read_avail() >= xprt_info->need_len)
 			wake_lock(&xprt_info->wakelock);
 		wake_up(&xprt_info->read_wait);
+		spin_unlock_irqrestore(&xprt_info->lock, flags);
 	}
 }
 
diff --git a/arch/arm/mach-msm/sysmon.c b/arch/arm/mach-msm/sysmon.c
index 1305bd1..02ba5ea 100644
--- a/arch/arm/mach-msm/sysmon.c
+++ b/arch/arm/mach-msm/sysmon.c
@@ -159,6 +159,41 @@
 }
 
 /**
+ * sysmon_send_shutdown() - send shutdown command to a
+ * subsystem.
+ * @dest_ss:	ID of subsystem to send to.
+ *
+ * Returns 0 for success, -EINVAL for an invalid destination, -ENODEV if
+ * the SMD transport channel is not open, -ETIMEDOUT if the destination
+ * subsystem does not respond, and -ENOSYS if the destination subsystem
+ * responds with something unexpected.
+ *
+ * If CONFIG_MSM_SYSMON_COMM is not defined, always return success (0).
+ */
+int sysmon_send_shutdown(enum subsys_id dest_ss)
+{
+	struct sysmon_subsys *ss = &subsys[dest_ss];
+	const char tx_buf[] = "system:shutdown";
+	const char expect[] = "system:ack";
+	size_t prefix_len = ARRAY_SIZE(expect) - 1;
+	int ret;
+
+	if (dest_ss < 0 || dest_ss >= SYSMON_NUM_SS)
+		return -EINVAL;
+
+	mutex_lock(&ss->lock);
+	ret = sysmon_send_msg(ss, tx_buf, ARRAY_SIZE(tx_buf));
+	if (ret)
+		goto out;
+
+	if (strncmp(ss->rx_buf, expect, prefix_len))
+		ret = -ENOSYS;
+out:
+	mutex_unlock(&ss->lock);
+	return ret;
+}
+
+/**
  * sysmon_get_reason() - Retrieve failure reason from a subsystem.
  * @dest_ss:	ID of subsystem to query
  * @buf:	Caller-allocated buffer for the returned NUL-terminated reason
diff --git a/arch/arm/mach-msm/sysmon.h b/arch/arm/mach-msm/sysmon.h
index 77c3329..8c2f6ea 100644
--- a/arch/arm/mach-msm/sysmon.h
+++ b/arch/arm/mach-msm/sysmon.h
@@ -38,6 +38,7 @@
 int sysmon_send_event(enum subsys_id dest_ss, const char *event_ss,
 		      enum subsys_notif_type notif);
 int sysmon_get_reason(enum subsys_id dest_ss, char *buf, size_t len);
+int sysmon_send_shutdown(enum subsys_id dest_ss);
 #else
 static inline int sysmon_send_event(enum subsys_id dest_ss,
 				    const char *event_ss,
@@ -50,6 +51,10 @@
 {
 	return 0;
 }
+static inline int sysmon_send_shutdown(enum subsys_id dest_ss)
+{
+	return 0;
+}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/wcnss-ssr-8974.c b/arch/arm/mach-msm/wcnss-ssr-8974.c
new file mode 100644
index 0000000..d8745fc
--- /dev/null
+++ b/arch/arm/mach-msm/wcnss-ssr-8974.c
@@ -0,0 +1,163 @@
+/* Copyright (c) 2012, The Linux Foundation. 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/interrupt.h>
+#include <linux/module.h>
+#include <linux/err.h>
+
+#include <mach/subsystem_restart.h>
+#include <mach/msm_smsm.h>
+
+#define MODULE_NAME			"wcnss_8974"
+#define MAX_SSR_REASON_LEN			0x51
+
+static int ss_restart_inprogress;
+static int wcnss_crash;
+static struct subsys_device *wcnss_ssr_dev;
+
+#define WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ		231
+
+static void log_wcnss_sfr(void)
+{
+	char *smem_reset_reason;
+	char buffer[MAX_SSR_REASON_LEN];
+	unsigned smem_reset_size;
+	unsigned size;
+
+	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_SSR_REASON_LEN ? smem_reset_size :
+			(MAX_SSR_REASON_LEN - 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();
+	}
+}
+
+static void restart_wcnss(void)
+{
+	log_wcnss_sfr();
+	subsystem_restart("wcnss");
+}
+
+static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
+					uint32_t new_state)
+{
+	wcnss_crash = true;
+
+	pr_err("%s: smsm state changed\n", MODULE_NAME);
+
+	if (!(new_state & SMSM_RESET))
+		return;
+
+	if (ss_restart_inprogress) {
+		pr_err("%s: Ignoring smsm reset req, restart in progress\n",
+						MODULE_NAME);
+		return;
+	}
+
+	ss_restart_inprogress = true;
+	restart_wcnss();
+}
+
+
+static irqreturn_t wcnss_wdog_bite_irq_hdlr(int irq, void *dev_id)
+{
+	wcnss_crash = true;
+
+	if (ss_restart_inprogress) {
+		pr_err("%s: Ignoring wcnss bite irq, restart in progress\n",
+						MODULE_NAME);
+		return IRQ_HANDLED;
+	}
+
+	ss_restart_inprogress = true;
+	restart_wcnss();
+
+	return IRQ_HANDLED;
+}
+
+
+static int wcnss_shutdown(const struct subsys_desc *subsys)
+{
+	return 0;
+}
+
+static int wcnss_powerup(const struct subsys_desc *subsys)
+{
+	return 0;
+}
+
+/* wcnss crash handler */
+static void wcnss_crash_shutdown(const struct subsys_desc *subsys)
+{
+	pr_err("%s: crash shutdown : %d\n", MODULE_NAME, wcnss_crash);
+	if (wcnss_crash != true)
+		smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
+}
+
+static int wcnss_ramdump(int enable,
+				const struct subsys_desc *crashed_subsys)
+{
+	return 0;
+}
+
+static struct subsys_desc wcnss_ssr = {
+	.name = "wcnss",
+	.shutdown = wcnss_shutdown,
+	.powerup = wcnss_powerup,
+	.ramdump = wcnss_ramdump,
+	.crash_shutdown = wcnss_crash_shutdown
+};
+
+static int __init wcnss_ssr_init(void)
+{
+	int ret;
+
+	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 wcnss Reset! %d\n",
+				MODULE_NAME, ret);
+		goto out;
+	}
+	ret = request_irq(WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ,
+			wcnss_wdog_bite_irq_hdlr, IRQF_TRIGGER_HIGH,
+				"wcnss_wdog", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: Unable to register for wcnss bite interrupt (%d)\n",
+				MODULE_NAME, ret);
+		goto out;
+	}
+	wcnss_ssr_dev = subsys_register(&wcnss_ssr);
+	if (IS_ERR(wcnss_ssr_dev))
+		return PTR_ERR(wcnss_ssr_dev);
+
+	pr_info("%s: module initialized\n", MODULE_NAME);
+out:
+	return ret;
+}
+
+arch_initcall(wcnss_ssr_init);
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index a2815de..033e5a0 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_CONTROL_TRACE) += control_trace.o
 obj-$(CONFIG_OF) += of_coresight.o
-obj-$(CONFIG_MSM_QDSS) += coresight.o coresight-csr.o coresight-tmc.o coresight-tpiu.o coresight-etb.o coresight-funnel.o coresight-replicator.o coresight-stm.o coresight-etm.o
+obj-$(CONFIG_MSM_QDSS) += coresight.o coresight-csr.o coresight-tmc.o coresight-tpiu.o coresight-etb.o coresight-funnel.o coresight-replicator.o coresight-stm.o coresight-etm.o coresight-etm-cp14.o
diff --git a/drivers/coresight/coresight-etm-cp14.c b/drivers/coresight/coresight-etm-cp14.c
new file mode 100644
index 0000000..9a6c13a
--- /dev/null
+++ b/drivers/coresight/coresight-etm-cp14.c
@@ -0,0 +1,510 @@
+/* Copyright (c) 2012, The Linux Foundation. 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/types.h>
+#include <asm/hardware/cp14.h>
+
+static unsigned int etm_read_reg(uint32_t reg)
+{
+	switch (reg) {
+	case 0x0:
+		return etm_read(ETMCR);
+	case 0x1:
+		return etm_read(ETMCCR);
+	case 0x2:
+		return etm_read(ETMTRIGGER);
+	case 0x4:
+		return etm_read(ETMSR);
+	case 0x5:
+		return etm_read(ETMSCR);
+	case 0x6:
+		return etm_read(ETMTSSCR);
+	case 0x8:
+		return etm_read(ETMTEEVR);
+	case 0x9:
+		return etm_read(ETMTECR1);
+	case 0xB:
+		return etm_read(ETMFFLR);
+	case 0x10:
+		return etm_read(ETMACVR0);
+	case 0x11:
+		return etm_read(ETMACVR1);
+	case 0x12:
+		return etm_read(ETMACVR2);
+	case 0x13:
+		return etm_read(ETMACVR3);
+	case 0x14:
+		return etm_read(ETMACVR4);
+	case 0x15:
+		return etm_read(ETMACVR5);
+	case 0x16:
+		return etm_read(ETMACVR6);
+	case 0x17:
+		return etm_read(ETMACVR7);
+	case 0x18:
+		return etm_read(ETMACVR8);
+	case 0x19:
+		return etm_read(ETMACVR9);
+	case 0x1A:
+		return etm_read(ETMACVR10);
+	case 0x1B:
+		return etm_read(ETMACVR11);
+	case 0x1C:
+		return etm_read(ETMACVR12);
+	case 0x1D:
+		return etm_read(ETMACVR13);
+	case 0x1E:
+		return etm_read(ETMACVR14);
+	case 0x1F:
+		return etm_read(ETMACVR15);
+	case 0x20:
+		return etm_read(ETMACTR0);
+	case 0x21:
+		return etm_read(ETMACTR1);
+	case 0x22:
+		return etm_read(ETMACTR2);
+	case 0x23:
+		return etm_read(ETMACTR3);
+	case 0x24:
+		return etm_read(ETMACTR4);
+	case 0x25:
+		return etm_read(ETMACTR5);
+	case 0x26:
+		return etm_read(ETMACTR6);
+	case 0x27:
+		return etm_read(ETMACTR7);
+	case 0x28:
+		return etm_read(ETMACTR8);
+	case 0x29:
+		return etm_read(ETMACTR9);
+	case 0x2A:
+		return etm_read(ETMACTR10);
+	case 0x2B:
+		return etm_read(ETMACTR11);
+	case 0x2C:
+		return etm_read(ETMACTR12);
+	case 0x2D:
+		return etm_read(ETMACTR13);
+	case 0x2E:
+		return etm_read(ETMACTR14);
+	case 0x2F:
+		return etm_read(ETMACTR15);
+	case 0x50:
+		return etm_read(ETMCNTRLDVR0);
+	case 0x51:
+		return etm_read(ETMCNTRLDVR1);
+	case 0x52:
+		return etm_read(ETMCNTRLDVR2);
+	case 0x53:
+		return etm_read(ETMCNTRLDVR3);
+	case 0x54:
+		return etm_read(ETMCNTENR0);
+	case 0x55:
+		return etm_read(ETMCNTENR1);
+	case 0x56:
+		return etm_read(ETMCNTENR2);
+	case 0x57:
+		return etm_read(ETMCNTENR3);
+	case 0x58:
+		return etm_read(ETMCNTRLDEVR0);
+	case 0x59:
+		return etm_read(ETMCNTRLDEVR1);
+	case 0x5A:
+		return etm_read(ETMCNTRLDEVR2);
+	case 0x5B:
+		return etm_read(ETMCNTRLDEVR3);
+	case 0x5C:
+		return etm_read(ETMCNTVR0);
+	case 0x5D:
+		return etm_read(ETMCNTVR1);
+	case 0x5E:
+		return etm_read(ETMCNTVR2);
+	case 0x5F:
+		return etm_read(ETMCNTVR3);
+	case 0x60:
+		return etm_read(ETMSQ12EVR);
+	case 0x61:
+		return etm_read(ETMSQ21EVR);
+	case 0x62:
+		return etm_read(ETMSQ23EVR);
+	case 0x63:
+		return etm_read(ETMSQ31EVR);
+	case 0x64:
+		return etm_read(ETMSQ32EVR);
+	case 0x65:
+		return etm_read(ETMSQ13EVR);
+	case 0x67:
+		return etm_read(ETMSQR);
+	case 0x68:
+		return etm_read(ETMEXTOUTEVR0);
+	case 0x69:
+		return etm_read(ETMEXTOUTEVR1);
+	case 0x6A:
+		return etm_read(ETMEXTOUTEVR2);
+	case 0x6B:
+		return etm_read(ETMEXTOUTEVR3);
+	case 0x6C:
+		return etm_read(ETMCIDCVR0);
+	case 0x6D:
+		return etm_read(ETMCIDCVR1);
+	case 0x6E:
+		return etm_read(ETMCIDCVR2);
+	case 0x6F:
+		return etm_read(ETMCIDCMR);
+	case 0x70:
+		return etm_read(ETMIMPSPEC0);
+	case 0x71:
+		return etm_read(ETMIMPSPEC1);
+	case 0x72:
+		return etm_read(ETMIMPSPEC2);
+	case 0x73:
+		return etm_read(ETMIMPSPEC3);
+	case 0x74:
+		return etm_read(ETMIMPSPEC4);
+	case 0x75:
+		return etm_read(ETMIMPSPEC5);
+	case 0x76:
+		return etm_read(ETMIMPSPEC6);
+	case 0x77:
+		return etm_read(ETMIMPSPEC7);
+	case 0x78:
+		return etm_read(ETMSYNCFR);
+	case 0x79:
+		return etm_read(ETMIDR);
+	case 0x7A:
+		return etm_read(ETMCCER);
+	case 0x7B:
+		return etm_read(ETMEXTINSELR);
+	case 0x7C:
+		return etm_read(ETMTESSEICR);
+	case 0x7D:
+		return etm_read(ETMEIBCR);
+	case 0x7E:
+		return etm_read(ETMTSEVR);
+	case 0x7F:
+		return etm_read(ETMAUXCR);
+	case 0x80:
+		return etm_read(ETMTRACEIDR);
+	case 0x90:
+		return etm_read(ETMVMIDCVR);
+	case 0xC1:
+		return etm_read(ETMOSLSR);
+	case 0xC2:
+		return etm_read(ETMOSSRR);
+	case 0xC4:
+		return etm_read(ETMPDCR);
+	case 0xC5:
+		return etm_read(ETMPDSR);
+	default:
+		WARN(1, "invalid CP14 access to ETM reg: %lx",
+							(unsigned long)reg);
+		return 0;
+	}
+}
+
+static void etm_write_reg(uint32_t val, uint32_t reg)
+{
+	switch (reg) {
+	case 0x0:
+		etm_write(val, ETMCR);
+		return;
+	case 0x2:
+		etm_write(val, ETMTRIGGER);
+		return;
+	case 0x4:
+		etm_write(val, ETMSR);
+		return;
+	case 0x6:
+		etm_write(val, ETMTSSCR);
+		return;
+	case 0x8:
+		etm_write(val, ETMTEEVR);
+		return;
+	case 0x9:
+		etm_write(val, ETMTECR1);
+		return;
+	case 0xB:
+		etm_write(val, ETMFFLR);
+		return;
+	case 0x10:
+		etm_write(val, ETMACVR0);
+		return;
+	case 0x11:
+		etm_write(val, ETMACVR1);
+		return;
+	case 0x12:
+		etm_write(val, ETMACVR2);
+		return;
+	case 0x13:
+		etm_write(val, ETMACVR3);
+		return;
+	case 0x14:
+		etm_write(val, ETMACVR4);
+		return;
+	case 0x15:
+		etm_write(val, ETMACVR5);
+		return;
+	case 0x16:
+		etm_write(val, ETMACVR6);
+		return;
+	case 0x17:
+		etm_write(val, ETMACVR7);
+		return;
+	case 0x18:
+		etm_write(val, ETMACVR8);
+		return;
+	case 0x19:
+		etm_write(val, ETMACVR9);
+		return;
+	case 0x1A:
+		etm_write(val, ETMACVR10);
+		return;
+	case 0x1B:
+		etm_write(val, ETMACVR11);
+		return;
+	case 0x1C:
+		etm_write(val, ETMACVR12);
+		return;
+	case 0x1D:
+		etm_write(val, ETMACVR13);
+		return;
+	case 0x1E:
+		etm_write(val, ETMACVR14);
+		return;
+	case 0x1F:
+		etm_write(val, ETMACVR15);
+		return;
+	case 0x20:
+		etm_write(val, ETMACTR0);
+		return;
+	case 0x21:
+		etm_write(val, ETMACTR1);
+		return;
+	case 0x22:
+		etm_write(val, ETMACTR2);
+		return;
+	case 0x23:
+		etm_write(val, ETMACTR3);
+		return;
+	case 0x24:
+		etm_write(val, ETMACTR4);
+		return;
+	case 0x25:
+		etm_write(val, ETMACTR5);
+		return;
+	case 0x26:
+		etm_write(val, ETMACTR6);
+		return;
+	case 0x27:
+		etm_write(val, ETMACTR7);
+		return;
+	case 0x28:
+		etm_write(val, ETMACTR8);
+		return;
+	case 0x29:
+		etm_write(val, ETMACTR9);
+		return;
+	case 0x2A:
+		etm_write(val, ETMACTR10);
+		return;
+	case 0x2B:
+		etm_write(val, ETMACTR11);
+		return;
+	case 0x2C:
+		etm_write(val, ETMACTR12);
+		return;
+	case 0x2D:
+		etm_write(val, ETMACTR13);
+		return;
+	case 0x2E:
+		etm_write(val, ETMACTR14);
+		return;
+	case 0x2F:
+		etm_write(val, ETMACTR15);
+		return;
+	case 0x50:
+		etm_write(val, ETMCNTRLDVR0);
+		return;
+	case 0x51:
+		etm_write(val, ETMCNTRLDVR1);
+		return;
+	case 0x52:
+		etm_write(val, ETMCNTRLDVR2);
+		return;
+	case 0x53:
+		etm_write(val, ETMCNTRLDVR3);
+		return;
+	case 0x54:
+		etm_write(val, ETMCNTENR0);
+		return;
+	case 0x55:
+		etm_write(val, ETMCNTENR1);
+		return;
+	case 0x56:
+		etm_write(val, ETMCNTENR2);
+		return;
+	case 0x57:
+		etm_write(val, ETMCNTENR3);
+		return;
+	case 0x58:
+		etm_write(val, ETMCNTRLDEVR0);
+		return;
+	case 0x59:
+		etm_write(val, ETMCNTRLDEVR1);
+		return;
+	case 0x5A:
+		etm_write(val, ETMCNTRLDEVR2);
+		return;
+	case 0x5B:
+		etm_write(val, ETMCNTRLDEVR3);
+		return;
+	case 0x5C:
+		etm_write(val, ETMCNTVR0);
+		return;
+	case 0x5D:
+		etm_write(val, ETMCNTVR1);
+		return;
+	case 0x5E:
+		etm_write(val, ETMCNTVR2);
+		return;
+	case 0x5F:
+		etm_write(val, ETMCNTVR3);
+		return;
+	case 0x60:
+		etm_write(val, ETMSQ12EVR);
+		return;
+	case 0x61:
+		etm_write(val, ETMSQ21EVR);
+		return;
+	case 0x62:
+		etm_write(val, ETMSQ23EVR);
+		return;
+	case 0x63:
+		etm_write(val, ETMSQ31EVR);
+		return;
+	case 0x64:
+		etm_write(val, ETMSQ32EVR);
+		return;
+	case 0x65:
+		etm_write(val, ETMSQ13EVR);
+		return;
+	case 0x67:
+		etm_write(val, ETMSQR);
+		return;
+	case 0x68:
+		etm_write(val, ETMEXTOUTEVR0);
+		return;
+	case 0x69:
+		etm_write(val, ETMEXTOUTEVR1);
+		return;
+	case 0x6A:
+		etm_write(val, ETMEXTOUTEVR2);
+		return;
+	case 0x6B:
+		etm_write(val, ETMEXTOUTEVR3);
+		return;
+	case 0x6C:
+		etm_write(val, ETMCIDCVR0);
+		return;
+	case 0x6D:
+		etm_write(val, ETMCIDCVR1);
+		return;
+	case 0x6E:
+		etm_write(val, ETMCIDCVR2);
+		return;
+	case 0x6F:
+		etm_write(val, ETMCIDCMR);
+		return;
+	case 0x70:
+		etm_write(val, ETMIMPSPEC0);
+		return;
+	case 0x71:
+		etm_write(val, ETMIMPSPEC1);
+		return;
+	case 0x72:
+		etm_write(val, ETMIMPSPEC2);
+		return;
+	case 0x73:
+		etm_write(val, ETMIMPSPEC3);
+		return;
+	case 0x74:
+		etm_write(val, ETMIMPSPEC4);
+		return;
+	case 0x75:
+		etm_write(val, ETMIMPSPEC5);
+		return;
+	case 0x76:
+		etm_write(val, ETMIMPSPEC6);
+		return;
+	case 0x77:
+		etm_write(val, ETMIMPSPEC7);
+		return;
+	case 0x78:
+		etm_write(val, ETMSYNCFR);
+		return;
+	case 0x7B:
+		etm_write(val, ETMEXTINSELR);
+		return;
+	case 0x7C:
+		etm_write(val, ETMTESSEICR);
+		return;
+	case 0x7D:
+		etm_write(val, ETMEIBCR);
+		return;
+	case 0x7E:
+		etm_write(val, ETMTSEVR);
+		return;
+	case 0x7F:
+		etm_write(val, ETMAUXCR);
+		return;
+	case 0x80:
+		etm_write(val, ETMTRACEIDR);
+		return;
+	case 0x90:
+		etm_write(val, ETMVMIDCVR);
+		return;
+	case 0xC0:
+		etm_write(val, ETMOSLAR);
+		return;
+	case 0xC2:
+		etm_write(val, ETMOSSRR);
+		return;
+	case 0xC4:
+		etm_write(val, ETMPDCR);
+		return;
+	case 0xC5:
+		etm_write(val, ETMPDSR);
+		return;
+	default:
+		WARN(1, "invalid CP14 access to ETM reg: %lx",
+							(unsigned long)reg);
+		return;
+	}
+}
+
+static inline uint32_t offset_to_reg_num(uint32_t off)
+{
+	return off >> 2;
+}
+
+unsigned int etm_readl_cp14(uint32_t off)
+{
+	uint32_t reg = offset_to_reg_num(off);
+	return etm_read_reg(reg);
+}
+
+void etm_writel_cp14(uint32_t val, uint32_t off)
+{
+	uint32_t reg = offset_to_reg_num(off);
+	etm_write_reg(val, reg);
+}
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index f4c4d08..ce4d7d1 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. 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
@@ -35,20 +35,45 @@
 
 #include "coresight-priv.h"
 
-#define etm_writel(drvdata, val, off)	\
+#define etm_writel_mm(drvdata, val, off)  \
 			__raw_writel((val), drvdata->base + off)
-#define etm_readl(drvdata, off)		\
+#define etm_readl_mm(drvdata, off)        \
 			__raw_readl(drvdata->base + off)
 
+#define etm_writel(drvdata, val, off)					\
+({									\
+	if (cpu_is_krait_v3())						\
+		etm_writel_cp14(val, off);				\
+	else								\
+		etm_writel_mm(drvdata, val, off);			\
+})
+#define etm_readl(drvdata, off)						\
+({									\
+	uint32_t val;							\
+	if (cpu_is_krait_v3())						\
+		val = etm_readl_cp14(off);				\
+	else								\
+		val = etm_readl_mm(drvdata, off);			\
+	val;								\
+})
+
 #define ETM_LOCK(drvdata)						\
 do {									\
+	/* recommended by spec to ensure ETM writes are committed prior
+	 * to resuming execution
+	 */								\
 	mb();								\
-	etm_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+	isb();								\
+	etm_writel_mm(drvdata, 0x0, CORESIGHT_LAR);			\
 } while (0)
 #define ETM_UNLOCK(drvdata)						\
 do {									\
-	etm_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	etm_writel_mm(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);	\
+	/* ensure unlock and any pending writes are committed prior to
+	 * programming ETM registers
+	 */								\
 	mb();								\
+	isb();								\
 } while (0)
 
 /*
@@ -214,22 +239,28 @@
  * clock vote in the driver and the save-restore code uses 1. above
  * for its vote
  */
-static void etm_set_pwrdwn(struct etm_drvdata *drvdata)
+static void etm_set_pwrup(struct etm_drvdata *drvdata)
 {
-	uint32_t etmcr;
+	uint32_t etmpdcr;
 
-	etmcr = etm_readl(drvdata, ETMCR);
-	etmcr |= BIT(0);
-	etm_writel(drvdata, etmcr, ETMCR);
+	etmpdcr = etm_readl_mm(drvdata, ETMPDCR);
+	etmpdcr |= BIT(3);
+	etm_writel_mm(drvdata, etmpdcr, ETMPDCR);
+	/* ensure pwrup completes before subsequent cp14 accesses */
+	mb();
+	isb();
 }
 
-static void etm_clr_pwrdwn(struct etm_drvdata *drvdata)
+static void etm_clr_pwrup(struct etm_drvdata *drvdata)
 {
-	uint32_t etmcr;
+	uint32_t etmpdcr;
 
-	etmcr = etm_readl(drvdata, ETMCR);
-	etmcr &= ~BIT(0);
-	etm_writel(drvdata, etmcr, ETMCR);
+	/* ensure pending cp14 accesses complete before clearing pwrup */
+	mb();
+	isb();
+	etmpdcr = etm_readl_mm(drvdata, ETMPDCR);
+	etmpdcr &= ~BIT(3);
+	etm_writel_mm(drvdata, etmpdcr, ETMPDCR);
 }
 
 static void etm_set_prog(struct etm_drvdata *drvdata)
@@ -240,6 +271,10 @@
 	etmcr = etm_readl(drvdata, ETMCR);
 	etmcr |= BIT(10);
 	etm_writel(drvdata, etmcr, ETMCR);
+	/* recommended by spec for cp14 accesses to ensure etmcr write is
+	 * complete before polling etmsr
+	 */
+	isb();
 	for (count = TIMEOUT_US; BVAL(etm_readl(drvdata, ETMSR), 1) != 1
 				&& count > 0; count--)
 		udelay(1);
@@ -255,6 +290,10 @@
 	etmcr = etm_readl(drvdata, ETMCR);
 	etmcr &= ~BIT(10);
 	etm_writel(drvdata, etmcr, ETMCR);
+	/* recommended by spec for cp14 accesses to ensure etmcr write is
+	 * complete before polling etmsr
+	 */
+	isb();
 	for (count = TIMEOUT_US; BVAL(etm_readl(drvdata, ETMSR), 1) != 0
 				&& count > 0; count--)
 		udelay(1);
@@ -269,7 +308,7 @@
 
 	ETM_UNLOCK(drvdata);
 	/* Vote for ETM power/clock enable */
-	etm_clr_pwrdwn(drvdata);
+	etm_set_pwrup(drvdata);
 	etm_set_prog(drvdata);
 
 	etm_writel(drvdata, drvdata->ctrl | BIT(10), ETMCR);
@@ -352,7 +391,7 @@
 	etm_writel(drvdata, 0x6F | BIT(14), ETMTEEVR);
 
 	/* Vote for ETM power/clock disable */
-	etm_set_pwrdwn(drvdata);
+	etm_clr_pwrup(drvdata);
 	ETM_LOCK(drvdata);
 
 	dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
@@ -1416,17 +1455,24 @@
 	return true;
 }
 
-static void __devinit etm_init_arch_data(struct etm_drvdata *drvdata)
+static void __devinit etm_prepare_arch(struct etm_drvdata *drvdata)
+{
+	/* Unlock OS lock first to allow memory mapped reads and writes. This
+	 * is required for Krait pass1
+	 * */
+	etm_os_unlock(NULL);
+	smp_call_function(etm_os_unlock, NULL, 1);
+}
+
+static void __devinit etm_init_arch_data(void *info)
 {
 	uint32_t etmidr;
 	uint32_t etmccr;
+	struct etm_drvdata *drvdata = info;
 
-	/* Unlock OS lock first to allow memory mapped reads and writes */
-	etm_os_unlock(NULL);
-	smp_call_function(etm_os_unlock, NULL, 1);
 	ETM_UNLOCK(drvdata);
 	/* Vote for ETM power/clock enable */
-	etm_clr_pwrdwn(drvdata);
+	etm_set_pwrup(drvdata);
 	/* Set prog bit. It will be set from reset but this is included to
 	 * ensure it is set
 	 */
@@ -1444,7 +1490,7 @@
 	drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
 
 	/* Vote for ETM power/clock disable */
-	etm_set_pwrdwn(drvdata);
+	etm_clr_pwrup(drvdata);
 	ETM_LOCK(drvdata);
 }
 
@@ -1518,12 +1564,6 @@
 	struct msm_client_dump dump;
 	struct coresight_desc *desc;
 
-	/* Fail probe for Krait pass3 until supported */
-	if (cpu_is_krait_v3()) {
-		dev_info(dev, "ETM: failing probe for Krait pass3\n");
-		return -EINVAL;
-	}
-
 	if (pdev->dev.of_node) {
 		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
 		if (IS_ERR(pdata))
@@ -1569,7 +1609,9 @@
 	 * ETMs copy it over from ETM0.
 	 */
 	if (drvdata->cpu == 0) {
-		etm_init_arch_data(drvdata);
+		etm_prepare_arch(drvdata);
+		smp_call_function_single(drvdata->cpu, etm_init_arch_data,
+					 drvdata, 1);
 		etm0drvdata = drvdata;
 	} else {
 		etm_copy_arch_data(drvdata);
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index 2b00242..0cf2b3d 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -39,9 +39,13 @@
 #ifdef CONFIG_MSM_QDSS
 extern void msm_qdss_csr_enable_bam_to_usb(void);
 extern void msm_qdss_csr_disable_bam_to_usb(void);
+extern unsigned int etm_readl_cp14(uint32_t off);
+extern void etm_writel_cp14(uint32_t val, uint32_t off);
 #else
 static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
 static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
+static inline unsigned int etm_readl_cp14(uint32_t off) { return 0; }
+static inline void etm_writel_cp14(uint32_t val, uint32_t off) {}
 #endif
 
 #endif
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 7f760ed..b23181f 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -107,24 +107,6 @@
 
 static void ion_iommu_release(struct kref *kref);
 
-static int ion_validate_buffer_flags(struct ion_buffer *buffer,
-					unsigned long flags)
-{
-	if (buffer->kmap_cnt || buffer->dmap_cnt || buffer->umap_cnt ||
-		buffer->iommu_map_cnt) {
-		if (buffer->flags != flags) {
-			pr_err("%s: buffer was already mapped with flags %lx,"
-				" cannot map with flags %lx\n", __func__,
-				buffer->flags, flags);
-			return 1;
-		}
-
-	} else {
-		buffer->flags = flags;
-	}
-	return 0;
-}
-
 /* this function should only be called while dev->lock is held */
 static void ion_buffer_add(struct ion_device *dev,
 			   struct ion_buffer *buffer)
@@ -232,6 +214,7 @@
 
 	buffer->dev = dev;
 	buffer->size = len;
+	buffer->flags = flags;
 
 	table = buffer->heap->ops->map_dma(buffer->heap, buffer);
 	if (IS_ERR_OR_NULL(table)) {
@@ -412,7 +395,8 @@
 }
 
 struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
-			     size_t align, unsigned int flags)
+			     size_t align, unsigned int heap_mask,
+			     unsigned int flags)
 {
 	struct rb_node *n;
 	struct ion_handle *handle;
@@ -443,7 +427,7 @@
 		if (!((1 << heap->type) & client->heap_mask))
 			continue;
 		/* if the caller didn't specify this heap type */
-		if (!((1 << heap->id) & flags))
+		if (!((1 << heap->id) & heap_mask))
 			continue;
 		/* Do not allow un-secure heap if secure is specified */
 		if (secure_allocation && (heap->type != ION_HEAP_TYPE_CP))
@@ -773,8 +757,7 @@
 }
 EXPORT_SYMBOL(ion_unmap_iommu);
 
-void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle,
-			unsigned long flags)
+void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle)
 {
 	struct ion_buffer *buffer;
 	void *vaddr;
@@ -796,11 +779,6 @@
 		return ERR_PTR(-ENODEV);
 	}
 
-	if (ion_validate_buffer_flags(buffer, flags)) {
-		mutex_unlock(&client->lock);
-		return ERR_PTR(-EEXIST);
-	}
-
 	mutex_lock(&buffer->lock);
 	vaddr = ion_handle_kmap_get(handle);
 	mutex_unlock(&buffer->lock);
@@ -1228,36 +1206,6 @@
 	.kunmap = ion_dma_buf_kunmap,
 };
 
-static int ion_share_set_flags(struct ion_client *client,
-				struct ion_handle *handle,
-				unsigned long flags)
-{
-	struct ion_buffer *buffer;
-	bool valid_handle;
-	unsigned long ion_flags = ION_SET_CACHE(CACHED);
-	if (flags & O_DSYNC)
-		ion_flags = ION_SET_CACHE(UNCACHED);
-
-	mutex_lock(&client->lock);
-	valid_handle = ion_handle_validate(client, handle);
-	mutex_unlock(&client->lock);
-	if (!valid_handle) {
-		WARN(1, "%s: invalid handle passed to set_flags.\n", __func__);
-		return -EINVAL;
-	}
-
-	buffer = handle->buffer;
-
-	mutex_lock(&buffer->lock);
-	if (ion_validate_buffer_flags(buffer, ion_flags)) {
-		mutex_unlock(&buffer->lock);
-		return -EEXIST;
-	}
-	mutex_unlock(&buffer->lock);
-	return 0;
-}
-
-
 int ion_share_dma_buf(struct ion_client *client, struct ion_handle *handle)
 {
 	struct ion_buffer *buffer;
@@ -1337,7 +1285,7 @@
 		if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
 			return -EFAULT;
 		data.handle = ion_alloc(client, data.len, data.align,
-					     data.flags);
+					     data.heap_mask, data.flags);
 
 		if (IS_ERR(data.handle))
 			return PTR_ERR(data.handle);
@@ -1368,14 +1316,9 @@
 	case ION_IOC_SHARE:
 	{
 		struct ion_fd_data data;
-		int ret;
 		if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
 			return -EFAULT;
 
-		ret = ion_share_set_flags(client, data.handle, filp->f_flags);
-		if (ret)
-			return ret;
-
 		data.fd = ion_share_dma_buf(client, data.handle);
 		if (copy_to_user((void __user *)arg, &data, sizeof(data)))
 			return -EFAULT;
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index f867dcb..ec3429b 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -16,7 +16,7 @@
 # MSM IOMMU support
 config MSM_IOMMU
 	bool "MSM IOMMU Support"
-	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974
+	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974 || ARCH_MPQ8092
 	select IOMMU_API
 	help
 	  Support for the IOMMUs found on certain Qualcomm SOCs.
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
index 836ca65..7435ab2 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -932,7 +932,8 @@
 		ion_alloc(mpq_demux->ion_client,
 				  actual_buffer_size,
 				  SZ_4K,
-				  (ION_HEAP(ION_CP_MM_HEAP_ID) | CACHED));
+				  ION_HEAP(ION_CP_MM_HEAP_ID),
+				  ION_FLAG_CACHED);
 
 	if (IS_ERR_OR_NULL(feed_data->payload_buff_handle)) {
 		ret = PTR_ERR(feed_data->payload_buff_handle);
@@ -948,8 +949,7 @@
 
 	payload_buffer =
 		ion_map_kernel(mpq_demux->ion_client,
-					   feed_data->payload_buff_handle,
-					   0);
+					   feed_data->payload_buff_handle);
 
 	if (IS_ERR_OR_NULL(payload_buffer)) {
 		ret = PTR_ERR(payload_buffer);
diff --git a/drivers/media/dvb/mpq/video/mpq_dvb_video.c b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
index 4b3fb0c..bd8c4a4 100644
--- a/drivers/media/dvb/mpq/video/mpq_dvb_video.c
+++ b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
@@ -572,7 +572,7 @@
 		ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
 				pmem_fd, kernel_vaddr, buffer_index,
 				&buff_handle);
-		if (ion_flag == CACHED && buff_handle) {
+		if (ion_flag == ION_FLAG_CACHED && buff_handle) {
 			msm_ion_do_cache_op(
 				client_ctx->user_ion_client,
 				buff_handle,
@@ -1133,8 +1133,7 @@
 		}
 		vcd_h264_mv_buffer->kernel_virtual_addr =
 			(u8 *) ion_map_kernel(client_ctx->user_ion_client,
-					client_ctx->h264_mv_ion_handle,
-					ionflag);
+					client_ctx->h264_mv_ion_handle);
 		if (!vcd_h264_mv_buffer->kernel_virtual_addr) {
 			DBG("%s(): get_ION_kernel virtual addr failed\n",
 				 __func__);
@@ -1146,7 +1145,7 @@
 				VIDEO_DOMAIN, VIDEO_MAIN_POOL,
 				SZ_4K, 0, (unsigned long *)&iova,
 				(unsigned long *)&buffer_size,
-				UNCACHED, 0);
+				0, 0);
 		if (rc) {
 			DBG("%s():get_ION_kernel physical addr fail\n",
 						 __func__);
@@ -1503,7 +1502,7 @@
 						kernel_vaddr,
 						buffer_index,
 						&buff_handle);
-			if (ion_flag == CACHED && buff_handle) {
+			if (ion_flag == ION_FLAG_CACHED && buff_handle) {
 				msm_ion_do_cache_op(
 				client_ctx->user_ion_client,
 				buff_handle,
diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.c b/drivers/media/video/msm/gemini/msm_gemini_platform.c
index 28d2439..111402b 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_platform.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_platform.c
@@ -52,7 +52,7 @@
 		return 0;
 
 	rc = ion_map_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL,
-			SZ_4K, 0, &paddr, (unsigned long *)&size, UNCACHED, 0);
+			SZ_4K, 0, &paddr, (unsigned long *)&size, 0, 0);
 #elif CONFIG_ANDROID_PMEM
 	unsigned long kvstart;
 	rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.c b/drivers/media/video/msm/io/msm_camera_i2c.c
index 27ebac5..9e4fcd1 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.c
+++ b/drivers/media/video/msm/io/msm_camera_i2c.c
@@ -376,81 +376,67 @@
 {
 	int i;
 	int32_t rc = -EFAULT;
-	if (client->cci_client) {
-		struct msm_camera_cci_ctrl cci_ctrl;
-		cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
-		cci_ctrl.cci_info = client->cci_client;
-		cci_ctrl.cfg.cci_i2c_write_cfg.reg_conf_tbl = reg_conf_tbl;
-		cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type;
-		cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
-		cci_ctrl.cfg.cci_i2c_write_cfg.size = size;
-		rc = v4l2_subdev_call(client->cci_client->cci_subdev,
-				core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
-		CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc);
-		rc = cci_ctrl.status;
-	} else {
-		for (i = 0; i < size; i++) {
-			enum msm_camera_i2c_data_type dt;
-			if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) {
-				rc = msm_camera_i2c_poll(client,
+	for (i = 0; i < size; i++) {
+		enum msm_camera_i2c_data_type dt;
+		if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) {
+			rc = msm_camera_i2c_poll(client,
+				reg_conf_tbl->reg_addr,
+				reg_conf_tbl->reg_data,
+				reg_conf_tbl->dt);
+		} else {
+			if (reg_conf_tbl->dt == 0)
+				dt = data_type;
+			else
+				dt = reg_conf_tbl->dt;
+			switch (dt) {
+			case MSM_CAMERA_I2C_BYTE_DATA:
+			case MSM_CAMERA_I2C_WORD_DATA:
+				rc = msm_camera_i2c_write(
+					client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data, dt);
+				break;
+			case MSM_CAMERA_I2C_SET_BYTE_MASK:
+				rc = msm_camera_i2c_set_mask(client,
 					reg_conf_tbl->reg_addr,
 					reg_conf_tbl->reg_data,
-					reg_conf_tbl->dt);
-			} else {
-				if (reg_conf_tbl->dt == 0)
-					dt = data_type;
-				else
-					dt = reg_conf_tbl->dt;
-				switch (dt) {
-				case MSM_CAMERA_I2C_BYTE_DATA:
-				case MSM_CAMERA_I2C_WORD_DATA:
-					rc = msm_camera_i2c_write(
-						client,
-						reg_conf_tbl->reg_addr,
-						reg_conf_tbl->reg_data, dt);
-					break;
-				case MSM_CAMERA_I2C_SET_BYTE_MASK:
-					rc = msm_camera_i2c_set_mask(client,
-						reg_conf_tbl->reg_addr,
-						reg_conf_tbl->reg_data,
-						MSM_CAMERA_I2C_BYTE_DATA, 1);
-					break;
-				case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
-					rc = msm_camera_i2c_set_mask(client,
-						reg_conf_tbl->reg_addr,
-						reg_conf_tbl->reg_data,
-						MSM_CAMERA_I2C_BYTE_DATA, 0);
-					break;
-				case MSM_CAMERA_I2C_SET_WORD_MASK:
-					rc = msm_camera_i2c_set_mask(client,
-						reg_conf_tbl->reg_addr,
-						reg_conf_tbl->reg_data,
-						MSM_CAMERA_I2C_WORD_DATA, 1);
-					break;
-				case MSM_CAMERA_I2C_UNSET_WORD_MASK:
-					rc = msm_camera_i2c_set_mask(client,
-						reg_conf_tbl->reg_addr,
-						reg_conf_tbl->reg_data,
-						MSM_CAMERA_I2C_WORD_DATA, 0);
-					break;
-				case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA:
-					rc = msm_camera_i2c_set_write_mask_data(
-						client,
-						reg_conf_tbl->reg_addr,
-						reg_conf_tbl->reg_data,
-						reg_conf_tbl->mask,
-						MSM_CAMERA_I2C_BYTE_DATA);
-					break;
-				default:
-					pr_err("%s: Unsupport data type: %d\n",
-						__func__, dt);
-					break;
-				}
-			}
-			if (rc < 0)
+					MSM_CAMERA_I2C_BYTE_DATA, 1);
 				break;
-			reg_conf_tbl++;
+			case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
+				rc = msm_camera_i2c_set_mask(client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					MSM_CAMERA_I2C_BYTE_DATA, 0);
+				break;
+			case MSM_CAMERA_I2C_SET_WORD_MASK:
+				rc = msm_camera_i2c_set_mask(client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					MSM_CAMERA_I2C_WORD_DATA, 1);
+				break;
+			case MSM_CAMERA_I2C_UNSET_WORD_MASK:
+				rc = msm_camera_i2c_set_mask(client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					MSM_CAMERA_I2C_WORD_DATA, 0);
+				break;
+			case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA:
+				rc = msm_camera_i2c_set_write_mask_data(
+					client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					reg_conf_tbl->mask,
+					MSM_CAMERA_I2C_BYTE_DATA);
+				break;
+			default:
+				pr_err("%s: Unsupport data type: %d\n",
+					__func__, dt);
+				break;
+			}
 		}
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
 	}
 	return rc;
 }
diff --git a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
index d508c1d..9e7ede4 100644
--- a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
@@ -145,13 +145,10 @@
 	case S_PREVIEW:
 		break;
 	case S_VIDEO:
-		update_axi_qos(MSM_AXI_QOS_RECORDING);
 		break;
 	case S_CAPTURE:
-		update_axi_qos(MSM_AXI_QOS_SNAPSHOT);
 		break;
 	case S_DEFAULT:
-		update_axi_qos(PM_QOS_DEFAULT_VALUE);
 		break;
 	case S_EXIT:
 		axi_free(AXI_FLOW_VIEWFINDER_HI);
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
index 0370f63..06135ec 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
@@ -50,7 +50,7 @@
 		return 0;
 
 	rc = ion_map_iommu(pgmn_dev->jpeg_client, *ionhandle, domain_num, 0,
-		SZ_4K, 0, &paddr, (unsigned long *)&size, UNCACHED,
+		SZ_4K, 0, &paddr, (unsigned long *)&size, 0,
 0); JPEG_DBG("%s:%d] addr 0x%x size %ld", __func__, __LINE__,
 							(uint32_t)paddr, size);
 
diff --git a/drivers/media/video/msm/mercury/msm_mercury_platform.c b/drivers/media/video/msm/mercury/msm_mercury_platform.c
index e90c63c..3dc7f4b 100644
--- a/drivers/media/video/msm/mercury/msm_mercury_platform.c
+++ b/drivers/media/video/msm/mercury/msm_mercury_platform.c
@@ -58,7 +58,7 @@
 
 	rc = ion_map_iommu(mercury_client, *ionhandle, CAMERA_DOMAIN,
 		GEN_POOL, SZ_4K, 0, &paddr,
-		(unsigned long *)&size, UNCACHED, 0);
+		(unsigned long *)&size, 0, 0);
 #elif CONFIG_ANDROID_PMEM
 	unsigned long kvstart;
 	rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 953f042..3083bb2 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -898,7 +898,7 @@
 			meta_frame->map[i].handle);
 		if (ion_map_iommu(client, meta_frame->map[i].handle,
 				domain_num, 0, SZ_4K,
-				0, &paddr, &len, UNCACHED, 0) < 0) {
+				0, &paddr, &len, 0, 0) < 0) {
 			pr_err("%s: cannot map address plane %d", __func__, i);
 			ion_free(client, meta_frame->map[i].handle);
 			/* Roll back previous plane mappings, if any */
diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c
index 5136d9d..1875df2 100644
--- a/drivers/media/video/msm/msm_mem.c
+++ b/drivers/media/video/msm/msm_mem.c
@@ -136,7 +136,7 @@
 	if (IS_ERR_OR_NULL(region->handle))
 		goto out1;
 	if (ion_map_iommu(client, region->handle, domain_num, 0,
-				  SZ_4K, 0, &paddr, &len, UNCACHED, 0) < 0)
+				  SZ_4K, 0, &paddr, &len, 0, 0) < 0)
 		goto out2;
 #elif CONFIG_ANDROID_PMEM
 	rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index f5c9a73..63cf38e 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -1143,18 +1143,6 @@
 			sensordata->pdata[i].csid_core);
 	}
 
-	rc = of_property_read_u32_array(of_node, "qcom,is-vpe", val_array,
-		count);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR2;
-	}
-	for (i = 0; i < count; i++) {
-		sensordata->pdata[i].is_vpe = val_array[i];
-		CDBG("%s csi_data[%d].is_vpe = %d\n", __func__, i,
-			sensordata->pdata[i].is_vpe);
-	}
-
 	pinfo->csi_lane_params = kzalloc(
 		sizeof(struct msm_camera_csi_lane_params), GFP_KERNEL);
 	if (!pinfo->csi_lane_params) {
diff --git a/drivers/media/video/msm/sensors/mt9m114_v4l2.c b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
index cba9538..c952f7b 100644
--- a/drivers/media/video/msm/sensors/mt9m114_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. 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
@@ -1219,11 +1219,52 @@
 	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
 };
 
+static const struct of_device_id mt9m114_dt_match[] = {
+	{.compatible = "qcom,mt9m114", .data = &mt9m114_s_ctrl},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, mt9m114_dt_match);
+
+static struct platform_driver mt9m114_platform_driver = {
+	.driver = {
+		.name = "qcom,mt9m114",
+		.owner = THIS_MODULE,
+		.of_match_table = mt9m114_dt_match,
+	},
+};
+
+static int32_t mt9m114_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	const struct of_device_id *match;
+	match = of_match_device(mt9m114_dt_match, &pdev->dev);
+	rc = msm_sensor_platform_probe(pdev, match->data);
+	return rc;
+}
+
 static int __init msm_sensor_init_module(void)
 {
+	int32_t rc = 0;
+	rc = platform_driver_probe(&mt9m114_platform_driver,
+		mt9m114_platform_probe);
+	if (!rc)
+		return rc;
 	return i2c_add_driver(&mt9m114_i2c_driver);
 }
 
+
+static void __exit msm_sensor_exit_module(void)
+{
+	if (mt9m114_s_ctrl.pdev) {
+		msm_sensor_free_sensor_data(&mt9m114_s_ctrl);
+		platform_driver_unregister(&mt9m114_platform_driver);
+	} else {
+		i2c_del_driver(&mt9m114_i2c_driver);
+	}
+	return;
+}
+
 static struct v4l2_subdev_core_ops mt9m114_subdev_core_ops = {
 	.s_ctrl = msm_sensor_v4l2_s_ctrl,
 	.queryctrl = msm_sensor_v4l2_query_ctrl,
@@ -1286,5 +1327,6 @@
 };
 
 module_init(msm_sensor_init_module);
+module_exit(msm_sensor_exit_module);
 MODULE_DESCRIPTION("Aptina 1.26MP YUV sensor driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/sensors/s5k3l1yx.c b/drivers/media/video/msm/sensors/s5k3l1yx.c
index 6a2372e..0bd625c 100644
--- a/drivers/media/video/msm/sensors/s5k3l1yx.c
+++ b/drivers/media/video/msm/sensors/s5k3l1yx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. 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
@@ -442,6 +442,43 @@
 	{0x0B00, 0x00},
 };
 
+static struct msm_camera_i2c_reg_conf s5k3l1yx_19mhz_prev_settings[] = {
+	{0x0501, 0x00}, /* compression_algorithim_L(1d) */
+	{0x0112, 0x0A}, /* CCP_data_format_H */
+	{0x0113, 0x0A}, /* CCP_data_format_L raw8=0808 ,DCPM10 -->8= 0A08 */
+	{0x0306, 0x00}, /* pll_multiplier */
+	{0x0307, 0xCE}, /* pll_multiplier */
+	{0x0202, 0x06}, /* coarse_integration_time */
+	{0x0203, 0x00}, /* coarse_integration_time */
+	{0x0340, 0x09}, /* frame_length_lines */
+	{0x0341, 0x6C}, /* frame_length_lines */
+	{0x0342, 0x11}, /* line_length_pck */
+	{0x0343, 0x80}, /* line_length_pck */
+	{0x0344, 0x00}, /* x_addr_start */
+	{0x0345, 0x18}, /* x_addr_start */
+	{0x0346, 0x00}, /* y_addr_start */
+	{0x0347, 0x00}, /* y_addr_start */
+	{0x0348, 0x0F}, /* x_addr_end */
+	{0x0349, 0x97}, /* x_addr_end */
+	{0x034A, 0x0B}, /* y_addr_end */
+	{0x034B, 0xC7}, /* y_addr_end */
+	{0x034C, 0x07}, /* x_output_size */
+	{0x034D, 0xC0}, /* x_output_size */
+	{0x034E, 0x05}, /* y_output_size */
+	{0x034F, 0xE4}, /* y_output_size */
+	{0x0380, 0x00}, /* x_even_inc */
+	{0x0381, 0x01}, /* x_even_inc */
+	{0x0382, 0x00}, /* x_odd_inc */
+	{0x0383, 0x03}, /* x_odd_inc */
+	{0x0384, 0x00}, /* y_even_inc */
+	{0x0385, 0x01}, /* y_even_inc */
+	{0x0386, 0x00}, /* y_odd_inc */
+	{0x0387, 0x03}, /* y_odd_inc */
+	{0x0900, 0x01}, /* binning_mode */
+	{0x0901, 0x22}, /* binning_type */
+	{0x0902, 0x01}, /* binning_weighting */
+};
+
 static struct v4l2_subdev_info s5k3l1yx_subdev_info[] = {
 	{
 	.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
@@ -471,6 +508,8 @@
 					MSM_CAMERA_I2C_BYTE_DATA},
 	{&s5k3l1yx_dpcm_settings[0],
 	ARRAY_SIZE(s5k3l1yx_dpcm_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+	{&s5k3l1yx_19mhz_prev_settings[0],
+	ARRAY_SIZE(s5k3l1yx_19mhz_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
 };
 
 static struct msm_sensor_output_info_t s5k3l1yx_dimensions[] = {
@@ -534,6 +573,16 @@
 		.op_pixel_clk = 320000000,
 		.binning_factor = 1,
 	},
+	/* 30 fps preview with 19.2 input clock*/
+	{
+		.x_output = 1984,
+		.y_output = 1508,
+		.line_length_pclk = 4480,
+		.frame_length_lines = 2412,
+		.vt_pixel_clk = 330000000,
+		.op_pixel_clk = 264000000,
+		.binning_factor = 1,
+	},
 };
 
 static struct msm_sensor_output_reg_addr_t s5k3l1yx_reg_addr = {
diff --git a/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c b/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c
index a813e09..36f8b11 100644
--- a/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c
+++ b/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c
@@ -221,7 +221,7 @@
 	}
 	if (ion_map_iommu(client, stats_buf->handle,
 			domain_num, 0, SZ_4K,
-			0, &paddr, &len, UNCACHED, 0) < 0) {
+			0, &paddr, &len, 0, 0) < 0) {
 		rc = -EINVAL;
 		pr_err("%s: cannot map address", __func__);
 		goto out2;
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index 156a721..3dd2193 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -24,7 +24,7 @@
 static int get_device_address(struct ion_client *clnt,
 		struct ion_handle *hndl, int domain_num, int partition_num,
 		unsigned long align, unsigned long *iova,
-		unsigned long *buffer_size,	unsigned long flags)
+		unsigned long *buffer_size)
 {
 	int rc;
 	if (!iova || !buffer_size || !hndl || !clnt) {
@@ -37,7 +37,7 @@
 	dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
 		domain_num, partition_num);
 	rc = ion_map_iommu(clnt, hndl, domain_num, partition_num, align,
-			0, iova, buffer_size, UNCACHED, 0);
+			0, iova, buffer_size, 0, 0);
 	if (rc)
 		dprintk(VIDC_ERR,
 		"ion_map_iommu failed(%d).domain: %d,partition: %d\n",
@@ -57,7 +57,6 @@
 			struct msm_smem *mem)
 {
 	struct ion_handle *hndl;
-	unsigned long ionflag;
 	unsigned long iova = 0;
 	unsigned long buffer_size = 0;
 	int rc = 0;
@@ -68,16 +67,11 @@
 		rc = -ENOMEM;
 		goto fail_import_fd;
 	}
-	rc = ion_handle_get_flags(client->clnt, hndl, &ionflag);
-	if (rc) {
-		dprintk(VIDC_ERR, "Failed to get ion flags: %d", rc);
-		goto fail_map;
-	}
 	mem->kvaddr = NULL;
 	mem->domain = domain;
 	mem->partition_num = partition;
 	rc = get_device_address(client->clnt, hndl, mem->domain,
-		mem->partition_num, 4096, &iova, &buffer_size, ionflag);
+		mem->partition_num, 4096, &iova, &buffer_size);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to get device address: %d\n", rc);
 		goto fail_device_address;
@@ -92,7 +86,6 @@
 	return rc;
 fail_device_address:
 	ion_unmap_kernel(client->clnt, hndl);
-fail_map:
 	ion_free(client->clnt, hndl);
 fail_import_fd:
 	return rc;
@@ -106,19 +99,20 @@
 	unsigned long iova = 0;
 	unsigned long buffer_size = 0;
 	unsigned long ionflags = 0;
+	unsigned long heap_mask = 0;
 	int rc = 0;
 	if (flags == SMEM_CACHED)
-		ionflags |= ION_SET_CACHE(CACHED);
+		ionflags = ION_SET_CACHED(ionflags);
 	else
-		ionflags |= ION_SET_CACHE(UNCACHED);
+		ionflags = ION_SET_UNCACHED(ionflags);
 
-	ionflags = ionflags | ION_HEAP(ION_CP_MM_HEAP_ID);
+	heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
 	if (align < 4096)
 		align = 4096;
 	size = (size + 4095) & (~4095);
 	dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
 		domain, partition);
-	hndl = ion_alloc(client->clnt, size, align, ionflags);
+	hndl = ion_alloc(client->clnt, size, align, heap_mask, ionflags);
 	if (IS_ERR_OR_NULL(hndl)) {
 		dprintk(VIDC_ERR,
 		"Failed to allocate shared memory = %p, %d, %d, 0x%lx\n",
@@ -131,7 +125,7 @@
 	mem->domain = domain;
 	mem->partition_num = partition;
 	if (map_kernel) {
-		mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
+		mem->kvaddr = ion_map_kernel(client->clnt, hndl);
 		if (!mem->kvaddr) {
 			dprintk(VIDC_ERR,
 				"Failed to map shared mem in kernel\n");
@@ -142,7 +136,7 @@
 		mem->kvaddr = NULL;
 
 	rc = get_device_address(client->clnt, hndl, mem->domain,
-		mem->partition_num, align, &iova, &buffer_size, UNCACHED);
+		mem->partition_num, align, &iova, &buffer_size);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to get device address: %d\n",
 			rc);
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 7fa4f26..fda03de 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -583,7 +583,7 @@
 				buffer_info.m.planes[0].reserved[0],
 				buffer_info.m.planes[0].reserved[1],
 				buffer_info.m.planes[0].length);
-			rc = msm_vidc_release_buf(&v4l2_inst->vidc_inst,
+			rc = msm_vidc_release_buf(v4l2_inst->vidc_inst,
 				&buffer_info);
 			if (rc)
 				dprintk(VIDC_ERR,
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index ead118d..d843d87 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -281,7 +281,7 @@
 int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
 {
 	int rc = 0;
-	struct vb2_queue *q;
+	struct buf_queue *q;
 	q = msm_comm_get_vb2q(inst, i);
 	if (!q) {
 		dprintk(VIDC_ERR,
@@ -289,7 +289,9 @@
 		return -EINVAL;
 	}
 	dprintk(VIDC_DBG, "Calling streamon\n");
-	rc = vb2_streamon(q, i);
+	mutex_lock(&q->lock);
+	rc = vb2_streamon(&q->vb2_bufq, i);
+	mutex_unlock(&q->lock);
 	if (rc)
 		dprintk(VIDC_ERR, "streamon failed on port: %d\n", i);
 	return rc;
@@ -298,7 +300,7 @@
 int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
 {
 	int rc = 0;
-	struct vb2_queue *q;
+	struct buf_queue *q;
 
 	q = msm_comm_get_vb2q(inst, i);
 	if (!q) {
@@ -307,7 +309,9 @@
 		return -EINVAL;
 	}
 	dprintk(VIDC_DBG, "Calling streamoff\n");
-	rc = vb2_streamoff(q, i);
+	mutex_lock(&q->lock);
+	rc = vb2_streamoff(&q->vb2_bufq, i);
+	mutex_unlock(&q->lock);
 	if (rc)
 		dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
 	return rc;
@@ -403,7 +407,7 @@
 
 int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
 {
-	struct vb2_queue *q = NULL;
+	struct buf_queue *q = NULL;
 	int rc = 0;
 	q = msm_comm_get_vb2q(inst, b->type);
 	if (!q) {
@@ -411,14 +415,16 @@
 			, b->type);
 		return -EINVAL;
 	}
-	rc = vb2_qbuf(q, b);
+	mutex_lock(&q->lock);
+	rc = vb2_qbuf(&q->vb2_bufq, b);
+	mutex_unlock(&q->lock);
 	if (rc)
 		dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
 	return rc;
 }
 int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
 {
-	struct vb2_queue *q = NULL;
+	struct buf_queue *q = NULL;
 	int rc = 0;
 	q = msm_comm_get_vb2q(inst, b->type);
 	if (!q) {
@@ -426,7 +432,9 @@
 			, b->type);
 		return -EINVAL;
 	}
-	rc = vb2_dqbuf(q, b, true);
+	mutex_lock(&q->lock);
+	rc = vb2_dqbuf(&q->vb2_bufq, b, true);
+	mutex_unlock(&q->lock);
 	if (rc)
 		dprintk(VIDC_WARN, "Failed to dqbuf, %d\n", rc);
 	return rc;
@@ -434,7 +442,7 @@
 
 int msm_vdec_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
 {
-	struct vb2_queue *q = NULL;
+	struct buf_queue *q = NULL;
 	int rc = 0;
 	if (!inst || !b) {
 		dprintk(VIDC_ERR,
@@ -448,7 +456,9 @@
 		return -EINVAL;
 	}
 
-	rc = vb2_reqbufs(q, b);
+	mutex_lock(&q->lock);
+	rc = vb2_reqbufs(&q->vb2_bufq, b);
+	mutex_unlock(&q->lock);
 	if (rc)
 		dprintk(VIDC_ERR, "Failed to get reqbufs, %d\n", rc);
 	return rc;
@@ -770,11 +780,11 @@
 		"Streamon called on: %d capability\n", q->type);
 	switch (q->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-		if (inst->vb2_bufq[CAPTURE_PORT].streaming)
+		if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
 			rc = start_streaming(inst);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-		if (inst->vb2_bufq[OUTPUT_PORT].streaming)
+		if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
 			rc = start_streaming(inst);
 		break;
 	default:
@@ -797,11 +807,11 @@
 	dprintk(VIDC_DBG, "Streamoff called on: %d capability\n", q->type);
 	switch (q->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-		if (!inst->vb2_bufq[CAPTURE_PORT].streaming)
+		if (!inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
 			rc = stop_streaming(inst);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-		if (!inst->vb2_bufq[OUTPUT_PORT].streaming)
+		if (!inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
 			rc = stop_streaming(inst);
 		break;
 	default:
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index c137c08..948676a 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -444,6 +444,17 @@
 		(1 << L_MODE)
 		),
 	},
+	{
+		.id = V4L2_CID_QCOM_VIDEO_SYNC_FRAME_SEQ_HDR,
+		.name = "CodecConfig with sync frame",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 1,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
 };
 
 #define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -625,7 +636,6 @@
 			sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
 					i, inst->prop.height, inst->prop.width);
 		}
-
 		break;
 	default:
 		dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
@@ -641,6 +651,7 @@
 	unsigned long flags;
 	struct vb2_buf_entry *temp;
 	struct list_head *ptr, *next;
+
 	rc = msm_comm_try_get_bufreqs(inst);
 	if (rc) {
 		dprintk(VIDC_ERR,
@@ -700,11 +711,11 @@
 	dprintk(VIDC_DBG, "Streamon called on: %d capability\n", q->type);
 	switch (q->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-		if (inst->vb2_bufq[CAPTURE_PORT].streaming)
+		if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
 			rc = start_streaming(inst);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-		if (inst->vb2_bufq[OUTPUT_PORT].streaming)
+		if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
 			rc = start_streaming(inst);
 		break;
 	default:
@@ -785,6 +796,7 @@
 	struct hal_intra_refresh intra_refresh;
 	struct hal_multi_slice_control multi_slice_control;
 	struct hal_h264_db_control h264_db_control;
+	struct hal_enable enable;
 	u32 property_id = 0;
 	u32 property_val = 0;
 	void *pdata;
@@ -1204,6 +1216,12 @@
 		h264_db_control.slice_beta_offset = control.value;
 		pdata = &h264_db_control;
 		break;
+	case V4L2_CID_QCOM_VIDEO_SYNC_FRAME_SEQ_HDR:
+		property_id =
+			HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER;
+		enable.enable = control.value;
+		pdata = &enable;
+		break;
 	default:
 		break;
 	}
@@ -1419,7 +1437,7 @@
 
 int msm_venc_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
 {
-	struct vb2_queue *q = NULL;
+	struct buf_queue *q = NULL;
 	int rc = 0;
 	if (!inst || !b) {
 		dprintk(VIDC_ERR,
@@ -1433,7 +1451,9 @@
 		return -EINVAL;
 	}
 
-	rc = vb2_reqbufs(q, b);
+	mutex_lock(&q->lock);
+	rc = vb2_reqbufs(&q->vb2_bufq, b);
+	mutex_unlock(&q->lock);
 	if (rc)
 		dprintk(VIDC_ERR, "Failed to get reqbufs, %d\n", rc);
 	return rc;
@@ -1479,7 +1499,7 @@
 
 int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
 {
-	struct vb2_queue *q = NULL;
+	struct buf_queue *q = NULL;
 	int rc = 0;
 	q = msm_comm_get_vb2q(inst, b->type);
 	if (!q) {
@@ -1487,7 +1507,9 @@
 			"Failed to find buffer queue for type = %d\n", b->type);
 		return -EINVAL;
 	}
-	rc = vb2_qbuf(q, b);
+	mutex_lock(&q->lock);
+	rc = vb2_qbuf(&q->vb2_bufq, b);
+	mutex_unlock(&q->lock);
 	if (rc)
 		dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
 	return rc;
@@ -1495,7 +1517,7 @@
 
 int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
 {
-	struct vb2_queue *q = NULL;
+	struct buf_queue *q = NULL;
 	int rc = 0;
 	q = msm_comm_get_vb2q(inst, b->type);
 	if (!q) {
@@ -1503,7 +1525,9 @@
 			"Failed to find buffer queue for type = %d\n", b->type);
 		return -EINVAL;
 	}
-	rc = vb2_dqbuf(q, b, true);
+	mutex_lock(&q->lock);
+	rc = vb2_dqbuf(&q->vb2_bufq, b, true);
+	mutex_unlock(&q->lock);
 	if (rc)
 		dprintk(VIDC_DBG, "Failed to dqbuf, %d\n", rc);
 	return rc;
@@ -1512,7 +1536,7 @@
 int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
 {
 	int rc = 0;
-	struct vb2_queue *q;
+	struct buf_queue *q;
 	q = msm_comm_get_vb2q(inst, i);
 	if (!q) {
 		dprintk(VIDC_ERR,
@@ -1520,7 +1544,9 @@
 		return -EINVAL;
 	}
 	dprintk(VIDC_DBG, "Calling streamon\n");
-	rc = vb2_streamon(q, i);
+	mutex_lock(&q->lock);
+	rc = vb2_streamon(&q->vb2_bufq, i);
+	mutex_unlock(&q->lock);
 	if (rc)
 		dprintk(VIDC_ERR, "streamon failed on port: %d\n", i);
 	return rc;
@@ -1529,7 +1555,7 @@
 int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
 {
 	int rc = 0;
-	struct vb2_queue *q;
+	struct buf_queue *q;
 	q = msm_comm_get_vb2q(inst, i);
 	if (!q) {
 		dprintk(VIDC_ERR,
@@ -1537,7 +1563,9 @@
 		return -EINVAL;
 	}
 	dprintk(VIDC_DBG, "Calling streamoff on port: %d\n", i);
-	rc = vb2_streamoff(q, i);
+	mutex_lock(&q->lock);
+	rc = vb2_streamoff(&q->vb2_bufq, i);
+	mutex_unlock(&q->lock);
 	if (rc)
 		dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
 	return rc;
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index ec9dac8..8ff7714 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -27,8 +27,8 @@
 static int get_poll_flags(void *instance)
 {
 	struct msm_vidc_inst *inst = instance;
-	struct vb2_queue *outq = &inst->vb2_bufq[OUTPUT_PORT];
-	struct vb2_queue *capq = &inst->vb2_bufq[CAPTURE_PORT];
+	struct vb2_queue *outq = &inst->bufq[OUTPUT_PORT].vb2_bufq;
+	struct vb2_queue *capq = &inst->bufq[CAPTURE_PORT].vb2_bufq;
 	struct vb2_buffer *out_vb = NULL;
 	struct vb2_buffer *cap_vb = NULL;
 	unsigned long flags;
@@ -62,8 +62,8 @@
 		struct poll_table_struct *wait)
 {
 	struct msm_vidc_inst *inst = instance;
-	struct vb2_queue *outq = &inst->vb2_bufq[OUTPUT_PORT];
-	struct vb2_queue *capq = &inst->vb2_bufq[CAPTURE_PORT];
+	struct vb2_queue *outq = &inst->bufq[OUTPUT_PORT].vb2_bufq;
+	struct vb2_queue *capq = &inst->bufq[CAPTURE_PORT].vb2_bufq;
 
 	poll_wait(filp, &inst->event_handler.wait, wait);
 	poll_wait(filp, &capq->done_wq, wait);
@@ -306,9 +306,9 @@
 {
 	struct vb2_queue *q = NULL;
 	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-		q = &inst->vb2_bufq[CAPTURE_PORT];
+		q = &inst->bufq[CAPTURE_PORT].vb2_bufq;
 	} else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-		q = &inst->vb2_bufq[OUTPUT_PORT];
+		q = &inst->bufq[OUTPUT_PORT].vb2_bufq;
 	} else {
 		dprintk(VIDC_ERR, "buf_type = %d not recognised\n", type);
 		return -EINVAL;
@@ -404,6 +404,8 @@
 	}
 
 	mutex_init(&inst->sync_lock);
+	mutex_init(&inst->bufq[CAPTURE_PORT].lock);
+	mutex_init(&inst->bufq[OUTPUT_PORT].lock);
 	spin_lock_init(&inst->lock);
 	inst->session_type = session_type;
 	INIT_LIST_HEAD(&inst->pendingq);
@@ -489,8 +491,10 @@
 				buf = list_entry(ptr, struct internal_buf,
 						list);
 				list_del(&buf->list);
+				spin_unlock_irqrestore(&inst->lock, flags);
 				msm_smem_free(inst->mem_client, buf->handle);
 				kfree(buf);
+				spin_lock_irqsave(&inst->lock, flags);
 			}
 		}
 		if (!list_empty(&inst->persistbufs)) {
@@ -498,12 +502,17 @@
 				buf = list_entry(ptr, struct internal_buf,
 						list);
 				list_del(&buf->list);
+				spin_unlock_irqrestore(&inst->lock, flags);
 				msm_smem_free(inst->mem_client, buf->handle);
 				kfree(buf);
+				spin_lock_irqsave(&inst->lock, flags);
 			}
 		}
-		if (inst->extradata_handle)
+		if (inst->extradata_handle) {
+			spin_unlock_irqrestore(&inst->lock, flags);
 			msm_smem_free(inst->mem_client, inst->extradata_handle);
+			spin_lock_irqsave(&inst->lock, flags);
+		}
 		spin_unlock_irqrestore(&inst->lock, flags);
 		msm_smem_delete_client(inst->mem_client);
 		debugfs_remove_recursive(inst->debugfs_root);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 2aed0b7..1cad40f 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -258,13 +258,13 @@
 	return &fmt[i];
 }
 
-struct vb2_queue *msm_comm_get_vb2q(
+struct buf_queue *msm_comm_get_vb2q(
 		struct msm_vidc_inst *inst,	enum v4l2_buf_type type)
 {
 	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-		return &inst->vb2_bufq[CAPTURE_PORT];
+		return &inst->bufq[CAPTURE_PORT];
 	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-		return &inst->vb2_bufq[OUTPUT_PORT];
+		return &inst->bufq[OUTPUT_PORT];
 	return NULL;
 }
 
@@ -527,21 +527,25 @@
 	}
 }
 
-static struct vb2_buffer *get_vb_from_device_addr(struct vb2_queue *q,
+static struct vb2_buffer *get_vb_from_device_addr(struct buf_queue *bufq,
 		u32 dev_addr)
 {
 	struct vb2_buffer *vb = NULL;
+	struct vb2_queue *q = NULL;
 	int found = 0;
-	if (!q) {
+	if (!bufq) {
 		dprintk(VIDC_ERR, "Invalid parameter\n");
 		return NULL;
 	}
+	q = &bufq->vb2_bufq;
+	mutex_lock(&bufq->lock);
 	list_for_each_entry(vb, &q->queued_list, queued_entry) {
 		if (vb->v4l2_planes[0].m.userptr == dev_addr) {
 			found = 1;
 			break;
 		}
 	}
+	mutex_unlock(&bufq->lock);
 	if (!found) {
 		dprintk(VIDC_ERR,
 			"Failed to find the buffer in queued list: %d, %d\n",
@@ -563,7 +567,9 @@
 	vb = response->clnt_data;
 	inst = (struct msm_vidc_inst *)response->session_id;
 	if (vb) {
+		mutex_lock(&inst->bufq[OUTPUT_PORT].lock);
 		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+		mutex_unlock(&inst->bufq[OUTPUT_PORT].lock);
 		wake_up(&inst->kernel_event_queue);
 	}
 }
@@ -580,7 +586,7 @@
 	}
 	inst = (struct msm_vidc_inst *)response->session_id;
 	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
-	vb = get_vb_from_device_addr(&inst->vb2_bufq[CAPTURE_PORT],
+	vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
 		(u32)fill_buf_done->packet_buffer1);
 	if (vb) {
 		vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
@@ -600,10 +606,8 @@
 			vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
 			vb->v4l2_buf.flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG;
-
-		if (!inst->fbd_count)
-			vb->v4l2_buf.flags = V4L2_BUF_FLAG_KEYFRAME;
-		++inst->fbd_count;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME)
+			vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
 
 		switch (fill_buf_done->picture_type) {
 		case HAL_PICTURE_IDR:
@@ -628,7 +632,9 @@
 		dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
 				vb->v4l2_planes[0].bytesused,
 				vb->v4l2_buf.flags);
+		mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
 		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+		mutex_unlock(&inst->bufq[CAPTURE_PORT].lock);
 		wake_up(&inst->kernel_event_queue);
 	} else {
 		/*
@@ -645,18 +651,19 @@
 		 */
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS
 			&& fill_buf_done->filled_len1 == 0) {
-			struct vb2_queue *q = &inst->vb2_bufq[CAPTURE_PORT];
+			struct buf_queue *q = &inst->bufq[CAPTURE_PORT];
 
-			if (!list_empty(&q->queued_list)) {
-				vb = list_first_entry(&q->queued_list,
+			if (!list_empty(&q->vb2_bufq.queued_list)) {
+				vb = list_first_entry(&q->vb2_bufq.queued_list,
 					struct vb2_buffer, queued_entry);
 				vb->v4l2_planes[0].bytesused = 0;
 				vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
+				mutex_lock(&q->lock);
 				vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+				mutex_unlock(&q->lock);
 			}
 
 		}
-
 	}
 }
 
@@ -672,7 +679,7 @@
 	}
 	inst = (struct msm_vidc_inst *)response->session_id;
 	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
-	vb = get_vb_from_device_addr(&inst->vb2_bufq[CAPTURE_PORT],
+	vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
 		(u32)fill_buf_done->packet_buffer1);
 	if (vb)
 		vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
@@ -682,7 +689,9 @@
 	dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
 				vb->v4l2_planes[0].bytesused,
 				vb->v4l2_buf.flags);
+	mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
 	vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+	mutex_unlock(&inst->bufq[CAPTURE_PORT].lock);
 }
 
 void handle_cmd_response(enum command_response cmd, void *data)
@@ -1203,7 +1212,6 @@
 		goto exit;
 	}
 	inst->ftb_count = 0;
-	inst->fbd_count = 0;
 	change_inst_state(inst, MSM_VIDC_OPEN);
 exit:
 	return rc;
@@ -1586,9 +1594,16 @@
 			buffer_info.align_device_addr = handle->device_addr;
 			rc = vidc_hal_session_release_buffers(
 				(void *) inst->session,	&buffer_info);
+			if (rc)
+				dprintk(VIDC_WARN,
+					"Failed to release scratch buffer: 0x%x, %d",
+					buffer_info.align_device_addr,
+					buffer_info.buffer_size);
 			list_del(&buf->list);
+			spin_unlock_irqrestore(&inst->lock, flags);
 			msm_smem_free(inst->mem_client, buf->handle);
 			kfree(buf);
+			spin_lock_irqsave(&inst->lock, flags);
 		}
 	}
 	spin_unlock_irqrestore(&inst->lock, flags);
@@ -1617,11 +1632,14 @@
 				(void *) inst->session,	&buffer_info);
 			if (rc)
 				dprintk(VIDC_WARN,
-					"Failed in %s for buffer %ld\n",
-					__func__, handle->device_addr);
+					"Failed to release persist buffer 0x%x, %d\n",
+					buffer_info.align_device_addr,
+					buffer_info.buffer_size);
 			list_del(&buf->list);
+			spin_unlock_irqrestore(&inst->lock, flags);
 			msm_smem_free(inst->mem_client, buf->handle);
 			kfree(buf);
+			spin_lock_irqsave(&inst->lock, flags);
 		}
 	}
 	spin_unlock_irqrestore(&inst->lock, flags);
@@ -1633,7 +1651,6 @@
 	int rc = 0;
 	struct msm_smem *handle;
 	struct internal_buf *binfo;
-	struct list_head *ptr, *next;
 	struct vidc_buffer_addr_info buffer_info;
 	unsigned long flags;
 	struct hal_buffer_requirements *scratch_buf =
@@ -1643,28 +1660,9 @@
 		"scratch: num = %d, size = %d\n",
 		scratch_buf->buffer_count_actual,
 		scratch_buf->buffer_size);
-	spin_lock_irqsave(&inst->lock, flags);
-	if (!list_empty(&inst->internalbufs)) {
-		list_for_each_safe(ptr, next, &inst->internalbufs) {
-			binfo = list_entry(ptr, struct internal_buf,
-					list);
-			handle = binfo->handle;
-			buffer_info.buffer_size = handle->size;
-			buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
-			buffer_info.num_buffers = 1;
-			buffer_info.align_device_addr = handle->device_addr;
-			rc = vidc_hal_session_release_buffers(
-				(void *) inst->session, &buffer_info);
-			if (rc)
-				dprintk(VIDC_WARN,
-					"Failed in release %s for buffer %ld\n",
-					__func__, handle->device_addr);
-			list_del(&binfo->list);
-			msm_smem_free(inst->mem_client, binfo->handle);
-			kfree(binfo);
-		}
-	}
-	spin_unlock_irqrestore(&inst->lock, flags);
+	if (msm_comm_release_scratch_buffers(inst))
+		dprintk(VIDC_WARN, "Failed to release scratch buffers\n");
+
 	if (scratch_buf->buffer_size) {
 		for (i = 0; i < scratch_buf->buffer_count_actual;
 				i++) {
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 1301e5c..0708724 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -23,7 +23,7 @@
 	const struct msm_vidc_format fmt[], int size, int index, int fmt_type);
 const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
 	const struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type);
-struct vb2_queue *msm_comm_get_vb2q(
+struct buf_queue *msm_comm_get_vb2q(
 		struct msm_vidc_inst *inst, enum v4l2_buf_type type);
 int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
 int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 1f2eff8..1ea92fc 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -188,6 +188,11 @@
 	u32 bitrate;
 };
 
+struct buf_queue {
+	struct vb2_queue vb2_bufq;
+	struct mutex lock;
+};
+
 struct msm_vidc_core {
 	struct list_head list;
 	struct mutex sync_lock;
@@ -216,7 +221,7 @@
 	struct session_prop prop;
 	int state;
 	const struct msm_vidc_format *fmts[MAX_PORT_NUM];
-	struct vb2_queue vb2_bufq[MAX_PORT_NUM];
+	struct buf_queue bufq[MAX_PORT_NUM];
 	spinlock_t lock;
 	struct list_head pendingq;
 	struct list_head internalbufs;
@@ -233,7 +238,6 @@
 	u32 reconfig_height;
 	struct dentry *debugfs_root;
 	u32 ftb_count;
-	u32 fbd_count;
 	struct vb2_buffer *vb2_seq_hdr;
 	void *priv;
 };
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index e610f8e..f0d0e73 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -1170,6 +1170,16 @@
 		pkt->size += sizeof(u32) * 2;
 		break;
 	}
+	case HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER:
+	{
+		struct hfi_enable *hfi;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER;
+		hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+		hfi->enable = ((struct hfi_enable *) pdata)->enable;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
 	case HAL_CONFIG_VENC_REQUEST_IFRAME:
 		pkt->rg_property_data[0] =
 			HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME;
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index c77ae12..659cf7e 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -137,6 +137,7 @@
 	HAL_PARAM_VENC_MULTI_SLICE_INFO,
 	HAL_CONFIG_VENC_TIMESTAMP_SCALE,
 	HAL_PARAM_VENC_LOW_LATENCY,
+	HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER,
 };
 
 enum hal_domain {
diff --git a/drivers/media/video/msm_wfd/enc-mfc-subdev.c b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
index 5997345..3292d78 100644
--- a/drivers/media/video/msm_wfd/enc-mfc-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
@@ -1352,6 +1352,48 @@
 err_set_perf_level:
 	return rc;
 }
+
+static long venc_set_avc_delimiter(struct video_client_ctx *client_ctx,
+			__s32 flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_avc_delimiter_enable delimiter_flag;
+	if (!client_ctx)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_ENABLE_DELIMITER_FLAG;
+	vcd_property_hdr.sz =
+			sizeof(struct vcd_property_avc_delimiter_enable);
+	delimiter_flag.avc_delimiter_enable_flag = flag;
+	return vcd_set_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &delimiter_flag);
+}
+
+static long venc_get_avc_delimiter(struct video_client_ctx *client_ctx,
+			__s32 *flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_avc_delimiter_enable delimiter_flag;
+	int rc = 0;
+
+	if (!client_ctx || !flag)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_ENABLE_DELIMITER_FLAG;
+	vcd_property_hdr.sz =
+			sizeof(struct vcd_property_avc_delimiter_enable);
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &delimiter_flag);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Failed getting property for delimiter");
+		return rc;
+	}
+
+	*flag = delimiter_flag.avc_delimiter_enable_flag;
+	return rc;
+}
+
 static long venc_set_header_mode(struct video_client_ctx *client_ctx,
 		__s32 mode)
 {
@@ -1932,7 +1974,7 @@
 	struct vcd_property_enc_recon_buffer *ctrl = NULL;
 	unsigned long phy_addr;
 	int i = 0;
-	int flags = 0;
+	int heap_mask = 0;
 	u32 len;
 	control.width = inst->width;
 	control.height = inst->height;
@@ -1945,8 +1987,8 @@
 		WFD_MSG_ERR("Failed to get recon buf size\n");
 		goto err;
 	}
-	flags = ION_HEAP(ION_CP_MM_HEAP_ID);
-	flags |= inst->secure ? ION_SECURE : ION_HEAP(ION_IOMMU_HEAP_ID);
+	heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
+	heap_mask |= inst->secure ? ION_SECURE : ION_HEAP(ION_IOMMU_HEAP_ID);
 
 	if (vcd_get_ion_status()) {
 		for (i = 0; i < 4; ++i) {
@@ -1957,11 +1999,11 @@
 			ctrl->user_virtual_addr = (void *)i;
 			client_ctx->recon_buffer_ion_handle[i]
 				= ion_alloc(client_ctx->user_ion_client,
-			control.size, SZ_8K, flags);
+			control.size, SZ_8K, heap_mask, 0);
 
 			ctrl->kernel_virtual_addr = ion_map_kernel(
 				client_ctx->user_ion_client,
-				client_ctx->recon_buffer_ion_handle[i],	0);
+				client_ctx->recon_buffer_ion_handle[i]);
 
 			if (IS_ERR_OR_NULL(ctrl->kernel_virtual_addr)) {
 				WFD_MSG_ERR("ion map kernel failed\n");
@@ -2232,6 +2274,9 @@
 	case V4L2_CID_MPEG_QCOM_SET_PERF_LEVEL:
 		rc = venc_set_max_perf_level(client_ctx, ctrl->value);
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
+		rc = venc_set_avc_delimiter(client_ctx, ctrl->value);
+		break;
 	case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
 		rc = venc_set_entropy_mode(client_ctx, ctrl->value);
 		break;
@@ -2303,6 +2348,9 @@
 	case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
 		rc = venc_get_cyclic_intra_refresh_mb(client_ctx, &ctrl->value);
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
+		rc = venc_get_avc_delimiter(client_ctx, &ctrl->value);
+		break;
 	default:
 		WFD_MSG_ERR("Get property not suported: %d\n", ctrl->id);
 		rc = -ENOTSUPP;
diff --git a/drivers/media/video/msm_wfd/enc-venus-subdev.c b/drivers/media/video/msm_wfd/enc-venus-subdev.c
index 04e42f5..89ad6c7 100644
--- a/drivers/media/video/msm_wfd/enc-venus-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-venus-subdev.c
@@ -617,7 +617,7 @@
 	}
 
 	mregion->kvaddr = ion_map_kernel(venc_ion_client,
-				mregion->ion_handle, flags);
+				mregion->ion_handle);
 
 	if (IS_ERR_OR_NULL(mregion->kvaddr)) {
 		WFD_MSG_ERR("Failed to map buffer into kernel\n");
diff --git a/drivers/media/video/msm_wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
index d3c5936..04b787a 100644
--- a/drivers/media/video/msm_wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm_wfd/wfd-ioctl.c
@@ -160,7 +160,7 @@
 	alloc_regions |= secure ? ION_SECURE :
 				ION_HEAP(ION_IOMMU_HEAP_ID);
 	handle = ion_alloc(client,
-			mregion->size, SZ_4K, alloc_regions);
+			mregion->size, SZ_4K, alloc_regions, 0);
 
 	if (IS_ERR_OR_NULL(handle)) {
 		WFD_MSG_ERR("Failed to allocate input buffer\n");
@@ -168,7 +168,7 @@
 		goto alloc_fail;
 	}
 
-	kvaddr = ion_map_kernel(client, handle, secure ? UNCACHED : CACHED);
+	kvaddr = ion_map_kernel(client, handle);
 
 	if (IS_ERR_OR_NULL(kvaddr)) {
 		WFD_MSG_ERR("Failed to get virtual addr\n");
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index 4c3ff16..aa39aad 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -464,7 +464,7 @@
 	}
 
 	handle = ion_alloc(dev->ion_client, size, SZ_4K,
-			ION_HEAP(ION_CP_MM_HEAP_ID));
+			ION_HEAP(ION_CP_MM_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		pr_err("%s: ion_alloc failed\n", __func__);
 		return -ENOMEM;
@@ -483,7 +483,7 @@
 		return rc;
 	}
 
-	vaddr = ion_map_kernel(dev->ion_client, handle, ionflag);
+	vaddr = ion_map_kernel(dev->ion_client, handle);
 	if (IS_ERR(vaddr)) {
 		pr_err("%s: Map motion buffer failed\n", __func__);
 		ion_free(dev->ion_client, handle);
@@ -535,7 +535,7 @@
 		tot_size = frame_size / 2 * 3;
 
 	handle = ion_alloc(dev->ion_client, tot_size, SZ_4K,
-			ION_HEAP(ION_CP_MM_HEAP_ID));
+			ION_HEAP(ION_CP_MM_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		pr_err("%s: ion_alloc failed\n", __func__);
 		return -ENOMEM;
@@ -665,7 +665,7 @@
 
 	dprintk(2, "%s: Start VP dummy event\n", __func__);
 	handle = ion_alloc(dev->ion_client, 0x1200, SZ_4K,
-			ION_HEAP(ION_CP_MM_HEAP_ID));
+			ION_HEAP(ION_CP_MM_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL(handle)) {
 		pr_err("%s: ion_alloc failed\n", __func__);
 		return -ENOMEM;
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index a7d13a8..668cc73 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -1330,14 +1330,11 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&q->q_lock);
 	ret = __vb2_get_done_vb(q, &vb, nonblocking);
 	if (ret < 0) {
 		dprintk(1, "dqbuf: error getting next done buffer\n");
-		mutex_unlock(&q->q_lock);
 		return ret;
 	}
-	mutex_unlock(&q->q_lock);
 	ret = call_qop(q, buf_finish, vb);
 	if (ret) {
 		dprintk(1, "dqbuf: buffer finish failed\n");
@@ -1449,17 +1446,14 @@
 	/*
 	 * Let driver notice that streaming state has been enabled.
 	 */
-	mutex_lock(&q->q_lock);
 	ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
 	if (ret) {
 		dprintk(1, "streamon: driver refused to start streaming\n");
 		__vb2_queue_cancel(q);
-		mutex_unlock(&q->q_lock);
 		return ret;
 	}
 
 	q->streaming = 1;
-	mutex_unlock(&q->q_lock);
 	dprintk(3, "Streamon successful\n");
 	return 0;
 }
@@ -1733,7 +1727,6 @@
 	INIT_LIST_HEAD(&q->queued_list);
 	INIT_LIST_HEAD(&q->done_list);
 	spin_lock_init(&q->done_lock);
-	mutex_init(&q->q_lock);
 	init_waitqueue_head(&q->done_wq);
 
 	if (q->buf_struct_size == 0)
diff --git a/drivers/media/video/videobuf2-msm-mem.c b/drivers/media/video/videobuf2-msm-mem.c
index c1a392e2..97bc7c3 100644
--- a/drivers/media/video/videobuf2-msm-mem.c
+++ b/drivers/media/video/videobuf2-msm-mem.c
@@ -56,7 +56,7 @@
 		goto client_failed;
 	}
 	mem->ion_handle = ion_alloc(mem->client, mem->size, SZ_4K,
-		(0x1 << ION_CP_MM_HEAP_ID | 0x1 << ION_IOMMU_HEAP_ID));
+		(0x1 << ION_CP_MM_HEAP_ID | 0x1 << ION_IOMMU_HEAP_ID), 0);
 	if (IS_ERR((void *)mem->ion_handle)) {
 		pr_err("%s Could not allocate\n", __func__);
 		goto alloc_failed;
@@ -64,7 +64,7 @@
 	rc = ion_map_iommu(mem->client, mem->ion_handle,
 			-1, 0, SZ_4K, 0,
 			(unsigned long *)&phyaddr,
-			(unsigned long *)&len, UNCACHED, 0);
+			(unsigned long *)&len, 0, 0);
 	if (rc < 0) {
 		pr_err("%s Could not get physical address\n", __func__);
 		goto phys_failed;
@@ -192,7 +192,7 @@
 		return PTR_ERR(mem->ion_handle);
 	}
 	rc = ion_map_iommu(client, mem->ion_handle, domain_num, 0,
-		SZ_4K, 0, (unsigned long *)&mem->phyaddr, &len, UNCACHED, 0);
+		SZ_4K, 0, (unsigned long *)&mem->phyaddr, &len, 0, 0);
 	if (rc < 0)
 		ion_free(client, mem->ion_handle);
 #elif CONFIG_ANDROID_PMEM
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index d6d209b..4840e64 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -254,7 +254,6 @@
 				struct qseecom_register_listener_req *listener)
 {
 	int ret = 0;
-	unsigned int flags = 0;
 	struct qseecom_register_listener_ireq req;
 	struct qseecom_command_scm_resp resp;
 	ion_phys_addr_t pa;
@@ -271,8 +270,7 @@
 	ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
 
 	/* Populate the structure for sending scm call to load image */
-	svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
-							svc->ihandle, flags);
+	svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
 	svc->sb_phys = pa;
 
 	if (qseecom.qseos_version == QSEOS_VERSION_14) {
@@ -494,7 +492,6 @@
 {
 	ion_phys_addr_t pa;
 	int32_t ret;
-	unsigned int flags = 0;
 	struct qseecom_set_sb_mem_param_req req;
 	uint32_t len;
 
@@ -513,8 +510,7 @@
 	ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
 	/* Populate the structure for sending scm call to load image */
 	data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
-							data->client.ihandle,
-							flags);
+							data->client.ihandle);
 	data->client.sb_phys = pa;
 	data->client.sb_length = req.sb_len;
 	data->client.user_virt_sb_base = req.virt_sb_base;
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index 15254fb..ebb4afe 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -76,14 +76,3 @@
 
 	  This driver is only of interest to those developing or
 	  testing a host driver. Most people should say N here.
-
-config MMC_BLOCK_TEST
-	tristate "MMC block test"
-	depends on MMC_BLOCK && IOSCHED_TEST
-	default m
-	help
-	  MMC block test can be used with test iosched to test the MMC block
-	  device.
-	  Currently used to test eMMC 4.5 features (packed commands, sanitize,
-	  BKOPs).
-
diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile
index d55107f..c73b406 100644
--- a/drivers/mmc/card/Makefile
+++ b/drivers/mmc/card/Makefile
@@ -8,4 +8,3 @@
 
 obj-$(CONFIG_SDIO_UART)		+= sdio_uart.o
 
-obj-$(CONFIG_MMC_BLOCK_TEST)		+= mmc_block_test.o
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 8b9d08b..63d2fa1 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -59,16 +59,6 @@
 #define INAND_CMD38_ARG_SECTRIM2 0x88
 
 #define MMC_SANITIZE_REQ_TIMEOUT 240000 /* msec */
-#define mmc_req_rel_wr(req)	(((req->cmd_flags & REQ_FUA) || \
-			(req->cmd_flags & REQ_META)) && \
-			(rq_data_dir(req) == WRITE))
-#define PACKED_CMD_VER		0x01
-#define PACKED_CMD_WR		0x02
-#define MMC_BLK_UPDATE_STOP_REASON(stats, reason)			\
-	do {								\
-		if (stats->enabled)					\
-			stats->pack_stop_reason[reason]++;		\
-	} while (0)
 
 static DEFINE_MUTEX(block_mutex);
 
@@ -120,26 +110,24 @@
 	struct device_attribute force_ro;
 	struct device_attribute power_ro_lock;
 	int	area_type;
-	struct device_attribute num_wr_reqs_to_start_packing;
 };
 
 static DEFINE_MUTEX(open_lock);
 
-enum {
-        MMC_PACKED_N_IDX = -1,
-        MMC_PACKED_N_ZERO,
-        MMC_PACKED_N_SINGLE,
+enum mmc_blk_status {
+	MMC_BLK_SUCCESS = 0,
+	MMC_BLK_PARTIAL,
+	MMC_BLK_CMD_ERR,
+	MMC_BLK_RETRY,
+	MMC_BLK_ABORT,
+	MMC_BLK_DATA_ERR,
+	MMC_BLK_ECC_ERR,
+	MMC_BLK_NOMEDIUM,
 };
 
 module_param(perdev_minors, int, 0444);
 MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
 
-static inline void mmc_blk_clear_packed(struct mmc_queue_req *mqrq)
-{
-        mqrq->packed_cmd = MMC_PACKED_NONE;
-        mqrq->packed_num = MMC_PACKED_N_ZERO;
-}
-
 static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
 {
 	struct mmc_blk_data *md;
@@ -273,38 +261,6 @@
 	return ret;
 }
 
-static ssize_t
-num_wr_reqs_to_start_packing_show(struct device *dev,
-				  struct device_attribute *attr, char *buf)
-{
-	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
-	int num_wr_reqs_to_start_packing;
-	int ret;
-
-	num_wr_reqs_to_start_packing = md->queue.num_wr_reqs_to_start_packing;
-
-	ret = snprintf(buf, PAGE_SIZE, "%d\n", num_wr_reqs_to_start_packing);
-
-	mmc_blk_put(md);
-	return ret;
-}
-
-static ssize_t
-num_wr_reqs_to_start_packing_store(struct device *dev,
-				 struct device_attribute *attr,
-				 const char *buf, size_t count)
-{
-	int value;
-	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
-
-	sscanf(buf, "%d", &value);
-	if (value >= 0)
-		md->queue.num_wr_reqs_to_start_packing = value;
-
-	mmc_blk_put(md);
-	return count;
-}
-
 static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
 {
 	struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -1140,60 +1096,12 @@
 	if (!brq->data.bytes_xfered)
 		return MMC_BLK_RETRY;
 
-	if (mq_mrq->packed_cmd != MMC_PACKED_NONE) {
-		if (unlikely(brq->data.blocks << 9 != brq->data.bytes_xfered))
-			return MMC_BLK_PARTIAL;
-		else
-			return MMC_BLK_SUCCESS;
-	}
-
 	if (blk_rq_bytes(req) != brq->data.bytes_xfered)
 		return MMC_BLK_PARTIAL;
 
 	return MMC_BLK_SUCCESS;
 }
 
-static int mmc_blk_packed_err_check(struct mmc_card *card,
-				    struct mmc_async_req *areq)
-{
-	struct mmc_queue_req *mq_rq = container_of(areq, struct mmc_queue_req,
-			mmc_active);
-	struct request *req = mq_rq->req;
-	int err, check, status;
-	u8 ext_csd[512];
-
-	check = mmc_blk_err_check(card, areq);
-	err = get_card_status(card, &status, 0);
-	if (err) {
-		pr_err("%s: error %d sending status command\n",
-				req->rq_disk->disk_name, err);
-		return MMC_BLK_ABORT;
-	}
-
-	if (status & R1_EXP_EVENT) {
-		err = mmc_send_ext_csd(card, ext_csd);
-		if (err) {
-			pr_err("%s: error %d sending ext_csd\n",
-					req->rq_disk->disk_name, err);
-			return MMC_BLK_ABORT;
-		}
-
-		if ((ext_csd[EXT_CSD_EXP_EVENTS_STATUS] &
-					EXT_CSD_PACKED_FAILURE) &&
-				(ext_csd[EXT_CSD_PACKED_CMD_STATUS] &
-				 EXT_CSD_PACKED_GENERIC_ERROR)) {
-			if (ext_csd[EXT_CSD_PACKED_CMD_STATUS] &
-					EXT_CSD_PACKED_INDEXED_ERROR) {
-				mq_rq->packed_fail_idx =
-				  ext_csd[EXT_CSD_PACKED_FAILURE_INDEX] - 1;
-				return MMC_BLK_PARTIAL;
-			}
-		}
-	}
-
-	return check;
-}
-
 static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
 			       struct mmc_card *card,
 			       int disable_multi,
@@ -1349,357 +1257,10 @@
 	mmc_queue_bounce_pre(mqrq);
 }
 
-static void mmc_blk_write_packing_control(struct mmc_queue *mq,
-					  struct request *req)
-{
-	struct mmc_host *host = mq->card->host;
-	int data_dir;
-
-	if (!(host->caps2 & MMC_CAP2_PACKED_WR))
-		return;
-
-	/*
-	 * In case the packing control is not supported by the host, it should
-	 * not have an effect on the write packing. Therefore we have to enable
-	 * the write packing
-	 */
-	if (!(host->caps2 & MMC_CAP2_PACKED_WR_CONTROL)) {
-		mq->wr_packing_enabled = true;
-		return;
-	}
-
-	if (!req || (req && (req->cmd_flags & REQ_FLUSH))) {
-		if (mq->num_of_potential_packed_wr_reqs >
-				mq->num_wr_reqs_to_start_packing)
-			mq->wr_packing_enabled = true;
-		mq->num_of_potential_packed_wr_reqs = 0;
-		return;
-	}
-
-	data_dir = rq_data_dir(req);
-
-	if (data_dir == READ) {
-		mq->num_of_potential_packed_wr_reqs = 0;
-		mq->wr_packing_enabled = false;
-		return;
-	} else if (data_dir == WRITE) {
-		mq->num_of_potential_packed_wr_reqs++;
-	}
-
-	if (mq->num_of_potential_packed_wr_reqs >
-			mq->num_wr_reqs_to_start_packing)
-		mq->wr_packing_enabled = true;
-
-}
-
-struct mmc_wr_pack_stats *mmc_blk_get_packed_statistics(struct mmc_card *card)
-{
-	if (!card)
-		return NULL;
-
-	return &card->wr_pack_stats;
-}
-EXPORT_SYMBOL(mmc_blk_get_packed_statistics);
-
-void mmc_blk_init_packed_statistics(struct mmc_card *card)
-{
-	int max_num_of_packed_reqs = 0;
-
-	if (!card || !card->wr_pack_stats.packing_events)
-		return;
-
-	max_num_of_packed_reqs = card->ext_csd.max_packed_writes;
-
-	spin_lock(&card->wr_pack_stats.lock);
-	memset(card->wr_pack_stats.packing_events, 0,
-		(max_num_of_packed_reqs + 1) *
-	       sizeof(*card->wr_pack_stats.packing_events));
-	memset(&card->wr_pack_stats.pack_stop_reason, 0,
-		sizeof(card->wr_pack_stats.pack_stop_reason));
-	card->wr_pack_stats.enabled = true;
-	spin_unlock(&card->wr_pack_stats.lock);
-}
-EXPORT_SYMBOL(mmc_blk_init_packed_statistics);
-
-void print_mmc_packing_stats(struct mmc_card *card)
-{
-	int i;
-	int max_num_of_packed_reqs = 0;
-
-	if ((!card) || (!card->wr_pack_stats.packing_events))
-		return;
-
-	max_num_of_packed_reqs = card->ext_csd.max_packed_writes;
-
-	spin_lock(&card->wr_pack_stats.lock);
-
-	pr_info("%s: write packing statistics:\n",
-		mmc_hostname(card->host));
-
-	for (i = 1 ; i <= max_num_of_packed_reqs ; ++i) {
-		if (card->wr_pack_stats.packing_events[i] != 0)
-			pr_info("%s: Packed %d reqs - %d times\n",
-				mmc_hostname(card->host), i,
-				card->wr_pack_stats.packing_events[i]);
-	}
-
-	pr_info("%s: stopped packing due to the following reasons:\n",
-		mmc_hostname(card->host));
-
-	if (card->wr_pack_stats.pack_stop_reason[EXCEEDS_SEGMENTS])
-		pr_info("%s: %d times: exceedmax num of segments\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[EXCEEDS_SEGMENTS]);
-	if (card->wr_pack_stats.pack_stop_reason[EXCEEDS_SECTORS])
-		pr_info("%s: %d times: exceeding the max num of sectors\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[EXCEEDS_SECTORS]);
-	if (card->wr_pack_stats.pack_stop_reason[WRONG_DATA_DIR])
-		pr_info("%s: %d times: wrong data direction\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[WRONG_DATA_DIR]);
-	if (card->wr_pack_stats.pack_stop_reason[FLUSH_OR_DISCARD])
-		pr_info("%s: %d times: flush or discard\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[FLUSH_OR_DISCARD]);
-	if (card->wr_pack_stats.pack_stop_reason[EMPTY_QUEUE])
-		pr_info("%s: %d times: empty queue\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[EMPTY_QUEUE]);
-	if (card->wr_pack_stats.pack_stop_reason[REL_WRITE])
-		pr_info("%s: %d times: rel write\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[REL_WRITE]);
-	if (card->wr_pack_stats.pack_stop_reason[THRESHOLD])
-		pr_info("%s: %d times: Threshold\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[THRESHOLD]);
-
-	spin_unlock(&card->wr_pack_stats.lock);
-}
-EXPORT_SYMBOL(print_mmc_packing_stats);
-
-static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
-{
-	struct request_queue *q = mq->queue;
-	struct mmc_card *card = mq->card;
-	struct request *cur = req, *next = NULL;
-	struct mmc_blk_data *md = mq->data;
-	bool en_rel_wr = card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN;
-	unsigned int req_sectors = 0, phys_segments = 0;
-	unsigned int max_blk_count, max_phys_segs;
-	u8 put_back = 0;
-	u8 max_packed_rw = 0;
-	u8 reqs = 0;
-	struct mmc_wr_pack_stats *stats = &card->wr_pack_stats;
-
-	mmc_blk_clear_packed(mq->mqrq_cur);
-
-	if (!(md->flags & MMC_BLK_CMD23) ||
-			!card->ext_csd.packed_event_en)
-		goto no_packed;
-
-	if (!mq->wr_packing_enabled)
-		goto no_packed;
-
-	if ((rq_data_dir(cur) == WRITE) &&
-			(card->host->caps2 & MMC_CAP2_PACKED_WR))
-		max_packed_rw = card->ext_csd.max_packed_writes;
-
-	if (max_packed_rw == 0)
-		goto no_packed;
-
-	if (mmc_req_rel_wr(cur) &&
-			(md->flags & MMC_BLK_REL_WR) &&
-			!en_rel_wr) {
-		goto no_packed;
-	}
-
-	max_blk_count = min(card->host->max_blk_count,
-			card->host->max_req_size >> 9);
-	if (unlikely(max_blk_count > 0xffff))
-		max_blk_count = 0xffff;
-
-	max_phys_segs = queue_max_segments(q);
-	req_sectors += blk_rq_sectors(cur);
-	phys_segments += cur->nr_phys_segments;
-
-	if (rq_data_dir(cur) == WRITE) {
-		req_sectors++;
-		phys_segments++;
-	}
-
-	spin_lock(&stats->lock);
-
-	while (reqs < max_packed_rw - 1) {
-		spin_lock_irq(q->queue_lock);
-		next = blk_fetch_request(q);
-		spin_unlock_irq(q->queue_lock);
-		if (!next) {
-			MMC_BLK_UPDATE_STOP_REASON(stats, EMPTY_QUEUE);
-			break;
-		}
-
-		if (next->cmd_flags & REQ_DISCARD ||
-				next->cmd_flags & REQ_FLUSH) {
-			MMC_BLK_UPDATE_STOP_REASON(stats, FLUSH_OR_DISCARD);
-			put_back = 1;
-			break;
-		}
-
-		if (rq_data_dir(cur) != rq_data_dir(next)) {
-			MMC_BLK_UPDATE_STOP_REASON(stats, WRONG_DATA_DIR);
-			put_back = 1;
-			break;
-		}
-
-		if (mmc_req_rel_wr(next) &&
-				(md->flags & MMC_BLK_REL_WR) &&
-				!en_rel_wr) {
-			MMC_BLK_UPDATE_STOP_REASON(stats, REL_WRITE);
-			put_back = 1;
-			break;
-		}
-
-		req_sectors += blk_rq_sectors(next);
-		if (req_sectors > max_blk_count) {
-			if (stats->enabled)
-				stats->pack_stop_reason[EXCEEDS_SECTORS]++;
-			put_back = 1;
-			break;
-		}
-
-		phys_segments +=  next->nr_phys_segments;
-		if (phys_segments > max_phys_segs) {
-			MMC_BLK_UPDATE_STOP_REASON(stats, EXCEEDS_SEGMENTS);
-			put_back = 1;
-			break;
-		}
-
-		if (rq_data_dir(next) == WRITE)
-			mq->num_of_potential_packed_wr_reqs++;
-		list_add_tail(&next->queuelist, &mq->mqrq_cur->packed_list);
-		cur = next;
-		reqs++;
-	}
-
-	if (put_back) {
-		spin_lock_irq(q->queue_lock);
-		blk_requeue_request(q, next);
-		spin_unlock_irq(q->queue_lock);
-	}
-
-	if (stats->enabled) {
-		if (reqs + 1 <= card->ext_csd.max_packed_writes)
-			stats->packing_events[reqs + 1]++;
-		if (reqs + 1 == max_packed_rw)
-			MMC_BLK_UPDATE_STOP_REASON(stats, THRESHOLD);
-	}
-
-	spin_unlock(&stats->lock);
-
-	if (reqs > 0) {
-		list_add(&req->queuelist, &mq->mqrq_cur->packed_list);
-		mq->mqrq_cur->packed_num = ++reqs;
-		return reqs;
-	}
-
-no_packed:
-	mmc_blk_clear_packed(mq->mqrq_cur);
-	return 0;
-}
-
-static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
-					struct mmc_card *card,
-					struct mmc_queue *mq)
-{
-	struct mmc_blk_request *brq = &mqrq->brq;
-	struct request *req = mqrq->req;
-	struct request *prq;
-	struct mmc_blk_data *md = mq->data;
-	bool do_rel_wr;
-	u32 *packed_cmd_hdr = mqrq->packed_cmd_hdr;
-	u8 i = 1;
-
-	mqrq->packed_cmd = MMC_PACKED_WRITE;
-	mqrq->packed_blocks = 0;
-	mqrq->packed_fail_idx = MMC_PACKED_N_IDX;
-
-	memset(packed_cmd_hdr, 0, sizeof(mqrq->packed_cmd_hdr));
-	packed_cmd_hdr[0] = (mqrq->packed_num << 16) |
-		(PACKED_CMD_WR << 8) | PACKED_CMD_VER;
-
-	/*
-	 * Argument for each entry of packed group
-	 */
-	list_for_each_entry(prq, &mqrq->packed_list, queuelist) {
-		do_rel_wr = mmc_req_rel_wr(prq) && (md->flags & MMC_BLK_REL_WR);
-		/* Argument of CMD23*/
-		packed_cmd_hdr[(i * 2)] =
-			(do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) |
-			blk_rq_sectors(prq);
-		/* Argument of CMD18 or CMD25 */
-		packed_cmd_hdr[((i * 2)) + 1] =
-			mmc_card_blockaddr(card) ?
-			blk_rq_pos(prq) : blk_rq_pos(prq) << 9;
-		mqrq->packed_blocks += blk_rq_sectors(prq);
-		i++;
-	}
-
-	memset(brq, 0, sizeof(struct mmc_blk_request));
-	brq->mrq.cmd = &brq->cmd;
-	brq->mrq.data = &brq->data;
-	brq->mrq.sbc = &brq->sbc;
-	brq->mrq.stop = &brq->stop;
-
-	brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
-	brq->sbc.arg = MMC_CMD23_ARG_PACKED | (mqrq->packed_blocks + 1);
-	brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
-	brq->cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK;
-	brq->cmd.arg = blk_rq_pos(req);
-	if (!mmc_card_blockaddr(card))
-		brq->cmd.arg <<= 9;
-	brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
-
-	brq->data.blksz = 512;
-	brq->data.blocks = mqrq->packed_blocks + 1;
-	brq->data.flags |= MMC_DATA_WRITE;
-	brq->data.fault_injected = false;
-
-	brq->stop.opcode = MMC_STOP_TRANSMISSION;
-	brq->stop.arg = 0;
-	brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-
-	mmc_set_data_timeout(&brq->data, card);
-
-	brq->data.sg = mqrq->sg;
-	brq->data.sg_len = mmc_queue_map_sg(mq, mqrq);
-
-	mqrq->mmc_active.mrq = &brq->mrq;
-
-	/*
-	 * This is intended for packed commands tests usage - in case these
-	 * functions are not in use the respective pointers are NULL
-	 */
-	if (mq->err_check_fn)
-		mqrq->mmc_active.err_check = mq->err_check_fn;
-	else
-		mqrq->mmc_active.err_check = mmc_blk_packed_err_check;
-
-	if (mq->packed_test_fn)
-		mq->packed_test_fn(mq->queue, mqrq);
-
-	mmc_queue_bounce_pre(mqrq);
-}
-
 static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
 			   struct mmc_blk_request *brq, struct request *req,
 			   int ret)
 {
-	struct mmc_queue_req *mq_rq;
-	mq_rq = container_of(brq, struct mmc_queue_req, brq);
-
 	/*
 	 * If this is an SD card and we're writing, we can first
 	 * mark the known good sectors as ok.
@@ -1716,41 +1277,8 @@
 				ret = blk_end_request(req, 0, blocks << 9);
 		} else
 			ret = blk_end_request(req, 0, brq->data.bytes_xfered);
-	} else {
-		if (mq_rq->packed_cmd == MMC_PACKED_NONE) {
-			ret = blk_end_request(req, 0, brq->data.bytes_xfered);
-		}
-	}
-	return ret;
-}
-
-static int mmc_blk_end_packed_req(struct mmc_queue *mq,
-				  struct mmc_queue_req *mq_rq)
-{
-	struct request *prq;
-	int idx = mq_rq->packed_fail_idx, i = 0;
-	int ret = 0;
-
-	while (!list_empty(&mq_rq->packed_list)) {
-		prq = list_entry_rq(mq_rq->packed_list.next);
-		if (idx == i) {
-			/* retry from error index */
-			mq_rq->packed_num -= idx;
-			mq_rq->req = prq;
-			ret = 1;
-
-			if (mq_rq->packed_num == MMC_PACKED_N_SINGLE) {
-				list_del_init(&prq->queuelist);
-				mmc_blk_clear_packed(mq_rq);
-			}
-			return ret;
-		}
-		list_del_init(&prq->queuelist);
-		blk_end_request(prq, 0, blk_rq_bytes(prq));
-		i++;
-	}
-
-	mmc_blk_clear_packed(mq_rq);
+	} else
+		ret = blk_end_request(req, 0, brq->data.bytes_xfered);
 	return ret;
 }
 
@@ -1762,24 +1290,15 @@
 	int ret = 1, disable_multi = 0, retry = 0, type;
 	enum mmc_blk_status status;
 	struct mmc_queue_req *mq_rq;
-	struct request *req, *prq;
+	struct request *req;
 	struct mmc_async_req *areq;
-	const u8 packed_num = 2;
-	u8 reqs = 0;
 
 	if (!rqc && !mq->mqrq_prev->req)
 		return 0;
 
-	if (rqc)
-		reqs = mmc_blk_prep_packed_list(mq, rqc);
-
 	do {
 		if (rqc) {
-			if (reqs >= packed_num)
-				mmc_blk_packed_hdr_wrq_prep(mq->mqrq_cur,
-						card, mq);
-			else
-				mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
+			mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
 			areq = &mq->mqrq_cur->mmc_active;
 		} else
 			areq = NULL;
@@ -1800,15 +1319,8 @@
 			 * A block was successfully transferred.
 			 */
 			mmc_blk_reset_success(md, type);
-
-			if (mq_rq->packed_cmd != MMC_PACKED_NONE) {
-				ret = mmc_blk_end_packed_req(mq, mq_rq);
-				break;
-			} else {
-				ret = blk_end_request(req, 0,
+			ret = blk_end_request(req, 0,
 						brq->data.bytes_xfered);
-			}
-
 			/*
 			 * If the blk_end_request function returns non-zero even
 			 * though all data has been transferred and no errors
@@ -1841,8 +1353,7 @@
 			err = mmc_blk_reset(md, card->host, type);
 			if (!err)
 				break;
-			if (err == -ENODEV ||
-				mq_rq->packed_cmd != MMC_PACKED_NONE)
+			if (err == -ENODEV)
 				goto cmd_abort;
 			/* Fall through */
 		}
@@ -1869,62 +1380,26 @@
 		}
 
 		if (ret) {
-			if (mq_rq->packed_cmd == MMC_PACKED_NONE) {
-				/*
-				 * In case of a incomplete request
-				 * prepare it again and resend.
-				 */
-				mmc_blk_rw_rq_prep(mq_rq, card,
-						disable_multi, mq);
-				mmc_start_req(card->host,
-						&mq_rq->mmc_active, NULL);
-			} else {
-				mmc_blk_packed_hdr_wrq_prep(mq_rq, card, mq);
-				mmc_start_req(card->host,
-						&mq_rq->mmc_active, NULL);
-			}
+			/*
+			 * In case of a incomplete request
+			 * prepare it again and resend.
+			 */
+			mmc_blk_rw_rq_prep(mq_rq, card, disable_multi, mq);
+			mmc_start_req(card->host, &mq_rq->mmc_active, NULL);
 		}
 	} while (ret);
 
 	return 1;
 
  cmd_abort:
-	if (mq_rq->packed_cmd == MMC_PACKED_NONE) {
-		if (mmc_card_removed(card))
-			req->cmd_flags |= REQ_QUIET;
-		while (ret)
-			ret = blk_end_request(req, -EIO,
-					blk_rq_cur_bytes(req));
-	} else {
-		while (!list_empty(&mq_rq->packed_list)) {
-			prq = list_entry_rq(mq_rq->packed_list.next);
-			list_del_init(&prq->queuelist);
-			blk_end_request(prq, -EIO, blk_rq_bytes(prq));
-		}
-		mmc_blk_clear_packed(mq_rq);
-	}
+	if (mmc_card_removed(card))
+		req->cmd_flags |= REQ_QUIET;
+	while (ret)
+		ret = blk_end_request(req, -EIO,
+				blk_rq_cur_bytes(req));
 
  start_new_req:
 	if (rqc) {
-		/*
-		 * If current request is packed, it needs to put back.
-		 */
-		if (mq->mqrq_cur->packed_cmd != MMC_PACKED_NONE) {
-			while (!list_empty(&mq->mqrq_cur->packed_list)) {
-				prq = list_entry_rq(
-					mq->mqrq_cur->packed_list.prev);
-				if (prq->queuelist.prev !=
-						&mq->mqrq_cur->packed_list) {
-					list_del_init(&prq->queuelist);
-					spin_lock_irq(mq->queue->queue_lock);
-					blk_requeue_request(mq->queue, prq);
-					spin_unlock_irq(mq->queue->queue_lock);
-				} else {
-					list_del_init(&prq->queuelist);
-				}
-			}
-			mmc_blk_clear_packed(mq->mqrq_cur);
-		}
 		mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
 		mmc_start_req(card->host, &mq->mqrq_cur->mmc_active, NULL);
 	}
@@ -1958,8 +1433,6 @@
 		goto out;
 	}
 
-	mmc_blk_write_packing_control(mq, req);
-
 	if (req && req->cmd_flags & REQ_SANITIZE) {
 		/* complete ongoing async transfer before issuing sanitize */
 		if (card->host && card->host->areq)
@@ -2191,8 +1664,6 @@
 
 	if (md) {
 		card = md->queue.card;
-		device_remove_file(disk_to_dev(md->disk),
-				   &md->num_wr_reqs_to_start_packing);
 		if (md->disk->flags & GENHD_FL_UP) {
 			device_remove_file(disk_to_dev(md->disk), &md->force_ro);
 			if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
@@ -2260,16 +1731,6 @@
 			goto power_ro_lock_fail;
 	}
 
-	md->num_wr_reqs_to_start_packing.show =
-		num_wr_reqs_to_start_packing_show;
-	md->num_wr_reqs_to_start_packing.store =
-		num_wr_reqs_to_start_packing_store;
-	sysfs_attr_init(&md->num_wr_reqs_to_start_packing.attr);
-	md->num_wr_reqs_to_start_packing.attr.name =
-		"num_wr_reqs_to_start_packing";
-	md->num_wr_reqs_to_start_packing.attr.mode = S_IRUGO | S_IWUSR;
-	ret = device_create_file(disk_to_dev(md->disk),
-				 &md->num_wr_reqs_to_start_packing);
 	if (ret)
 		goto power_ro_lock_fail;
 
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
deleted file mode 100644
index 871675c..0000000
--- a/drivers/mmc/card/mmc_block_test.c
+++ /dev/null
@@ -1,2068 +0,0 @@
-
-/* 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.
- *
- */
-
-/* MMC block test */
-
-#include <linux/module.h>
-#include <linux/blkdev.h>
-#include <linux/debugfs.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/delay.h>
-#include <linux/test-iosched.h>
-#include "queue.h"
-
-#define MODULE_NAME "mmc_block_test"
-#define TEST_MAX_SECTOR_RANGE		(600*1024*1024) /* 600 MB */
-#define TEST_MAX_BIOS_PER_REQ		120
-#define CMD23_PACKED_BIT	(1 << 30)
-#define LARGE_PRIME_1	1103515367
-#define LARGE_PRIME_2	35757
-#define PACKED_HDR_VER_MASK 0x000000FF
-#define PACKED_HDR_RW_MASK 0x0000FF00
-#define PACKED_HDR_NUM_REQS_MASK 0x00FF0000
-#define PACKED_HDR_BITS_16_TO_29_SET 0x3FFF0000
-#define SECTOR_SIZE 512
-#define NUM_OF_SECTORS_PER_BIO		((BIO_U32_SIZE * 4) / SECTOR_SIZE)
-#define BIO_TO_SECTOR(x)		(x * NUM_OF_SECTORS_PER_BIO)
-
-#define test_pr_debug(fmt, args...) pr_debug("%s: "fmt"\n", MODULE_NAME, args)
-#define test_pr_info(fmt, args...) pr_info("%s: "fmt"\n", MODULE_NAME, args)
-#define test_pr_err(fmt, args...) pr_err("%s: "fmt"\n", MODULE_NAME, args)
-
-#define SANITIZE_TEST_TIMEOUT 240000
-
-enum is_random {
-	NON_RANDOM_TEST,
-	RANDOM_TEST,
-};
-
-enum mmc_block_test_testcases {
-	/* Start of send write packing test group */
-	SEND_WRITE_PACKING_MIN_TESTCASE,
-	TEST_STOP_DUE_TO_READ = SEND_WRITE_PACKING_MIN_TESTCASE,
-	TEST_STOP_DUE_TO_READ_AFTER_MAX_REQS,
-	TEST_STOP_DUE_TO_FLUSH,
-	TEST_STOP_DUE_TO_FLUSH_AFTER_MAX_REQS,
-	TEST_STOP_DUE_TO_EMPTY_QUEUE,
-	TEST_STOP_DUE_TO_MAX_REQ_NUM,
-	TEST_STOP_DUE_TO_THRESHOLD,
-	SEND_WRITE_PACKING_MAX_TESTCASE = TEST_STOP_DUE_TO_THRESHOLD,
-
-	/* Start of err check test group */
-	ERR_CHECK_MIN_TESTCASE,
-	TEST_RET_ABORT = ERR_CHECK_MIN_TESTCASE,
-	TEST_RET_PARTIAL_FOLLOWED_BY_SUCCESS,
-	TEST_RET_PARTIAL_FOLLOWED_BY_ABORT,
-	TEST_RET_PARTIAL_MULTIPLE_UNTIL_SUCCESS,
-	TEST_RET_PARTIAL_MAX_FAIL_IDX,
-	TEST_RET_RETRY,
-	TEST_RET_CMD_ERR,
-	TEST_RET_DATA_ERR,
-	ERR_CHECK_MAX_TESTCASE = TEST_RET_DATA_ERR,
-
-	/* Start of send invalid test group */
-	INVALID_CMD_MIN_TESTCASE,
-	TEST_HDR_INVALID_VERSION = INVALID_CMD_MIN_TESTCASE,
-	TEST_HDR_WRONG_WRITE_CODE,
-	TEST_HDR_INVALID_RW_CODE,
-	TEST_HDR_DIFFERENT_ADDRESSES,
-	TEST_HDR_REQ_NUM_SMALLER_THAN_ACTUAL,
-	TEST_HDR_REQ_NUM_LARGER_THAN_ACTUAL,
-	TEST_HDR_CMD23_PACKED_BIT_SET,
-	TEST_CMD23_MAX_PACKED_WRITES,
-	TEST_CMD23_ZERO_PACKED_WRITES,
-	TEST_CMD23_PACKED_BIT_UNSET,
-	TEST_CMD23_REL_WR_BIT_SET,
-	TEST_CMD23_BITS_16TO29_SET,
-	TEST_CMD23_HDR_BLK_NOT_IN_COUNT,
-	INVALID_CMD_MAX_TESTCASE = TEST_CMD23_HDR_BLK_NOT_IN_COUNT,
-
-	/*
-	 * Start of packing control test group.
-	 * in these next testcases the abbreviation FB = followed by
-	 */
-	PACKING_CONTROL_MIN_TESTCASE,
-	TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ =
-				PACKING_CONTROL_MIN_TESTCASE,
-	TEST_PACKING_EXP_N_OVER_TRIGGER,
-	TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ,
-	TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N,
-	TEST_PACKING_EXP_THRESHOLD_OVER_TRIGGER,
-	TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS,
-	TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS,
-	TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER,
-	TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER,
-	TEST_PACK_MIX_PACKED_NO_PACKED_PACKED,
-	TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED,
-	PACKING_CONTROL_MAX_TESTCASE = TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED,
-
-	TEST_WRITE_DISCARD_SANITIZE_READ,
-};
-
-enum mmc_block_test_group {
-	TEST_NO_GROUP,
-	TEST_GENERAL_GROUP,
-	TEST_SEND_WRITE_PACKING_GROUP,
-	TEST_ERR_CHECK_GROUP,
-	TEST_SEND_INVALID_GROUP,
-	TEST_PACKING_CONTROL_GROUP,
-};
-
-struct mmc_block_test_debug {
-	struct dentry *send_write_packing_test;
-	struct dentry *err_check_test;
-	struct dentry *send_invalid_packed_test;
-	struct dentry *random_test_seed;
-	struct dentry *packing_control_test;
-	struct dentry *discard_sanitize_test;
-};
-
-struct mmc_block_test_data {
-	/* The number of write requests that the test will issue */
-	int num_requests;
-	/* The expected write packing statistics for the current test */
-	struct mmc_wr_pack_stats exp_packed_stats;
-	/*
-	 * A user-defined seed for random choices of number of bios written in
-	 * a request, and of number of requests issued in a test
-	 * This field is randomly updated after each use
-	 */
-	unsigned int random_test_seed;
-	/* A retry counter used in err_check tests */
-	int err_check_counter;
-	/* Can be one of the values of enum test_group */
-	enum mmc_block_test_group test_group;
-	/*
-	 * Indicates if the current testcase is running with random values of
-	 * num_requests and num_bios (in each request)
-	 */
-	int is_random;
-	/* Data structure for debugfs dentrys */
-	struct mmc_block_test_debug debug;
-	/*
-	 * Data structure containing individual test information, including
-	 * self-defined specific data
-	 */
-	struct test_info test_info;
-	/* mmc block device test */
-	struct blk_dev_test_type bdt;
-};
-
-static struct mmc_block_test_data *mbtd;
-
-/*
- * A callback assigned to the packed_test_fn field.
- * Called from block layer in mmc_blk_packed_hdr_wrq_prep.
- * Here we alter the packed header or CMD23 in order to send an invalid
- * packed command to the card.
- */
-static void test_invalid_packed_cmd(struct request_queue *q,
-				    struct mmc_queue_req *mqrq)
-{
-	struct mmc_queue *mq = q->queuedata;
-	u32 *packed_cmd_hdr = mqrq->packed_cmd_hdr;
-	struct request *req = mqrq->req;
-	struct request *second_rq;
-	struct test_request *test_rq;
-	struct mmc_blk_request *brq = &mqrq->brq;
-	int num_requests;
-	int max_packed_reqs;
-
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return;
-	}
-
-	test_rq = (struct test_request *)req->elv.priv[0];
-	if (!test_rq) {
-		test_pr_err("%s: NULL test_rq", __func__);
-		return;
-	}
-	max_packed_reqs = mq->card->ext_csd.max_packed_writes;
-
-	switch (mbtd->test_info.testcase) {
-	case TEST_HDR_INVALID_VERSION:
-		test_pr_info("%s: set invalid header version", __func__);
-		/* Put 0 in header version field (1 byte, offset 0 in header) */
-		packed_cmd_hdr[0] = packed_cmd_hdr[0] & ~PACKED_HDR_VER_MASK;
-		break;
-	case TEST_HDR_WRONG_WRITE_CODE:
-		test_pr_info("%s: wrong write code", __func__);
-		/* Set R/W field with R value (1 byte, offset 1 in header) */
-		packed_cmd_hdr[0] = packed_cmd_hdr[0] & ~PACKED_HDR_RW_MASK;
-		packed_cmd_hdr[0] = packed_cmd_hdr[0] | 0x00000100;
-		break;
-	case TEST_HDR_INVALID_RW_CODE:
-		test_pr_info("%s: invalid r/w code", __func__);
-		/* Set R/W field with invalid value */
-		packed_cmd_hdr[0] = packed_cmd_hdr[0] & ~PACKED_HDR_RW_MASK;
-		packed_cmd_hdr[0] = packed_cmd_hdr[0] | 0x00000400;
-		break;
-	case TEST_HDR_DIFFERENT_ADDRESSES:
-		test_pr_info("%s: different addresses", __func__);
-		second_rq = list_entry(req->queuelist.next, struct request,
-				queuelist);
-		test_pr_info("%s: test_rq->sector=%ld, second_rq->sector=%ld",
-			      __func__, (long)req->__sector,
-			     (long)second_rq->__sector);
-		/*
-		 * Put start sector of second write request in the first write
-		 * request's cmd25 argument in the packed header
-		 */
-		packed_cmd_hdr[3] = second_rq->__sector;
-		break;
-	case TEST_HDR_REQ_NUM_SMALLER_THAN_ACTUAL:
-		test_pr_info("%s: request num smaller than actual" , __func__);
-		num_requests = (packed_cmd_hdr[0] & PACKED_HDR_NUM_REQS_MASK)
-									>> 16;
-		/* num of entries is decremented by 1 */
-		num_requests = (num_requests - 1) << 16;
-		/*
-		 * Set number of requests field in packed write header to be
-		 * smaller than the actual number (1 byte, offset 2 in header)
-		 */
-		packed_cmd_hdr[0] = (packed_cmd_hdr[0] &
-				     ~PACKED_HDR_NUM_REQS_MASK) + num_requests;
-		break;
-	case TEST_HDR_REQ_NUM_LARGER_THAN_ACTUAL:
-		test_pr_info("%s: request num larger than actual" , __func__);
-		num_requests = (packed_cmd_hdr[0] & PACKED_HDR_NUM_REQS_MASK)
-									>> 16;
-		/* num of entries is incremented by 1 */
-		num_requests = (num_requests + 1) << 16;
-		/*
-		 * Set number of requests field in packed write header to be
-		 * larger than the actual number (1 byte, offset 2 in header).
-		 */
-		packed_cmd_hdr[0] = (packed_cmd_hdr[0] &
-				     ~PACKED_HDR_NUM_REQS_MASK) + num_requests;
-		break;
-	case TEST_HDR_CMD23_PACKED_BIT_SET:
-		test_pr_info("%s: header CMD23 packed bit set" , __func__);
-		/*
-		 * Set packed bit (bit 30) in cmd23 argument of first and second
-		 * write requests in packed write header.
-		 * These are located at bytes 2 and 4 in packed write header
-		 */
-		packed_cmd_hdr[2] = packed_cmd_hdr[2] | CMD23_PACKED_BIT;
-		packed_cmd_hdr[4] = packed_cmd_hdr[4] | CMD23_PACKED_BIT;
-		break;
-	case TEST_CMD23_MAX_PACKED_WRITES:
-		test_pr_info("%s: CMD23 request num > max_packed_reqs",
-			      __func__);
-		/*
-		 * Set the individual packed cmd23 request num to
-		 * max_packed_reqs + 1
-		 */
-		brq->sbc.arg = MMC_CMD23_ARG_PACKED | (max_packed_reqs + 1);
-		break;
-	case TEST_CMD23_ZERO_PACKED_WRITES:
-		test_pr_info("%s: CMD23 request num = 0", __func__);
-		/* Set the individual packed cmd23 request num to zero */
-		brq->sbc.arg = MMC_CMD23_ARG_PACKED;
-		break;
-	case TEST_CMD23_PACKED_BIT_UNSET:
-		test_pr_info("%s: CMD23 packed bit unset", __func__);
-		/*
-		 * Set the individual packed cmd23 packed bit to 0,
-		 *  although there is a packed write request
-		 */
-		brq->sbc.arg &= ~CMD23_PACKED_BIT;
-		break;
-	case TEST_CMD23_REL_WR_BIT_SET:
-		test_pr_info("%s: CMD23 REL WR bit set", __func__);
-		/* Set the individual packed cmd23 reliable write bit */
-		brq->sbc.arg = MMC_CMD23_ARG_PACKED | MMC_CMD23_ARG_REL_WR;
-		break;
-	case TEST_CMD23_BITS_16TO29_SET:
-		test_pr_info("%s: CMD23 bits [16-29] set", __func__);
-		brq->sbc.arg = MMC_CMD23_ARG_PACKED |
-			PACKED_HDR_BITS_16_TO_29_SET;
-		break;
-	case TEST_CMD23_HDR_BLK_NOT_IN_COUNT:
-		test_pr_info("%s: CMD23 hdr not in block count", __func__);
-		brq->sbc.arg = MMC_CMD23_ARG_PACKED |
-		((rq_data_dir(req) == READ) ? 0 : mqrq->packed_blocks);
-		break;
-	default:
-		test_pr_err("%s: unexpected testcase %d",
-			__func__, mbtd->test_info.testcase);
-		break;
-	}
-}
-
-/*
- * A callback assigned to the err_check_fn field of the mmc_request by the
- * MMC/card/block layer.
- * Called upon request completion by the MMC/core layer.
- * Here we emulate an error return value from the card.
- */
-static int test_err_check(struct mmc_card *card, struct mmc_async_req *areq)
-{
-	struct mmc_queue_req *mq_rq = container_of(areq, struct mmc_queue_req,
-			mmc_active);
-	struct request_queue *req_q = test_iosched_get_req_queue();
-	struct mmc_queue *mq;
-	int max_packed_reqs;
-	int ret = 0;
-
-	if (req_q)
-		mq = req_q->queuedata;
-	else {
-		test_pr_err("%s: NULL request_queue", __func__);
-		return 0;
-	}
-
-	if (!mq) {
-		test_pr_err("%s: %s: NULL mq", __func__,
-			mmc_hostname(card->host));
-		return 0;
-	}
-
-	max_packed_reqs = mq->card->ext_csd.max_packed_writes;
-
-	if (!mq_rq) {
-		test_pr_err("%s: %s: NULL mq_rq", __func__,
-			mmc_hostname(card->host));
-		return 0;
-	}
-
-	switch (mbtd->test_info.testcase) {
-	case TEST_RET_ABORT:
-		test_pr_info("%s: return abort", __func__);
-		ret = MMC_BLK_ABORT;
-		break;
-	case TEST_RET_PARTIAL_FOLLOWED_BY_SUCCESS:
-		test_pr_info("%s: return partial followed by success",
-			      __func__);
-		/*
-		 * Since in this testcase num_requests is always >= 2,
-		 * we can be sure that packed_fail_idx is always >= 1
-		 */
-		mq_rq->packed_fail_idx = (mbtd->num_requests / 2);
-		test_pr_info("%s: packed_fail_idx = %d"
-			, __func__, mq_rq->packed_fail_idx);
-		mq->err_check_fn = NULL;
-		ret = MMC_BLK_PARTIAL;
-		break;
-	case TEST_RET_PARTIAL_FOLLOWED_BY_ABORT:
-		if (!mbtd->err_check_counter) {
-			test_pr_info("%s: return partial followed by abort",
-				      __func__);
-			mbtd->err_check_counter++;
-			/*
-			 * Since in this testcase num_requests is always >= 3,
-			 * we have that packed_fail_idx is always >= 1
-			 */
-			mq_rq->packed_fail_idx = (mbtd->num_requests / 2);
-			test_pr_info("%s: packed_fail_idx = %d"
-				, __func__, mq_rq->packed_fail_idx);
-			ret = MMC_BLK_PARTIAL;
-			break;
-		}
-		mbtd->err_check_counter = 0;
-		mq->err_check_fn = NULL;
-		ret = MMC_BLK_ABORT;
-		break;
-	case TEST_RET_PARTIAL_MULTIPLE_UNTIL_SUCCESS:
-		test_pr_info("%s: return partial multiple until success",
-			     __func__);
-		if (++mbtd->err_check_counter >= (mbtd->num_requests)) {
-			mq->err_check_fn = NULL;
-			mbtd->err_check_counter = 0;
-			ret = MMC_BLK_PARTIAL;
-			break;
-		}
-		mq_rq->packed_fail_idx = 1;
-		ret = MMC_BLK_PARTIAL;
-		break;
-	case TEST_RET_PARTIAL_MAX_FAIL_IDX:
-		test_pr_info("%s: return partial max fail_idx", __func__);
-		mq_rq->packed_fail_idx = max_packed_reqs - 1;
-		mq->err_check_fn = NULL;
-		ret = MMC_BLK_PARTIAL;
-		break;
-	case TEST_RET_RETRY:
-		test_pr_info("%s: return retry", __func__);
-		ret = MMC_BLK_RETRY;
-		break;
-	case TEST_RET_CMD_ERR:
-		test_pr_info("%s: return cmd err", __func__);
-		ret = MMC_BLK_CMD_ERR;
-		break;
-	case TEST_RET_DATA_ERR:
-		test_pr_info("%s: return data err", __func__);
-		ret = MMC_BLK_DATA_ERR;
-		break;
-	default:
-		test_pr_err("%s: unexpected testcase %d",
-			__func__, mbtd->test_info.testcase);
-	}
-
-	return ret;
-}
-
-/*
- * This is a specific implementation for the get_test_case_str_fn function
- * pointer in the test_info data structure. Given a valid test_data instance,
- * the function returns a string resembling the test name, based on the testcase
- */
-static char *get_test_case_str(struct test_data *td)
-{
-	if (!td) {
-		test_pr_err("%s: NULL td", __func__);
-		return NULL;
-	}
-
-	switch (td->test_info.testcase) {
-	case TEST_STOP_DUE_TO_FLUSH:
-		return "Test stop due to flush";
-	case TEST_STOP_DUE_TO_FLUSH_AFTER_MAX_REQS:
-		return "Test stop due to flush after max-1 reqs";
-	case TEST_STOP_DUE_TO_READ:
-		return "Test stop due to read";
-	case TEST_STOP_DUE_TO_READ_AFTER_MAX_REQS:
-		return "Test stop due to read after max-1 reqs";
-	case TEST_STOP_DUE_TO_EMPTY_QUEUE:
-		return "Test stop due to empty queue";
-	case TEST_STOP_DUE_TO_MAX_REQ_NUM:
-		return "Test stop due to max req num";
-	case TEST_STOP_DUE_TO_THRESHOLD:
-		return "Test stop due to exceeding threshold";
-	case TEST_RET_ABORT:
-		return "Test err_check return abort";
-	case TEST_RET_PARTIAL_FOLLOWED_BY_SUCCESS:
-		return "Test err_check return partial followed by success";
-	case TEST_RET_PARTIAL_FOLLOWED_BY_ABORT:
-		return "Test err_check return partial followed by abort";
-	case TEST_RET_PARTIAL_MULTIPLE_UNTIL_SUCCESS:
-		return "Test err_check return partial multiple until success";
-	case TEST_RET_PARTIAL_MAX_FAIL_IDX:
-		return "Test err_check return partial max fail index";
-	case TEST_RET_RETRY:
-		return "Test err_check return retry";
-	case TEST_RET_CMD_ERR:
-		return "Test err_check return cmd error";
-	case TEST_RET_DATA_ERR:
-		return "Test err_check return data error";
-	case TEST_HDR_INVALID_VERSION:
-		return "Test invalid - wrong header version";
-	case TEST_HDR_WRONG_WRITE_CODE:
-		return "Test invalid - wrong write code";
-	case TEST_HDR_INVALID_RW_CODE:
-		return "Test invalid - wrong R/W code";
-	case TEST_HDR_DIFFERENT_ADDRESSES:
-		return "Test invalid - header different addresses";
-	case TEST_HDR_REQ_NUM_SMALLER_THAN_ACTUAL:
-		return "Test invalid - header req num smaller than actual";
-	case TEST_HDR_REQ_NUM_LARGER_THAN_ACTUAL:
-		return "Test invalid - header req num larger than actual";
-	case TEST_HDR_CMD23_PACKED_BIT_SET:
-		return "Test invalid - header cmd23 packed bit set";
-	case TEST_CMD23_MAX_PACKED_WRITES:
-		return "Test invalid - cmd23 max packed writes";
-	case TEST_CMD23_ZERO_PACKED_WRITES:
-		return "Test invalid - cmd23 zero packed writes";
-	case TEST_CMD23_PACKED_BIT_UNSET:
-		return "Test invalid - cmd23 packed bit unset";
-	case TEST_CMD23_REL_WR_BIT_SET:
-		return "Test invalid - cmd23 rel wr bit set";
-	case TEST_CMD23_BITS_16TO29_SET:
-		return "Test invalid - cmd23 bits [16-29] set";
-	case TEST_CMD23_HDR_BLK_NOT_IN_COUNT:
-		return "Test invalid - cmd23 header block not in count";
-	case TEST_PACKING_EXP_N_OVER_TRIGGER:
-		return "\nTest packing control - pack n";
-	case TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ:
-		return "\nTest packing control - pack n followed by read";
-	case TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N:
-		return "\nTest packing control - pack n followed by flush";
-	case TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ:
-		return "\nTest packing control - pack one followed by read";
-	case TEST_PACKING_EXP_THRESHOLD_OVER_TRIGGER:
-		return "\nTest packing control - pack threshold";
-	case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
-		return "\nTest packing control - no packing";
-	case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
-		return "\nTest packing control - no packing, trigger requests";
-	case TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER:
-		return "\nTest packing control - no pack, trigger-read-trigger";
-	case TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER:
-		return "\nTest packing control- no pack, trigger-flush-trigger";
-	case TEST_PACK_MIX_PACKED_NO_PACKED_PACKED:
-		return "\nTest packing control - mix: pack -> no pack -> pack";
-	case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
-		return "\nTest packing control - mix: no pack->pack->no pack";
-	case TEST_WRITE_DISCARD_SANITIZE_READ:
-		return "\nTest write, discard, sanitize";
-	default:
-		 return "Unknown testcase";
-	}
-
-	return NULL;
-}
-
-/*
- * Compare individual testcase's statistics to the expected statistics:
- * Compare stop reason and number of packing events
- */
-static int check_wr_packing_statistics(struct test_data *td)
-{
-	struct mmc_wr_pack_stats *mmc_packed_stats;
-	struct mmc_queue *mq = td->req_q->queuedata;
-	int max_packed_reqs = mq->card->ext_csd.max_packed_writes;
-	int i;
-	struct mmc_card *card = mq->card;
-	struct mmc_wr_pack_stats expected_stats;
-	int *stop_reason;
-	int ret = 0;
-
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	expected_stats = mbtd->exp_packed_stats;
-
-	mmc_packed_stats = mmc_blk_get_packed_statistics(card);
-	if (!mmc_packed_stats) {
-		test_pr_err("%s: NULL mmc_packed_stats", __func__);
-		return -EINVAL;
-	}
-
-	if (!mmc_packed_stats->packing_events) {
-		test_pr_err("%s: NULL packing_events", __func__);
-		return -EINVAL;
-	}
-
-	spin_lock(&mmc_packed_stats->lock);
-
-	if (!mmc_packed_stats->enabled) {
-		test_pr_err("%s write packing statistics are not enabled",
-			     __func__);
-		ret = -EINVAL;
-		goto exit_err;
-	}
-
-	stop_reason = mmc_packed_stats->pack_stop_reason;
-
-	for (i = 1; i <= max_packed_reqs; ++i) {
-		if (mmc_packed_stats->packing_events[i] !=
-		    expected_stats.packing_events[i]) {
-			test_pr_err(
-			"%s: Wrong pack stats in index %d, got %d, expected %d",
-			__func__, i, mmc_packed_stats->packing_events[i],
-			       expected_stats.packing_events[i]);
-			if (td->fs_wr_reqs_during_test)
-				goto cancel_round;
-			ret = -EINVAL;
-			goto exit_err;
-		}
-	}
-
-	if (mmc_packed_stats->pack_stop_reason[EXCEEDS_SEGMENTS] !=
-	    expected_stats.pack_stop_reason[EXCEEDS_SEGMENTS]) {
-		test_pr_err(
-		"%s: Wrong pack stop reason EXCEEDS_SEGMENTS %d, expected %d",
-			__func__, stop_reason[EXCEEDS_SEGMENTS],
-		       expected_stats.pack_stop_reason[EXCEEDS_SEGMENTS]);
-		if (td->fs_wr_reqs_during_test)
-			goto cancel_round;
-		ret = -EINVAL;
-		goto exit_err;
-	}
-
-	if (mmc_packed_stats->pack_stop_reason[EXCEEDS_SECTORS] !=
-	    expected_stats.pack_stop_reason[EXCEEDS_SECTORS]) {
-		test_pr_err(
-		"%s: Wrong pack stop reason EXCEEDS_SECTORS %d, expected %d",
-			__func__, stop_reason[EXCEEDS_SECTORS],
-		       expected_stats.pack_stop_reason[EXCEEDS_SECTORS]);
-		if (td->fs_wr_reqs_during_test)
-			goto cancel_round;
-		ret = -EINVAL;
-		goto exit_err;
-	}
-
-	if (mmc_packed_stats->pack_stop_reason[WRONG_DATA_DIR] !=
-	    expected_stats.pack_stop_reason[WRONG_DATA_DIR]) {
-		test_pr_err(
-		"%s: Wrong pack stop reason WRONG_DATA_DIR %d, expected %d",
-		       __func__, stop_reason[WRONG_DATA_DIR],
-		       expected_stats.pack_stop_reason[WRONG_DATA_DIR]);
-		if (td->fs_wr_reqs_during_test)
-			goto cancel_round;
-		ret = -EINVAL;
-		goto exit_err;
-	}
-
-	if (mmc_packed_stats->pack_stop_reason[FLUSH_OR_DISCARD] !=
-	    expected_stats.pack_stop_reason[FLUSH_OR_DISCARD]) {
-		test_pr_err(
-		"%s: Wrong pack stop reason FLUSH_OR_DISCARD %d, expected %d",
-		       __func__, stop_reason[FLUSH_OR_DISCARD],
-		       expected_stats.pack_stop_reason[FLUSH_OR_DISCARD]);
-		if (td->fs_wr_reqs_during_test)
-			goto cancel_round;
-		ret = -EINVAL;
-		goto exit_err;
-	}
-
-	if (mmc_packed_stats->pack_stop_reason[EMPTY_QUEUE] !=
-	    expected_stats.pack_stop_reason[EMPTY_QUEUE]) {
-		test_pr_err(
-		"%s: Wrong pack stop reason EMPTY_QUEUE %d, expected %d",
-		       __func__, stop_reason[EMPTY_QUEUE],
-		       expected_stats.pack_stop_reason[EMPTY_QUEUE]);
-		if (td->fs_wr_reqs_during_test)
-			goto cancel_round;
-		ret = -EINVAL;
-		goto exit_err;
-	}
-
-	if (mmc_packed_stats->pack_stop_reason[REL_WRITE] !=
-	    expected_stats.pack_stop_reason[REL_WRITE]) {
-		test_pr_err(
-			"%s: Wrong pack stop reason REL_WRITE %d, expected %d",
-		       __func__, stop_reason[REL_WRITE],
-		       expected_stats.pack_stop_reason[REL_WRITE]);
-		if (td->fs_wr_reqs_during_test)
-			goto cancel_round;
-		ret = -EINVAL;
-		goto exit_err;
-	}
-
-exit_err:
-	spin_unlock(&mmc_packed_stats->lock);
-	if (ret && mmc_packed_stats->enabled)
-		print_mmc_packing_stats(card);
-	return ret;
-cancel_round:
-	spin_unlock(&mmc_packed_stats->lock);
-	test_iosched_set_ignore_round(true);
-	return 0;
-}
-
-/*
- * Pseudo-randomly choose a seed based on the last seed, and update it in
- * seed_number. then return seed_number (mod max_val), or min_val.
- */
-static unsigned int pseudo_random_seed(unsigned int *seed_number,
-				       unsigned int min_val,
-				       unsigned int max_val)
-{
-	int ret = 0;
-
-	if (!seed_number)
-		return 0;
-
-	*seed_number = ((unsigned int)(((unsigned long)*seed_number *
-				(unsigned long)LARGE_PRIME_1) + LARGE_PRIME_2));
-	ret = (unsigned int)((*seed_number) % max_val);
-
-	return (ret > min_val ? ret : min_val);
-}
-
-/*
- * Given a pseudo-random seed, find a pseudo-random num_of_bios.
- * Make sure that num_of_bios is not larger than TEST_MAX_SECTOR_RANGE
- */
-static void pseudo_rnd_num_of_bios(unsigned int *num_bios_seed,
-				   unsigned int *num_of_bios)
-{
-	do {
-		*num_of_bios = pseudo_random_seed(num_bios_seed, 1,
-						  TEST_MAX_BIOS_PER_REQ);
-		if (!(*num_of_bios))
-			*num_of_bios = 1;
-	} while ((*num_of_bios) * BIO_U32_SIZE * 4 > TEST_MAX_SECTOR_RANGE);
-}
-
-/* Add a single read request to the given td's request queue */
-static int prepare_request_add_read(struct test_data *td)
-{
-	int ret;
-	int start_sec;
-
-	if (td)
-		start_sec = td->start_sector;
-	else {
-		test_pr_err("%s: NULL td", __func__);
-		return 0;
-	}
-
-	test_pr_info("%s: Adding a read request, first req_id=%d", __func__,
-		     td->wr_rd_next_req_id);
-
-	ret = test_iosched_add_wr_rd_test_req(0, READ, start_sec, 2,
-					      TEST_PATTERN_5A, NULL);
-	if (ret) {
-		test_pr_err("%s: failed to add a read request", __func__);
-		return ret;
-	}
-
-	return 0;
-}
-
-/* Add a single flush request to the given td's request queue */
-static int prepare_request_add_flush(struct test_data *td)
-{
-	int ret;
-
-	if (!td) {
-		test_pr_err("%s: NULL td", __func__);
-		return 0;
-	}
-
-	test_pr_info("%s: Adding a flush request, first req_id=%d", __func__,
-		     td->unique_next_req_id);
-	ret = test_iosched_add_unique_test_req(0, REQ_UNIQUE_FLUSH,
-				  0, 0, NULL);
-	if (ret) {
-		test_pr_err("%s: failed to add a flush request", __func__);
-		return ret;
-	}
-
-	return ret;
-}
-
-/*
- * Add num_requets amount of write requests to the given td's request queue.
- * If random test mode is chosen we pseudo-randomly choose the number of bios
- * for each write request, otherwise add between 1 to 5 bio per request.
- */
-static int prepare_request_add_write_reqs(struct test_data *td,
-					  int num_requests, int is_err_expected,
-					  int is_random)
-{
-	int i;
-	unsigned int start_sec;
-	int num_bios;
-	int ret = 0;
-	unsigned int *bio_seed = &mbtd->random_test_seed;
-
-	if (td)
-		start_sec = td->start_sector;
-	else {
-		test_pr_err("%s: NULL td", __func__);
-		return ret;
-	}
-
-	test_pr_info("%s: Adding %d write requests, first req_id=%d", __func__,
-		     num_requests, td->wr_rd_next_req_id);
-
-	for (i = 1; i <= num_requests; i++) {
-		start_sec = td->start_sector + 4096 * td->num_of_write_bios;
-		if (is_random)
-			pseudo_rnd_num_of_bios(bio_seed, &num_bios);
-		else
-			/*
-			 * For the non-random case, give num_bios a value
-			 * between 1 and 5, to keep a small number of BIOs
-			 */
-			num_bios = (i%5)+1;
-
-		ret = test_iosched_add_wr_rd_test_req(is_err_expected, WRITE,
-				start_sec, num_bios, TEST_PATTERN_5A, NULL);
-
-		if (ret) {
-			test_pr_err("%s: failed to add a write request",
-				    __func__);
-			return ret;
-		}
-	}
-	return 0;
-}
-
-/*
- * Prepare the write, read and flush requests for a generic packed commands
- * testcase
- */
-static int prepare_packed_requests(struct test_data *td, int is_err_expected,
-				   int num_requests, int is_random)
-{
-	int ret = 0;
-	struct mmc_queue *mq;
-	int max_packed_reqs;
-	struct request_queue *req_q;
-
-	if (!td) {
-		pr_err("%s: NULL td", __func__);
-		return -EINVAL;
-	}
-
-	req_q = td->req_q;
-
-	if (!req_q) {
-		pr_err("%s: NULL request queue", __func__);
-		return -EINVAL;
-	}
-
-	mq = req_q->queuedata;
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	max_packed_reqs = mq->card->ext_csd.max_packed_writes;
-
-	if (mbtd->random_test_seed <= 0) {
-		mbtd->random_test_seed =
-			(unsigned int)(get_jiffies_64() & 0xFFFF);
-		test_pr_info("%s: got seed from jiffies %d",
-			     __func__, mbtd->random_test_seed);
-	}
-
-	mmc_blk_init_packed_statistics(mq->card);
-
-	ret = prepare_request_add_write_reqs(td, num_requests, is_err_expected,
-					     is_random);
-	if (ret)
-		return ret;
-
-	/* Avoid memory corruption in upcoming stats set */
-	if (td->test_info.testcase == TEST_STOP_DUE_TO_THRESHOLD)
-		num_requests--;
-
-	memset((void *)mbtd->exp_packed_stats.pack_stop_reason, 0,
-		sizeof(mbtd->exp_packed_stats.pack_stop_reason));
-	memset(mbtd->exp_packed_stats.packing_events, 0,
-		(max_packed_reqs + 1) * sizeof(u32));
-	if (num_requests <= max_packed_reqs)
-		mbtd->exp_packed_stats.packing_events[num_requests] = 1;
-
-	switch (td->test_info.testcase) {
-	case TEST_STOP_DUE_TO_FLUSH:
-	case TEST_STOP_DUE_TO_FLUSH_AFTER_MAX_REQS:
-		ret = prepare_request_add_flush(td);
-		if (ret)
-			return ret;
-
-		mbtd->exp_packed_stats.pack_stop_reason[FLUSH_OR_DISCARD] = 1;
-		break;
-	case TEST_STOP_DUE_TO_READ:
-	case TEST_STOP_DUE_TO_READ_AFTER_MAX_REQS:
-		ret = prepare_request_add_read(td);
-		if (ret)
-			return ret;
-
-		mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
-		break;
-	case TEST_STOP_DUE_TO_THRESHOLD:
-		mbtd->exp_packed_stats.packing_events[num_requests] = 1;
-		mbtd->exp_packed_stats.packing_events[1] = 1;
-		mbtd->exp_packed_stats.pack_stop_reason[THRESHOLD] = 1;
-		mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
-		break;
-	case TEST_STOP_DUE_TO_MAX_REQ_NUM:
-	case TEST_RET_PARTIAL_MAX_FAIL_IDX:
-		mbtd->exp_packed_stats.pack_stop_reason[THRESHOLD] = 1;
-		break;
-	default:
-		mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
-	}
-	mbtd->num_requests = num_requests;
-
-	return 0;
-}
-
-/*
- * Prepare the write, read and flush requests for the packing control
- * testcases
- */
-static int prepare_packed_control_tests_requests(struct test_data *td,
-			int is_err_expected, int num_requests, int is_random)
-{
-	int ret = 0;
-	struct mmc_queue *mq;
-	int max_packed_reqs;
-	int temp_num_req = num_requests;
-	struct request_queue *req_q;
-	int test_packed_trigger;
-	int num_packed_reqs;
-
-	if (!td) {
-		test_pr_err("%s: NULL td\n", __func__);
-		return -EINVAL;
-	}
-
-	req_q = td->req_q;
-
-	if (!req_q) {
-		test_pr_err("%s: NULL request queue\n", __func__);
-		return -EINVAL;
-	}
-
-	mq = req_q->queuedata;
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	max_packed_reqs = mq->card->ext_csd.max_packed_writes;
-	test_packed_trigger = mq->num_wr_reqs_to_start_packing;
-	num_packed_reqs = num_requests - test_packed_trigger;
-
-	if (mbtd->random_test_seed == 0) {
-		mbtd->random_test_seed =
-			(unsigned int)(get_jiffies_64() & 0xFFFF);
-		test_pr_info("%s: got seed from jiffies %d",
-			     __func__, mbtd->random_test_seed);
-	}
-
-	mmc_blk_init_packed_statistics(mq->card);
-
-	if (td->test_info.testcase ==
-			TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED) {
-		temp_num_req = num_requests;
-		num_requests = test_packed_trigger - 1;
-	}
-
-	/* Verify that the packing is disabled before starting the test */
-	mq->wr_packing_enabled = false;
-	mq->num_of_potential_packed_wr_reqs = 0;
-
-	if (td->test_info.testcase == TEST_PACK_MIX_PACKED_NO_PACKED_PACKED) {
-		mq->num_of_potential_packed_wr_reqs = test_packed_trigger + 1;
-		mq->wr_packing_enabled = true;
-		num_requests = test_packed_trigger + 2;
-	}
-
-	ret = prepare_request_add_write_reqs(td, num_requests, is_err_expected,
-					     is_random);
-	if (ret)
-		goto exit;
-
-	if (td->test_info.testcase == TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED)
-		num_requests = temp_num_req;
-
-	memset((void *)mbtd->exp_packed_stats.pack_stop_reason, 0,
-		sizeof(mbtd->exp_packed_stats.pack_stop_reason));
-	memset(mbtd->exp_packed_stats.packing_events, 0,
-		(max_packed_reqs + 1) * sizeof(u32));
-
-	switch (td->test_info.testcase) {
-	case TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ:
-	case TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ:
-		ret = prepare_request_add_read(td);
-		if (ret)
-			goto exit;
-
-		mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
-		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
-		break;
-	case TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N:
-		ret = prepare_request_add_flush(td);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_write_reqs(td, num_packed_reqs,
-					     is_err_expected, is_random);
-		if (ret)
-			goto exit;
-
-		mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
-		mbtd->exp_packed_stats.pack_stop_reason[FLUSH_OR_DISCARD] = 1;
-		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 2;
-		break;
-	case TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER:
-		ret = prepare_request_add_read(td);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_write_reqs(td, test_packed_trigger,
-						    is_err_expected, is_random);
-		if (ret)
-			goto exit;
-
-		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
-		break;
-	case TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER:
-		ret = prepare_request_add_flush(td);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_write_reqs(td, test_packed_trigger,
-						    is_err_expected, is_random);
-		if (ret)
-			goto exit;
-
-		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
-		break;
-	case TEST_PACK_MIX_PACKED_NO_PACKED_PACKED:
-		ret = prepare_request_add_read(td);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_write_reqs(td, test_packed_trigger-1,
-						    is_err_expected, is_random);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_write_reqs(td, num_requests,
-						    is_err_expected, is_random);
-		if (ret)
-			goto exit;
-
-		mbtd->exp_packed_stats.packing_events[num_requests] = 1;
-		mbtd->exp_packed_stats.packing_events[num_requests-1] = 1;
-		mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
-		mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
-		break;
-	case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
-		ret = prepare_request_add_read(td);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_write_reqs(td, num_requests,
-						    is_err_expected, is_random);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_read(td);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_write_reqs(td, test_packed_trigger-1,
-						    is_err_expected, is_random);
-		if (ret)
-			goto exit;
-
-		mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
-		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
-		break;
-	case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
-	case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
-		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
-		break;
-	default:
-		mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
-		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
-	}
-	mbtd->num_requests = num_requests;
-
-exit:
-	return ret;
-}
-
-/*
- * Prepare requests for the TEST_RET_PARTIAL_FOLLOWED_BY_ABORT testcase.
- * In this testcase we have mixed error expectations from different
- * write requests, hence the special prepare function.
- */
-static int prepare_partial_followed_by_abort(struct test_data *td,
-					      int num_requests)
-{
-	int i, start_address;
-	int is_err_expected = 0;
-	int ret = 0;
-	struct mmc_queue *mq = test_iosched_get_req_queue()->queuedata;
-	int max_packed_reqs;
-
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	max_packed_reqs = mq->card->ext_csd.max_packed_writes;
-
-	mmc_blk_init_packed_statistics(mq->card);
-
-	for (i = 1; i <= num_requests; i++) {
-		if (i > (num_requests / 2))
-			is_err_expected = 1;
-
-		start_address = td->start_sector + 4096 * td->num_of_write_bios;
-		ret = test_iosched_add_wr_rd_test_req(is_err_expected, WRITE,
-				start_address, (i % 5) + 1, TEST_PATTERN_5A,
-				NULL);
-		if (ret) {
-			test_pr_err("%s: failed to add a write request",
-				    __func__);
-			return ret;
-		}
-	}
-
-	memset((void *)&mbtd->exp_packed_stats.pack_stop_reason, 0,
-		sizeof(mbtd->exp_packed_stats.pack_stop_reason));
-	memset(mbtd->exp_packed_stats.packing_events, 0,
-		(max_packed_reqs + 1) * sizeof(u32));
-	mbtd->exp_packed_stats.packing_events[num_requests] = 1;
-	mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
-
-	mbtd->num_requests = num_requests;
-
-	return ret;
-}
-
-/*
- * Get number of write requests for current testcase. If random test mode was
- * chosen, pseudo-randomly choose the number of requests, otherwise set to
- * two less than the packing threshold.
- */
-static int get_num_requests(struct test_data *td)
-{
-	int *seed = &mbtd->random_test_seed;
-	struct request_queue *req_q;
-	struct mmc_queue *mq;
-	int max_num_requests;
-	int num_requests;
-	int min_num_requests = 2;
-	int is_random = mbtd->is_random;
-	int max_for_double;
-	int test_packed_trigger;
-
-	req_q = test_iosched_get_req_queue();
-	if (req_q)
-		mq = req_q->queuedata;
-	else {
-		test_pr_err("%s: NULL request queue", __func__);
-		return 0;
-	}
-
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	max_num_requests = mq->card->ext_csd.max_packed_writes;
-	num_requests = max_num_requests - 2;
-	test_packed_trigger = mq->num_wr_reqs_to_start_packing;
-
-	/*
-	 * Here max_for_double is intended for packed control testcases
-	 * in which we issue many write requests. It's purpose is to prevent
-	 * exceeding max number of req_queue requests.
-	 */
-	max_for_double = max_num_requests - 10;
-
-	if (td->test_info.testcase ==
-				TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS)
-		/* Don't expect packing, so issue up to trigger-1 reqs */
-		num_requests = test_packed_trigger - 1;
-
-	if (is_random) {
-		if (td->test_info.testcase ==
-		    TEST_RET_PARTIAL_FOLLOWED_BY_ABORT)
-			/*
-			 * Here we don't want num_requests to be less than 1
-			 * as a consequence of division by 2.
-			 */
-			min_num_requests = 3;
-
-		if (td->test_info.testcase ==
-				TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS)
-			/* Don't expect packing, so issue up to trigger reqs */
-			max_num_requests = test_packed_trigger;
-
-		num_requests = pseudo_random_seed(seed, min_num_requests,
-						  max_num_requests - 1);
-	}
-
-	if (td->test_info.testcase ==
-				TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS)
-		num_requests -= test_packed_trigger;
-
-	if (td->test_info.testcase == TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N)
-		num_requests =
-		num_requests > max_for_double ? max_for_double : num_requests;
-
-	if (mbtd->test_group == TEST_PACKING_CONTROL_GROUP)
-		num_requests += test_packed_trigger;
-
-	if (td->test_info.testcase == TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS)
-		num_requests = test_packed_trigger;
-
-	return num_requests;
-}
-
-/*
- * An implementation for the prepare_test_fn pointer in the test_info
- * data structure. According to the testcase we add the right number of requests
- * and decide if an error is expected or not.
- */
-static int prepare_test(struct test_data *td)
-{
-	struct mmc_queue *mq = test_iosched_get_req_queue()->queuedata;
-	int max_num_requests;
-	int num_requests = 0;
-	int ret = 0;
-	int is_random = mbtd->is_random;
-	int test_packed_trigger = mq->num_wr_reqs_to_start_packing;
-
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	max_num_requests = mq->card->ext_csd.max_packed_writes;
-
-	if (is_random && mbtd->random_test_seed == 0) {
-		mbtd->random_test_seed =
-			(unsigned int)(get_jiffies_64() & 0xFFFF);
-		test_pr_info("%s: got seed from jiffies %d",
-			__func__, mbtd->random_test_seed);
-	}
-
-	num_requests = get_num_requests(td);
-
-	if (mbtd->test_group == TEST_SEND_INVALID_GROUP)
-		mq->packed_test_fn =
-				test_invalid_packed_cmd;
-
-	if (mbtd->test_group == TEST_ERR_CHECK_GROUP)
-		mq->err_check_fn = test_err_check;
-
-	switch (td->test_info.testcase) {
-	case TEST_STOP_DUE_TO_FLUSH:
-	case TEST_STOP_DUE_TO_READ:
-	case TEST_RET_PARTIAL_FOLLOWED_BY_SUCCESS:
-	case TEST_RET_PARTIAL_MULTIPLE_UNTIL_SUCCESS:
-	case TEST_STOP_DUE_TO_EMPTY_QUEUE:
-	case TEST_CMD23_PACKED_BIT_UNSET:
-		ret = prepare_packed_requests(td, 0, num_requests, is_random);
-		break;
-	case TEST_STOP_DUE_TO_FLUSH_AFTER_MAX_REQS:
-	case TEST_STOP_DUE_TO_READ_AFTER_MAX_REQS:
-		ret = prepare_packed_requests(td, 0, max_num_requests - 1,
-					      is_random);
-		break;
-	case TEST_RET_PARTIAL_FOLLOWED_BY_ABORT:
-		ret = prepare_partial_followed_by_abort(td, num_requests);
-		break;
-	case TEST_STOP_DUE_TO_MAX_REQ_NUM:
-	case TEST_RET_PARTIAL_MAX_FAIL_IDX:
-		ret = prepare_packed_requests(td, 0, max_num_requests,
-					      is_random);
-		break;
-	case TEST_STOP_DUE_TO_THRESHOLD:
-		ret = prepare_packed_requests(td, 0, max_num_requests + 1,
-					      is_random);
-		break;
-	case TEST_RET_ABORT:
-	case TEST_RET_RETRY:
-	case TEST_RET_CMD_ERR:
-	case TEST_RET_DATA_ERR:
-	case TEST_HDR_INVALID_VERSION:
-	case TEST_HDR_WRONG_WRITE_CODE:
-	case TEST_HDR_INVALID_RW_CODE:
-	case TEST_HDR_DIFFERENT_ADDRESSES:
-	case TEST_HDR_REQ_NUM_SMALLER_THAN_ACTUAL:
-	case TEST_HDR_REQ_NUM_LARGER_THAN_ACTUAL:
-	case TEST_CMD23_MAX_PACKED_WRITES:
-	case TEST_CMD23_ZERO_PACKED_WRITES:
-	case TEST_CMD23_REL_WR_BIT_SET:
-	case TEST_CMD23_BITS_16TO29_SET:
-	case TEST_CMD23_HDR_BLK_NOT_IN_COUNT:
-	case TEST_HDR_CMD23_PACKED_BIT_SET:
-		ret = prepare_packed_requests(td, 1, num_requests, is_random);
-		break;
-	case TEST_PACKING_EXP_N_OVER_TRIGGER:
-	case TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ:
-	case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
-	case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
-	case TEST_PACK_MIX_PACKED_NO_PACKED_PACKED:
-	case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
-		ret = prepare_packed_control_tests_requests(td, 0, num_requests,
-			is_random);
-		break;
-	case TEST_PACKING_EXP_THRESHOLD_OVER_TRIGGER:
-		ret = prepare_packed_control_tests_requests(td, 0,
-			max_num_requests, is_random);
-		break;
-	case TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ:
-		ret = prepare_packed_control_tests_requests(td, 0,
-			test_packed_trigger + 1,
-					is_random);
-		break;
-	case TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N:
-		ret = prepare_packed_control_tests_requests(td, 0, num_requests,
-			is_random);
-		break;
-	case TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER:
-	case TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER:
-		ret = prepare_packed_control_tests_requests(td, 0,
-			test_packed_trigger, is_random);
-		break;
-	default:
-		test_pr_info("%s: Invalid test case...", __func__);
-		return -EINVAL;
-	}
-
-	return ret;
-}
-
-/*
- * An implementation for the post_test_fn in the test_info data structure.
- * In our case we just reset the function pointers in the mmc_queue in order for
- * the FS to be able to dispatch it's requests correctly after the test is
- * finished.
- */
-static int post_test(struct test_data *td)
-{
-	struct mmc_queue *mq;
-
-	if (!td)
-		return -EINVAL;
-
-	mq = td->req_q->queuedata;
-
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	mq->packed_test_fn = NULL;
-	mq->err_check_fn = NULL;
-
-	return 0;
-}
-
-/*
- * This function checks, based on the current test's test_group, that the
- * packed commands capability and control are set right. In addition, we check
- * if the card supports the packed command feature.
- */
-static int validate_packed_commands_settings(void)
-{
-	struct request_queue *req_q;
-	struct mmc_queue *mq;
-	int max_num_requests;
-	struct mmc_host *host;
-
-	req_q = test_iosched_get_req_queue();
-	if (!req_q) {
-		test_pr_err("%s: test_iosched_get_req_queue failed", __func__);
-		test_iosched_set_test_result(TEST_FAILED);
-		return -EINVAL;
-	}
-
-	mq = req_q->queuedata;
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	max_num_requests = mq->card->ext_csd.max_packed_writes;
-	host = mq->card->host;
-
-	if (!(host->caps2 && MMC_CAP2_PACKED_WR)) {
-		test_pr_err("%s: Packed Write capability disabled, exit test",
-			    __func__);
-		test_iosched_set_test_result(TEST_NOT_SUPPORTED);
-		return -EINVAL;
-	}
-
-	if (max_num_requests == 0) {
-		test_pr_err(
-		"%s: no write packing support, ext_csd.max_packed_writes=%d",
-		__func__, mq->card->ext_csd.max_packed_writes);
-		test_iosched_set_test_result(TEST_NOT_SUPPORTED);
-		return -EINVAL;
-	}
-
-	test_pr_info("%s: max number of packed requests supported is %d ",
-		     __func__, max_num_requests);
-
-	switch (mbtd->test_group) {
-	case TEST_SEND_WRITE_PACKING_GROUP:
-	case TEST_ERR_CHECK_GROUP:
-	case TEST_SEND_INVALID_GROUP:
-		/* disable the packing control */
-		host->caps2 &= ~MMC_CAP2_PACKED_WR_CONTROL;
-		break;
-	case TEST_PACKING_CONTROL_GROUP:
-		host->caps2 |=  MMC_CAP2_PACKED_WR_CONTROL;
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static void pseudo_rnd_sector_and_size(unsigned int *seed,
-				       unsigned int min_start_sector,
-				       unsigned int *start_sector,
-				       unsigned int *num_of_bios)
-{
-	unsigned int max_sec = min_start_sector + TEST_MAX_SECTOR_RANGE;
-	do {
-		*start_sector = pseudo_random_seed(seed,
-						   1, max_sec);
-		*num_of_bios = pseudo_random_seed(seed,
-						  1, TEST_MAX_BIOS_PER_REQ);
-		if (!(*num_of_bios))
-			*num_of_bios = 1;
-	} while ((*start_sector < min_start_sector) ||
-		 (*start_sector + (*num_of_bios * BIO_U32_SIZE * 4)) > max_sec);
-}
-
-/* sanitize test functions */
-static int prepare_write_discard_sanitize_read(struct test_data *td)
-{
-	unsigned int start_sector;
-	unsigned int num_of_bios = 0;
-	static unsigned int total_bios;
-	unsigned int *num_bios_seed;
-	int i = 0;
-
-	if (mbtd->random_test_seed == 0) {
-		mbtd->random_test_seed =
-			(unsigned int)(get_jiffies_64() & 0xFFFF);
-		test_pr_info("%s: got seed from jiffies %d",
-			     __func__, mbtd->random_test_seed);
-	}
-	num_bios_seed = &mbtd->random_test_seed;
-
-	do {
-		pseudo_rnd_sector_and_size(num_bios_seed, td->start_sector,
-					   &start_sector, &num_of_bios);
-
-		/* DISCARD */
-		total_bios += num_of_bios;
-		test_pr_info("%s: discard req: id=%d, startSec=%d, NumBios=%d",
-		       __func__, td->unique_next_req_id, start_sector,
-			     num_of_bios);
-		test_iosched_add_unique_test_req(0, REQ_UNIQUE_DISCARD,
-				    start_sector, BIO_TO_SECTOR(num_of_bios),
-						 NULL);
-
-	} while (++i < (BLKDEV_MAX_RQ-10));
-
-	test_pr_info("%s: total discard bios = %d", __func__, total_bios);
-
-	test_pr_info("%s: add sanitize req", __func__);
-	test_iosched_add_unique_test_req(0, REQ_UNIQUE_SANITIZE, 0, 0, NULL);
-
-	return 0;
-}
-
-static bool message_repeat;
-static int test_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	message_repeat = 1;
-	return 0;
-}
-
-/* send_packing TEST */
-static ssize_t send_write_packing_test_write(struct file *file,
-				const char __user *buf,
-				size_t count,
-				loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-	int j = 0;
-
-	test_pr_info("%s: -- send_write_packing TEST --", __func__);
-
-	sscanf(buf, "%d", &number);
-
-	if (number <= 0)
-		number = 1;
-
-
-	mbtd->test_group = TEST_SEND_WRITE_PACKING_GROUP;
-
-	if (validate_packed_commands_settings())
-		return count;
-
-	if (mbtd->random_test_seed > 0)
-		test_pr_info("%s: Test seed: %d", __func__,
-			      mbtd->random_test_seed);
-
-	memset(&mbtd->test_info, 0, sizeof(struct test_info));
-
-	mbtd->test_info.data = mbtd;
-	mbtd->test_info.prepare_test_fn = prepare_test;
-	mbtd->test_info.check_test_result_fn = check_wr_packing_statistics;
-	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
-	mbtd->test_info.post_test_fn = post_test;
-
-	for (i = 0; i < number; ++i) {
-		test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
-		test_pr_info("%s: ====================", __func__);
-
-		for (j = SEND_WRITE_PACKING_MIN_TESTCASE;
-		      j <= SEND_WRITE_PACKING_MAX_TESTCASE; j++) {
-
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret)
-				break;
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = NON_RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret)
-				break;
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-		}
-	}
-
-	test_pr_info("%s: Completed all the test cases.", __func__);
-
-	return count;
-}
-
-static ssize_t send_write_packing_test_read(struct file *file,
-			       char __user *buffer,
-			       size_t count,
-			       loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nsend_write_packing_test\n"
-		 "=========\n"
-		 "Description:\n"
-		 "This test checks the following scenarios\n"
-		 "- Pack due to FLUSH message\n"
-		 "- Pack due to FLUSH after threshold writes\n"
-		 "- Pack due to READ message\n"
-		 "- Pack due to READ after threshold writes\n"
-		 "- Pack due to empty queue\n"
-		 "- Pack due to threshold writes\n"
-		 "- Pack due to one over threshold writes\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations send_write_packing_test_ops = {
-	.open = test_open,
-	.write = send_write_packing_test_write,
-	.read = send_write_packing_test_read,
-};
-
-/* err_check TEST */
-static ssize_t err_check_test_write(struct file *file,
-				const char __user *buf,
-				size_t count,
-				loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-	int j = 0;
-
-	test_pr_info("%s: -- err_check TEST --", __func__);
-
-	sscanf(buf, "%d", &number);
-
-	if (number <= 0)
-		number = 1;
-
-	mbtd->test_group = TEST_ERR_CHECK_GROUP;
-
-	if (validate_packed_commands_settings())
-		return count;
-
-	if (mbtd->random_test_seed > 0)
-		test_pr_info("%s: Test seed: %d", __func__,
-			      mbtd->random_test_seed);
-
-	memset(&mbtd->test_info, 0, sizeof(struct test_info));
-
-	mbtd->test_info.data = mbtd;
-	mbtd->test_info.prepare_test_fn = prepare_test;
-	mbtd->test_info.check_test_result_fn = check_wr_packing_statistics;
-	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
-	mbtd->test_info.post_test_fn = post_test;
-
-	for (i = 0; i < number; ++i) {
-		test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
-		test_pr_info("%s: ====================", __func__);
-
-		for (j = ERR_CHECK_MIN_TESTCASE;
-					j <= ERR_CHECK_MAX_TESTCASE ; j++) {
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret)
-				break;
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = NON_RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret)
-				break;
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-		}
-	}
-
-	test_pr_info("%s: Completed all the test cases.", __func__);
-
-	return count;
-}
-
-static ssize_t err_check_test_read(struct file *file,
-			       char __user *buffer,
-			       size_t count,
-			       loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nerr_check_TEST\n"
-		 "=========\n"
-		 "Description:\n"
-		 "This test checks the following scenarios\n"
-		 "- Return ABORT\n"
-		 "- Return PARTIAL followed by success\n"
-		 "- Return PARTIAL followed by abort\n"
-		 "- Return PARTIAL multiple times until success\n"
-		 "- Return PARTIAL with fail index = threshold\n"
-		 "- Return RETRY\n"
-		 "- Return CMD_ERR\n"
-		 "- Return DATA_ERR\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations err_check_test_ops = {
-	.open = test_open,
-	.write = err_check_test_write,
-	.read = err_check_test_read,
-};
-
-/* send_invalid_packed TEST */
-static ssize_t send_invalid_packed_test_write(struct file *file,
-				const char __user *buf,
-				size_t count,
-				loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-	int j = 0;
-	int num_of_failures = 0;
-
-	test_pr_info("%s: -- send_invalid_packed TEST --", __func__);
-
-	sscanf(buf, "%d", &number);
-
-	if (number <= 0)
-		number = 1;
-
-	mbtd->test_group = TEST_SEND_INVALID_GROUP;
-
-	if (validate_packed_commands_settings())
-		return count;
-
-	if (mbtd->random_test_seed > 0)
-		test_pr_info("%s: Test seed: %d", __func__,
-			      mbtd->random_test_seed);
-
-	memset(&mbtd->test_info, 0, sizeof(struct test_info));
-
-	mbtd->test_info.data = mbtd;
-	mbtd->test_info.prepare_test_fn = prepare_test;
-	mbtd->test_info.check_test_result_fn = check_wr_packing_statistics;
-	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
-	mbtd->test_info.post_test_fn = post_test;
-
-	for (i = 0; i < number; ++i) {
-		test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
-		test_pr_info("%s: ====================", __func__);
-
-		for (j = INVALID_CMD_MIN_TESTCASE;
-				j <= INVALID_CMD_MAX_TESTCASE ; j++) {
-
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret)
-				num_of_failures++;
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = NON_RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret)
-				num_of_failures++;
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-		}
-	}
-
-	test_pr_info("%s: Completed all the test cases.", __func__);
-
-	if (num_of_failures > 0) {
-		test_iosched_set_test_result(TEST_FAILED);
-		test_pr_err(
-			"There were %d failures during the test, TEST FAILED",
-			num_of_failures);
-	}
-	return count;
-}
-
-static ssize_t send_invalid_packed_test_read(struct file *file,
-			       char __user *buffer,
-			       size_t count,
-			       loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nsend_invalid_packed_TEST\n"
-		 "=========\n"
-		 "Description:\n"
-		 "This test checks the following scenarios\n"
-		 "- Send an invalid header version\n"
-		 "- Send the wrong write code\n"
-		 "- Send an invalid R/W code\n"
-		 "- Send wrong start address in header\n"
-		 "- Send header with block_count smaller than actual\n"
-		 "- Send header with block_count larger than actual\n"
-		 "- Send header CMD23 packed bit set\n"
-		 "- Send CMD23 with block count over threshold\n"
-		 "- Send CMD23 with block_count equals zero\n"
-		 "- Send CMD23 packed bit unset\n"
-		 "- Send CMD23 reliable write bit set\n"
-		 "- Send CMD23 bits [16-29] set\n"
-		 "- Send CMD23 header block not in block_count\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations send_invalid_packed_test_ops = {
-	.open = test_open,
-	.write = send_invalid_packed_test_write,
-	.read = send_invalid_packed_test_read,
-};
-
-/* packing_control TEST */
-static ssize_t write_packing_control_test_write(struct file *file,
-				const char __user *buf,
-				size_t count,
-				loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-	int j = 0;
-	struct mmc_queue *mq = test_iosched_get_req_queue()->queuedata;
-	int max_num_requests = mq->card->ext_csd.max_packed_writes;
-	int test_successful = 1;
-
-	test_pr_info("%s: -- write_packing_control TEST --", __func__);
-
-	sscanf(buf, "%d", &number);
-
-	if (number <= 0)
-		number = 1;
-
-	test_pr_info("%s: max_num_requests = %d ", __func__,
-			max_num_requests);
-
-	memset(&mbtd->test_info, 0, sizeof(struct test_info));
-	mbtd->test_group = TEST_PACKING_CONTROL_GROUP;
-
-	if (validate_packed_commands_settings())
-		return count;
-
-	mbtd->test_info.data = mbtd;
-	mbtd->test_info.prepare_test_fn = prepare_test;
-	mbtd->test_info.check_test_result_fn = check_wr_packing_statistics;
-	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
-
-	for (i = 0; i < number; ++i) {
-		test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
-		test_pr_info("%s: ====================", __func__);
-
-		for (j = PACKING_CONTROL_MIN_TESTCASE;
-				j <= PACKING_CONTROL_MAX_TESTCASE; j++) {
-
-			test_successful = 1;
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret) {
-				test_successful = 0;
-				break;
-			}
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = NON_RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret) {
-				test_successful = 0;
-				break;
-			}
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-		}
-
-		if (!test_successful)
-			break;
-	}
-
-	test_pr_info("%s: Completed all the test cases.", __func__);
-
-	return count;
-}
-
-static ssize_t write_packing_control_test_read(struct file *file,
-			       char __user *buffer,
-			       size_t count,
-			       loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nwrite_packing_control_test\n"
-		 "=========\n"
-		 "Description:\n"
-		 "This test checks the following scenarios\n"
-		 "- Packing expected - one over trigger\n"
-		 "- Packing expected - N over trigger\n"
-		 "- Packing expected - N over trigger followed by read\n"
-		 "- Packing expected - N over trigger followed by flush\n"
-		 "- Packing expected - threshold over trigger FB by flush\n"
-		 "- Packing not expected - less than trigger\n"
-		 "- Packing not expected - trigger requests\n"
-		 "- Packing not expected - trigger, read, trigger\n"
-		 "- Mixed state - packing -> no packing -> packing\n"
-		 "- Mixed state - no packing -> packing -> no packing\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations write_packing_control_test_ops = {
-	.open = test_open,
-	.write = write_packing_control_test_write,
-	.read = write_packing_control_test_read,
-};
-
-static ssize_t write_discard_sanitize_test_write(struct file *file,
-				const char __user *buf,
-				size_t count,
-				loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	sscanf(buf, "%d", &number);
-	if (number <= 0)
-		number = 1;
-
-	test_pr_info("%s: -- write_discard_sanitize TEST --\n", __func__);
-
-	memset(&mbtd->test_info, 0, sizeof(struct test_info));
-
-	mbtd->test_group = TEST_GENERAL_GROUP;
-
-	mbtd->test_info.data = mbtd;
-	mbtd->test_info.prepare_test_fn = prepare_write_discard_sanitize_read;
-	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
-	mbtd->test_info.timeout_msec = SANITIZE_TEST_TIMEOUT;
-
-	for (i = 0 ; i < number ; ++i) {
-		test_pr_info("%s: Cycle # %d / %d\n", __func__, i+1, number);
-		test_pr_info("%s: ===================", __func__);
-
-		mbtd->test_info.testcase = TEST_WRITE_DISCARD_SANITIZE_READ;
-		ret = test_iosched_start_test(&mbtd->test_info);
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-const struct file_operations write_discard_sanitize_test_ops = {
-	.open = test_open,
-	.write = write_discard_sanitize_test_write,
-};
-
-static void mmc_block_test_debugfs_cleanup(void)
-{
-	debugfs_remove(mbtd->debug.random_test_seed);
-	debugfs_remove(mbtd->debug.send_write_packing_test);
-	debugfs_remove(mbtd->debug.err_check_test);
-	debugfs_remove(mbtd->debug.send_invalid_packed_test);
-	debugfs_remove(mbtd->debug.packing_control_test);
-	debugfs_remove(mbtd->debug.discard_sanitize_test);
-}
-
-static int mmc_block_test_debugfs_init(void)
-{
-	struct dentry *utils_root, *tests_root;
-
-	utils_root = test_iosched_get_debugfs_utils_root();
-	tests_root = test_iosched_get_debugfs_tests_root();
-
-	if (!utils_root || !tests_root)
-		return -EINVAL;
-
-	mbtd->debug.random_test_seed = debugfs_create_u32(
-					"random_test_seed",
-					S_IRUGO | S_IWUGO,
-					utils_root,
-					&mbtd->random_test_seed);
-
-	if (!mbtd->debug.random_test_seed)
-		goto err_nomem;
-
-	mbtd->debug.send_write_packing_test =
-		debugfs_create_file("send_write_packing_test",
-				    S_IRUGO | S_IWUGO,
-				    tests_root,
-				    NULL,
-				    &send_write_packing_test_ops);
-
-	if (!mbtd->debug.send_write_packing_test)
-		goto err_nomem;
-
-	mbtd->debug.err_check_test =
-		debugfs_create_file("err_check_test",
-				    S_IRUGO | S_IWUGO,
-				    tests_root,
-				    NULL,
-				    &err_check_test_ops);
-
-	if (!mbtd->debug.err_check_test)
-		goto err_nomem;
-
-	mbtd->debug.send_invalid_packed_test =
-		debugfs_create_file("send_invalid_packed_test",
-				    S_IRUGO | S_IWUGO,
-				    tests_root,
-				    NULL,
-				    &send_invalid_packed_test_ops);
-
-	if (!mbtd->debug.send_invalid_packed_test)
-		goto err_nomem;
-
-	mbtd->debug.packing_control_test = debugfs_create_file(
-					"packing_control_test",
-					S_IRUGO | S_IWUGO,
-					tests_root,
-					NULL,
-					&write_packing_control_test_ops);
-
-	if (!mbtd->debug.packing_control_test)
-		goto err_nomem;
-
-	mbtd->debug.discard_sanitize_test =
-		debugfs_create_file("write_discard_sanitize_test",
-				    S_IRUGO | S_IWUGO,
-				    tests_root,
-				    NULL,
-				    &write_discard_sanitize_test_ops);
-	if (!mbtd->debug.discard_sanitize_test) {
-		mmc_block_test_debugfs_cleanup();
-		return -ENOMEM;
-	}
-
-	return 0;
-
-err_nomem:
-	mmc_block_test_debugfs_cleanup();
-	return -ENOMEM;
-}
-
-static void mmc_block_test_probe(void)
-{
-	struct request_queue *q = test_iosched_get_req_queue();
-	struct mmc_queue *mq;
-	int max_packed_reqs;
-
-	if (!q) {
-		test_pr_err("%s: NULL request queue", __func__);
-		return;
-	}
-
-	mq = q->queuedata;
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return;
-	}
-
-	max_packed_reqs = mq->card->ext_csd.max_packed_writes;
-	mbtd->exp_packed_stats.packing_events =
-			kzalloc((max_packed_reqs + 1) *
-				sizeof(*mbtd->exp_packed_stats.packing_events),
-				GFP_KERNEL);
-
-	mmc_block_test_debugfs_init();
-}
-
-static void mmc_block_test_remove(void)
-{
-	mmc_block_test_debugfs_cleanup();
-}
-
-static int __init mmc_block_test_init(void)
-{
-	mbtd = kzalloc(sizeof(struct mmc_block_test_data), GFP_KERNEL);
-	if (!mbtd) {
-		test_pr_err("%s: failed to allocate mmc_block_test_data",
-			    __func__);
-		return -ENODEV;
-	}
-
-	mbtd->bdt.init_fn = mmc_block_test_probe;
-	mbtd->bdt.exit_fn = mmc_block_test_remove;
-	INIT_LIST_HEAD(&mbtd->bdt.list);
-	test_iosched_register(&mbtd->bdt);
-
-	return 0;
-}
-
-static void __exit mmc_block_test_exit(void)
-{
-	test_iosched_unregister(&mbtd->bdt);
-	kfree(mbtd);
-}
-
-module_init(mmc_block_test_init);
-module_exit(mmc_block_test_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("MMC block test");
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index e1e4408..9e9dfcd 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -25,13 +25,6 @@
 #define MMC_QUEUE_SUSPENDED	(1 << 0)
 
 /*
- * Based on benchmark tests the default num of requests to trigger the write
- * packing was determined, to keep the read latency as low as possible and
- * manage to keep the high write throughput.
- */
-#define DEFAULT_NUM_REQS_TO_START_PACK 17
-
-/*
  * Prepare a MMC request. This just filters out odd stuff.
  */
 static int mmc_prep_request(struct request_queue *q, struct request *req)
@@ -190,12 +183,9 @@
 
 	memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
 	memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
-	INIT_LIST_HEAD(&mqrq_cur->packed_list);
-	INIT_LIST_HEAD(&mqrq_prev->packed_list);
 	mq->mqrq_cur = mqrq_cur;
 	mq->mqrq_prev = mqrq_prev;
 	mq->queue->queuedata = mq;
-	mq->num_wr_reqs_to_start_packing = DEFAULT_NUM_REQS_TO_START_PACK;
 
 	blk_queue_prep_rq(mq->queue, mmc_prep_request);
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
@@ -396,35 +386,6 @@
 	}
 }
 
-static unsigned int mmc_queue_packed_map_sg(struct mmc_queue *mq,
-					    struct mmc_queue_req *mqrq,
-					    struct scatterlist *sg)
-{
-	struct scatterlist *__sg;
-	unsigned int sg_len = 0;
-	struct request *req;
-	enum mmc_packed_cmd cmd;
-
-	cmd = mqrq->packed_cmd;
-
-	if (cmd == MMC_PACKED_WRITE) {
-		__sg = sg;
-		sg_set_buf(__sg, mqrq->packed_cmd_hdr,
-				sizeof(mqrq->packed_cmd_hdr));
-		sg_len++;
-		__sg->page_link &= ~0x02;
-	}
-
-	__sg = sg + sg_len;
-	list_for_each_entry(req, &mqrq->packed_list, queuelist) {
-		sg_len += blk_rq_map_sg(mq->queue, req, __sg);
-		__sg = sg + (sg_len - 1);
-		(__sg++)->page_link &= ~0x02;
-	}
-	sg_mark_end(sg + (sg_len - 1));
-	return sg_len;
-}
-
 /*
  * Prepare the sg list(s) to be handed of to the host driver
  */
@@ -435,19 +396,12 @@
 	struct scatterlist *sg;
 	int i;
 
-	if (!mqrq->bounce_buf) {
-		if (!list_empty(&mqrq->packed_list))
-			return mmc_queue_packed_map_sg(mq, mqrq, mqrq->sg);
-		else
-			return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
-	}
+	if (!mqrq->bounce_buf)
+		return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
 
 	BUG_ON(!mqrq->bounce_sg);
 
-	if (!list_empty(&mqrq->packed_list))
-		sg_len = mmc_queue_packed_map_sg(mq, mqrq, mqrq->bounce_sg);
-	else
-		sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
+	sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
 
 	mqrq->bounce_sg_len = sg_len;
 
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index ec3d6d2..d2a1eb4 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -12,22 +12,6 @@
 	struct mmc_data		data;
 };
 
-enum mmc_blk_status {
-	MMC_BLK_SUCCESS = 0,
-	MMC_BLK_PARTIAL,
-	MMC_BLK_CMD_ERR,
-	MMC_BLK_RETRY,
-	MMC_BLK_ABORT,
-	MMC_BLK_DATA_ERR,
-	MMC_BLK_ECC_ERR,
-	MMC_BLK_NOMEDIUM,
-};
-
-enum mmc_packed_cmd {
-	MMC_PACKED_NONE = 0,
-	MMC_PACKED_WRITE,
-};
-
 struct mmc_queue_req {
 	struct request		*req;
 	struct mmc_blk_request	brq;
@@ -36,12 +20,6 @@
 	struct scatterlist	*bounce_sg;
 	unsigned int		bounce_sg_len;
 	struct mmc_async_req	mmc_active;
-	struct list_head	packed_list;
-	u32			packed_cmd_hdr[128];
-	unsigned int		packed_blocks;
-	enum mmc_packed_cmd	packed_cmd;
-	int		packed_fail_idx;
-	u8		packed_num;
 };
 
 struct mmc_queue {
@@ -55,11 +33,6 @@
 	struct mmc_queue_req	mqrq[2];
 	struct mmc_queue_req	*mqrq_cur;
 	struct mmc_queue_req	*mqrq_prev;
-	bool			wr_packing_enabled;
-	int			num_of_potential_packed_wr_reqs;
-	int			num_wr_reqs_to_start_packing;
-	int (*err_check_fn) (struct mmc_card *, struct mmc_async_req *);
-	void (*packed_test_fn) (struct request_queue *, struct mmc_queue_req *);
 };
 
 extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
@@ -73,6 +46,4 @@
 extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
 extern void mmc_queue_bounce_post(struct mmc_queue_req *);
 
-extern void print_mmc_packing_stats(struct mmc_card *card);
-
 #endif
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 0592f9d..33f7d29 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -254,8 +254,6 @@
 	card->dev.release = mmc_release_card;
 	card->dev.type = type;
 
-	spin_lock_init(&card->wr_pack_stats.lock);
-
 	return card;
 }
 
@@ -358,8 +356,6 @@
 		device_del(&card->dev);
 	}
 
-	kfree(card->wr_pack_stats.packing_events);
-
 	put_device(&card->dev);
 }
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 478cfac..9b316bb 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -28,6 +28,7 @@
 #include <linux/random.h>
 #include <linux/wakelock.h>
 #include <linux/pm.h>
+#include <linux/slab.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -43,6 +44,12 @@
 #include "sd_ops.h"
 #include "sdio_ops.h"
 
+/*
+ * Background operations can take a long time, depending on the housekeeping
+ * operations the card has to perform.
+ */
+#define MMC_BKOPS_MAX_TIMEOUT	(4 * 60 * 1000) /* max time to wait in ms */
+
 static struct workqueue_struct *workqueue;
 
 /*
@@ -272,6 +279,70 @@
 	host->ops->request(host, mrq);
 }
 
+/**
+ *	mmc_start_bkops - start BKOPS for supported cards
+ *	@card: MMC card to start BKOPS
+ *	@form_exception: A flag to indicate if this function was
+ *			 called due to an exception raised by the card
+ *
+ *	Start background operations whenever requested.
+ *	When the urgent BKOPS bit is set in a R1 command response
+ *	then background operations should be started immediately.
+*/
+void mmc_start_bkops(struct mmc_card *card, bool from_exception)
+{
+	int err;
+	int timeout;
+	bool use_busy_signal;
+
+	BUG_ON(!card);
+
+	if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
+		return;
+
+	err = mmc_read_bkops_status(card);
+	if (err) {
+		pr_err("%s: Failed to read bkops status: %d\n",
+		       mmc_hostname(card->host), err);
+		return;
+	}
+
+	if (!card->ext_csd.raw_bkops_status)
+		return;
+
+	if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2 &&
+	    from_exception)
+		return;
+
+	mmc_claim_host(card->host);
+	if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) {
+		timeout = MMC_BKOPS_MAX_TIMEOUT;
+		use_busy_signal = true;
+	} else {
+		timeout = 0;
+		use_busy_signal = false;
+	}
+
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal);
+	if (err) {
+		pr_warn("%s: Error %d starting bkops\n",
+			mmc_hostname(card->host), err);
+		goto out;
+	}
+
+	/*
+	 * For urgent bkops status (LEVEL_2 and more)
+	 * bkops executed synchronously, otherwise
+	 * the operation is in progress
+	 */
+	if (!use_busy_signal)
+		mmc_card_set_doing_bkops(card);
+out:
+	mmc_release_host(card->host);
+}
+EXPORT_SYMBOL(mmc_start_bkops);
+
 static void mmc_wait_done(struct mmc_request *mrq)
 {
 	complete(&mrq->completion);
@@ -381,6 +452,14 @@
 	if (host->areq) {
 		mmc_wait_for_req_done(host, host->areq->mrq);
 		err = host->areq->err_check(host->card, host->areq);
+		/*
+		 * Check BKOPS urgency for each R1 response
+		 */
+		if (host->card && mmc_card_mmc(host->card) &&
+		    ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) ||
+		     (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) &&
+		    (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT))
+			mmc_start_bkops(host->card, true);
 	}
 
 	if (!err && areq)
@@ -425,7 +504,7 @@
  *	@card: the MMC card associated with the HPI transfer
  *
  *	Issued High Priority Interrupt, and check for card status
- *	util out-of prg-state.
+ *	until out-of prg-state.
  */
 int mmc_interrupt_hpi(struct mmc_card *card)
 {
@@ -507,6 +586,64 @@
 EXPORT_SYMBOL(mmc_wait_for_cmd);
 
 /**
+ *	mmc_stop_bkops - stop ongoing BKOPS
+ *	@card: MMC card to check BKOPS
+ *
+ *	Send HPI command to stop ongoing background operations to
+ *	allow rapid servicing of foreground operations, e.g. read/
+ *	writes. Wait until the card comes out of the programming state
+ *	to avoid errors in servicing read/write requests.
+ */
+int mmc_stop_bkops(struct mmc_card *card)
+{
+	int err = 0;
+
+	BUG_ON(!card);
+	err = mmc_interrupt_hpi(card);
+
+	/*
+	 * If err is EINVAL, we can't issue an HPI.
+	 * It should complete the BKOPS.
+	 */
+	if (!err || (err == -EINVAL)) {
+		mmc_card_clr_doing_bkops(card);
+		err = 0;
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(mmc_stop_bkops);
+
+int mmc_read_bkops_status(struct mmc_card *card)
+{
+	int err;
+	u8 *ext_csd;
+
+	/*
+	 * In future work, we should consider storing the entire ext_csd.
+	 */
+	ext_csd = kmalloc(512, GFP_KERNEL);
+	if (!ext_csd) {
+		pr_err("%s: could not allocate buffer to receive the ext_csd.\n",
+		       mmc_hostname(card->host));
+		return -ENOMEM;
+	}
+
+	mmc_claim_host(card->host);
+	err = mmc_send_ext_csd(card, ext_csd);
+	mmc_release_host(card->host);
+	if (err)
+		goto out;
+
+	card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS];
+	card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXP_EVENTS_STATUS];
+out:
+	kfree(ext_csd);
+	return err;
+}
+EXPORT_SYMBOL(mmc_read_bkops_status);
+
+/**
  *	mmc_set_data_timeout - set the timeout for a data command
  *	@data: data phase for command
  *	@card: the MMC card associated with the data transfer
@@ -2370,8 +2507,14 @@
 				err = -EBUSY;
 
 		if (!err) {
-			if (host->bus_ops->suspend)
+			if (host->bus_ops->suspend) {
+				if (mmc_card_doing_bkops(host->card)) {
+					err = mmc_stop_bkops(host->card);
+					if (err)
+						goto stop_bkops_err;
+				}
 				err = host->bus_ops->suspend(host);
+			}
 			if (!(host->card && mmc_card_sdio(host->card)))
 				mmc_release_host(host);
 
@@ -2401,6 +2544,10 @@
 
 out:
 	return err;
+stop_bkops_err:
+	if (!(host->card && mmc_card_sdio(host->card)))
+		mmc_release_host(host);
+	return err;
 }
 
 EXPORT_SYMBOL(mmc_suspend_host);
@@ -2463,11 +2610,21 @@
 	struct mmc_host *host = container_of(
 		notify_block, struct mmc_host, pm_notify);
 	unsigned long flags;
-
+	int err = 0;
 
 	switch (mode) {
 	case PM_HIBERNATION_PREPARE:
 	case PM_SUSPEND_PREPARE:
+		if (host->card && mmc_card_mmc(host->card) &&
+		    mmc_card_doing_bkops(host->card)) {
+			err = mmc_stop_bkops(host->card);
+			if (err) {
+				pr_err("%s: didn't stop bkops\n",
+					mmc_hostname(host));
+				return err;
+			}
+			mmc_card_clr_doing_bkops(host->card);
+		}
 
 		spin_lock_irqsave(&host->lock, flags);
 		if (mmc_bus_needs_resume(host)) {
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 898e358..9ab5b17 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -318,164 +318,6 @@
 	.llseek		= default_llseek,
 };
 
-static int mmc_wr_pack_stats_open(struct inode *inode, struct file *filp)
-{
-	struct mmc_card *card = inode->i_private;
-
-	filp->private_data = card;
-	card->wr_pack_stats.print_in_read = 1;
-	return 0;
-}
-
-#define TEMP_BUF_SIZE 256
-static ssize_t mmc_wr_pack_stats_read(struct file *filp, char __user *ubuf,
-				size_t cnt, loff_t *ppos)
-{
-	struct mmc_card *card = filp->private_data;
-	struct mmc_wr_pack_stats *pack_stats;
-	int i;
-	int max_num_of_packed_reqs = 0;
-	char *temp_buf;
-
-	if (!card)
-		return cnt;
-
-	if (!card->wr_pack_stats.print_in_read)
-		return 0;
-
-	if (!card->wr_pack_stats.enabled) {
-		pr_info("%s: write packing statistics are disabled\n",
-			 mmc_hostname(card->host));
-		goto exit;
-	}
-
-	pack_stats = &card->wr_pack_stats;
-
-	if (!pack_stats->packing_events) {
-		pr_info("%s: NULL packing_events\n", mmc_hostname(card->host));
-		goto exit;
-	}
-
-	max_num_of_packed_reqs = card->ext_csd.max_packed_writes;
-
-	temp_buf = kmalloc(TEMP_BUF_SIZE, GFP_KERNEL);
-	if (!temp_buf)
-		goto exit;
-
-	spin_lock(&pack_stats->lock);
-
-	snprintf(temp_buf, TEMP_BUF_SIZE, "%s: write packing statistics:\n",
-		mmc_hostname(card->host));
-	strlcat(ubuf, temp_buf, cnt);
-
-	for (i = 1 ; i <= max_num_of_packed_reqs ; ++i) {
-		if (pack_stats->packing_events[i]) {
-			snprintf(temp_buf, TEMP_BUF_SIZE,
-				 "%s: Packed %d reqs - %d times\n",
-				mmc_hostname(card->host), i,
-				pack_stats->packing_events[i]);
-			strlcat(ubuf, temp_buf, cnt);
-		}
-	}
-
-	snprintf(temp_buf, TEMP_BUF_SIZE,
-		 "%s: stopped packing due to the following reasons:\n",
-		 mmc_hostname(card->host));
-	strlcat(ubuf, temp_buf, cnt);
-
-	if (pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]) {
-		snprintf(temp_buf, TEMP_BUF_SIZE,
-			 "%s: %d times: exceed max num of segments\n",
-			 mmc_hostname(card->host),
-			 pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]);
-		strlcat(ubuf, temp_buf, cnt);
-	}
-	if (pack_stats->pack_stop_reason[EXCEEDS_SECTORS]) {
-		snprintf(temp_buf, TEMP_BUF_SIZE,
-			 "%s: %d times: exceed max num of sectors\n",
-			mmc_hostname(card->host),
-			pack_stats->pack_stop_reason[EXCEEDS_SECTORS]);
-		strlcat(ubuf, temp_buf, cnt);
-	}
-	if (pack_stats->pack_stop_reason[WRONG_DATA_DIR]) {
-		snprintf(temp_buf, TEMP_BUF_SIZE,
-			 "%s: %d times: wrong data direction\n",
-			mmc_hostname(card->host),
-			pack_stats->pack_stop_reason[WRONG_DATA_DIR]);
-		strlcat(ubuf, temp_buf, cnt);
-	}
-	if (pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]) {
-		snprintf(temp_buf, TEMP_BUF_SIZE,
-			 "%s: %d times: flush or discard\n",
-			mmc_hostname(card->host),
-			pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]);
-		strlcat(ubuf, temp_buf, cnt);
-	}
-	if (pack_stats->pack_stop_reason[EMPTY_QUEUE]) {
-		snprintf(temp_buf, TEMP_BUF_SIZE,
-			 "%s: %d times: empty queue\n",
-			mmc_hostname(card->host),
-			pack_stats->pack_stop_reason[EMPTY_QUEUE]);
-		strlcat(ubuf, temp_buf, cnt);
-	}
-	if (pack_stats->pack_stop_reason[REL_WRITE]) {
-		snprintf(temp_buf, TEMP_BUF_SIZE,
-			 "%s: %d times: rel write\n",
-			mmc_hostname(card->host),
-			pack_stats->pack_stop_reason[REL_WRITE]);
-		strlcat(ubuf, temp_buf, cnt);
-	}
-	if (pack_stats->pack_stop_reason[THRESHOLD]) {
-		snprintf(temp_buf, TEMP_BUF_SIZE,
-			 "%s: %d times: Threshold\n",
-			mmc_hostname(card->host),
-			pack_stats->pack_stop_reason[THRESHOLD]);
-		strlcat(ubuf, temp_buf, cnt);
-	}
-
-	spin_unlock(&pack_stats->lock);
-
-	kfree(temp_buf);
-
-	pr_info("%s", ubuf);
-
-exit:
-	if (card->wr_pack_stats.print_in_read == 1) {
-		card->wr_pack_stats.print_in_read = 0;
-		return strnlen(ubuf, cnt);
-	}
-
-	return 0;
-}
-
-static ssize_t mmc_wr_pack_stats_write(struct file *filp,
-				       const char __user *ubuf, size_t cnt,
-				       loff_t *ppos)
-{
-	struct mmc_card *card = filp->private_data;
-	int value;
-
-	if (!card)
-		return cnt;
-
-	sscanf(ubuf, "%d", &value);
-	if (value) {
-		mmc_blk_init_packed_statistics(card);
-	} else {
-		spin_lock(&card->wr_pack_stats.lock);
-		card->wr_pack_stats.enabled = false;
-		spin_unlock(&card->wr_pack_stats.lock);
-	}
-
-	return cnt;
-}
-
-static const struct file_operations mmc_dbg_wr_pack_stats_fops = {
-	.open		= mmc_wr_pack_stats_open,
-	.read		= mmc_wr_pack_stats_read,
-	.write		= mmc_wr_pack_stats_write,
-};
-
 void mmc_add_card_debugfs(struct mmc_card *card)
 {
 	struct mmc_host	*host = card->host;
@@ -508,12 +350,6 @@
 					&mmc_dbg_ext_csd_fops))
 			goto err;
 
-	if (mmc_card_mmc(card) && (card->ext_csd.rev >= 6) &&
-	    (card->host->caps2 & MMC_CAP2_PACKED_WR))
-		if (!debugfs_create_file("wr_pack_stats", S_IRUSR, root, card,
-					 &mmc_dbg_wr_pack_stats_fops))
-			goto err;
-
 	return;
 
 err:
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index f87b8cc..a9f2ea9 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -463,6 +463,27 @@
 	}
 
 	if (card->ext_csd.rev >= 5) {
+		/* check whether the eMMC card supports BKOPS */
+		if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
+			card->ext_csd.bkops = 1;
+			card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN];
+			card->ext_csd.raw_bkops_status =
+				ext_csd[EXT_CSD_BKOPS_STATUS];
+			if (!card->ext_csd.bkops_en &&
+				card->host->caps2 & MMC_CAP2_INIT_BKOPS) {
+				err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+					EXT_CSD_BKOPS_EN, 1, 0);
+				if (err)
+					pr_warn("%s: Enabling BKOPS failed\n",
+						mmc_hostname(card->host));
+				else
+					card->ext_csd.bkops_en = 1;
+			}
+			if (!card->ext_csd.bkops_en)
+				pr_info("%s: BKOPS_EN bit is not set\n",
+					mmc_hostname(card->host));
+		}
+
 		/* check whether the eMMC card supports HPI */
 		if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
 			card->ext_csd.hpi = 1;
@@ -516,10 +537,6 @@
 		} else {
 			card->ext_csd.data_tag_unit_size = 0;
 		}
-		card->ext_csd.max_packed_writes =
-			ext_csd[EXT_CSD_MAX_PACKED_WRITES];
-		card->ext_csd.max_packed_reads =
-			ext_csd[EXT_CSD_MAX_PACKED_READS];
 	}
 
 out:
@@ -1257,43 +1274,6 @@
 		}
 	}
 
-	if ((host->caps2 & MMC_CAP2_PACKED_CMD) &&
-			(card->ext_csd.max_packed_writes > 0) &&
-			(card->ext_csd.max_packed_reads > 0)) {
-		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				EXT_CSD_EXP_EVENTS_CTRL,
-				EXT_CSD_PACKED_EVENT_EN,
-				card->ext_csd.generic_cmd6_time);
-		if (err && err != -EBADMSG)
-			goto free_card;
-		if (err) {
-			pr_warning("%s: Enabling packed event failed\n",
-					mmc_hostname(card->host));
-			card->ext_csd.packed_event_en = 0;
-			err = 0;
-		} else {
-			card->ext_csd.packed_event_en = 1;
-		}
-
-	}
-
-	if (!oldcard) {
-		if ((host->caps2 & MMC_CAP2_PACKED_CMD) &&
-		    (card->ext_csd.max_packed_writes > 0)) {
-			/*
-			 * We would like to keep the statistics in an index
-			 * that equals the num of packed requests
-			 * (1 to max_packed_writes)
-			 */
-			card->wr_pack_stats.packing_events = kzalloc(
-				(card->ext_csd.max_packed_writes + 1) *
-				sizeof(*card->wr_pack_stats.packing_events),
-				GFP_KERNEL);
-			if (!card->wr_pack_stats.packing_events)
-				goto free_card;
-		}
-	}
-
 	if (!oldcard)
 		host->card = card;
 
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index e18d922..2d282b5 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -335,7 +335,6 @@
 	return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,
 			ext_csd, 512);
 }
-EXPORT_SYMBOL_GPL(mmc_send_ext_csd);
 
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
 {
@@ -368,18 +367,19 @@
 }
 
 /**
- *	mmc_switch - modify EXT_CSD register
+ *	__mmc_switch - modify EXT_CSD register
  *	@card: the MMC card associated with the data transfer
  *	@set: cmd set values
  *	@index: EXT_CSD register index
  *	@value: value to program into EXT_CSD register
  *	@timeout_ms: timeout (ms) for operation performed by register write,
  *                   timeout of zero implies maximum possible timeout
+ *	@use_busy_signal: use the busy signal as response type
  *
  *	Modifies the EXT_CSD register for selected card.
  */
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
-	       unsigned int timeout_ms)
+int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+	       unsigned int timeout_ms, bool use_busy_signal)
 {
 	int err;
 	struct mmc_command cmd = {0};
@@ -393,13 +393,23 @@
 		  (index << 16) |
 		  (value << 8) |
 		  set;
-	cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+	cmd.flags = MMC_CMD_AC;
+	if (use_busy_signal)
+		cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
+	else
+		cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
+
+
 	cmd.cmd_timeout_ms = timeout_ms;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
 	if (err)
 		return err;
 
+	/* No need to check card status in case of unblocking command */
+	if (!use_busy_signal)
+		return 0;
+
 	/* Must check status to be sure of no errors */
 	do {
 		err = mmc_send_status(card, &status);
@@ -424,6 +434,13 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(__mmc_switch);
+
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+		unsigned int timeout_ms)
+{
+	return __mmc_switch(card, set, index, value, timeout_ms, true);
+}
 EXPORT_SYMBOL_GPL(mmc_switch);
 
 int mmc_send_status(struct mmc_card *card, u32 *status)
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index c4b41e1..ee32298 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -79,7 +79,6 @@
 #if defined(CONFIG_DEBUG_FS)
 static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
 static struct dentry *debugfs_dir;
-static struct dentry *debugfs_file;
 static int  msmsdcc_dbg_init(void);
 #endif
 
@@ -874,6 +873,10 @@
 	bool ret = true;
 	u32 xfer_size = data->blksz * data->blocks;
 
+	if (host->enforce_pio_mode) {
+		ret = false;
+		goto out;
+	}
 	if (is_sps_mode(host)) {
 		/*
 		 * BAM Mode: Fall back on PIO if size is less
@@ -892,7 +895,7 @@
 		/* PIO Mode */
 		ret = false;
 	}
-
+ out:
 	return ret;
 }
 
@@ -4806,7 +4809,7 @@
 	struct msmsdcc_host *host = mmc_priv(mmc);
 
 	return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
-		host->idle_tout_ms / 1000);
+		host->idle_tout / 1000);
 }
 
 static ssize_t
@@ -4821,7 +4824,7 @@
 	if (!kstrtou32(buf, 0, &timeout)
 			&& (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
 		spin_lock_irqsave(&host->lock, flags);
-		host->idle_tout_ms = timeout * 1000;
+		host->idle_tout = timeout * 1000;
 		spin_unlock_irqrestore(&host->lock, flags);
 	}
 	return count;
@@ -5801,11 +5804,10 @@
 		mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
 				MMC_CAP_SET_XPC_180);
 
-	mmc->caps2 |= MMC_CAP2_PACKED_WR;
-	mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
 	mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
 	mmc->caps2 |= MMC_CAP2_SANITIZE;
 	mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
+	mmc->caps2 |= MMC_CAP2_INIT_BKOPS;
 
 	if (plat->nonremovable)
 		mmc->caps |= MMC_CAP_NONREMOVABLE;
@@ -5947,7 +5949,7 @@
 		pm_runtime_enable(&(pdev)->dev);
 	}
 #endif
-	host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
+	host->idle_tout = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
 	setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
 			(unsigned long)host);
 
@@ -6126,6 +6128,16 @@
 	return ret;
 }
 
+#ifdef CONFIG_DEBUG_FS
+static void msmsdcc_remove_debugfs(struct msmsdcc_host *host)
+{
+	debugfs_remove_recursive(host->debugfs_host_dir);
+	host->debugfs_host_dir = NULL;
+}
+#else
+static void msmsdcc_remove_debugfs(msmsdcc_host *host) {}
+#endif
+
 static int msmsdcc_remove(struct platform_device *pdev)
 {
 	struct mmc_host *mmc = mmc_get_drvdata(pdev);
@@ -6152,6 +6164,8 @@
 		device_remove_file(&pdev->dev, &host->polling);
 	device_remove_file(&pdev->dev, &host->idle_timeout);
 
+	msmsdcc_remove_debugfs(host);
+
 	del_timer_sync(&host->req_tout_timer);
 	tasklet_kill(&host->dma_tlet);
 	tasklet_kill(&host->sps.tlet);
@@ -6328,6 +6342,23 @@
 }
 #endif
 
+#if CONFIG_DEBUG_FS
+static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
+		const char *func)
+{
+	ktime_t diff;
+
+	if (host->print_pm_stats) {
+		diff = ktime_sub(ktime_get(), start);
+		pr_info("%s: %s: Completed in %llu usec\n", func,
+		mmc_hostname(host->mmc), (u64)ktime_to_us(diff));
+	}
+}
+#else
+static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
+		const char *func) {}
+#endif
+
 static int
 msmsdcc_runtime_suspend(struct device *dev)
 {
@@ -6335,6 +6366,7 @@
 	struct msmsdcc_host *host = mmc_priv(mmc);
 	int rc = 0;
 	unsigned long flags;
+	ktime_t start = ktime_get();
 
 	if (host->plat->is_sdio_al_client) {
 		rc = 0;
@@ -6391,6 +6423,7 @@
 out:
 	/* set bus bandwidth to 0 immediately */
 	msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
+	msmsdcc_print_pm_stats(host, start, __func__);
 	return rc;
 }
 
@@ -6400,9 +6433,10 @@
 	struct mmc_host *mmc = dev_get_drvdata(dev);
 	struct msmsdcc_host *host = mmc_priv(mmc);
 	unsigned long flags;
+	ktime_t start = ktime_get();
 
 	if (host->plat->is_sdio_al_client)
-		return 0;
+		goto out;
 
 	pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
 	if (mmc) {
@@ -6437,6 +6471,8 @@
 	}
 	host->pending_resume = false;
 	pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
+out:
+	msmsdcc_print_pm_stats(host, start, __func__);
 	return 0;
 }
 
@@ -6449,7 +6485,7 @@
 		return 0;
 
 	/* Idle timeout is not configurable for now */
-	pm_schedule_suspend(dev, host->idle_tout_ms);
+	pm_schedule_suspend(dev, host->idle_tout);
 
 	return -EAGAIN;
 }
@@ -6459,17 +6495,19 @@
 	struct mmc_host *mmc = dev_get_drvdata(dev);
 	struct msmsdcc_host *host = mmc_priv(mmc);
 	int rc = 0;
+	ktime_t start = ktime_get();
 
-	if (host->plat->is_sdio_al_client)
-		return 0;
-
-
+	if (host->plat->is_sdio_al_client) {
+		rc = 0;
+		goto out;
+	}
 	if (host->plat->status_irq)
 		disable_irq(host->plat->status_irq);
 
 	if (!pm_runtime_suspended(dev))
 		rc = msmsdcc_runtime_suspend(dev);
-
+ out:
+	msmsdcc_print_pm_stats(host, start, __func__);
 	return rc;
 }
 
@@ -6502,10 +6540,12 @@
 	struct mmc_host *mmc = dev_get_drvdata(dev);
 	struct msmsdcc_host *host = mmc_priv(mmc);
 	int rc = 0;
+	ktime_t start = ktime_get();
 
-	if (host->plat->is_sdio_al_client)
-		return 0;
-
+	if (host->plat->is_sdio_al_client) {
+		rc = 0;
+		goto out;
+	}
 	if (mmc->card && mmc_card_sdio(mmc->card))
 		rc = msmsdcc_runtime_resume(dev);
 	/*
@@ -6521,7 +6561,8 @@
 		msmsdcc_check_status((unsigned long)host);
 		enable_irq(host->plat->status_irq);
 	}
-
+out:
+	msmsdcc_print_pm_stats(host, start, __func__);
 	return rc;
 }
 
@@ -6595,7 +6636,6 @@
 	platform_driver_unregister(&msmsdcc_driver);
 
 #if defined(CONFIG_DEBUG_FS)
-	debugfs_remove(debugfs_file);
 	debugfs_remove(debugfs_dir);
 #endif
 }
@@ -6607,59 +6647,128 @@
 MODULE_LICENSE("GPL");
 
 #if defined(CONFIG_DEBUG_FS)
-
-static int
-msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
+static int msmsdcc_dbg_idle_tout_get(void *data, u64 *val)
 {
-	file->private_data = inode->i_private;
+	struct msmsdcc_host *host = data;
+
+	*val = host->idle_tout / 1000L;
 	return 0;
 }
 
-static ssize_t
-msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
-		       size_t count, loff_t *ppos)
+static int msmsdcc_dbg_idle_tout_set(void *data, u64 val)
 {
-	struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
-	char buf[200];
-	int max, i;
+	struct msmsdcc_host *host = data;
+	unsigned long flags;
 
-	i = 0;
-	max = sizeof(buf) - 1;
+	spin_lock_irqsave(&host->lock, flags);
+	host->idle_tout = (u32)val * 1000;
+	spin_unlock_irqrestore(&host->lock, flags);
 
-	i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
-		       host->curr.cmd, host->curr.data);
-	if (host->curr.cmd) {
-		struct mmc_command *cmd = host->curr.cmd;
-
-		i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
-			      cmd->opcode, cmd->arg, cmd->flags);
-	}
-	if (host->curr.data) {
-		struct mmc_data *data = host->curr.data;
-		i += scnprintf(buf + i, max - i,
-			      "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
-			      data->timeout_ns, data->timeout_clks,
-			      data->blksz, data->blocks, data->error,
-			      data->flags);
-		i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
-			      host->curr.xfer_size, host->curr.xfer_remain,
-			      host->curr.data_xfered, host->dma.sg);
-	}
-
-	return simple_read_from_buffer(ubuf, count, ppos, buf, i);
+	return 0;
 }
 
-static const struct file_operations msmsdcc_dbg_state_ops = {
-	.read	= msmsdcc_dbg_state_read,
-	.open	= msmsdcc_dbg_state_open,
-};
+DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_idle_tout_ops,
+			msmsdcc_dbg_idle_tout_get,
+			msmsdcc_dbg_idle_tout_set,
+			"%llu\n");
+
+static int msmsdcc_dbg_pio_mode_get(void *data, u64 *val)
+{
+	struct msmsdcc_host *host = data;
+
+	*val = (u64) host->enforce_pio_mode;
+	return 0;
+}
+
+static int msmsdcc_dbg_pio_mode_set(void *data, u64 val)
+{
+	struct msmsdcc_host *host = data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	host->enforce_pio_mode = !!val;
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pio_mode_ops,
+			msmsdcc_dbg_pio_mode_get,
+			msmsdcc_dbg_pio_mode_set,
+			"%llu\n");
+
+static int msmsdcc_dbg_pm_stats_get(void *data, u64 *val)
+{
+	struct msmsdcc_host *host = data;
+
+	*val = !!host->print_pm_stats;
+	return 0;
+}
+
+static int msmsdcc_dbg_pm_stats_set(void *data, u64 val)
+{
+	struct msmsdcc_host *host = data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	host->print_pm_stats = !!val;
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pm_stats_ops,
+			msmsdcc_dbg_pm_stats_get,
+			msmsdcc_dbg_pm_stats_set,
+			"%llu\n");
 
 static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
 {
-	if (debugfs_dir) {
-		debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
-							0644, debugfs_dir, host,
-							&msmsdcc_dbg_state_ops);
+	int err = 0;
+
+	if (!debugfs_dir)
+		return;
+
+	host->debugfs_host_dir = debugfs_create_dir(
+			mmc_hostname(host->mmc), debugfs_dir);
+	if (IS_ERR(host->debugfs_host_dir)) {
+		err = PTR_ERR(host->debugfs_host_dir);
+		host->debugfs_host_dir = NULL;
+		pr_err("%s: Failed to create debugfs dir for host with err=%d\n",
+			mmc_hostname(host->mmc), err);
+		return;
+	}
+
+	host->debugfs_idle_tout = debugfs_create_file("idle_tout",
+		S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
+		&msmsdcc_dbg_idle_tout_ops);
+
+	if (IS_ERR(host->debugfs_idle_tout)) {
+		err = PTR_ERR(host->debugfs_idle_tout);
+		host->debugfs_idle_tout = NULL;
+		pr_err("%s: Failed to create idle_tout debugfs entry with err=%d\n",
+			mmc_hostname(host->mmc), err);
+	}
+
+	host->debugfs_pio_mode = debugfs_create_file("pio_mode",
+		S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
+		&msmsdcc_dbg_pio_mode_ops);
+
+	if (IS_ERR(host->debugfs_pio_mode)) {
+		err = PTR_ERR(host->debugfs_pio_mode);
+		host->debugfs_pio_mode = NULL;
+		pr_err("%s: Failed to create pio_mode debugfs entry with err=%d\n",
+			mmc_hostname(host->mmc), err);
+	}
+
+	host->debugfs_pm_stats = debugfs_create_file("pm_stats",
+		S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
+		&msmsdcc_dbg_pm_stats_ops);
+	if (IS_ERR(host->debugfs_pm_stats)) {
+		err = PTR_ERR(host->debugfs_pm_stats);
+		host->debugfs_pm_stats = NULL;
+		pr_err("%s: Failed to create pm_stats debugfs entry with err=%d\n",
+			mmc_hostname(host->mmc), err);
 	}
 }
 
@@ -6667,7 +6776,7 @@
 {
 	int err;
 
-	debugfs_dir = debugfs_create_dir("msmsdcc", 0);
+	debugfs_dir = debugfs_create_dir("msm_sdcc", 0);
 	if (IS_ERR(debugfs_dir)) {
 		err = PTR_ERR(debugfs_dir);
 		debugfs_dir = NULL;
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 5779491..c66d1a5 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -414,14 +414,20 @@
 	bool sdio_wakeupirq_disabled;
 	struct mutex clk_mutex;
 	bool pending_resume;
-	unsigned int idle_tout_ms;			/* Timeout in msecs */
+	unsigned int idle_tout;			/* Timeout in msecs */
 	bool pending_dpsm_reset;
+	bool enforce_pio_mode;
+	bool print_pm_stats;
 	struct msmsdcc_msm_bus_vote msm_bus_vote;
 	struct device_attribute	max_bus_bw;
 	struct device_attribute	polling;
 	struct device_attribute idle_timeout;
 	struct device_attribute auto_cmd19_attr;
 	struct device_attribute auto_cmd21_attr;
+	struct dentry *debugfs_host_dir;
+	struct dentry *debugfs_idle_tout;
+	struct dentry *debugfs_pio_mode;
+	struct dentry *debugfs_pm_stats;
 };
 
 #define MSMSDCC_VERSION_STEP_MASK	0x0000FFFF
@@ -483,7 +489,7 @@
 	if ((step == 0x18) && (minor >= 3))
 		host->hw_caps |= MSMSDCC_AUTO_CMD21;
 
-	if (version >= 0x2b) /* SDCC v4 2.1.0 and greater */
+	if (step >= 0x2b) /* SDCC v4 2.1.0 and greater */
 		host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_AUTO_CMD21;
 }
 
diff --git a/drivers/net/ethernet/msm/msm_rmnet_smux.c b/drivers/net/ethernet/msm/msm_rmnet_smux.c
index fbb3489..5f29406 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_smux.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_smux.c
@@ -79,6 +79,7 @@
 	unsigned long timeout_us;
 #endif
 	spinlock_t lock;
+	spinlock_t tx_queue_lock;
 	struct tasklet_struct tsklt;
 	/* IOCTL specified mode (protocol, QoS header) */
 	u32 operation_mode;
@@ -346,12 +347,15 @@
 		 ((struct net_device *)(dev))->name, p->stats.tx_packets,
 		 skb->len, skb->mark);
 	dev_kfree_skb_any(skb);
+
+	spin_lock_irqsave(&p->tx_queue_lock, flags);
 	if (netif_queue_stopped(dev) &&
 		msm_smux_is_ch_low(p->ch_id)) {
 		DBG0("%s: Low WM hit, waking queue=%p\n",
 			 __func__, skb);
 		netif_wake_queue(dev);
 	}
+	spin_unlock_irqrestore(&p->tx_queue_lock, flags);
 }
 
 void rmnet_smux_notify(void *priv, int event_type, const void *metadata)
@@ -475,14 +479,20 @@
 
 	case SMUX_LOW_WM_HIT:
 		dev = priv;
+		p = netdev_priv(priv);
 		DBG0("[%s] Low WM hit dev:%s\n", __func__, dev->name);
+		spin_lock_irqsave(&p->tx_queue_lock, flags);
 		netif_start_queue(dev);
+		spin_unlock_irqrestore(&p->tx_queue_lock, flags);
 		break;
 
 	case SMUX_HIGH_WM_HIT:
 		dev = priv;
-		DBG0("[%s] Low WM hit dev:%s\n", __func__, dev->name);
+		p = netdev_priv(priv);
+		DBG0("[%s] High WM hit dev:%s\n", __func__, dev->name);
+		spin_lock_irqsave(&p->tx_queue_lock, flags);
 		netif_stop_queue(dev);
+		spin_unlock_irqrestore(&p->tx_queue_lock, flags);
 		break;
 
 	default:
@@ -573,7 +583,6 @@
 static int _rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct rmnet_private *p = netdev_priv(dev);
-	int smux_ret;
 	struct QMI_QOS_HDR_S *qmih;
 	u32 opmode;
 	unsigned long flags;
@@ -593,21 +602,13 @@
 
 	dev->trans_start = jiffies;
 
-	/* if write() succeeds, skb access is unsafe in this process */
-	smux_ret = msm_smux_write(p->ch_id, skb, skb->data, skb->len);
-
-	if (smux_ret != 0 && smux_ret != -EAGAIN) {
-		pr_err("[%s] %s: write returned error %d",
-			   dev->name, __func__, smux_ret);
-		return -EPERM;
-	}
-
-	return smux_ret;
+	return msm_smux_write(p->ch_id, skb, skb->data, skb->len);
 }
 
 static int rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct rmnet_private *p = netdev_priv(dev);
+	unsigned long flags;
 	int ret = 0;
 
 	if (netif_queue_stopped(dev) || (p->device_state == DEVICE_INACTIVE)) {
@@ -616,17 +617,10 @@
 		return 0;
 	}
 
+	spin_lock_irqsave(&p->tx_queue_lock, flags);
 	ret = _rmnet_xmit(skb, dev);
 
-	if (ret == -EPERM) {
-		/* Do not stop the queue here.
-		 * It will lead to ir-recoverable state.
-		 */
-		ret = NETDEV_TX_BUSY;
-		goto exit;
-	}
-
-	if (msm_smux_is_ch_full(p->ch_id) || (ret == -EAGAIN)) {
+	if (ret == -EAGAIN) {
 		/*
 		 * EAGAIN means we attempted to overflow the high watermark
 		 * Clearly the queue is not stopped like it should be, so
@@ -636,9 +630,9 @@
 		 */
 		netif_stop_queue(dev);
 		ret = NETDEV_TX_BUSY;
-		goto exit;
 	}
-exit:
+	spin_unlock_irqrestore(&p->tx_queue_lock, flags);
+
 	return ret;
 }
 
@@ -892,6 +886,7 @@
 		p->ch_id = n;
 		p->in_reset = 0;
 		spin_lock_init(&p->lock);
+		spin_lock_init(&p->tx_queue_lock);
 #ifdef CONFIG_MSM_RMNET_DEBUG
 		p->timeout_us = timeout_us;
 		p->wakeups_xmit = p->wakeups_rcv = 0;
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index ac0a2fd..2bf857c 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -27,6 +27,7 @@
 #include <linux/of_gpio.h>
 #include <mach/peripheral-loader.h>
 #include <mach/msm_smd.h>
+#include <mach/msm_iomap.h>
 #ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
 #include "wcnss_prealloc.h"
 #endif
@@ -159,6 +160,18 @@
 static DEVICE_ATTR(wcnss_version, S_IRUSR,
 		wcnss_version_show, NULL);
 
+/* interface to reset Riva by sending the reset interrupt */
+void wcnss_reset_intr(void)
+{
+	if (wcnss_hardware_type() == WCNSS_RIVA_HW) {
+		wmb();
+		__raw_writel(1 << 24, MSM_APCS_GCC_BASE + 0x8);
+	} else {
+		pr_err("%s: reset interrupt not supported\n", __func__);
+	}
+}
+EXPORT_SYMBOL(wcnss_reset_intr);
+
 static int wcnss_create_sysfs(struct device *dev)
 {
 	int ret;
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 2542845..c474e36 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -395,6 +395,16 @@
 	help
 	  Say Y here to enable support for pm8921 chip charger subdevice
 
+config QPNP_CHARGER
+	tristate "QPNP Charger driver"
+	depends on SPMI
+	depends on OF_SPMI
+	help
+	  Say Y here to enable the switch mode battery charger
+	  and boost device which supports USB detection and charging. The driver
+	  also offers relevant information to userspace via the power supply
+	  framework.
+
 config PM8XXX_CCADC
 	tristate "PM8XXX battery current adc driver"
 	depends on MFD_PM8921_CORE
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 9dc1960..3521cfd 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -57,6 +57,7 @@
 obj-$(CONFIG_PM8921_BMS)	+= pm8921-bms.o
 obj-$(CONFIG_QPNP_BMS)		+= qpnp-bms.o
 obj-$(CONFIG_PM8921_CHARGER)	+= pm8921-charger.o
+obj-$(CONFIG_QPNP_CHARGER)	+= qpnp-charger.o
 obj-$(CONFIG_LTC4088_CHARGER)	+= ltc4088-charger.o
 obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
 obj-$(CONFIG_BATTERY_BCL)	+= battery_current_limit.o
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index c63c99f..b107040 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. 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
@@ -10,8 +10,8 @@
  * GNU General Public License for more details.
  *
  */
-#define pr_fmt(fmt)	"%s: " fmt, __func__
 
+#define pr_fmt(fmt)	"%s: " fmt, __func__
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
@@ -22,6 +22,7 @@
 #include <linux/mfd/pm8xxx/pm8xxx-adc.h>
 #include <linux/mfd/pm8xxx/pm8921-charger.h>
 #include <linux/mfd/pm8xxx/ccadc.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/debugfs.h>
@@ -224,7 +225,6 @@
 module_param_cb(bms_end_ocv_uv, &bms_ro_param_ops, &bms_end_ocv_uv, 0644);
 module_param_cb(bms_end_cc_uah, &bms_ro_param_ops, &bms_end_cc_uah, 0644);
 
-static int interpolate_fcc(struct pm8921_bms_chip *chip, int batt_temp);
 static void readjust_fcc_table(void)
 {
 	struct single_row_lut *temp, *old;
@@ -241,7 +241,7 @@
 		return;
 	}
 
-	fcc = interpolate_fcc(the_chip, last_real_fcc_batt_temp);
+	fcc = interpolate_fcc(the_chip->fcc_temp_lut, last_real_fcc_batt_temp);
 
 	temp->cols = the_chip->fcc_temp_lut->cols;
 	for (i = 0; i < the_chip->fcc_temp_lut->cols; i++) {
@@ -583,342 +583,6 @@
 	return 0;
 }
 
-static int linear_interpolate(int y0, int x0, int y1, int x1, int x)
-{
-	if (y0 == y1 || x == x0)
-		return y0;
-	if (x1 == x0 || x == x1)
-		return y1;
-
-	return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
-}
-
-static int interpolate_single_lut(struct single_row_lut *lut, int x)
-{
-	int i, result;
-
-	if (x < lut->x[0]) {
-		pr_debug("x %d less than known range return y = %d lut = %pS\n",
-							x, lut->y[0], lut);
-		return lut->y[0];
-	}
-	if (x > lut->x[lut->cols - 1]) {
-		pr_debug("x %d more than known range return y = %d lut = %pS\n",
-						x, lut->y[lut->cols - 1], lut);
-		return lut->y[lut->cols - 1];
-	}
-
-	for (i = 0; i < lut->cols; i++)
-		if (x <= lut->x[i])
-			break;
-	if (x == lut->x[i]) {
-		result = lut->y[i];
-	} else {
-		result = linear_interpolate(
-			lut->y[i - 1],
-			lut->x[i - 1],
-			lut->y[i],
-			lut->x[i],
-			x);
-	}
-	return result;
-}
-
-static int interpolate_fcc(struct pm8921_bms_chip *chip, int batt_temp)
-{
-	/* batt_temp is in tenths of degC - convert it to degC for lookups */
-	batt_temp = batt_temp/10;
-	return interpolate_single_lut(chip->fcc_temp_lut, batt_temp);
-}
-
-static int interpolate_fcc_adjusted(struct pm8921_bms_chip *chip, int batt_temp)
-{
-	/* batt_temp is in tenths of degC - convert it to degC for lookups */
-	batt_temp = batt_temp/10;
-	return interpolate_single_lut(chip->adjusted_fcc_temp_lut, batt_temp);
-}
-
-static int interpolate_scalingfactor_fcc(struct pm8921_bms_chip *chip,
-								int cycles)
-{
-	/*
-	 * sf table could be null when no battery aging data is available, in
-	 * that case return 100%
-	 */
-	if (chip->fcc_sf_lut)
-		return interpolate_single_lut(chip->fcc_sf_lut, cycles);
-	else
-		return 100;
-}
-
-static int interpolate_scalingfactor(struct pm8921_bms_chip *chip,
-				struct sf_lut *sf_lut,
-				int row_entry, int pc)
-{
-	int i, scalefactorrow1, scalefactorrow2, scalefactor;
-	int rows, cols;
-	int row1 = 0;
-	int row2 = 0;
-
-	/*
-	 * sf table could be null when no battery aging data is available, in
-	 * that case return 100%
-	 */
-	if (!sf_lut)
-		return 100;
-
-	rows = sf_lut->rows;
-	cols = sf_lut->cols;
-	if (pc > sf_lut->percent[0]) {
-		pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
-		row1 = 0;
-		row2 = 0;
-	}
-	if (pc < sf_lut->percent[rows - 1]) {
-		pr_debug("pc %d less than known pc ranges for sf", pc);
-		row1 = rows - 1;
-		row2 = rows - 1;
-	}
-	for (i = 0; i < rows; i++) {
-		if (pc == sf_lut->percent[i]) {
-			row1 = i;
-			row2 = i;
-			break;
-		}
-		if (pc > sf_lut->percent[i]) {
-			row1 = i - 1;
-			row2 = i;
-			break;
-		}
-	}
-
-	if (row_entry < sf_lut->row_entries[0])
-		row_entry = sf_lut->row_entries[0];
-	if (row_entry > sf_lut->row_entries[cols - 1])
-		row_entry = sf_lut->row_entries[cols - 1];
-
-	for (i = 0; i < cols; i++)
-		if (row_entry <= sf_lut->row_entries[i])
-			break;
-	if (row_entry == sf_lut->row_entries[i]) {
-		scalefactor = linear_interpolate(
-				sf_lut->sf[row1][i],
-				sf_lut->percent[row1],
-				sf_lut->sf[row2][i],
-				sf_lut->percent[row2],
-				pc);
-		return scalefactor;
-	}
-
-	scalefactorrow1 = linear_interpolate(
-				sf_lut->sf[row1][i - 1],
-				sf_lut->row_entries[i - 1],
-				sf_lut->sf[row1][i],
-				sf_lut->row_entries[i],
-				row_entry);
-
-	scalefactorrow2 = linear_interpolate(
-				sf_lut->sf[row2][i - 1],
-				sf_lut->row_entries[i - 1],
-				sf_lut->sf[row2][i],
-				sf_lut->row_entries[i],
-				row_entry);
-
-	scalefactor = linear_interpolate(
-				scalefactorrow1,
-				sf_lut->percent[row1],
-				scalefactorrow2,
-				sf_lut->percent[row2],
-				pc);
-
-	return scalefactor;
-}
-
-static int is_between(int left, int right, int value)
-{
-	if (left >= right && left >= value && value >= right)
-		return 1;
-	if (left <= right && left <= value && value <= right)
-		return 1;
-
-	return 0;
-}
-
-/* get ocv given a soc  -- reverse lookup */
-static int interpolate_ocv(struct pm8921_bms_chip *chip,
-				int batt_temp_degc, int pc)
-{
-	int i, ocvrow1, ocvrow2, ocv;
-	int rows, cols;
-	int row1 = 0;
-	int row2 = 0;
-
-	rows = chip->pc_temp_ocv_lut->rows;
-	cols = chip->pc_temp_ocv_lut->cols;
-	if (pc > chip->pc_temp_ocv_lut->percent[0]) {
-		pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
-		row1 = 0;
-		row2 = 0;
-	}
-	if (pc < chip->pc_temp_ocv_lut->percent[rows - 1]) {
-		pr_debug("pc %d less than known pc ranges for sf\n", pc);
-		row1 = rows - 1;
-		row2 = rows - 1;
-	}
-	for (i = 0; i < rows; i++) {
-		if (pc == chip->pc_temp_ocv_lut->percent[i]) {
-			row1 = i;
-			row2 = i;
-			break;
-		}
-		if (pc > chip->pc_temp_ocv_lut->percent[i]) {
-			row1 = i - 1;
-			row2 = i;
-			break;
-		}
-	}
-
-	if (batt_temp_degc < chip->pc_temp_ocv_lut->temp[0])
-		batt_temp_degc = chip->pc_temp_ocv_lut->temp[0];
-	if (batt_temp_degc > chip->pc_temp_ocv_lut->temp[cols - 1])
-		batt_temp_degc = chip->pc_temp_ocv_lut->temp[cols - 1];
-
-	for (i = 0; i < cols; i++)
-		if (batt_temp_degc <= chip->pc_temp_ocv_lut->temp[i])
-			break;
-	if (batt_temp_degc == chip->pc_temp_ocv_lut->temp[i]) {
-		ocv = linear_interpolate(
-				chip->pc_temp_ocv_lut->ocv[row1][i],
-				chip->pc_temp_ocv_lut->percent[row1],
-				chip->pc_temp_ocv_lut->ocv[row2][i],
-				chip->pc_temp_ocv_lut->percent[row2],
-				pc);
-		return ocv;
-	}
-
-	ocvrow1 = linear_interpolate(
-				chip->pc_temp_ocv_lut->ocv[row1][i - 1],
-				chip->pc_temp_ocv_lut->temp[i - 1],
-				chip->pc_temp_ocv_lut->ocv[row1][i],
-				chip->pc_temp_ocv_lut->temp[i],
-				batt_temp_degc);
-
-	ocvrow2 = linear_interpolate(
-				chip->pc_temp_ocv_lut->ocv[row2][i - 1],
-				chip->pc_temp_ocv_lut->temp[i - 1],
-				chip->pc_temp_ocv_lut->ocv[row2][i],
-				chip->pc_temp_ocv_lut->temp[i],
-				batt_temp_degc);
-
-	ocv = linear_interpolate(
-				ocvrow1,
-				chip->pc_temp_ocv_lut->percent[row1],
-				ocvrow2,
-				chip->pc_temp_ocv_lut->percent[row2],
-				pc);
-
-	return ocv;
-}
-
-static int interpolate_pc(struct pm8921_bms_chip *chip,
-				int batt_temp_degc, int ocv)
-{
-	int i, j, pcj, pcj_minus_one, pc;
-	int rows = chip->pc_temp_ocv_lut->rows;
-	int cols = chip->pc_temp_ocv_lut->cols;
-
-
-	if (batt_temp_degc < chip->pc_temp_ocv_lut->temp[0]) {
-		pr_debug("batt_temp %d < known temp range\n", batt_temp_degc);
-		batt_temp_degc = chip->pc_temp_ocv_lut->temp[0];
-	}
-	if (batt_temp_degc > chip->pc_temp_ocv_lut->temp[cols - 1]) {
-		pr_debug("batt_temp %d > known temp range\n", batt_temp_degc);
-		batt_temp_degc = chip->pc_temp_ocv_lut->temp[cols - 1];
-	}
-
-	for (j = 0; j < cols; j++)
-		if (batt_temp_degc <= chip->pc_temp_ocv_lut->temp[j])
-			break;
-	if (batt_temp_degc == chip->pc_temp_ocv_lut->temp[j]) {
-		/* found an exact match for temp in the table */
-		if (ocv >= chip->pc_temp_ocv_lut->ocv[0][j])
-			return chip->pc_temp_ocv_lut->percent[0];
-		if (ocv <= chip->pc_temp_ocv_lut->ocv[rows - 1][j])
-			return chip->pc_temp_ocv_lut->percent[rows - 1];
-		for (i = 0; i < rows; i++) {
-			if (ocv >= chip->pc_temp_ocv_lut->ocv[i][j]) {
-				if (ocv == chip->pc_temp_ocv_lut->ocv[i][j])
-					return
-					chip->pc_temp_ocv_lut->percent[i];
-				pc = linear_interpolate(
-					chip->pc_temp_ocv_lut->percent[i],
-					chip->pc_temp_ocv_lut->ocv[i][j],
-					chip->pc_temp_ocv_lut->percent[i - 1],
-					chip->pc_temp_ocv_lut->ocv[i - 1][j],
-					ocv);
-				return pc;
-			}
-		}
-	}
-
-	/*
-	 * batt_temp_degc is within temperature for
-	 * column j-1 and j
-	 */
-	if (ocv >= chip->pc_temp_ocv_lut->ocv[0][j])
-		return chip->pc_temp_ocv_lut->percent[0];
-	if (ocv <= chip->pc_temp_ocv_lut->ocv[rows - 1][j - 1])
-		return chip->pc_temp_ocv_lut->percent[rows - 1];
-
-	pcj_minus_one = 0;
-	pcj = 0;
-	for (i = 0; i < rows-1; i++) {
-		if (pcj == 0
-			&& is_between(chip->pc_temp_ocv_lut->ocv[i][j],
-				chip->pc_temp_ocv_lut->ocv[i+1][j], ocv)) {
-			pcj = linear_interpolate(
-				chip->pc_temp_ocv_lut->percent[i],
-				chip->pc_temp_ocv_lut->ocv[i][j],
-				chip->pc_temp_ocv_lut->percent[i + 1],
-				chip->pc_temp_ocv_lut->ocv[i+1][j],
-				ocv);
-		}
-
-		if (pcj_minus_one == 0
-			&& is_between(chip->pc_temp_ocv_lut->ocv[i][j-1],
-				chip->pc_temp_ocv_lut->ocv[i+1][j-1], ocv)) {
-
-			pcj_minus_one = linear_interpolate(
-				chip->pc_temp_ocv_lut->percent[i],
-				chip->pc_temp_ocv_lut->ocv[i][j-1],
-				chip->pc_temp_ocv_lut->percent[i + 1],
-				chip->pc_temp_ocv_lut->ocv[i+1][j-1],
-				ocv);
-		}
-
-		if (pcj && pcj_minus_one) {
-			pc = linear_interpolate(
-				pcj_minus_one,
-				chip->pc_temp_ocv_lut->temp[j-1],
-				pcj,
-				chip->pc_temp_ocv_lut->temp[j],
-				batt_temp_degc);
-			return pc;
-		}
-	}
-
-	if (pcj)
-		return pcj;
-
-	if (pcj_minus_one)
-		return pcj_minus_one;
-
-	pr_debug("%d ocv wasn't found for temp %d in the LUT returning 100%%",
-							ocv, batt_temp_degc);
-	return 100;
-}
-
 #define BMS_MODE_BIT	BIT(6)
 #define EN_VBAT_BIT	BIT(5)
 #define OVERRIDE_MODE_DELAY_MS	20
@@ -1042,7 +706,7 @@
 	}
 	/* Convert the batt_temp to DegC from deciDegC */
 	batt_temp = batt_temp / 10;
-	scalefactor = interpolate_scalingfactor(chip, chip->rbatt_sf_lut,
+	scalefactor = interpolate_scalingfactor(chip->rbatt_sf_lut,
 							batt_temp, soc_rbatt);
 	pr_debug("rbatt sf = %d for batt_temp = %d, soc_rbatt = %d\n",
 				scalefactor, batt_temp, soc_rbatt);
@@ -1069,16 +733,18 @@
 	int initfcc, result, scalefactor = 0;
 
 	if (chip->adjusted_fcc_temp_lut == NULL) {
-		initfcc = interpolate_fcc(chip, batt_temp);
+		initfcc = interpolate_fcc(chip->fcc_temp_lut, batt_temp);
 
-		scalefactor = interpolate_scalingfactor_fcc(chip, chargecycles);
+		scalefactor = interpolate_scalingfactor_fcc(chip->fcc_sf_lut,
+				chargecycles);
 
 		/* Multiply the initial FCC value by the scale factor. */
 		result = (initfcc * scalefactor * 1000) / 100;
 		pr_debug("fcc = %d uAh\n", result);
 		return result;
 	} else {
-		return 1000 * interpolate_fcc_adjusted(chip, batt_temp);
+		return 1000 * interpolate_fcc(chip->adjusted_fcc_temp_lut,
+				batt_temp);
 	}
 }
 
@@ -1120,17 +786,18 @@
 	return 0;
 }
 
-static int calculate_pc(struct pm8921_bms_chip *chip, int ocv_uv, int batt_temp,
-							int chargecycles)
+static int calculate_pc(struct pm8921_bms_chip *chip, int ocv_uv,
+					int batt_temp, int chargecycles)
 {
 	int pc, scalefactor;
 
-	pc = interpolate_pc(chip, batt_temp / 10, ocv_uv / 1000);
+	pc = interpolate_pc(chip->pc_temp_ocv_lut,
+			batt_temp / 10, ocv_uv / 1000);
 	pr_debug("pc = %u for ocv = %dmicroVolts batt_temp = %d\n",
 					pc, ocv_uv, batt_temp);
 
-	scalefactor = interpolate_scalingfactor(chip,
-					chip->pc_sf_lut, chargecycles, pc);
+	scalefactor = interpolate_scalingfactor(chip->pc_sf_lut,
+			chargecycles, pc);
 	pr_debug("scalefactor = %u batt_temp = %d\n", scalefactor, batt_temp);
 
 	/* Multiply the initial FCC value by the scale factor. */
@@ -1183,7 +850,8 @@
 	int uuc_rbatt_uv;
 
 	for (i = 0; i <= 100; i++) {
-		ocv_mv = interpolate_ocv(chip, batt_temp_degc, i);
+		ocv_mv = interpolate_ocv(chip->pc_temp_ocv_lut,
+				batt_temp_degc, i);
 		rbatt_mohm = get_rbatt(chip, i, batt_temp);
 		unusable_uv = (rbatt_mohm * i_ma) + (chip->v_cutoff * 1000);
 		delta_uv = ocv_mv * 1000 - unusable_uv;
@@ -1239,8 +907,8 @@
 	new_uuc = (fcc_uah * chip->prev_pc_unusable) / 100;
 
 	/* also find update the iavg_ma accordingly */
-	new_unusable_mv = interpolate_ocv(chip, batt_temp_degc,
-						chip->prev_pc_unusable);
+	new_unusable_mv = interpolate_ocv(chip->pc_temp_ocv_lut,
+			batt_temp_degc, chip->prev_pc_unusable);
 	if (new_unusable_mv < chip->v_cutoff)
 		new_unusable_mv = chip->v_cutoff;
 
@@ -1531,11 +1199,11 @@
 	pc = DIV_ROUND_CLOSEST((int)rc * 100, fcc_uah);
 	pc = clamp(pc, 0, 100);
 
-	ocv = interpolate_ocv(chip, batt_temp_degc, pc);
+	ocv = interpolate_ocv(chip->pc_temp_ocv_lut, batt_temp_degc, pc);
 
 	pr_debug("s_soc = %d, fcc = %d uuc = %d rc = %d, pc = %d, ocv mv = %d\n",
 			shutdown_soc, fcc_uah, uuc_uah, (int)rc, pc, ocv);
-	new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+	new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv);
 	pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
 
 	while (abs(new_pc - pc) > 1) {
@@ -1545,7 +1213,8 @@
 			delta_mv = -1 * delta_mv;
 
 		ocv = ocv + delta_mv;
-		new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+		new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
+				batt_temp_degc, ocv);
 		pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
 	}
 
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
new file mode 100644
index 0000000..dda8976
--- /dev/null
+++ b/drivers/power/qpnp-charger.c
@@ -0,0 +1,1259 @@
+/* Copyright (c) 2012 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/spmi.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/radix-tree.h>
+#include <linux/interrupt.h>
+#include <linux/qpnp/qpnp-adc.h>
+#include <linux/power_supply.h>
+#include <linux/bitops.h>
+
+/* Interrupt offsets */
+#define INT_RT_STS(base)			(base + 0x10)
+#define INT_SET_TYPE(base)			(base + 0x11)
+#define INT_POLARITY_HIGH(base)			(base + 0x12)
+#define INT_POLARITY_LOW(base)			(base + 0x13)
+#define INT_LATCHED_CLR(base)			(base + 0x14)
+#define INT_EN_SET(base)			(base + 0x15)
+#define INT_EN_CLR(base)			(base + 0x16)
+#define INT_LATCHED_STS(base)			(base + 0x18)
+#define INT_PENDING_STS(base)			(base + 0x19)
+#define INT_MID_SEL(base)			(base + 0x1A)
+#define INT_PRIORITY(base)			(base + 0x1B)
+
+/* Peripheral register offsets */
+#define CHGR_CHG_OPTION				0x08
+#define CHGR_ATC_STATUS				0x0A
+#define CHGR_VBAT_STATUS			0x0B
+#define CHGR_IBAT_BMS				0x0C
+#define CHGR_IBAT_STS				0x0D
+#define CHGR_VDD_MAX				0x40
+#define CHGR_VDD_SAFE				0x41
+#define CHGR_VDD_MAX_STEP			0x42
+#define CHGR_IBAT_MAX				0x44
+#define CHGR_IBAT_SAFE				0x45
+#define CHGR_VIN_MIN				0x47
+#define CHGR_VIN_MIN_STEP			0x48
+#define CHGR_CHG_CTRL				0x49
+#define CHGR_CHG_FAILED				0x4A
+#define CHGR_ATC_CTRL				0x4B
+#define CHGR_ATC_FAILED				0x4C
+#define CHGR_VBAT_TRKL				0x50
+#define CHGR_VBAT_WEAK				0x52
+#define CHGR_IBAT_ATC_A				0x54
+#define CHGR_IBAT_ATC_B				0x55
+#define CHGR_IBAT_TERM_CHGR			0x5B
+#define CHGR_IBAT_TERM_BMS			0x5C
+#define CHGR_VBAT_DET				0x5D
+#define CHGR_TTRKL_MAX				0x5F
+#define CHGR_TTRKL_MAX_EN			0x60
+#define CHGR_TCHG_MAX				0x61
+#define CHGR_CHG_WDOG_TIME			0x62
+#define CHGR_CHG_WDOG_DLY			0x63
+#define CHGR_CHG_WDOG_PET			0x64
+#define CHGR_CHG_WDOG_EN			0x65
+#define CHGR_USB_IUSB_MAX			0x44
+#define CHGR_USB_ENUM_T_STOP			0x4E
+#define CHGR_CHG_TEMP_THRESH			0x66
+#define CHGR_BAT_IF_PRES_STATUS			0x08
+#define CHGR_BAT_TEMP_STATUS			0x09
+#define CHGR_BAT_IF_VCP				0x42
+#define CHGR_BAT_IF_BATFET_CTRL1		0x90
+#define CHGR_MISC_BOOT_DONE			0x42
+#define MISC_REVISION2				0x01
+
+/* SMBB peripheral subtype values */
+#define REG_OFFSET_PERP_SUBTYPE			0x05
+#define SMBB_CHGR_SUBTYPE			0x01
+#define SMBB_BUCK_SUBTYPE			0x02
+#define SMBB_BAT_IF_SUBTYPE			0x03
+#define SMBB_USB_CHGPTH_SUBTYPE			0x04
+#define SMBB_DC_CHGPTH_SUBTYPE			0x05
+#define SMBB_BOOST_SUBTYPE			0x06
+#define SMBB_MISC_SUBTYPE			0x07
+
+#define QPNP_CHARGER_DEV_NAME	"qcom,qpnp-charger"
+
+/* Interrupt definitions */
+/* smbb_chg_interrupts */
+#define CHG_DONE_IRQ			BIT(7)
+#define CHG_FAILED_IRQ			BIT(6)
+#define FAST_CHG_ON_IRQ			BIT(5)
+#define TRKL_CHG_ON_IRQ			BIT(4)
+#define STATE_CHANGE_ON_IR		BIT(3)
+#define CHGWDDOG_IRQ			BIT(2)
+#define VBAT_DET_HI_IRQ			BIT(1)
+#define VBAT_DET_LOW_IRQ		BIT(0)
+
+/* smbb_buck_interrupts */
+#define VDD_LOOP_IRQ			BIT(6)
+#define IBAT_LOOP_IRQ			BIT(5)
+#define ICHG_LOOP_IRQ			BIT(4)
+#define VCHG_LOOP_IRQ			BIT(3)
+#define OVERTEMP_IRQ			BIT(2)
+#define VREF_OV_IRQ			BIT(1)
+#define VBAT_OV_IRQ			BIT(0)
+
+/* smbb_bat_if_interrupts */
+#define PSI_IRQ				BIT(4)
+#define VCP_ON_IRQ			BIT(3)
+#define BAT_FET_ON_IRQ			BIT(2)
+#define BAT_TEMP_OK_IRQ			BIT(1)
+#define BATT_PRES_IRQ			BIT(0)
+
+/* smbb_usb_interrupts */
+#define CHG_GONE_IRQ			BIT(2)
+#define USBIN_VALID_IRQ			BIT(1)
+#define COARSE_DET_USB_IRQ		BIT(0)
+
+/* smbb_dc_interrupts */
+#define DCIN_VALID_IRQ			BIT(1)
+#define COARSE_DET_DC_IRQ		BIT(0)
+
+/* smbb_boost_interrupts */
+#define LIMIT_ERROR_IRQ			BIT(1)
+#define BOOST_PWR_OK_IRQ		BIT(0)
+
+/* smbb_misc_interrupts */
+#define TFTWDOG_IRQ			BIT(0)
+
+/**
+ * struct qpnp_chg_chip - device information
+ * @dev:			device pointer to access the parent
+ * @spmi:			spmi pointer to access spmi information
+ * @chgr_base:			charger peripheral base address
+ * @buck_base:			buck  peripheral base address
+ * @bat_if_base:		battery interface  peripheral base address
+ * @usb_chgpth_base:		USB charge path peripheral base address
+ * @dc_chgpth_base:		DC charge path peripheral base address
+ * @boost_base:			boost peripheral base address
+ * @misc_base:			misc peripheral base address
+ * @freq_base:			freq peripheral base address
+ * @chg_done:			indicates that charging is completed
+ * @usb_present:		present status of usb
+ * @dc_present:			present status of dc
+ * @max_voltage_mv:		the max volts the batt should be charged up to
+ * @min_voltage_mv:		the min battery voltage before turning the FETon
+ * @term_current:		the charging based term current
+ * @revision:			PMIC revision
+ * @dc_psy			power supply to export information to userspace
+ * @usb_psy			power supply to export information to userspace
+ * @bms_psy			power supply to export information to userspace
+ * @batt_psy:			power supply to export information to userspace
+ *
+ */
+struct qpnp_chg_chip {
+	struct device			*dev;
+	struct spmi_device		*spmi;
+	u16				chgr_base;
+	u16				buck_base;
+	u16				bat_if_base;
+	u16				usb_chgpth_base;
+	u16				dc_chgpth_base;
+	u16				boost_base;
+	u16				misc_base;
+	u16				freq_base;
+	unsigned int			usbin_valid_irq;
+	unsigned int			chg_done_irq;
+	unsigned int			chg_failed_irq;
+	bool				chg_done;
+	bool				usb_present;
+	bool				dc_present;
+	unsigned int			max_bat_chg_current;
+	unsigned int			safe_voltage_mv;
+	unsigned int			max_voltage_mv;
+	unsigned int			min_voltage_mv;
+	unsigned int			term_current;
+	unsigned int			revision;
+	struct power_supply		dc_psy;
+	struct power_supply		*usb_psy;
+	struct power_supply		*bms_psy;
+	struct power_supply		batt_psy;
+};
+
+static struct qpnp_chg_chip *the_chip;
+static int charging_disabled;
+
+static struct of_device_id qpnp_charger_match_table[] = {
+	{ .compatible = QPNP_CHARGER_DEV_NAME, },
+	{}
+};
+
+static int
+qpnp_chg_read(struct qpnp_chg_chip *chip, u8 *val,
+			u16 base, int count)
+{
+	int rc;
+	struct spmi_device *spmi = chip->spmi;
+
+	rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, base, val,
+					count);
+	if (rc) {
+		pr_err("SPMI read failed base=0x%02x sid=0x%02x rc=%d\n", base,
+				spmi->sid, rc);
+		return rc;
+	}
+	return 0;
+}
+
+static int
+qpnp_chg_write(struct qpnp_chg_chip *chip, u8 *val,
+			u16 base, int count)
+{
+	int rc;
+	struct spmi_device *spmi = chip->spmi;
+
+	rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, base, val,
+					count);
+	if (rc) {
+		pr_err("write failed base=0x%02x sid=0x%02x rc=%d\n",
+			base, spmi->sid, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int
+qpnp_chg_masked_write(struct qpnp_chg_chip *chip, u16 base,
+						u8 mask, u8 val, int count)
+{
+	int rc;
+	u8 reg;
+
+	rc = qpnp_chg_read(chip, &reg, base, count);
+	if (rc) {
+		pr_err("spmi read failed: addr=%03X, rc=%d\n", base, rc);
+		return rc;
+	}
+	pr_debug("addr = 0x%x read 0x%x\n", base, reg);
+
+	reg &= ~mask;
+	reg |= val & mask;
+
+	pr_debug("Writing 0x%x\n", reg);
+
+	rc = qpnp_chg_write(chip, &reg, base, count);
+	if (rc) {
+		pr_err("spmi write failed: addr=%03X, rc=%d\n", base, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int
+qpnp_chg_is_usb_chg_plugged_in(struct qpnp_chg_chip *chip)
+{
+	u8 usbin_valid_rt_sts;
+	int rc;
+
+	rc = qpnp_chg_read(chip, &usbin_valid_rt_sts,
+				 INT_RT_STS(chip->usb_chgpth_base), 1);
+
+	if (rc) {
+		pr_err("spmi read failed: addr=%03X, rc=%d\n",
+				INT_RT_STS(chip->usb_chgpth_base), rc);
+		return rc;
+	}
+	pr_debug("chgr usb sts 0x%x\n", usbin_valid_rt_sts);
+
+	return (usbin_valid_rt_sts & USBIN_VALID_IRQ) ? 1 : 0;
+}
+
+static int
+qpnp_chg_is_dc_chg_plugged_in(struct qpnp_chg_chip *chip)
+{
+	u8 dcin_valid_rt_sts;
+	int rc;
+
+	rc = qpnp_chg_read(chip, &dcin_valid_rt_sts,
+				 INT_RT_STS(chip->dc_chgpth_base), 1);
+	if (rc) {
+		pr_err("spmi read failed: addr=%03X, rc=%d\n",
+				INT_RT_STS(chip->dc_chgpth_base), rc);
+		return rc;
+	}
+
+	return (dcin_valid_rt_sts & DCIN_VALID_IRQ) ? 1 : 0;
+}
+
+#define VCP_IUSBMAX_SETTING_MA			2000
+#define QPNP_CHG_IUSB_MAX_MIN_100		100
+#define QPNP_CHG_IUSB_MAX_MIN_150		150
+#define QPNP_CHG_IUSB_MAX_MIN_MA		200
+#define QPNP_CHG_IUSB_MAX_MAX_MA		2500
+#define QPNP_CHG_IUSB_MAX_STEP_MA		100
+static int
+qpnp_chg_iusbmax_set(struct qpnp_chg_chip *chip, int mA)
+{
+	u8 usb_reg = 0;
+
+	if (mA == QPNP_CHG_IUSB_MAX_MIN_100) {
+		usb_reg = 0x00;
+		pr_debug("current=%d setting %02x\n", mA, usb_reg);
+		return qpnp_chg_write(chip, &usb_reg,
+		chip->usb_chgpth_base + CHGR_USB_IUSB_MAX, 1);
+	} else if (mA == QPNP_CHG_IUSB_MAX_MIN_150) {
+		usb_reg = 0x01;
+		pr_debug("current=%d setting %02x\n", mA, usb_reg);
+		return qpnp_chg_write(chip, &usb_reg,
+		chip->usb_chgpth_base + CHGR_USB_IUSB_MAX, 1);
+	}
+
+	if (mA < QPNP_CHG_IUSB_MAX_MIN_MA
+			|| mA > QPNP_CHG_IUSB_MAX_MAX_MA) {
+		pr_err("bad mA=%d asked to set\n", mA);
+		return -EINVAL;
+	}
+
+	/* Hack for VCP issue make sure IUSBMAX setting
+	 * is at least 2 A to not brown out device */
+	mA = VCP_IUSBMAX_SETTING_MA;
+
+	usb_reg = mA / QPNP_CHG_IUSB_MAX_STEP_MA;
+
+	pr_debug("current=%d setting 0x%x\n", mA, usb_reg);
+	return qpnp_chg_write(chip, &usb_reg,
+		chip->usb_chgpth_base + CHGR_USB_IUSB_MAX, 1);
+	pr_debug("done\n");
+	return 0;
+}
+
+#define ENUM_T_STOP_BIT		BIT(0)
+static irqreturn_t
+qpnp_chg_usb_usbin_valid_irq_handler(int irq, void *_chip)
+{
+	struct qpnp_chg_chip *chip = _chip;
+	int usb_present;
+
+	usb_present = qpnp_chg_is_usb_chg_plugged_in(chip);
+	pr_debug("usbin-valid triggered: %d\n", usb_present);
+
+	if (chip->usb_present ^ usb_present) {
+		chip->usb_present = usb_present;
+		power_supply_set_present(chip->usb_psy,
+			chip->usb_present);
+	} else if (!(chip->usb_present && usb_present)) {
+			qpnp_chg_masked_write(chip,
+				chip->usb_chgpth_base + CHGR_USB_ENUM_T_STOP,
+				ENUM_T_STOP_BIT,
+				ENUM_T_STOP_BIT, 1);
+	}
+
+	return IRQ_HANDLED;
+}
+
+#define CHGR_CHG_FAILED_BIT	BIT(7)
+static irqreturn_t
+qpnp_chg_chgr_chg_failed_irq_handler(int irq, void *_chip)
+{
+	struct qpnp_chg_chip *chip = _chip;
+	int rc, usb_present;
+
+	rc = qpnp_chg_masked_write(chip,
+		chip->usb_chgpth_base + CHGR_CHG_FAILED,
+		CHGR_CHG_FAILED_BIT,
+		CHGR_CHG_FAILED_BIT, 1);
+	if (rc)
+		pr_err("Failed to write chg_fail clear bit!\n");
+
+	/* Hack: recheck usbin_valid status after chg_fail triggered */
+	usb_present = qpnp_chg_is_usb_chg_plugged_in(chip);
+	pr_debug("usb_status: %d\n", usb_present);
+	if (usb_present)
+		qpnp_chg_usb_usbin_valid_irq_handler(chip->usbin_valid_irq,
+			_chip);
+
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
+qpnp_chg_chgr_chg_done_irq_handler(int irq, void *_chip)
+{
+	struct qpnp_chg_chip *chip = _chip;
+
+	pr_debug("CHG_DONE IRQ triggered\n");
+	chip->chg_done = true;
+
+	return IRQ_HANDLED;
+}
+
+static enum power_supply_property pm_power_props_mains[] = {
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+};
+
+static enum power_supply_property msm_batt_power_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+	POWER_SUPPLY_PROP_TEMP,
+};
+
+static char *pm_power_supplied_to[] = {
+	"battery",
+};
+
+#define USB_WALL_THRESHOLD_MA	500
+static int
+qpnp_power_get_property_mains(struct power_supply *psy,
+				  enum power_supply_property psp,
+				  union power_supply_propval *val)
+{
+	struct qpnp_chg_chip *chip = container_of(psy, struct qpnp_chg_chip,
+								dc_psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_PRESENT:
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = 0;
+		if (charging_disabled)
+			return 0;
+
+		val->intval = qpnp_chg_is_dc_chg_plugged_in(chip);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+get_prop_battery_voltage_now(struct qpnp_chg_chip *chip)
+{
+	int rc = 0;
+	struct qpnp_vadc_result results;
+
+	if (chip->revision > 0) {
+		rc = qpnp_vadc_read(VBAT_SNS, &results);
+		if (rc) {
+			pr_err("Unable to read vbat rc=%d\n", rc);
+			return 0;
+		}
+		return results.physical;
+	} else {
+		pr_err("vbat reading not supported for 1.0 rc=%d\n", rc);
+		return 0;
+	}
+}
+
+#define BATT_PRES_BIT BIT(7)
+static int
+get_prop_batt_present(struct qpnp_chg_chip *chip)
+{
+	u8 batt_present;
+	int rc;
+
+	rc = qpnp_chg_read(chip, &batt_present,
+				chip->bat_if_base + CHGR_BAT_IF_PRES_STATUS, 1);
+	if (rc) {
+		pr_err("Couldn't read battery status read failed rc=%d\n", rc);
+		return 0;
+	};
+	return (batt_present & BATT_PRES_BIT) ? 1 : 0;
+}
+
+#define BATT_TEMP_HOT	BIT(6)
+#define BATT_TEMP_OK	BIT(7)
+static int
+get_prop_batt_health(struct qpnp_chg_chip *chip)
+{
+	u8 batt_health;
+	int rc;
+
+	rc = qpnp_chg_read(chip, &batt_health,
+				chip->bat_if_base + CHGR_BAT_TEMP_STATUS, 1);
+	if (rc) {
+		pr_err("Couldn't read battery health read failed rc=%d\n", rc);
+		return POWER_SUPPLY_HEALTH_UNKNOWN;
+	};
+
+	if (BATT_TEMP_OK & batt_health)
+		return POWER_SUPPLY_HEALTH_GOOD;
+	if (BATT_TEMP_HOT & batt_health)
+		return POWER_SUPPLY_HEALTH_OVERHEAT;
+	else
+		return POWER_SUPPLY_HEALTH_COLD;
+}
+
+static int
+get_prop_charge_type(struct qpnp_chg_chip *chip)
+{
+	int rc;
+	u8 chgr_sts;
+
+	if (!get_prop_batt_present(chip))
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
+
+	rc = qpnp_chg_read(chip, &chgr_sts,
+				INT_RT_STS(chip->chgr_base), 1);
+	if (rc) {
+		pr_err("failed to read interrupt sts %d\n", rc);
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
+	}
+
+	if (chgr_sts & TRKL_CHG_ON_IRQ)
+		return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+	if (chgr_sts & FAST_CHG_ON_IRQ)
+		return POWER_SUPPLY_CHARGE_TYPE_FAST;
+
+	return POWER_SUPPLY_CHARGE_TYPE_NONE;
+}
+
+static int
+get_prop_batt_status(struct qpnp_chg_chip *chip)
+{
+	int rc;
+	u8 chgr_sts;
+
+	rc = qpnp_chg_read(chip, &chgr_sts,
+				INT_RT_STS(chip->chgr_base), 1);
+	if (rc) {
+		pr_err("failed to read interrupt sts %d\n", rc);
+		return POWER_SUPPLY_STATUS_DISCHARGING;
+	}
+
+	pr_debug("chgr sts 0x%x\n", chgr_sts);
+	if (chgr_sts & CHG_DONE_IRQ || chip->chg_done)
+		return POWER_SUPPLY_STATUS_FULL;
+	else
+		chip->chg_done = false;
+
+	if (chgr_sts & TRKL_CHG_ON_IRQ)
+		return POWER_SUPPLY_STATUS_CHARGING;
+	if (chgr_sts & FAST_CHG_ON_IRQ)
+		return POWER_SUPPLY_STATUS_CHARGING;
+
+	return POWER_SUPPLY_STATUS_DISCHARGING;
+}
+
+static int
+get_prop_current_now(struct qpnp_chg_chip *chip)
+{
+	union power_supply_propval ret = {0,};
+
+	if (chip->bms_psy) {
+		chip->bms_psy->get_property(chip->bms_psy,
+			  POWER_SUPPLY_PROP_CURRENT_NOW, &ret);
+		return ret.intval;
+	} else {
+		pr_debug("No BMS supply registered return 0\n");
+	}
+
+	return 0;
+}
+
+static int
+get_prop_full_design(struct qpnp_chg_chip *chip)
+{
+	union power_supply_propval ret = {0,};
+
+	if (chip->bms_psy) {
+		chip->bms_psy->get_property(chip->bms_psy,
+			  POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, &ret);
+		return ret.intval;
+	} else {
+		pr_debug("No BMS supply registered return 0\n");
+	}
+
+	return 0;
+}
+
+#define DEFAULT_CAPACITY	50
+static int
+get_prop_capacity(struct qpnp_chg_chip *chip)
+{
+	union power_supply_propval ret = {0,};
+
+	if (chip->bms_psy) {
+		chip->bms_psy->get_property(chip->bms_psy,
+			  POWER_SUPPLY_PROP_CAPACITY, &ret);
+		return ret.intval;
+	} else {
+		pr_debug("No BMS supply registered return 50\n");
+	}
+
+	/* return default capacity to avoid userspace
+	 * from shutting down unecessarily */
+	return DEFAULT_CAPACITY;
+}
+
+#define DEFAULT_TEMP		25
+#define MAX_TOLERABLE_BATT_TEMP_DDC	680
+static int
+get_prop_batt_temp(struct qpnp_chg_chip *chip)
+{
+	int rc = 0;
+	struct qpnp_vadc_result results;
+
+	if (chip->revision > 0) {
+		rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &results);
+		if (rc) {
+			pr_debug("Unable to read batt temperature rc=%d\n", rc);
+			return 0;
+		}
+		pr_debug("get_bat_temp %d %lld\n",
+			results.adc_code, results.physical);
+		return (int)results.physical;
+	} else {
+		pr_debug("batt temp not supported for PMIC 1.0 rc=%d\n", rc);
+	}
+
+	/* return default temperature to avoid userspace
+	 * from shutting down unecessarily */
+	return DEFAULT_TEMP;
+}
+
+static void
+qpnp_batt_external_power_changed(struct power_supply *psy)
+{
+	struct qpnp_chg_chip *chip = container_of(psy, struct qpnp_chg_chip,
+								batt_psy);
+	union power_supply_propval ret = {0,};
+
+	if (!chip->bms_psy)
+		chip->bms_psy = power_supply_get_by_name("bms");
+
+	chip->usb_psy->get_property(chip->usb_psy,
+			  POWER_SUPPLY_PROP_ONLINE, &ret);
+
+	if (ret.intval && qpnp_chg_is_usb_chg_plugged_in(chip)) {
+		chip->usb_psy->get_property(chip->usb_psy,
+			  POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
+		qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
+	} else {
+		qpnp_chg_iusbmax_set(chip, QPNP_CHG_IUSB_MAX_MIN_MA);
+	}
+
+	pr_debug("end of power supply changed\n");
+	power_supply_changed(&chip->batt_psy);
+}
+
+static int
+qpnp_batt_power_get_property(struct power_supply *psy,
+				       enum power_supply_property psp,
+				       union power_supply_propval *val)
+{
+	struct qpnp_chg_chip *chip = container_of(psy, struct qpnp_chg_chip,
+								batt_psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = get_prop_batt_status(chip);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		val->intval = get_prop_charge_type(chip);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = get_prop_batt_health(chip);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = get_prop_batt_present(chip);
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+		val->intval = chip->max_voltage_mv * 1000;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+		val->intval = chip->min_voltage_mv * 1000;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = get_prop_battery_voltage_now(chip);
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		val->intval = get_prop_batt_temp(chip);
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = get_prop_capacity(chip);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = get_prop_current_now(chip);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+		val->intval = get_prop_full_design(chip);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+#define CHGR_BOOT_DONE	BIT(7)
+#define CHGR_CHG_EN	BIT(7)
+#define CHGR_ON_BAT_FORCE_BIT	BIT(0)
+#define CHGR_BAT_IF_CONST_RDS_EN	BIT(7)
+#define CHGR_BAT_IF_VCP_EN	BIT(0)
+static int
+qpnp_chg_charge_dis(struct qpnp_chg_chip *chip, int disable)
+{
+	/* This bit forces the charger to run off of the battery rather
+	 * than a connected charger */
+	return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_CHG_CTRL,
+			CHGR_ON_BAT_FORCE_BIT,
+			disable ? CHGR_ON_BAT_FORCE_BIT : 0, 1);
+}
+
+static int
+qpnp_chg_charge_en(struct qpnp_chg_chip *chip, int enable)
+{
+	return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_CHG_CTRL,
+			CHGR_CHG_EN,
+			enable ? CHGR_CHG_EN : 0, 1);
+}
+
+static int
+qpnp_chg_set_disable_status_param(const char *val, struct kernel_param *kp)
+{
+	int ret;
+	struct qpnp_chg_chip *chip = the_chip;
+
+	ret = param_set_int(val, kp);
+	if (ret) {
+		pr_err("error setting value %d\n", ret);
+		return ret;
+	}
+	pr_info("factory set disable param to %d\n", charging_disabled);
+	if (chip)
+		qpnp_chg_charge_dis(chip, charging_disabled);
+	return 0;
+}
+module_param_call(disabled, qpnp_chg_set_disable_status_param, param_get_uint,
+					&charging_disabled, 0644);
+
+#define QPNP_CHG_VINMIN_MIN_MV		3400
+#define QPNP_CHG_VINMIN_HIGH_MIN_MV	5600
+#define QPNP_CHG_VINMIN_HIGH_MIN_VAL	0x2B
+#define QPNP_CHG_VINMIN_MAX_MV		9600
+#define QPNP_CHG_VINMIN_STEP_MV		50
+#define QPNP_CHG_VINMIN_STEP_HIGH_MV	200
+#define QPNP_CHG_VINMIN_MASK		0x1F
+static int
+qpnp_chg_vinmin_set(struct qpnp_chg_chip *chip, int voltage)
+{
+	u8 temp;
+
+	if (voltage < QPNP_CHG_VINMIN_MIN_MV
+			|| voltage > QPNP_CHG_VINMIN_MAX_MV) {
+		pr_err("bad mV=%d asked to set\n", voltage);
+		return -EINVAL;
+	}
+	if (voltage >= QPNP_CHG_VINMIN_HIGH_MIN_MV) {
+		temp = QPNP_CHG_VINMIN_HIGH_MIN_VAL;
+		temp += (voltage - QPNP_CHG_VINMIN_MIN_MV)
+			/ QPNP_CHG_VINMIN_STEP_HIGH_MV;
+	} else {
+		temp = (voltage - QPNP_CHG_VINMIN_MIN_MV)
+			/ QPNP_CHG_VINMIN_STEP_MV;
+	}
+
+	pr_debug("voltage=%d setting %02x\n", voltage, temp);
+	return qpnp_chg_masked_write(chip,
+			chip->chgr_base + CHGR_VIN_MIN,
+			QPNP_CHG_VINMIN_MASK, temp, 1);
+}
+
+
+#define QPNP_CHG_ITERM_MIN_MA		100
+#define QPNP_CHG_ITERM_MAX_MA		250
+#define QPNP_CHG_ITERM_STEP_MA		50
+#define QPNP_CHG_ITERM_MASK			0x03
+static int
+qpnp_chg_ibatterm_set(struct qpnp_chg_chip *chip, int term_current)
+{
+	u8 temp;
+
+	if (term_current < QPNP_CHG_ITERM_MIN_MA
+			|| term_current > QPNP_CHG_ITERM_MAX_MA) {
+		pr_err("bad mA=%d asked to set\n", term_current);
+		return -EINVAL;
+	}
+
+	temp = (term_current - QPNP_CHG_ITERM_MIN_MA)
+				/ QPNP_CHG_ITERM_STEP_MA;
+	return qpnp_chg_masked_write(chip,
+			chip->chgr_base + CHGR_IBAT_TERM_CHGR,
+			QPNP_CHG_ITERM_MASK, temp, 1);
+}
+
+#define QPNP_CHG_IBATMAX_MIN	100
+#define QPNP_CHG_IBATMAX_MAX	3250
+#define QPNP_CHG_I_STEP_MA		50
+#define QPNP_CHG_I_MIN_MA		100
+#define QPNP_CHG_I_MASK			0x3F
+static int
+qpnp_chg_ibatmax_set(struct qpnp_chg_chip *chip, int chg_current)
+{
+	u8 temp;
+
+	if (chg_current < QPNP_CHG_IBATMAX_MIN
+			|| chg_current > QPNP_CHG_IBATMAX_MAX) {
+		pr_err("bad mA=%d asked to set\n", chg_current);
+		return -EINVAL;
+	}
+	temp = (chg_current - QPNP_CHG_I_MIN_MA) / QPNP_CHG_I_STEP_MA;
+	return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_IBAT_MAX,
+			QPNP_CHG_I_MASK, temp, 1);
+}
+
+
+#define QPNP_CHG_V_MIN_MV	3240
+#define QPNP_CHG_V_MAX_MV	4500
+#define QPNP_CHG_V_STEP_MV	10
+static int
+qpnp_chg_vddsafe_set(struct qpnp_chg_chip *chip, int voltage)
+{
+	u8 temp;
+
+	if (voltage < QPNP_CHG_V_MIN_MV
+			|| voltage > QPNP_CHG_V_MAX_MV) {
+		pr_err("bad mV=%d asked to set\n", voltage);
+		return -EINVAL;
+	}
+	temp = (voltage - QPNP_CHG_V_MIN_MV) / QPNP_CHG_V_STEP_MV;
+	pr_debug("voltage=%d setting %02x\n", voltage, temp);
+	return qpnp_chg_write(chip, &temp,
+		chip->chgr_base + CHGR_VDD_SAFE, 1);
+}
+
+#define QPNP_CHG_VDDMAX_MIN	3400
+static int
+qpnp_chg_vddmax_set(struct qpnp_chg_chip *chip, int voltage)
+{
+	u8 temp = 0;
+
+	if (voltage < QPNP_CHG_VDDMAX_MIN
+			|| voltage > QPNP_CHG_V_MAX_MV) {
+		pr_err("bad mV=%d asked to set\n", voltage);
+		return -EINVAL;
+	}
+
+	temp = (voltage - QPNP_CHG_V_MIN_MV) / QPNP_CHG_V_STEP_MV;
+
+	pr_debug("voltage=%d setting %02x\n", voltage, temp);
+	return qpnp_chg_write(chip, &temp,
+		chip->chgr_base + CHGR_VDD_MAX, 1);
+}
+
+#define WDOG_EN_BIT	BIT(7)
+static int
+qpnp_chg_hwinit(struct qpnp_chg_chip *chip, u8 subtype,
+				struct spmi_resource *spmi_resource)
+{
+	int rc = 0;
+	u8 reg;
+
+	switch (subtype) {
+	case SMBB_CHGR_SUBTYPE:
+		chip->chg_done_irq = spmi_get_irq_byname(chip->spmi,
+						spmi_resource, "chg-done");
+		if (chip->chg_done_irq < 0) {
+			pr_err("Unable to get chg_done irq\n");
+			return -ENXIO;
+		}
+
+		chip->chg_failed_irq = spmi_get_irq_byname(chip->spmi,
+						spmi_resource, "chg-failed");
+		if (chip->chg_failed_irq < 0) {
+			pr_err("Unable to get chg_failed irq\n");
+			return -ENXIO;
+		}
+		rc |= devm_request_irq(chip->dev, chip->chg_done_irq,
+				qpnp_chg_chgr_chg_done_irq_handler,
+				IRQF_TRIGGER_RISING, "chg_done", chip);
+		if (rc < 0) {
+			pr_err("Can't request %d chg_done for chg: %d\n",
+						chip->chg_done_irq, rc);
+			return -ENXIO;
+		}
+		rc |= devm_request_irq(chip->dev, chip->chg_failed_irq,
+				qpnp_chg_chgr_chg_failed_irq_handler,
+				IRQF_TRIGGER_RISING, "chg_failed", chip);
+		if (rc < 0) {
+			pr_err("Can't request %d chg_failed chg: %d\n",
+						chip->chg_failed_irq, rc);
+			return -ENXIO;
+		}
+
+		rc = qpnp_chg_vinmin_set(chip, chip->min_voltage_mv);
+		if (rc) {
+			pr_debug("failed setting  min_voltage rc=%d\n", rc);
+			return rc;
+		}
+		rc = qpnp_chg_vddmax_set(chip, chip->max_voltage_mv);
+		if (rc) {
+			pr_debug("failed setting max_voltage rc=%d\n", rc);
+			return rc;
+		}
+		rc = qpnp_chg_vddsafe_set(chip, chip->safe_voltage_mv);
+		if (rc) {
+			pr_debug("failed setting safe_voltage rc=%d\n", rc);
+			return rc;
+		}
+		rc = qpnp_chg_ibatmax_set(chip, chip->max_bat_chg_current);
+		if (rc) {
+			pr_debug("failed setting ibatmax rc=%d\n", rc);
+			return rc;
+		}
+		rc = qpnp_chg_ibatterm_set(chip, chip->term_current);
+		if (rc) {
+			pr_debug("failed setting ibatterm rc=%d\n", rc);
+			return rc;
+		}
+		/* HACK: Disable wdog */
+		rc = qpnp_chg_masked_write(chip, chip->chgr_base + 0x62,
+			0xFF, 0xA0, 1);
+
+		/* HACK: use analog EOC */
+		rc = qpnp_chg_masked_write(chip, chip->chgr_base +
+			CHGR_IBAT_TERM_CHGR,
+			0x80, 0x80, 1);
+
+		enable_irq_wake(chip->chg_done_irq);
+		break;
+	case SMBB_BUCK_SUBTYPE:
+		break;
+	case SMBB_BAT_IF_SUBTYPE:
+		/* HACK: Unlock secure access to override temp comparator */
+		rc = qpnp_chg_masked_write(chip,
+				chip->bat_if_base + 0xD0,
+				0xA5, 0xA5, 1);
+		pr_debug("override hot cold\n");
+		rc = qpnp_chg_masked_write(chip,
+				chip->bat_if_base + 0xE5,
+				0xFF, 0x28, 1);
+		break;
+	case SMBB_USB_CHGPTH_SUBTYPE:
+		chip->usbin_valid_irq = spmi_get_irq_byname(chip->spmi,
+						spmi_resource, "usbin-valid");
+		if (chip->usbin_valid_irq < 0) {
+			pr_err("Unable to get usbin irq\n");
+			return -ENXIO;
+		}
+		rc = devm_request_irq(chip->dev, chip->usbin_valid_irq,
+				qpnp_chg_usb_usbin_valid_irq_handler,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				"chg_usbin_valid", chip);
+		if (rc < 0) {
+			pr_err("Can't request %d usbinvalid  for chg: %d\n",
+						chip->usbin_valid_irq, rc);
+			return -ENXIO;
+		}
+
+		enable_irq_wake(chip->usbin_valid_irq);
+		chip->usb_present = qpnp_chg_is_usb_chg_plugged_in(chip);
+		if (chip->usb_present) {
+			rc = qpnp_chg_masked_write(chip,
+				chip->usb_chgpth_base + CHGR_USB_ENUM_T_STOP,
+				ENUM_T_STOP_BIT,
+				ENUM_T_STOP_BIT, 1);
+			if (rc) {
+				pr_err("failed to write enum stop rc=%d\n", rc);
+				return -ENXIO;
+			}
+		}
+		break;
+	case SMBB_DC_CHGPTH_SUBTYPE:
+		break;
+	case SMBB_BOOST_SUBTYPE:
+		break;
+	case SMBB_MISC_SUBTYPE:
+		pr_debug("Setting BOOT_DONE\n");
+		rc = qpnp_chg_masked_write(chip,
+			chip->misc_base + CHGR_MISC_BOOT_DONE,
+			CHGR_BOOT_DONE, CHGR_BOOT_DONE, 1);
+		rc = qpnp_chg_read(chip, &reg,
+				 chip->misc_base + MISC_REVISION2, 1);
+		if (rc) {
+			pr_err("failed to read revision register rc=%d\n", rc);
+			return rc;
+		}
+
+		chip->revision = reg;
+		break;
+	default:
+		pr_err("Invalid peripheral subtype\n");
+	}
+	return rc;
+}
+
+static int __devinit
+qpnp_charger_probe(struct spmi_device *spmi)
+{
+	u8 subtype;
+	struct qpnp_chg_chip	*chip;
+	struct resource *resource;
+	struct spmi_resource *spmi_resource;
+	int rc = 0;
+
+	chip = kzalloc(sizeof *chip, GFP_KERNEL);
+	if (chip == NULL) {
+		pr_err("kzalloc() failed.\n");
+		return -ENOMEM;
+	}
+
+	rc = qpnp_vadc_is_ready();
+	if (rc)
+		goto fail_chg_enable;
+
+	chip->dev = &(spmi->dev);
+	chip->spmi = spmi;
+
+	chip->usb_psy = power_supply_get_by_name("usb");
+	if (!chip->usb_psy) {
+		pr_err("usb supply not found deferring probe\n");
+		rc = -EPROBE_DEFER;
+		goto fail_chg_enable;
+	}
+
+	/* Get the vddmax property */
+	rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-vddmax-mv",
+						&chip->max_voltage_mv);
+	if (rc && rc != -EINVAL) {
+		pr_err("Error reading vddmax property %d\n", rc);
+		goto fail_chg_enable;
+	}
+
+	/* Get the vinmin property */
+	rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-vinmin-mv",
+						&chip->min_voltage_mv);
+	if (rc && rc != -EINVAL) {
+		pr_err("Error reading vddmax property %d\n", rc);
+		goto fail_chg_enable;
+	}
+
+	/* Get the vddmax property */
+	rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-vddsafe-mv",
+						&chip->safe_voltage_mv);
+	if (rc && rc != -EINVAL) {
+		pr_err("Error reading vddsave property %d\n", rc);
+		goto fail_chg_enable;
+	}
+
+	/* Get the ibatterm property */
+	rc = of_property_read_u32(spmi->dev.of_node,
+				"qcom,chg-ibatterm-ma",
+				&chip->term_current);
+	if (rc && rc != -EINVAL) {
+		pr_err("Error reading ibatterm property %d\n", rc);
+		goto fail_chg_enable;
+	}
+
+	/* Get the ibatmax property */
+	rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-ibatmax-ma",
+						&chip->max_bat_chg_current);
+	if (rc && rc != -EINVAL) {
+		pr_err("Error reading ibatmax property %d\n", rc);
+		goto fail_chg_enable;
+	}
+
+	spmi_for_each_container_dev(spmi_resource, spmi) {
+		if (!spmi_resource) {
+			pr_err("qpnp_chg: spmi resource absent\n");
+			rc = -ENXIO;
+			goto fail_chg_enable;
+		}
+
+		resource = spmi_get_resource(spmi, spmi_resource,
+						IORESOURCE_MEM, 0);
+		if (!(resource && resource->start)) {
+			pr_err("node %s IO resource absent!\n",
+				spmi->dev.of_node->full_name);
+			rc = -ENXIO;
+			goto fail_chg_enable;
+		}
+
+		rc = qpnp_chg_read(chip, &subtype,
+				resource->start + REG_OFFSET_PERP_SUBTYPE, 1);
+		if (rc) {
+			pr_err("Peripheral subtype read failed rc=%d\n", rc);
+			goto fail_chg_enable;
+		}
+
+		switch (subtype) {
+		case SMBB_CHGR_SUBTYPE:
+			chip->chgr_base = resource->start;
+			rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
+			if (rc) {
+				pr_err("Failed to init subtype 0x%x rc=%d\n",
+						subtype, rc);
+				goto fail_chg_enable;
+			}
+			break;
+		case SMBB_BUCK_SUBTYPE:
+			chip->buck_base = resource->start;
+			rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
+			if (rc) {
+				pr_err("Failed to init subtype 0x%x rc=%d\n",
+						subtype, rc);
+				goto fail_chg_enable;
+			}
+			break;
+		case SMBB_BAT_IF_SUBTYPE:
+			chip->bat_if_base = resource->start;
+			rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
+			if (rc) {
+				pr_err("Failed to init subtype 0x%x rc=%d\n",
+						subtype, rc);
+				goto fail_chg_enable;
+			}
+			break;
+		case SMBB_USB_CHGPTH_SUBTYPE:
+			chip->usb_chgpth_base = resource->start;
+			rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
+			if (rc) {
+				pr_err("Failed to init subtype 0x%x rc=%d\n",
+						subtype, rc);
+				goto fail_chg_enable;
+			}
+			break;
+		case SMBB_DC_CHGPTH_SUBTYPE:
+			chip->dc_chgpth_base = resource->start;
+			rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
+			if (rc) {
+				pr_err("Failed to init subtype 0x%x rc=%d\n",
+						subtype, rc);
+				goto fail_chg_enable;
+			}
+			break;
+		case SMBB_BOOST_SUBTYPE:
+			chip->boost_base = resource->start;
+			rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
+			if (rc) {
+				pr_err("Failed to init subtype 0x%x rc=%d\n",
+						subtype, rc);
+				goto fail_chg_enable;
+			}
+			break;
+		case SMBB_MISC_SUBTYPE:
+			chip->misc_base = resource->start;
+			rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
+			if (rc) {
+				pr_err("Failed to init subtype=0x%x rc=%d\n",
+						subtype, rc);
+				goto fail_chg_enable;
+			}
+			break;
+		default:
+			pr_err("Invalid peripheral subtype=0x%x\n", subtype);
+			rc = -EINVAL;
+			goto fail_chg_enable;
+		}
+	}
+	dev_set_drvdata(&spmi->dev, chip);
+	device_init_wakeup(&spmi->dev, 1);
+
+	chip->dc_psy.name = "qpnp-dc";
+	chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
+	chip->dc_psy.supplied_to = pm_power_supplied_to;
+	chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
+	chip->dc_psy.properties = pm_power_props_mains;
+	chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
+	chip->dc_psy.get_property = qpnp_power_get_property_mains;
+
+	chip->batt_psy.name = "battery";
+	chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
+	chip->batt_psy.properties = msm_batt_power_props;
+	chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
+	chip->batt_psy.get_property = qpnp_batt_power_get_property;
+	chip->batt_psy.external_power_changed =
+				qpnp_batt_external_power_changed;
+
+	rc = power_supply_register(chip->dev, &chip->dc_psy);
+	if (rc < 0) {
+		pr_err("power_supply_register usb failed rc = %d\n", rc);
+		goto fail_chg_enable;
+	}
+
+	rc = power_supply_register(chip->dev, &chip->batt_psy);
+	if (rc < 0) {
+		pr_err("power_supply_register batt failed rc = %d\n", rc);
+		goto unregister_dc;
+	}
+
+	power_supply_set_present(chip->usb_psy,
+			qpnp_chg_is_usb_chg_plugged_in(chip));
+
+	qpnp_chg_charge_en(chip, 1);
+	the_chip = chip;
+	pr_info("Probe success !\n");
+	return 0;
+
+unregister_dc:
+	power_supply_unregister(&chip->dc_psy);
+fail_chg_enable:
+	kfree(chip);
+	dev_set_drvdata(&spmi->dev, NULL);
+	return rc;
+}
+
+static int __devexit
+qpnp_charger_remove(struct spmi_device *spmi)
+{
+	struct qpnp_chg_chip *chip = dev_get_drvdata(&spmi->dev);
+
+	dev_set_drvdata(&spmi->dev, NULL);
+	kfree(chip);
+
+	return 0;
+}
+
+static struct spmi_driver qpnp_charger_driver = {
+	.probe		= qpnp_charger_probe,
+	.remove		= __devexit_p(qpnp_charger_remove),
+	.driver		= {
+		.name	= QPNP_CHARGER_DEV_NAME,
+		.owner  = THIS_MODULE,
+		.of_match_table = qpnp_charger_match_table,
+	},
+};
+
+/**
+ * qpnp_chg_init() - register spmi driver for qpnp-chg
+ */
+int __init
+qpnp_chg_init(void)
+{
+	return spmi_driver_register(&qpnp_charger_driver);
+}
+module_init(qpnp_chg_init);
+
+static void __exit
+qpnp_chg_exit(void)
+{
+	spmi_driver_unregister(&qpnp_charger_driver);
+}
+module_exit(qpnp_chg_exit);
+
+
+MODULE_DESCRIPTION("QPNP charger driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" QPNP_CHARGER_DEV_NAME);
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 45429a1..d099074 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -100,6 +100,7 @@
 	void __iomem		*base;
 	void __iomem		*intr;
 	int			pic_irq;
+	bool			allow_wakeup;
 	spinlock_t		lock;
 	u8			owner;
 	u8			channel;
@@ -638,10 +639,14 @@
 		return -ENODEV;
 	pmic_arb->channel = (u8)prop;
 
-	ret = irq_set_irq_wake(pmic_arb->pic_irq, 1);
-	if (unlikely(ret)) {
-		pr_err("Unable to set wakeup irq, err=%d\n", ret);
-		return -ENODEV;
+	pmic_arb->allow_wakeup = !of_property_read_bool(pdev->dev.of_node,
+					"qcom,not-wakeup");
+	if (pmic_arb->allow_wakeup) {
+		ret = irq_set_irq_wake(pmic_arb->pic_irq, 1);
+		if (unlikely(ret)) {
+			pr_err("Unable to set wakeup irq, err=%d\n", ret);
+			return -ENODEV;
+		}
 	}
 
 	pmic_arb->dev = &pdev->dev;
@@ -685,7 +690,8 @@
 	spmi_del_controller(&pmic_arb->controller);
 err_add_controller:
 	platform_set_drvdata(pdev, NULL);
-	irq_set_irq_wake(pmic_arb->pic_irq, 0);
+	if (pmic_arb->allow_wakeup)
+		irq_set_irq_wake(pmic_arb->pic_irq, 0);
 	return ret;
 }
 
@@ -693,7 +699,8 @@
 {
 	struct spmi_pmic_arb_dev *pmic_arb = platform_get_drvdata(pdev);
 
-	irq_set_irq_wake(pmic_arb->pic_irq, 0);
+	if (pmic_arb->allow_wakeup)
+		irq_set_irq_wake(pmic_arb->pic_irq, 0);
 	platform_set_drvdata(pdev, NULL);
 	spmi_del_controller(&pmic_arb->controller);
 	return 0;
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index 0c49a89..f60e318 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -907,17 +907,6 @@
 	return 0;
 }
 
-static int tsens_check_version_support(void)
-{
-	int rc = 0;
-
-	if (tmdev->hw_type == MSM_8960)
-		if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1)
-			rc = -ENODEV;
-
-	return rc;
-}
-
 static int tsens_calib_sensors(void)
 {
 	int rc = -ENODEV;
@@ -955,13 +944,6 @@
 	tmdev->tsens_num_sensor = pdata->tsens_num_sensor;
 	tmdev->hw_type = pdata->hw_type;
 
-	rc = tsens_check_version_support();
-	if (rc < 0) {
-		kfree(tmdev);
-		tmdev = NULL;
-		return rc;
-	}
-
 	rc = tsens_calib_sensors();
 	if (rc < 0) {
 		kfree(tmdev);
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 19e1244..a292416 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1357,6 +1357,9 @@
 {
 	struct usb_device	*udev = to_usb_device(dev);
 
+	if (udev->bus->skip_resume && udev->state == USB_STATE_SUSPENDED)
+		return 0;
+
 	unbind_no_pm_drivers_interfaces(udev);
 
 	/* From now on we are sure all drivers support suspend/resume
@@ -1386,6 +1389,15 @@
 	struct usb_device	*udev = to_usb_device(dev);
 	int			status;
 
+	/*
+	 * Some buses would like to keep their devices in suspend
+	 * state after system resume.  Their resume happen when
+	 * a remote wakeup is detected or interface driver start
+	 * I/O.
+	 */
+	if (udev->bus->skip_resume)
+		return 0;
+
 	/* For all calls, take the device back to full power and
 	 * tell the PM core in case it was autosuspended previously.
 	 * Unbind the interfaces that will need rebinding later,
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 46f21a7..e3bfbd0 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -71,11 +71,11 @@
 #define USB_ETH_RNDIS y
 #include "f_rndis.c"
 #include "rndis.c"
-#include "u_ether.c"
 #include "u_bam_data.c"
 #include "f_mbim.c"
 #include "f_qc_ecm.c"
 #include "f_qc_rndis.c"
+#include "u_ether.c"
 #include "u_qc_ether.c"
 #ifdef CONFIG_TARGET_CORE
 #include "f_tcm.c"
@@ -2131,7 +2131,6 @@
 	gadget->ep0->driver_data = cdev;
 
 	list_for_each_entry(conf, &dev->configs, list_item)
-		if (&conf->usb_config == cdev->config)
 			list_for_each_entry(f,
 					    &conf->enabled_functions,
 					    enabled_list)
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 7fedaf6..1c64955 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -403,6 +403,8 @@
 static void ecm_qc_notify_complete(struct usb_ep *ep, struct usb_request *req)
 {
 	struct f_ecm_qc			*ecm = req->context;
+	struct usb_composite_dev	*cdev = ecm->port.func.config->cdev;
+	struct usb_cdc_notification	*event = req->buf;
 
 	switch (req->status) {
 	case 0:
@@ -584,6 +586,7 @@
 static void ecm_qc_disable(struct usb_function *f)
 {
 	struct f_ecm_qc		*ecm = func_to_ecm_qc(f);
+	struct usb_composite_dev	*cdev = ecm->port.func.config->cdev;
 
 	DBG(cdev, "ecm deactivated\n");
 
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index 60b96fe..7a181eb 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -512,8 +512,9 @@
 static void rndis_qc_response_complete(struct usb_ep *ep,
 						struct usb_request *req)
 {
-	struct f_rndis_qc			*rndis = req->context;
+	struct f_rndis_qc		*rndis = req->context;
 	int				status = req->status;
+	struct usb_composite_dev	*cdev = rndis->port.func.config->cdev;
 
 	/* after TX:
 	 *  - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 55fd59e..3f4e428 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -294,15 +294,17 @@
 
 static inline enum chg_type usb_get_chg_type(struct usb_info *ui)
 {
-	if ((readl(USB_PORTSC) & PORTSC_LS) == PORTSC_LS)
+	if ((readl_relaxed(USB_PORTSC) & PORTSC_LS) == PORTSC_LS) {
 		return USB_CHG_TYPE__WALLCHARGER;
-	else {
+	} else if (ui->pdata->prop_chg) {
 		if (ui->gadget.speed == USB_SPEED_LOW ||
 			ui->gadget.speed == USB_SPEED_FULL ||
 			ui->gadget.speed == USB_SPEED_HIGH)
 			return USB_CHG_TYPE__SDP;
 		else
 			return USB_CHG_TYPE__INVALID;
+	} else {
+		return USB_CHG_TYPE__SDP;
 	}
 }
 
@@ -332,7 +334,7 @@
 
 	if (temp == USB_CHG_TYPE__WALLCHARGER && !ui->proprietary_chg)
 		return USB_WALLCHARGER_CHG_CURRENT;
-	else
+	else if (ui->pdata->prop_chg)
 		return USB_PROPRIETARY_CHG_CURRENT;
 
 	if (suspended || !configured)
@@ -2049,6 +2051,54 @@
 	.write = debug_reprime_ep,
 };
 
+static ssize_t debug_prop_chg_write(struct file *file,
+		const char __user *buf, size_t count, loff_t *ppos)
+{
+	struct usb_info *ui = file->private_data;
+	char kbuf[2];
+
+	memset(kbuf, 0, sizeof(kbuf));
+
+	if (copy_from_user(kbuf, buf, sizeof(kbuf)))
+		return -EFAULT;
+
+	if (!strncmp(kbuf, "1", 1))
+		ui->pdata->prop_chg = 1;
+	else
+		ui->pdata->prop_chg = 0;
+
+	return count;
+}
+
+static ssize_t debug_prop_chg_read(struct file *file, char __user *ubuf,
+				 size_t count, loff_t *ppos)
+{
+	struct usb_info *ui = file->private_data;
+	char kbuf[2];
+	size_t c = 0;
+
+	memset(kbuf, 0, sizeof(kbuf));
+
+	c = scnprintf(kbuf, sizeof(kbuf), "%d\n", ui->pdata->prop_chg);
+
+	if (copy_to_user(ubuf, kbuf, c))
+		return -EFAULT;
+
+	return simple_read_from_buffer(ubuf, count, ppos, kbuf, c);
+}
+
+static int debug_prop_chg_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+const struct file_operations debug_prop_chg_ops = {
+	.open = debug_prop_chg_open,
+	.read = debug_prop_chg_read,
+	.write = debug_prop_chg_write,
+};
+
 static void usb_debugfs_init(struct usb_info *ui)
 {
 	struct dentry *dent;
@@ -2063,6 +2113,8 @@
 						&debug_wlocks_ops);
 	debugfs_create_file("prime_fail_countt", 0666, dent, ui,
 						&prime_fail_ops);
+	debugfs_create_file("proprietary_chg", 0666, dent, ui,
+						&debug_prop_chg_ops);
 }
 #else
 static void usb_debugfs_init(struct usb_info *ui) {}
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index b7f1878..a887c61 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1279,6 +1279,7 @@
 static irqreturn_t msm_hsic_wakeup_irq(int irq, void *data)
 {
 	struct msm_hsic_hcd *mehci = data;
+	int ret;
 
 	mehci->wakeup_int_cnt++;
 	dbg_log_event(NULL, "Remote Wakeup IRQ", mehci->wakeup_int_cnt);
@@ -1296,8 +1297,17 @@
 	spin_unlock(&mehci->wakeup_lock);
 
 	if (!atomic_read(&mehci->pm_usage_cnt)) {
-		atomic_set(&mehci->pm_usage_cnt, 1);
-		pm_runtime_get(mehci->dev);
+		ret = pm_runtime_get(mehci->dev);
+		/*
+		 * HSIC runtime resume can race with us.
+		 * if we are active (ret == 1) or resuming
+		 * (ret == -EINPROGRESS), decrement the
+		 * PM usage counter before returning.
+		 */
+		if ((ret == 1) || (ret == -EINPROGRESS))
+			pm_runtime_put_noidle(mehci->dev);
+		else
+			atomic_set(&mehci->pm_usage_cnt, 1);
 	}
 
 	return IRQ_HANDLED;
@@ -1522,6 +1532,8 @@
 		return  -ENOMEM;
 	}
 
+	hcd_to_bus(hcd)->skip_resume = true;
+
 	hcd->irq = platform_get_irq(pdev, 0);
 	if (hcd->irq < 0) {
 		dev_err(&pdev->dev, "Unable to get IRQ resource\n");
@@ -1791,6 +1803,15 @@
 	if (device_may_wakeup(dev))
 		disable_irq_wake(hcd->irq);
 
+	/*
+	 * Keep HSIC in Low Power Mode if system is resumed
+	 * by any other wakeup source.  HSIC is resumed later
+	 * when remote wakeup is received or interface driver
+	 * start I/O.
+	 */
+	if (!atomic_read(&mehci->pm_usage_cnt))
+		return 0;
+
 	ret = msm_hsic_resume(mehci);
 	if (ret)
 		return ret;
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index 87f43e1c..656e379 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -168,11 +168,10 @@
 		size_t len;
 
 		pkt = list_first_entry(&ksb->to_ks_list, struct data_pkt, list);
-		len = min_t(size_t, space, pkt->len);
-		pkt->n_read += len;
+		len = min_t(size_t, space, pkt->len - pkt->n_read);
 		spin_unlock_irqrestore(&ksb->lock, flags);
 
-		ret = copy_to_user(buf + copied, pkt->buf, len);
+		ret = copy_to_user(buf + copied, pkt->buf + pkt->n_read, len);
 		if (ret) {
 			pr_err("copy_to_user failed err:%d\n", ret);
 			ksb_free_data_pkt(pkt);
@@ -180,6 +179,7 @@
 			return ret;
 		}
 
+		pkt->n_read += len;
 		space -= len;
 		copied += len;
 
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 998978c..60018bf 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -52,6 +52,7 @@
 #define DRIVER_NAME	"msm_otg"
 
 #define ID_TIMER_FREQ		(jiffies + msecs_to_jiffies(500))
+#define CHG_RECHECK_DELAY	(jiffies + msecs_to_jiffies(2000))
 #define ULPI_IO_TIMEOUT_USEC	(10 * 1000)
 #define USB_PHY_3P3_VOL_MIN	3050000 /* uV */
 #define USB_PHY_3P3_VOL_MAX	3300000 /* uV */
@@ -1629,6 +1630,26 @@
 	return ret;
 }
 
+static void msm_otg_chg_check_timer_func(unsigned long data)
+{
+	struct msm_otg *motg = (struct msm_otg *) data;
+	struct usb_otg *otg = motg->phy.otg;
+
+	if (atomic_read(&motg->in_lpm) ||
+		!test_bit(B_SESS_VLD, &motg->inputs) ||
+		otg->phy->state != OTG_STATE_B_PERIPHERAL ||
+		otg->gadget->speed != USB_SPEED_UNKNOWN) {
+		dev_dbg(otg->phy->dev, "Nothing to do in chg_check_timer\n");
+		return;
+	}
+
+	if ((readl_relaxed(USB_PORTSC) & PORTSC_LS) == PORTSC_LS) {
+		dev_dbg(otg->phy->dev, "DCP is detected as SDP\n");
+		set_bit(B_FALSE_SDP, &motg->inputs);
+		queue_work(system_nrt_wq, &motg->sm_work);
+	}
+}
+
 static bool msm_chg_aca_detect(struct msm_otg *motg)
 {
 	struct usb_phy *phy = &motg->phy;
@@ -2347,6 +2368,8 @@
 					msm_otg_start_peripheral(otg, 1);
 					otg->phy->state =
 						OTG_STATE_B_PERIPHERAL;
+					mod_timer(&motg->chg_check_timer,
+							CHG_RECHECK_DELAY);
 					break;
 				default:
 					break;
@@ -2367,6 +2390,8 @@
 			break;
 		} else {
 			pr_debug("chg_work cancel");
+			del_timer_sync(&motg->chg_check_timer);
+			clear_bit(B_FALSE_SDP, &motg->inputs);
 			cancel_delayed_work_sync(&motg->chg_work);
 			motg->chg_state = USB_CHG_STATE_UNDEFINED;
 			motg->chg_type = USB_INVALID_CHARGER;
@@ -2404,7 +2429,15 @@
 		}
 		break;
 	case OTG_STATE_B_PERIPHERAL:
-		if (!test_bit(ID, &motg->inputs) ||
+		if (test_bit(B_SESS_VLD, &motg->inputs) &&
+				test_bit(B_FALSE_SDP, &motg->inputs)) {
+			pr_debug("B_FALSE_SDP\n");
+			msm_otg_start_peripheral(otg, 0);
+			motg->chg_type = USB_DCP_CHARGER;
+			clear_bit(B_FALSE_SDP, &motg->inputs);
+			otg->phy->state = OTG_STATE_B_IDLE;
+			work = 1;
+		} else if (!test_bit(ID, &motg->inputs) ||
 				test_bit(ID_A, &motg->inputs) ||
 				test_bit(ID_B, &motg->inputs) ||
 				!test_bit(B_SESS_VLD, &motg->inputs)) {
@@ -3709,6 +3742,8 @@
 	INIT_DELAYED_WORK(&motg->suspend_work, msm_otg_suspend_work);
 	setup_timer(&motg->id_timer, msm_otg_id_timer_func,
 				(unsigned long) motg);
+	setup_timer(&motg->chg_check_timer, msm_otg_chg_check_timer_func,
+				(unsigned long) motg);
 	ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
 					"msm_otg", motg);
 	if (ret) {
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index f6d9eb7..79e3808 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -35,6 +35,7 @@
 #include <asm/mach-types.h>
 #include <linux/semaphore.h>
 #include <linux/uaccess.h>
+#include <mach/event_timer.h>
 #include <mach/clk.h>
 #include "mdp.h"
 #include "msm_fb.h"
@@ -518,7 +519,9 @@
 	int ret;
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	mdp_clk_ctrl(1);
 	ret = mdp_lut_hw_update(cmap);
+	mdp_clk_ctrl(0);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
 	if (ret)
@@ -540,9 +543,11 @@
 	uint32_t out;
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	mdp_clk_ctrl(1);
 	ret = mdp_lut_hw_update(cmap);
 
 	if (ret) {
+		mdp_clk_ctrl(0);
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 		return ret;
 	}
@@ -550,6 +555,7 @@
 	/*mask off non LUT select bits*/
 	out = inpdw(MDP_BASE + 0x90070);
 	MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x7 | out);
+	mdp_clk_ctrl(0);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	mdp_lut_i = (mdp_lut_i + 1)%2;
 
@@ -1066,6 +1072,7 @@
 	}
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	mdp_clk_ctrl(1);
 	for (i = 0; i < mgmt->num_bins; i++) {
 		mgmt->c0[i] = inpdw(mdp_hist_base + r_data_offset + (4*i));
 		mgmt->c1[i] = inpdw(mdp_hist_base + g_data_offset + (4*i));
@@ -1081,6 +1088,7 @@
 		} else
 			ret = -ENOMEM;
 	}
+	mdp_clk_ctrl(0);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
 	if (!ret)
@@ -1116,6 +1124,7 @@
 	}
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	mdp_clk_ctrl(1);
 	for (i = 0; i < mgmt->num_bins; i++)
 		mgmt->c0[i] = inpdw(mdp_hist_base + MDP_HIST_DATA_LUMA_OFF +
 									(4*i));
@@ -1127,6 +1136,7 @@
 		} else
 			ret = -ENOMEM;
 	}
+	mdp_clk_ctrl(0);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
 	if (!ret)
@@ -1352,15 +1362,95 @@
 	if (wait == TRUE) {
 		ret = wait_for_completion_interruptible_timeout(&mdp_ppp_comp,
 								5 * HZ);
-
 		if (!ret)
 			printk(KERN_ERR "%s: Timed out waiting for the MDP.\n",
-					__func__);
+				__func__);
 	}
 
 	return ret;
 }
 
+#define MAX_VSYNC_GAP		4
+#define DEFAULT_FRAME_RATE	60
+
+static u32 mdp_get_panel_framerate(struct msm_fb_data_type *mfd)
+{
+	u32 frame_rate = 0, total_pixel;
+	struct msm_panel_info *panel_info = &mfd->panel_info;
+	if (mfd->dest == DISPLAY_LCD) {
+		if (panel_info->type == MDDI_PANEL && panel_info->mddi.is_type1)
+			frame_rate = panel_info->lcd.refx100 / (100 * 2);
+		else
+			frame_rate = panel_info->lcd.refx100 / 100;
+	} else {
+		if (panel_info->type == MIPI_VIDEO_PANEL) {
+			frame_rate = panel_info->mipi.frame_rate;
+		} else {
+			total_pixel = (panel_info->lcdc.h_back_porch +
+				  panel_info->lcdc.h_front_porch +
+				  panel_info->lcdc.h_pulse_width +
+				  panel_info->xres) *
+				 (panel_info->lcdc.v_back_porch +
+				  panel_info->lcdc.v_front_porch +
+				  panel_info->lcdc.v_pulse_width +
+				  panel_info->yres);
+			if (total_pixel)
+				frame_rate = panel_info->clk_rate /
+					total_pixel;
+		}
+	}
+	if (frame_rate == 0)
+		frame_rate = DEFAULT_FRAME_RATE;
+	return frame_rate;
+}
+
+static int mdp_diff_to_next_vsync(ktime_t cur_time,
+			ktime_t last_vsync, u32 vsync_period)
+{
+	int diff_from_last, diff_to_next;
+	/*
+	 * Get interval beween last vsync and current time
+	 * Current time = CPU programming MDP for next Vsync
+	 */
+	diff_from_last =
+		(ktime_to_us(ktime_sub(cur_time, last_vsync)));
+	diff_from_last /= USEC_PER_MSEC;
+	/*
+	 * If the last Vsync occurred too long ago, skip programming
+	 * the timer
+	 */
+	if (diff_from_last < (vsync_period * MAX_VSYNC_GAP)) {
+		if (diff_from_last > vsync_period)
+			diff_to_next =
+				(diff_from_last - vsync_period) % vsync_period;
+		else
+			diff_to_next = vsync_period - diff_from_last;
+	} else {
+		/* mark it out of range */
+		diff_to_next = vsync_period + 1;
+	}
+	return diff_to_next;
+}
+
+void mdp_update_pm(struct msm_fb_data_type *mfd, ktime_t pre_vsync)
+{
+	u32 vsync_period;
+	int diff_to_next;
+	ktime_t cur_time, wakeup_time;
+
+	if (!mfd->cpu_pm_hdl)
+		return;
+	vsync_period = mfd->panel_info.frame_interval;
+	cur_time = ktime_get();
+	diff_to_next = mdp_diff_to_next_vsync(cur_time,
+					      pre_vsync,
+					      vsync_period);
+	if (diff_to_next > vsync_period)
+		return;
+	wakeup_time = ktime_add_ns(cur_time, diff_to_next * NSEC_PER_MSEC);
+	activate_event_timer(mfd->cpu_pm_hdl, wakeup_time);
+}
+
 static DEFINE_SPINLOCK(mdp_lock);
 static int mdp_irq_mask;
 static int mdp_irq_enabled;
@@ -1782,7 +1872,7 @@
 	unsigned long flag;
 	struct mdp_hist_mgmt *mgmt = NULL;
 	int i, ret;
-	int vsync_isr;
+	int vsync_isr, disabled_clocks;
 	/* Ensure all the register write are complete */
 	mb();
 
@@ -1805,19 +1895,23 @@
 	if (mdp_interrupt & MDP_PRIM_RDPTR) {
 		spin_lock_irqsave(&mdp_spin_lock, flag);
 		vsync_isr = vsync_cntrl.vsync_irq_enabled;
-		if (!vsync_isr) {
+		disabled_clocks = vsync_cntrl.disabled_clocks;
+		if ((!vsync_isr && !vsync_cntrl.disabled_clocks)
+			|| (!vsync_isr && vsync_cntrl.vsync_dma_enabled)) {
 			mdp_intr_mask &= ~MDP_PRIM_RDPTR;
 			outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+			mdp_disable_irq_nosync(MDP_VSYNC_TERM);
+			vsync_cntrl.disabled_clocks = 1;
+		} else if (vsync_isr) {
+			vsync_isr_handler();
 		}
+		vsync_cntrl.vsync_dma_enabled = 0;
 		spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
-		if (vsync_isr) {
-			vsync_isr_handler();
-		} else {
+		complete(&vsync_cntrl.vsync_comp);
+		if (!vsync_isr && !disabled_clocks)
 			mdp_pipe_ctrl(MDP_CMD_BLOCK,
 				MDP_BLOCK_POWER_OFF, TRUE);
-			complete(&vsync_cntrl.vsync_wait);
-		}
 	}
 
 	/* DMA3 TV-Out Start */
@@ -1870,16 +1964,16 @@
 			if (!vsync_isr) {
 				mdp_intr_mask &= ~LCDC_FRAME_START;
 				outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+				mdp_disable_irq_nosync(MDP_VSYNC_TERM);
+				vsync_cntrl.disabled_clocks = 1;
+			} else {
+				vsync_isr_handler();
 			}
 			spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
-			if (vsync_isr) {
-				vsync_isr_handler();
-			} else {
+			if (!vsync_isr)
 				mdp_pipe_ctrl(MDP_CMD_BLOCK,
 					MDP_BLOCK_POWER_OFF, TRUE);
-				complete(&vsync_cntrl.vsync_wait);
-			}
 		}
 
 		/* DMA2 LCD-Out Complete */
@@ -1927,6 +2021,7 @@
 			spin_unlock_irqrestore(&mdp_spin_lock, flag);
 			mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF,
 				TRUE);
+			mdp_disable_irq_nosync(MDP_DMA2_TERM);
 			complete(&dma->comp);
 		}
 #endif
@@ -1978,6 +2073,7 @@
 	dma2_data.dmap_busy = FALSE;
 	dma2_data.waiting = FALSE;
 	init_completion(&dma2_data.comp);
+	init_completion(&vsync_cntrl.vsync_comp);
 	init_completion(&dma2_data.dmap_comp);
 	sema_init(&dma2_data.mutex, 1);
 	mutex_init(&dma2_data.ov_mutex);
@@ -2010,7 +2106,7 @@
 		atomic_set(&mdp_block_power_cnt[i], 0);
 	}
 	INIT_WORK(&(vsync_cntrl.vsync_work), send_vsync_work);
-	init_completion(&vsync_cntrl.vsync_wait);
+	vsync_cntrl.disabled_clocks = 1;
 #ifdef MSM_FB_ENABLE_DBGFS
 	{
 		struct dentry *root;
@@ -2383,6 +2479,7 @@
 	int rc;
 	resource_size_t  size ;
 	unsigned long flag;
+	u32 frame_rate;
 #ifdef CONFIG_FB_MSM_MDP40
 	int intf, if_no;
 #endif
@@ -2434,7 +2531,9 @@
 #ifdef CONFIG_FB_MSM_OVERLAY
 		mdp_hw_cursor_init();
 #endif
-		mdp_clk_ctrl(0);
+
+		if (!(mdp_pdata->cont_splash_enabled))
+			mdp_clk_ctrl(0);
 
 		mdp_resource_initialized = 1;
 		return 0;
@@ -2823,6 +2922,11 @@
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	}
 
+	frame_rate = mdp_get_panel_framerate(mfd);
+	if (frame_rate) {
+		mfd->panel_info.frame_interval = 1000 / frame_rate;
+		mfd->cpu_pm_hdl = add_event_timer(NULL, (void *)mfd);
+	}
 	mdp_clk_ctrl(0);
 
 #ifdef CONFIG_MSM_BUS_SCALING
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 371174c..b86116d 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -94,10 +94,12 @@
 
 struct vsync {
 	ktime_t vsync_time;
+	struct completion vsync_comp;
 	struct device *dev;
 	struct work_struct vsync_work;
 	int vsync_irq_enabled;
-	struct completion vsync_wait;
+	int vsync_dma_enabled;
+	int disabled_clocks;
 };
 
 extern struct vsync vsync_cntrl;
@@ -901,6 +903,7 @@
 int mdp_ppp_v4l2_overlay_play(struct fb_info *info,
 	unsigned long srcp0_addr, unsigned long srcp0_size,
 	unsigned long srcp1_addr, unsigned long srcp1_size);
+void mdp_update_pm(struct msm_fb_data_type *mfd, ktime_t pre_vsync);
 
 #ifdef CONFIG_FB_MSM_DTV
 void mdp_vid_quant_set(void);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 18cf817..a5307e6 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -735,37 +735,53 @@
 	*luma_off = 0;
 	*chroma_off = 0;
 
-	if (pipe->src_x && (pipe->frame_format ==
+	if ((pipe->src_x || pipe->src_y) && (pipe->frame_format ==
 		MDP4_FRAME_FORMAT_LINEAR)) {
-		src_xy = (pipe->src_y << 16) | pipe->src_x;
-		src_xy &= 0xffff0000;
+		src_xy = 0;
 		outpdw(vg_base + 0x0004, src_xy);	/* MDP_RGB_SRC_XY */
 
 		switch (pipe->src_format) {
 		case MDP_Y_CR_CB_H2V2:
 		case MDP_Y_CR_CB_GH2V2:
 		case MDP_Y_CB_CR_H2V2:
-				*luma_off = pipe->src_x;
-				*chroma_off = pipe->src_x/2;
+			*luma_off = pipe->src_x +
+				(pipe->src_y * pipe->srcp0_ystride);
+			*chroma_off = pipe->src_x / 2 +
+				((pipe->src_y / 2) * pipe->srcp1_ystride);
 			break;
 
 		case MDP_Y_CBCR_H2V2_TILE:
 		case MDP_Y_CRCB_H2V2_TILE:
 		case MDP_Y_CBCR_H2V2:
 		case MDP_Y_CRCB_H2V2:
+			*luma_off = pipe->src_x +
+				(pipe->src_y * pipe->srcp0_ystride);
+			*chroma_off = pipe->src_x +
+				((pipe->src_y / 2) * pipe->srcp1_ystride);
+			break;
+
 		case MDP_Y_CRCB_H1V1:
 		case MDP_Y_CBCR_H1V1:
+			*luma_off = pipe->src_x +
+				(pipe->src_y * pipe->srcp0_ystride);
+			*chroma_off = pipe->src_x +
+				((pipe->src_y * 2) * pipe->srcp1_ystride);
+			break;
+
 		case MDP_Y_CRCB_H2V1:
 		case MDP_Y_CBCR_H2V1:
 		case MDP_Y_CRCB_H1V2:
-			*luma_off = pipe->src_x;
-			*chroma_off = pipe->src_x;
+			*luma_off = pipe->src_x +
+				(pipe->src_y * pipe->srcp0_ystride);
+			*chroma_off = pipe->src_x +
+				(pipe->src_y * pipe->srcp1_ystride);
 			break;
 
 		case MDP_YCRYCB_H2V1:
 			if (pipe->src_x & 0x1)
 				pipe->src_x += 1;
-			*luma_off += pipe->src_x * 2;
+			*luma_off += pipe->src_x * 2 +
+				((pipe->src_y * 2) * pipe->srcp0_ystride);
 			break;
 
 		case MDP_ARGB_8888:
@@ -778,7 +794,8 @@
 		case MDP_RGB_888:
 		case MDP_YCBCR_H1V1:
 		case MDP_YCRCB_H1V1:
-			*luma_off = pipe->src_x * pipe->bpp;
+			*luma_off = (pipe->src_x * pipe->bpp) +
+					(pipe->src_y * pipe->srcp0_ystride);
 			break;
 
 		default:
diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c
index e67b244..90c3da9 100644
--- a/drivers/video/msm/mdp4_overlay_atv.c
+++ b/drivers/video/msm/mdp4_overlay_atv.c
@@ -184,6 +184,8 @@
 	} else {
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
 	}
+	mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time);
+
 	mdp4_overlay_mdp_perf_req(pipe, mfd);
 	mdp4_overlay_mdp_perf_upd(mfd, 1);
 	mdp4_overlay_rgb_setup(pipe);
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 2d21929..e448d08 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -522,6 +522,9 @@
 		mdp4_dsi_video_wait4dmap_done(0);
 		MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
 		mipi_dsi_controller_cfg(0);
+		/* Clks are enabled in probe.
+		   Disabling clocks now */
+		mdp_clk_ctrl(0);
 	}
 
 	pipe->src_height = fbi->var.yres;
@@ -670,6 +673,11 @@
 
 	dsi_video_enabled = 0;
 
+	if (vctrl->vsync_irq_enabled) {
+		vctrl->vsync_irq_enabled = 0;
+		vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+	}
+
 	if (pipe) {
 		/* sanity check, free pipes besides base layer */
 		mdp4_overlay_unset_mixer(pipe->mixer_num);
@@ -1028,6 +1036,7 @@
 		mdp4_dsi_video_pipe_queue(0, pipe);
 	}
 
+	mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time);
 	mdp4_overlay_mdp_perf_upd(mfd, 1);
 
 	mutex_lock(&mfd->dma->ov_mutex);
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index f01543b..ffb1416 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -594,6 +594,11 @@
 
 	mdp4_overlay_panel_mode_unset(MDP4_MIXER1, MDP4_PANEL_DTV);
 
+	if (vctrl->vsync_irq_enabled) {
+		vctrl->vsync_irq_enabled = 0;
+		vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+	}
+
 	ret = panel_next_off(pdev);
 	mdp_footswitch_ctrl(FALSE);
 	vctrl->fake_vsync = 1;
@@ -1011,6 +1016,7 @@
 		pipe->srcp0_addr = (uint32)mfd->ibuf.buf;
 		mdp4_dtv_pipe_queue(0, pipe);
 	}
+	mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time);
 
 	mutex_lock(&mfd->dma->ov_mutex);
 	mdp4_overlay_mdp_perf_upd(mfd, 1);
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index bc8ded5..f700da9 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -657,6 +657,11 @@
 
 	lcdc_enabled = 0;
 
+	if (vctrl->vsync_irq_enabled) {
+		vctrl->vsync_irq_enabled = 0;
+		vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+	}
+
 	if (pipe) {
 		/* sanity check, free pipes besides base layer */
 		mdp4_overlay_unset_mixer(pipe->mixer_num);
@@ -917,6 +922,7 @@
 
 		mdp4_lcdc_pipe_queue(0, pipe);
 	}
+	mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time);
 
 	mdp4_overlay_mdp_perf_upd(mfd, 1);
 
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index b35acfb..80ef22a 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -2309,7 +2309,7 @@
 		pr_info("%s:%d ion based allocation mfd->mem_hid 0x%x\n",
 			__func__, __LINE__, mfd->mem_hid);
 		buf->ihdl = ion_alloc(mfd->iclient, buffer_size, SZ_4K,
-			mfd->mem_hid);
+			mfd->mem_hid, 0);
 		if (!IS_ERR_OR_NULL(buf->ihdl)) {
 			if (mdp_iommu_split_domain) {
 				if (ion_map_iommu(mfd->iclient, buf->ihdl,
diff --git a/drivers/video/msm/mdp_dma.c b/drivers/video/msm/mdp_dma.c
index 4b76e72..826453b 100644
--- a/drivers/video/msm/mdp_dma.c
+++ b/drivers/video/msm/mdp_dma.c
@@ -482,10 +482,22 @@
 #endif
 {
 	unsigned long flag;
+	static int first_vsync;
+	int need_wait = 0;
 
 	down(&mfd->dma->mutex);
-	if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) {
+	if ((mfd) && (mfd->panel_power_on)) {
 		down(&mfd->sem);
+		spin_lock_irqsave(&mdp_spin_lock, flag);
+		if (mfd->dma->busy == TRUE)
+			need_wait++;
+		spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+		if (need_wait)
+			wait_for_completion_killable(&mfd->dma->comp);
+
+		/* schedule DMA to start */
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 		mfd->ibuf_flushed = TRUE;
 		mdp_dma2_update_lcd(mfd);
 
@@ -493,15 +505,31 @@
 		mdp_enable_irq(MDP_DMA2_TERM);
 		mfd->dma->busy = TRUE;
 		INIT_COMPLETION(mfd->dma->comp);
-
+		INIT_COMPLETION(vsync_cntrl.vsync_comp);
+		if (!vsync_cntrl.vsync_irq_enabled &&
+				vsync_cntrl.disabled_clocks) {
+			MDP_OUTP(MDP_BASE + 0x021c, 0x10); /* read pointer */
+			outp32(MDP_INTR_CLEAR, MDP_PRIM_RDPTR);
+			mdp_intr_mask |= MDP_PRIM_RDPTR;
+			outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+			mdp_enable_irq(MDP_VSYNC_TERM);
+			vsync_cntrl.vsync_dma_enabled = 1;
+		}
 		spin_unlock_irqrestore(&mdp_spin_lock, flag);
 		/* schedule DMA to start */
 		mdp_dma_schedule(mfd, MDP_DMA2_TERM);
 		up(&mfd->sem);
 
-		/* wait until DMA finishes the current job */
-		wait_for_completion_killable(&mfd->dma->comp);
-		mdp_disable_irq(MDP_DMA2_TERM);
+		/* wait until Vsync finishes the current job */
+		if (first_vsync) {
+			if (!wait_for_completion_killable_timeout
+					(&vsync_cntrl.vsync_comp, HZ/10))
+				pr_err("Timedout DMA %s %d", __func__,
+								__LINE__);
+		} else {
+			first_vsync = 1;
+		}
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
 	/* signal if pan function is waiting for the update completion */
 		if (mfd->pan_waiting) {
@@ -515,28 +543,31 @@
 void mdp_dma_vsync_ctrl(int enable)
 {
 	unsigned long flag;
+	int disabled_clocks;
 	if (vsync_cntrl.vsync_irq_enabled == enable)
 		return;
 
 	spin_lock_irqsave(&mdp_spin_lock, flag);
-	if (!enable)
-		INIT_COMPLETION(vsync_cntrl.vsync_wait);
 	vsync_cntrl.vsync_irq_enabled = enable;
+	disabled_clocks = vsync_cntrl.disabled_clocks;
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
-	if (enable) {
+	if (enable && disabled_clocks)
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+	spin_lock_irqsave(&mdp_spin_lock, flag);
+	if (enable && vsync_cntrl.disabled_clocks &&
+			!vsync_cntrl.vsync_dma_enabled) {
 		MDP_OUTP(MDP_BASE + 0x021c, 0x10); /* read pointer */
-		spin_lock_irqsave(&mdp_spin_lock, flag);
 		outp32(MDP_INTR_CLEAR, MDP_PRIM_RDPTR);
 		mdp_intr_mask |= MDP_PRIM_RDPTR;
 		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 		mdp_enable_irq(MDP_VSYNC_TERM);
-		spin_unlock_irqrestore(&mdp_spin_lock, flag);
-	} else {
-		wait_for_completion(&vsync_cntrl.vsync_wait);
-		mdp_disable_irq(MDP_VSYNC_TERM);
+		vsync_cntrl.disabled_clocks = 0;
+	} else if (enable && vsync_cntrl.disabled_clocks) {
+		vsync_cntrl.disabled_clocks = 0;
 	}
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 }
 
 void mdp_lcd_update_workqueue_handler(struct work_struct *work)
diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c
index a1f2b65..ed224c2 100644
--- a/drivers/video/msm/mdp_dma_dsi_video.c
+++ b/drivers/video/msm/mdp_dma_dsi_video.c
@@ -250,16 +250,18 @@
 void mdp_dma_video_vsync_ctrl(int enable)
 {
 	unsigned long flag;
+	int disabled_clocks;
 	if (vsync_cntrl.vsync_irq_enabled == enable)
 		return;
 
 	spin_lock_irqsave(&mdp_spin_lock, flag);
-	if (!enable)
-		INIT_COMPLETION(vsync_cntrl.vsync_wait);
 	vsync_cntrl.vsync_irq_enabled = enable;
+	if (!enable)
+		vsync_cntrl.disabled_clocks = 0;
+	disabled_clocks = vsync_cntrl.disabled_clocks;
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
-	if (enable) {
+	if (enable && disabled_clocks) {
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 		spin_lock_irqsave(&mdp_spin_lock, flag);
 		outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
@@ -267,9 +269,6 @@
 		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 		mdp_enable_irq(MDP_VSYNC_TERM);
 		spin_unlock_irqrestore(&mdp_spin_lock, flag);
-	} else {
-		wait_for_completion(&vsync_cntrl.vsync_wait);
-		mdp_disable_irq(MDP_VSYNC_TERM);
 	}
 }
 
diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c
index 10d60ab..6146b45 100644
--- a/drivers/video/msm/mdp_dma_lcdc.c
+++ b/drivers/video/msm/mdp_dma_lcdc.c
@@ -331,16 +331,18 @@
 void mdp_dma_lcdc_vsync_ctrl(int enable)
 {
 	unsigned long flag;
+	int disabled_clocks;
 	if (vsync_cntrl.vsync_irq_enabled == enable)
 		return;
 
 	spin_lock_irqsave(&mdp_spin_lock, flag);
-	if (!enable)
-		INIT_COMPLETION(vsync_cntrl.vsync_wait);
 	vsync_cntrl.vsync_irq_enabled = enable;
+	if (!enable)
+		vsync_cntrl.disabled_clocks = 0;
+	disabled_clocks = vsync_cntrl.disabled_clocks;
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
-	if (enable) {
+	if (enable && disabled_clocks) {
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 		spin_lock_irqsave(&mdp_spin_lock, flag);
 		outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
@@ -348,9 +350,6 @@
 		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 		mdp_enable_irq(MDP_VSYNC_TERM);
 		spin_unlock_irqrestore(&mdp_spin_lock, flag);
-	} else {
-		wait_for_completion(&vsync_cntrl.vsync_wait);
-		mdp_disable_irq(MDP_VSYNC_TERM);
 	}
 }
 
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 6f42565..3c60c2b 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -15,6 +15,7 @@
 #define MDSS_H
 
 #include <linux/msm_ion.h>
+#include <linux/earlysuspend.h>
 #include <linux/msm_mdp.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
@@ -23,8 +24,6 @@
 #define MDSS_REG_WRITE(addr, val) writel_relaxed(val, mdss_res->mdp_base + addr)
 #define MDSS_REG_READ(addr) readl_relaxed(mdss_res->mdp_base + addr)
 
-extern spinlock_t dsi_clk_lock;
-
 enum mdss_mdp_clk_type {
 	MDSS_CLK_AHB,
 	MDSS_CLK_AXI,
@@ -53,6 +52,7 @@
 	u32 irq_buzy;
 
 	u32 mdp_irq_mask;
+	u32 mdp_hist_irq_mask;
 
 	u32 suspend;
 	u32 timeout;
@@ -74,6 +74,8 @@
 	struct ion_client *iclient;
 	int iommu_domain;
 	int iommu_attached;
+
+	struct early_suspend early_suspend;
 };
 extern struct mdss_data_type *mdss_res;
 
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index e409a0b..a9f810f 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -199,11 +199,7 @@
 {
 	int ret = 0;
 
-	spin_lock_bh(&dsi_clk_lock);
 	mdss_dsi_clk_disable(pdata);
-
-	spin_unlock_bh(&dsi_clk_lock);
-
 	mdss_dsi_unprepare_clocks();
 
 	/* disable DSI controller */
@@ -250,11 +246,7 @@
 	mdss_dsi_phy_init(pdata);
 
 	mdss_dsi_prepare_clocks();
-
-	spin_lock_bh(&dsi_clk_lock);
-
 	mdss_dsi_clk_enable(pdata);
-	spin_unlock_bh(&dsi_clk_lock);
 
 	clk_rate = pdata->panel_info.clk_rate;
 	clk_rate = min(clk_rate, pdata->panel_info.clk_max);
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 5d0d578..3abf4d0 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -32,8 +32,6 @@
 static spinlock_t dsi_mdp_lock;
 static int dsi_mdp_busy;
 
-spinlock_t dsi_clk_lock;
-
 struct mdss_hw mdss_dsi_hw = {
 	.hw_ndx = MDSS_HW_DSI0,
 	.ptr = NULL,
@@ -45,7 +43,6 @@
 	init_completion(&dsi_dma_comp);
 	spin_lock_init(&dsi_irq_lock);
 	spin_lock_init(&dsi_mdp_lock);
-	spin_lock_init(&dsi_clk_lock);
 }
 
 void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 3bef9b3..7400a7b 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -316,6 +316,9 @@
 					mfd->op_enable);
 		if (ret)
 			pr_warn("can't turn on display!\n");
+
+		if (mfd->vsync_pending)
+			mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
 	}
 
 	return ret;
@@ -598,14 +601,14 @@
 		if (iclient) {
 			mfd->ihdl = ion_alloc(iclient, size, SZ_4K,
 					 ION_HEAP(ION_CP_MM_HEAP_ID) |
-					 ION_HEAP(ION_SF_HEAP_ID));
+					 ION_HEAP(ION_SF_HEAP_ID), 0);
 			if (IS_ERR_OR_NULL(mfd->ihdl)) {
 				pr_err("unable to alloc fbmem from ion (%p)\n",
 					mfd->ihdl);
 				return -ENOMEM;
 			}
 
-			virt = ion_map_kernel(iclient, mfd->ihdl, 0);
+			virt = ion_map_kernel(iclient, mfd->ihdl);
 			ion_phys(iclient, mfd->ihdl, &phys, &size);
 
 			if (is_mdss_iommu_attached()) {
@@ -1148,6 +1151,46 @@
 		ret = mdss_mdp_pa_config(&mdp_pp.data.pa_cfg_data,
 				&copyback);
 		break;
+
+	case mdp_op_pcc_cfg:
+		ret = mdss_mdp_pcc_config(&mdp_pp.data.pcc_cfg_data,
+			   &copyback);
+		break;
+
+	case mdp_op_lut_cfg:
+		switch (mdp_pp.data.lut_cfg_data.lut_type) {
+		case mdp_lut_igc:
+			ret = mdss_mdp_igc_lut_config(
+					(struct mdp_igc_lut_data *)
+					&mdp_pp.data.lut_cfg_data.data,
+					&copyback);
+			break;
+
+		case mdp_lut_pgc:
+			ret = mdss_mdp_argc_config(
+				&mdp_pp.data.lut_cfg_data.data.pgc_lut_data,
+				&copyback);
+			break;
+
+		case mdp_lut_hist:
+			ret = mdss_mdp_hist_lut_config(
+				(struct mdp_hist_lut_data *)
+				&mdp_pp.data.lut_cfg_data.data, &copyback);
+			break;
+
+		default:
+			ret = -ENOTSUPP;
+			break;
+		}
+		break;
+	case mdp_op_dither_cfg:
+		ret = mdss_mdp_dither_config(&mdp_pp.data.dither_cfg_data,
+				&copyback);
+		break;
+	case mdp_op_gamut_cfg:
+		ret = mdss_mdp_gamut_config(&mdp_pp.data.gamut_cfg_data,
+				&copyback);
+		break;
 	default:
 		pr_err("Unsupported request to MDP_PP IOCTL.\n");
 		ret = -EINVAL;
@@ -1163,6 +1206,9 @@
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 	void __user *argp = (void __user *)arg;
+	struct mdp_histogram_data hist;
+	struct mdp_histogram_start_req hist_req;
+	u32 block, hist_data_addr = 0;
 	struct mdp_page_protection fb_page_protection;
 	int ret = -ENOSYS;
 
@@ -1175,6 +1221,43 @@
 		ret = mdss_fb_set_lut(info, argp);
 		break;
 
+	case MSMFB_HISTOGRAM:
+		if (!mfd->panel_power_on)
+			return -EPERM;
+
+		ret = copy_from_user(&hist, argp, sizeof(hist));
+		if (ret)
+			return ret;
+
+		ret = mdss_mdp_hist_collect(info, &hist, &hist_data_addr);
+		if ((ret == 0) && hist_data_addr) {
+			ret = copy_to_user(hist.c0, (u32 *)hist_data_addr,
+				sizeof(u32) * hist.bin_cnt);
+			if (ret == 0)
+				ret = copy_to_user(argp, &hist,
+						   sizeof(hist));
+		}
+		break;
+
+	case MSMFB_HISTOGRAM_START:
+		if (!mfd->panel_power_on)
+			return -EPERM;
+
+		ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
+		if (ret)
+			return ret;
+
+		ret = mdss_mdp_histogram_start(&hist_req);
+		break;
+
+	case MSMFB_HISTOGRAM_STOP:
+		ret = copy_from_user(&block, argp, sizeof(int));
+		if (ret)
+			return ret;
+
+		ret = mdss_mdp_histogram_stop(block);
+		break;
+
 	case MSMFB_GET_PAGE_PROTECTION:
 		fb_page_protection.page_protection =
 			mfd->mdp_fb_page_protection;
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index a10e5e4..80ebc4f 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -56,6 +56,7 @@
 	int op_enable;
 	u32 fb_imgType;
 	u32 dst_format;
+	int vsync_pending;
 
 	int hw_refresh;
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 63df84c..4f641cc 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -128,6 +128,8 @@
 static DEFINE_SPINLOCK(mdss_lock);
 struct mdss_hw *mdss_irq_handlers[MDSS_MAX_HW_BLK];
 
+static int mdss_mdp_register_early_suspend(struct mdss_data_type *mdata);
+
 static inline int mdss_irq_dispatch(u32 hw_ndx, int irq, void *ptr)
 {
 	struct mdss_hw *hw;
@@ -216,8 +218,9 @@
 
 	spin_lock_irqsave(&mdss_lock, irq_flags);
 	if (!(mdss_res->irq_mask & ndx_bit)) {
-		pr_warn("MDSS HW ndx=%d is NOT set, mask=%x\n",
-			hw->hw_ndx, mdss_res->mdp_irq_mask);
+		pr_warn("MDSS HW ndx=%d is NOT set, mask=%x, hist mask=%x\n",
+			hw->hw_ndx, mdss_res->mdp_irq_mask,
+			mdss_res->mdp_hist_irq_mask);
 	} else {
 		mdss_irq_handlers[hw->hw_ndx] = NULL;
 		mdss_res->irq_mask &= ~ndx_bit;
@@ -244,8 +247,9 @@
 
 	spin_lock(&mdss_lock);
 	if (!(mdss_res->irq_mask & ndx_bit)) {
-		pr_warn("MDSS HW ndx=%d is NOT set, mask=%x\n",
-			hw->hw_ndx, mdss_res->mdp_irq_mask);
+		pr_warn("MDSS HW ndx=%d is NOT set, mask=%x, hist mask=%x\n",
+			hw->hw_ndx, mdss_res->mdp_irq_mask,
+			mdss_res->mdp_hist_irq_mask);
 	} else {
 		mdss_irq_handlers[hw->hw_ndx] = NULL;
 		mdss_res->irq_mask &= ~ndx_bit;
@@ -357,6 +361,29 @@
 
 	return ret;
 }
+int mdss_mdp_hist_irq_enable(u32 irq)
+{
+	unsigned long irq_flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&mdp_lock, irq_flags);
+	if (mdss_res->mdp_hist_irq_mask & irq) {
+		pr_warn("MDSS MDP Hist IRQ-0x%x is already set, mask=%x\n",
+				irq, mdss_res->mdp_hist_irq_mask);
+		ret = -EBUSY;
+	} else {
+		pr_debug("MDP IRQ mask old=%x new=%x\n",
+				mdss_res->mdp_hist_irq_mask, irq);
+		mdss_res->mdp_hist_irq_mask |= irq;
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_HIST_INTR_CLEAR, irq);
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_HIST_INTR_EN,
+				mdss_res->mdp_hist_irq_mask);
+		mdss_enable_irq(&mdss_mdp_hw);
+	}
+	spin_unlock_irqrestore(&mdp_lock, irq_flags);
+
+	return ret;
+}
 
 void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num)
 {
@@ -374,7 +401,27 @@
 
 		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
 				mdss_res->mdp_irq_mask);
-		if (mdss_res->mdp_irq_mask == 0)
+		if ((mdss_res->mdp_irq_mask == 0) &&
+			(mdss_res->mdp_hist_irq_mask == 0))
+			mdss_disable_irq(&mdss_mdp_hw);
+	}
+	spin_unlock_irqrestore(&mdp_lock, irq_flags);
+}
+
+void mdss_mdp_hist_irq_disable(u32 irq)
+{
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&mdp_lock, irq_flags);
+	if (!(mdss_res->mdp_hist_irq_mask & irq)) {
+		pr_warn("MDSS MDP IRQ-%x is NOT set, mask=%x\n",
+				irq, mdss_res->mdp_hist_irq_mask);
+	} else {
+		mdss_res->mdp_hist_irq_mask &= ~irq;
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_HIST_INTR_EN,
+				mdss_res->mdp_hist_irq_mask);
+		if ((mdss_res->mdp_irq_mask == 0) &&
+			(mdss_res->mdp_hist_irq_mask == 0))
 			mdss_disable_irq(&mdss_mdp_hw);
 	}
 	spin_unlock_irqrestore(&mdp_lock, irq_flags);
@@ -394,7 +441,8 @@
 		mdss_res->mdp_irq_mask &= ~irq;
 		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
 				mdss_res->mdp_irq_mask);
-		if (mdss_res->mdp_irq_mask == 0)
+		if ((mdss_res->mdp_irq_mask == 0) &&
+			(mdss_res->mdp_hist_irq_mask == 0))
 			mdss_disable_irq_nosync(&mdss_mdp_hw);
 	}
 	spin_unlock(&mdp_lock);
@@ -852,6 +900,16 @@
 		goto probe_done;
 	}
 	rc = mdss_mdp_bus_scale_register(mdata);
+	if (rc) {
+		pr_err("unable to register bus scaling\n");
+		goto probe_done;
+	}
+
+	rc = mdss_mdp_register_early_suspend(mdata);
+	if (rc) {
+		pr_err("unable to register early suspend\n");
+		goto probe_done;
+	}
 probe_done:
 	if (IS_ERR_VALUE(rc)) {
 		mdss_res = NULL;
@@ -861,88 +919,154 @@
 	return rc;
 }
 
-void mdss_mdp_footswitch_ctrl(int on)
+static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on)
 {
 	mutex_lock(&mdp_suspend_mutex);
-	if (!mdss_res->suspend || mdss_res->eintf_ena || !mdss_res->fs) {
+	if (!mdata->suspend || mdata->eintf_ena || !mdata->fs) {
 		mutex_unlock(&mdp_suspend_mutex);
 		return;
 	}
 
-	if (on && !mdss_res->fs_ena) {
+	if (on && !mdata->fs_ena) {
 		pr_debug("Enable MDP FS\n");
-		regulator_enable(mdss_res->fs);
+		regulator_enable(mdata->fs);
 		mdss_iommu_attach();
-		mdss_res->fs_ena = true;
-	} else if (!on && mdss_res->fs_ena) {
+		mdata->fs_ena = true;
+	} else if (!on && mdata->fs_ena) {
 		pr_debug("Disable MDP FS\n");
 		mdss_iommu_dettach();
-		regulator_disable(mdss_res->fs);
-		mdss_res->fs_ena = false;
+		regulator_disable(mdata->fs);
+		mdata->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_MASTER_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)
+static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata)
 {
 	int ret;
-	pr_debug("display suspend");
 
 	ret = mdss_fb_suspend_all();
 	if (IS_ERR_VALUE(ret)) {
 		pr_err("Unable to suspend all fb panels (%d)\n", ret);
 		return ret;
 	}
-	mdss_mdp_suspend_sub();
-	if (mdss_res->clk_ena) {
+
+	cancel_delayed_work(&mdata->clk_ctrl_worker);
+
+	flush_workqueue(mdata->clk_ctrl_wq);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_MASTER_OFF, false);
+
+	mutex_lock(&mdp_suspend_mutex);
+	mdata->suspend = true;
+	mutex_unlock(&mdp_suspend_mutex);
+
+	if (mdata->clk_ena) {
 		pr_err("MDP suspend failed\n");
 		return -EBUSY;
 	}
-	mdss_mdp_footswitch_ctrl(false);
+	mdss_mdp_footswitch_ctrl(mdata, false);
+
+	pr_debug("suspend done\n");
 
 	return 0;
 }
 
-static int mdss_mdp_resume(struct platform_device *pdev)
+static inline int mdss_mdp_resume_sub(struct mdss_data_type *mdata)
 {
-	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
 	int ret = 0;
 
-	if (!mdata)
-		return -ENODEV;
-
-	pr_debug("resume display");
-
-	mdss_mdp_footswitch_ctrl(true);
+	mdss_mdp_footswitch_ctrl(mdata, true);
 	mutex_lock(&mdp_suspend_mutex);
-	mdss_res->suspend = false;
+	mdata->suspend = false;
 	mutex_unlock(&mdp_suspend_mutex);
 	mdss_hw_init(mdata);
 	ret = mdss_fb_resume_all();
 	if (IS_ERR_VALUE(ret))
 		pr_err("Unable to resume all fb panels (%d)\n", ret);
 
+	pr_debug("resume done\n");
+
 	return ret;
 }
+
+#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
+static int mdss_mdp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+
+	if (!mdata)
+		return -ENODEV;
+
+	pr_debug("display suspend\n");
+
+	return mdss_mdp_suspend_sub(mdata);
+}
+
+static int mdss_mdp_resume(struct platform_device *pdev)
+{
+	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+
+	if (!mdata)
+		return -ENODEV;
+
+	pr_debug("display resume\n");
+
+	return mdss_mdp_resume_sub(mdata);
+}
 #else
 #define mdss_mdp_suspend NULL
 #define mdss_mdp_resume NULL
 #endif
 
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void mdss_mdp_early_suspend(struct early_suspend *h)
+{
+	struct mdss_data_type *mdata;
+	mdata = container_of(h, struct mdss_data_type, early_suspend);
+
+	pr_debug("display early suspend\n");
+
+	mdss_mdp_suspend_sub(mdata);
+}
+
+static void mdss_mdp_late_resume(struct early_suspend *h)
+{
+	struct mdss_data_type *mdata;
+	mdata = container_of(h, struct mdss_data_type, early_suspend);
+
+	pr_debug("display early resume\n");
+
+	mdss_mdp_resume_sub(mdata);
+}
+
+static int mdss_mdp_register_early_suspend(struct mdss_data_type *mdata)
+{
+	mdata->early_suspend.suspend = mdss_mdp_early_suspend;
+	mdata->early_suspend.resume = mdss_mdp_late_resume;
+	mdata->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
+	register_early_suspend(&mdata->early_suspend);
+
+	return 0;
+}
+
+static int mdss_mdp_remove_early_suspend(struct mdss_data_type *mdata)
+{
+	unregister_early_suspend(&mdata->early_suspend);
+
+	return 0;
+}
+#else
+static int mdss_mdp_register_early_suspend(struct mdss_data_type *mdata)
+{
+	return 0;
+}
+static int mdss_mdp_remove_early_suspend(struct mdss_data_type *mdata)
+{
+	return 0;
+}
+#endif
+
 static int mdss_mdp_remove(struct platform_device *pdev)
 {
 	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
@@ -951,6 +1075,7 @@
 	pm_runtime_disable(&pdev->dev);
 	mdss_mdp_pp_term(&pdev->dev);
 	mdss_mdp_bus_scale_unregister(mdata);
+	mdss_mdp_remove_early_suspend(mdata);
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 610c132..2493570 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -242,6 +242,7 @@
 
 	struct mdss_mdp_data buffers[2];
 	struct list_head list;
+	struct mdp_overlay_pp_params pp_cfg;
 };
 
 struct mdss_mdp_writeback_arg {
@@ -250,6 +251,7 @@
 	void *priv_data;
 };
 
+#define is_vig_pipe(_pipe_id_) ((_pipe_id_) <= MDSS_MDP_SSPP_VIG2)
 static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
 				      u32 reg, u32 val)
 {
@@ -266,6 +268,8 @@
 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);
+int mdss_mdp_hist_irq_enable(u32 irq);
+void mdss_mdp_hist_irq_disable(u32 irq);
 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);
@@ -275,10 +279,10 @@
 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_overlay_release_all(struct msm_fb_data_type *mfd);
+int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en);
 int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl);
 
@@ -295,7 +299,24 @@
 int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
 
 int mdss_mdp_csc_setup(u32 block, u32 blk_idx, u32 tbl_idx, u32 csc_type);
+int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
+				   struct mdp_csc_cfg *data);
+
 int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback);
+
+int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback);
+int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback);
+int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback);
+int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback);
+int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback);
+
+int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req);
+int mdss_mdp_histogram_stop(u32 block);
+int mdss_mdp_hist_collect(struct fb_info *info,
+		   struct mdp_histogram_data *hist, u32 *hist_data_addr);
+void mdss_mdp_hist_intr_done(u32 isr);
+
 
 struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum);
 struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type);
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 0139afd..651d595 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -74,6 +74,11 @@
 	MDSS_MDP_IRQ_INTF_VSYNC = 25,
 };
 
+#define MDSS_MDP_REG_IGC_VIG_BASE			0x300
+#define MDSS_MDP_REG_IGC_RGB_BASE			0x310
+#define MDSS_MDP_REG_IGC_DMA_BASE			0x320
+#define MDSS_MDP_REG_IGC_DSPP_BASE			0x400
+
 enum mdss_mdp_ctl_index {
 	MDSS_MDP_CTL0,
 	MDSS_MDP_CTL1,
@@ -189,6 +194,9 @@
 #define MDSS_MDP_REG_VIG_CSC_0_BASE			0x280
 #define MDSS_MDP_REG_VIG_CSC_1_BASE			0x320
 
+#define MDSS_MDP_REG_VIG_HIST_CTL_BASE			0x2C4
+#define MDSS_MDP_REG_VIG_HIST_LUT_BASE			0x2F0
+
 #define MDSS_MDP_SCALE_FILTER_NEAREST		0x0
 #define MDSS_MDP_SCALE_FILTER_BIL		0x1
 #define MDSS_MDP_SCALE_FILTER_PCMN		0x2
@@ -260,6 +268,8 @@
 #define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH0	0x108
 #define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH1	0x10C
 
+#define MDSS_MDP_REG_LM_GC_LUT_BASE	0x110
+
 #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)
@@ -323,7 +333,12 @@
 
 #define MDSS_MDP_REG_DSPP_OFFSET(pipe)	(0x4600 + ((pipe) * 0x400))
 #define MDSS_MDP_REG_DSPP_OP_MODE			0x000
+#define MDSS_MDP_REG_DSPP_PCC_BASE			0x030
+#define MDSS_MDP_REG_DSPP_DITHER_DEPTH			0x150
+#define MDSS_MDP_REG_DSPP_HIST_CTL_BASE			0x210
+#define MDSS_MDP_REG_DSPP_HIST_LUT_BASE			0x230
 #define MDSS_MDP_REG_DSPP_PA_BASE			0x238
+#define MDSS_MDP_REG_DSPP_GAMUT_BASE			0x2DC
 
 enum mdss_mpd_intf_index {
 	MDSS_MDP_NO_INTF,
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index fed7d21..3c7c362 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -183,7 +183,7 @@
 	if (mutex_lock_interruptible(&ctx->vsync_lock))
 		return -EINTR;
 
-	if (!ctx->timegen_en) {
+	if (vsync_handler && !ctx->timegen_en) {
 		ctx->vsync_time = ktime_get();
 		schedule_work(&ctx->vsync_work);
 	}
@@ -213,6 +213,9 @@
 		return -ENODEV;
 	}
 
+	if (ctx->vsync_handler)
+		mdss_mdp_video_set_vsync_handler(ctl, NULL);
+
 	if (ctx->timegen_en) {
 		off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
 		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index e8e8163..91f94ea 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -316,7 +316,17 @@
 
 	pipe->req_data = *req;
 
+	if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) {
+		if (pipe->num <= MDSS_MDP_SSPP_VIG2)
+			memcpy(&pipe->pp_cfg, &req->overlay_pp_cfg,
+					sizeof(struct mdp_overlay_pp_params));
+		else
+			pr_debug("%s: RGB Pipes don't support CSC/QSEED\n",
+								__func__);
+	}
+
 	pipe->params_changed++;
+	pipe->play_cnt = 0;
 
 	req->id = pipe->ndx;
 
@@ -765,7 +775,7 @@
 	pr_debug("sent vsync on ctl=%d ts=%llu\n", ctl->num, ktime_to_ns(t));
 }
 
-static int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
+int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
 {
 	struct mdss_mdp_ctl *ctl = mfd->ctl;
 	int rc;
@@ -777,6 +787,11 @@
 
 	pr_debug("vsync en=%d\n", en);
 
+	if (!ctl->power_on) {
+		mfd->vsync_pending = en;
+		return 0;
+	}
+
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	if (en)
 		rc = ctl->set_vsync_handler(ctl, mdss_mdp_overlay_handle_vsync);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index c936b7d..c90ce8c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -560,16 +560,32 @@
 
 	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 */
-
-	/* only need to program once */
-	if (pipe->play_cnt == 0) {
-		mdss_mdp_csc_setup(MDSS_MDP_BLOCK_SSPP, pipe->num, 1,
-				   MDSS_MDP_CSC_YUV2RGB);
+	/* CSC Post Processing enabled? */
+	if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) {
+		if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_CSC_CFG) {
+			if (pipe->pp_cfg.csc_cfg.flags & MDP_CSC_FLAG_ENABLE)
+				opmode |= 1 << 17;	/* CSC_1_EN */
+			if (pipe->pp_cfg.csc_cfg.flags & MDP_CSC_FLAG_YUV_IN)
+				opmode |= 1 << 18;	/* SRC_DATA=YCBCR */
+			if (pipe->pp_cfg.csc_cfg.flags & MDP_CSC_FLAG_YUV_OUT)
+				opmode |= 1 << 19;	/* DST_DATA=YCBCR */
+			/* only need to program once */
+			if (pipe->play_cnt == 0)
+				mdss_mdp_csc_setup_data(MDSS_MDP_BLOCK_SSPP,
+				  pipe->num, 1, &pipe->pp_cfg.csc_cfg);
+		}
+	} else {
+		if (pipe->src_fmt->is_yuv)
+			opmode |= (0 << 19) |	/* DST_DATA=RGB */
+				  (1 << 18) |	/* SRC_DATA=YCBCR */
+				  (1 << 17);	/* CSC_1_EN */
+		/* only need to program once */
+		if (pipe->play_cnt == 0) {
+			mdss_mdp_csc_setup(MDSS_MDP_BLOCK_SSPP, pipe->num, 1,
+					   MDSS_MDP_CSC_YUV2RGB);
+		}
 	}
+
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_OP_MODE, opmode);
 
 	return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 7ab3b01..6e04124 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -15,6 +15,9 @@
 
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
 
 struct mdp_csc_cfg mdp_csc_convert[MDSS_MDP_MAX_CSC] = {
 	[MDSS_MDP_CSC_RGB2RGB] = {
@@ -74,26 +77,118 @@
 
 #define MDSS_BLOCK_DISP_NUM	(MDP_BLOCK_MAX - MDP_LOGICAL_BLOCK_DISP_0)
 
+#define IGC_LUT_ENTRIES	256
+#define GC_LUT_SEGMENTS	16
+#define ENHIST_LUT_ENTRIES 256
+#define HIST_V_SIZE	256
+
+#define HIST_WAIT_TIMEOUT	1000
+/* hist collect state */
+enum {
+	HIST_UNKNOWN,
+	HIST_IDLE,
+	HIST_RESET,
+	HIST_START,
+	HIST_READY,
+};
+
+struct pp_hist_col_info {
+	u32 col_state;
+	u32 col_en;
+	u32 read_request;
+	u32 hist_cnt_read;
+	u32 hist_cnt_sent;
+	u32 frame_cnt;
+	struct completion comp;
+	u32 data[HIST_V_SIZE];
+};
+
+static u32 dither_matrix[16] = {
+	15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10};
+static u32 dither_depth_map[9] = {
+	0, 0, 0, 0, 0, 1, 2, 3, 3};
+
+#define GAMUT_T0_SIZE	125
+#define GAMUT_T1_SIZE	100
+#define GAMUT_T2_SIZE	80
+#define GAMUT_T3_SIZE	100
+#define GAMUT_T4_SIZE	100
+#define GAMUT_T5_SIZE	80
+#define GAMUT_T6_SIZE	64
+#define GAMUT_T7_SIZE	80
+#define GAMUT_TOTAL_TABLE_SIZE (GAMUT_T0_SIZE + GAMUT_T1_SIZE + \
+	GAMUT_T2_SIZE + GAMUT_T3_SIZE + GAMUT_T4_SIZE + \
+	GAMUT_T5_SIZE + GAMUT_T6_SIZE + GAMUT_T7_SIZE)
+
 struct pp_sts_type {
 	u32 pa_sts;
+	u32 pcc_sts;
+	u32 igc_sts;
+	u32 igc_tbl_idx;
+	u32 argc_sts;
+	u32 enhist_sts;
+	u32 dither_sts;
+	u32 gamut_sts;
 };
 
 #define PP_FLAGS_DIRTY_PA	0x1
+#define PP_FLAGS_DIRTY_PCC	0x2
+#define PP_FLAGS_DIRTY_IGC	0x4
+#define PP_FLAGS_DIRTY_ARGC	0x8
+#define PP_FLAGS_DIRTY_ENHIST	0x10
+#define PP_FLAGS_DIRTY_DITHER	0x20
+#define PP_FLAGS_DIRTY_GAMUT	0x40
+#define PP_FLAGS_DIRTY_HIST_COL	0x80
 
 #define PP_STS_ENABLE	0x1
+#define PP_STS_GAMUT_FIRST	0x2
 
 struct mdss_pp_res_type {
 	/* logical info */
 	u32 pp_disp_flags[MDSS_BLOCK_DISP_NUM];
+	u32 igc_lut_c0c1[MDSS_BLOCK_DISP_NUM][IGC_LUT_ENTRIES];
+	u32 igc_lut_c2[MDSS_BLOCK_DISP_NUM][IGC_LUT_ENTRIES];
+	struct mdp_ar_gc_lut_data
+		gc_lut_r[MDSS_BLOCK_DISP_NUM][GC_LUT_SEGMENTS];
+	struct mdp_ar_gc_lut_data
+		gc_lut_g[MDSS_BLOCK_DISP_NUM][GC_LUT_SEGMENTS];
+	struct mdp_ar_gc_lut_data
+		gc_lut_b[MDSS_BLOCK_DISP_NUM][GC_LUT_SEGMENTS];
+	u32 enhist_lut[MDSS_BLOCK_DISP_NUM][ENHIST_LUT_ENTRIES];
 	struct mdp_pa_cfg_data pa_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	struct mdp_pcc_cfg_data pcc_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	struct mdp_igc_lut_data igc_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	struct mdp_pgc_lut_data pgc_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	struct mdp_hist_lut_data enhist_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	struct mdp_dither_cfg_data dither_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	struct mdp_gamut_cfg_data gamut_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	uint16_t gamut_tbl[MDSS_BLOCK_DISP_NUM][GAMUT_TOTAL_TABLE_SIZE];
+	struct pp_hist_col_info
+		*hist_col[MDSS_BLOCK_DISP_NUM][MDSS_MDP_MAX_DSPP];
+	u32 hist_data[MDSS_BLOCK_DISP_NUM][HIST_V_SIZE];
 	/* physical info */
 	struct pp_sts_type pp_dspp_sts[MDSS_MDP_MAX_DSPP];
+	struct pp_hist_col_info dspp_hist[MDSS_MDP_MAX_DSPP];
 };
 
 static DEFINE_MUTEX(mdss_pp_mutex);
+static DEFINE_SPINLOCK(mdss_hist_lock);
+static DEFINE_MUTEX(mdss_mdp_hist_mutex);
 static struct mdss_pp_res_type *mdss_pp_res;
 
-static int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
+
+static void pp_hist_read(u32 v_base, struct pp_hist_col_info *hist_info);
+
+static void pp_update_pcc_regs(u32 offset,
+				struct mdp_pcc_cfg_data *cfg_ptr);
+static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
+				u32 offset, u32 blk_idx);
+static void pp_update_gc_one_lut(u32 offset,
+		struct mdp_ar_gc_lut_data *lut_data);
+static void pp_update_argc_lut(u32 offset,
+		struct mdp_pgc_lut_data *config);
+
+int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
 				   struct mdp_csc_cfg *data)
 {
 	int i, ret = 0;
@@ -181,19 +276,123 @@
 	data = &mdp_csc_convert[csc_type];
 	return mdss_mdp_csc_setup_data(block, blk_idx, tbl_idx, data);
 }
-
-static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
+static int pp_mixer_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
 		struct mdss_mdp_mixer *mixer)
 {
-	u32 flags, base, offset, dspp_num, opmode = 0;
-	struct mdp_pa_cfg_data *pa_config;
+	u32 flags, offset, dspp_num, opmode = 0;
+	struct mdp_pgc_lut_data *pgc_config;
 	struct pp_sts_type *pp_sts;
-
 	dspp_num = mixer->num;
 	/* no corresponding dspp */
 	if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
 		(dspp_num >= MDSS_MDP_MAX_DSPP))
 		return 0;
+	if (disp_num < MDSS_BLOCK_DISP_NUM)
+		flags = mdss_pp_res->pp_disp_flags[disp_num];
+	else
+		flags = 0;
+
+	pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
+	/* GC_LUT is in layer mixer */
+	if (flags & PP_FLAGS_DIRTY_ARGC) {
+		pgc_config = &mdss_pp_res->pgc_disp_cfg[disp_num];
+		if (pgc_config->flags & MDP_PP_OPS_WRITE) {
+			offset = MDSS_MDP_REG_LM_OFFSET(disp_num) +
+				MDSS_MDP_REG_LM_GC_LUT_BASE;
+			pp_update_argc_lut(offset, pgc_config);
+		}
+		if (pgc_config->flags & MDP_PP_OPS_DISABLE)
+			pp_sts->argc_sts &= ~PP_STS_ENABLE;
+		else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
+			pp_sts->argc_sts |= PP_STS_ENABLE;
+		ctl->flush_bits |= BIT(6) << dspp_num; /* LAYER_MIXER */
+	}
+	/* update LM opmode if LM needs flush */
+	if ((pp_sts->argc_sts & PP_STS_ENABLE) &&
+		(ctl->flush_bits & (BIT(6) << dspp_num))) {
+		offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) +
+			MDSS_MDP_REG_LM_OP_MODE;
+		opmode = MDSS_MDP_REG_READ(offset);
+		opmode |= (1 << 0); /* GC_LUT_EN */
+		MDSS_MDP_REG_WRITE(offset, opmode);
+	}
+	return 0;
+}
+static void pp_gamut_config(struct mdp_gamut_cfg_data *gamut_cfg,
+							u32 base,
+							u32 *gamut_sts)
+{
+	u32 offset;
+	int i, j;
+	if (gamut_cfg->flags & MDP_PP_OPS_WRITE) {
+		offset = base + MDSS_MDP_REG_DSPP_GAMUT_BASE;
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
+				MDSS_MDP_REG_WRITE(offset,
+					(u32)gamut_cfg->r_tbl[i][j]);
+			offset += 4;
+		}
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
+				MDSS_MDP_REG_WRITE(offset,
+					(u32)gamut_cfg->g_tbl[i][j]);
+			offset += 4;
+		}
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
+				MDSS_MDP_REG_WRITE(offset,
+					(u32)gamut_cfg->b_tbl[i][j]);
+			offset += 4;
+		}
+		if (gamut_cfg->gamut_first)
+			*gamut_sts |= PP_STS_GAMUT_FIRST;
+	}
+
+	if (gamut_cfg->flags & MDP_PP_OPS_DISABLE)
+		*gamut_sts &= ~PP_STS_ENABLE;
+	else if (gamut_cfg->flags & MDP_PP_OPS_ENABLE)
+		*gamut_sts |= PP_STS_ENABLE;
+}
+static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
+		struct mdss_mdp_mixer *mixer)
+{
+	u32 flags, base, offset, dspp_num, opmode = 0;
+	struct mdp_pa_cfg_data *pa_config;
+	struct mdp_pcc_cfg_data *pcc_config;
+	struct mdp_igc_lut_data *igc_config;
+	struct mdp_hist_lut_data *enhist_cfg;
+	struct mdp_dither_cfg_data *dither_cfg;
+	struct pp_hist_col_info *hist_info;
+	struct pp_sts_type *pp_sts;
+	u32 data, tbl_idx, col_state;
+	int i;
+	dspp_num = mixer->num;
+	/* no corresponding dspp */
+	if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
+		(dspp_num >= MDSS_MDP_MAX_DSPP))
+		return 0;
+	base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num);
+	hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+	if (hist_info->col_en) {
+		/* HIST_EN & AUTO_CLEAR */
+		opmode |= (1 << 16) | (1 << 17);
+		mutex_lock(&mdss_mdp_hist_mutex);
+		if (hist_info->col_state == HIST_READY)
+			pp_hist_read(base + MDSS_MDP_REG_DSPP_HIST_CTL_BASE +
+				0x1C, hist_info);
+		spin_lock(&mdss_hist_lock);
+		col_state = hist_info->col_state;
+		if ((col_state == HIST_IDLE) ||
+			(col_state == HIST_READY) ||
+			(col_state == HIST_START)) {
+			/* Kick off collection */
+			MDSS_MDP_REG_WRITE(base +
+				MDSS_MDP_REG_DSPP_HIST_CTL_BASE, 1);
+			hist_info->col_state = HIST_START;
+		}
+		spin_unlock(&mdss_hist_lock);
+		mutex_unlock(&mdss_mdp_hist_mutex);
+	}
 
 	if (disp_num < MDSS_BLOCK_DISP_NUM)
 		flags = mdss_pp_res->pp_disp_flags[disp_num];
@@ -201,10 +400,9 @@
 		flags = 0;
 
 	/* nothing to update */
-	if (!flags)
+	if ((!flags) && (!(hist_info->col_en)))
 		return 0;
 	pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
-	base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num);
 	if (flags & PP_FLAGS_DIRTY_PA) {
 		pa_config = &mdss_pp_res->pa_disp_cfg[disp_num];
 		if (pa_config->flags & MDP_PP_OPS_WRITE) {
@@ -224,10 +422,108 @@
 	}
 	if (pp_sts->pa_sts & PP_STS_ENABLE)
 		opmode |= (1 << 20); /* PA_EN */
+	if (flags & PP_FLAGS_DIRTY_PCC) {
+		pcc_config = &mdss_pp_res->pcc_disp_cfg[disp_num];
+		if (pcc_config->ops & MDP_PP_OPS_WRITE) {
+			offset = base + MDSS_MDP_REG_DSPP_PCC_BASE;
+			pp_update_pcc_regs(offset, pcc_config);
+		}
+		if (pcc_config->ops & MDP_PP_OPS_DISABLE)
+			pp_sts->pcc_sts &= ~PP_STS_ENABLE;
+		else if (pcc_config->ops & MDP_PP_OPS_ENABLE)
+			pp_sts->pcc_sts |= PP_STS_ENABLE;
+	}
+	if (pp_sts->pcc_sts & PP_STS_ENABLE)
+		opmode |= (1 << 4); /* PCC_EN */
+
+	if (flags & PP_FLAGS_DIRTY_IGC) {
+		igc_config = &mdss_pp_res->igc_disp_cfg[disp_num];
+		if (igc_config->ops & MDP_PP_OPS_WRITE) {
+			offset = MDSS_MDP_REG_IGC_DSPP_BASE;
+			pp_update_igc_lut(igc_config, offset, dspp_num);
+		}
+		if (igc_config->ops & MDP_PP_IGC_FLAG_ROM0) {
+			pp_sts->pcc_sts |= PP_STS_ENABLE;
+			tbl_idx = 1;
+		} else if (igc_config->ops & MDP_PP_IGC_FLAG_ROM1) {
+			pp_sts->pcc_sts |= PP_STS_ENABLE;
+			tbl_idx = 2;
+		} else {
+			tbl_idx = 0;
+		}
+		pp_sts->igc_tbl_idx = tbl_idx;
+		if (igc_config->ops & MDP_PP_OPS_DISABLE)
+			pp_sts->igc_sts &= ~PP_STS_ENABLE;
+		else if (igc_config->ops & MDP_PP_OPS_ENABLE)
+			pp_sts->igc_sts |= PP_STS_ENABLE;
+	}
+	if (pp_sts->igc_sts & PP_STS_ENABLE) {
+		opmode |= (1 << 0) | /* IGC_LUT_EN */
+			      (pp_sts->igc_tbl_idx << 1);
+	}
+	if (flags & PP_FLAGS_DIRTY_ENHIST) {
+		enhist_cfg = &mdss_pp_res->enhist_disp_cfg[disp_num];
+		if (enhist_cfg->ops & MDP_PP_OPS_WRITE) {
+			offset = base + MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
+			for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
+				MDSS_MDP_REG_WRITE(offset, enhist_cfg->data[i]);
+			/* swap */
+			MDSS_MDP_REG_WRITE(offset + 4, 1);
+		}
+		if (enhist_cfg->ops & MDP_PP_OPS_DISABLE)
+			pp_sts->enhist_sts &= ~PP_STS_ENABLE;
+		else if (enhist_cfg->ops & MDP_PP_OPS_ENABLE)
+			pp_sts->enhist_sts |= PP_STS_ENABLE;
+	}
+	if (pp_sts->enhist_sts & PP_STS_ENABLE) {
+		opmode |= (1 << 19) | /* HIST_LUT_EN */
+				  (1 << 20); /* PA_EN */
+		if (!(pp_sts->pa_sts & PP_STS_ENABLE)) {
+			/* Program default value */
+			offset = base + MDSS_MDP_REG_DSPP_PA_BASE;
+			MDSS_MDP_REG_WRITE(offset, 0);
+			MDSS_MDP_REG_WRITE(offset + 4, 0);
+			MDSS_MDP_REG_WRITE(offset + 8, 0);
+			MDSS_MDP_REG_WRITE(offset + 12, 0);
+		}
+	}
+	if (flags & PP_FLAGS_DIRTY_DITHER) {
+		dither_cfg = &mdss_pp_res->dither_disp_cfg[disp_num];
+		if (dither_cfg->flags & MDP_PP_OPS_WRITE) {
+			offset = base + MDSS_MDP_REG_DSPP_DITHER_DEPTH;
+			MDSS_MDP_REG_WRITE(offset,
+			  dither_depth_map[dither_cfg->g_y_depth] |
+			  (dither_depth_map[dither_cfg->b_cb_depth] << 2) |
+			  (dither_depth_map[dither_cfg->r_cr_depth] << 4));
+			offset += 0x14;
+			for (i = 0; i << 16; i += 4) {
+				data = dither_matrix[i] |
+					(dither_matrix[i + 1] << 4) |
+					(dither_matrix[i + 2] << 8) |
+					(dither_matrix[i + 3] << 12);
+				MDSS_MDP_REG_WRITE(offset, data);
+				offset += 4;
+			}
+		}
+		if (dither_cfg->flags & MDP_PP_OPS_DISABLE)
+			pp_sts->dither_sts &= ~PP_STS_ENABLE;
+		else if (dither_cfg->flags & MDP_PP_OPS_ENABLE)
+			pp_sts->dither_sts |= PP_STS_ENABLE;
+	}
+	if (pp_sts->dither_sts & PP_STS_ENABLE)
+		opmode |= (1 << 8); /* DITHER_EN */
+	if (flags & PP_FLAGS_DIRTY_GAMUT)
+		pp_gamut_config(&mdss_pp_res->gamut_disp_cfg[disp_num],
+					base, &pp_sts->gamut_sts);
+	if (pp_sts->gamut_sts & PP_STS_ENABLE) {
+		opmode |= (1 << 23); /* GAMUT_EN */
+		if (pp_sts->gamut_sts & PP_STS_GAMUT_FIRST)
+			opmode |= (1 << 24); /* GAMUT_ORDER */
+	}
+
 	MDSS_MDP_REG_WRITE(base + MDSS_MDP_REG_DSPP_OP_MODE, opmode);
 	ctl->flush_bits |= BIT(13 + dspp_num); /* DSPP */
 	return 0;
-
 }
 int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl)
 {
@@ -239,10 +535,14 @@
 	disp_num = ctl->mfd->index;
 
 	mutex_lock(&mdss_pp_mutex);
-	if (ctl->mixer_left)
+	if (ctl->mixer_left) {
+		pp_mixer_setup(disp_num, ctl, ctl->mixer_left);
 		pp_dspp_setup(disp_num, ctl, ctl->mixer_left);
-	if (ctl->mixer_right)
+	}
+	if (ctl->mixer_right) {
+		pp_mixer_setup(disp_num, ctl, ctl->mixer_right);
 		pp_dspp_setup(disp_num, ctl, ctl->mixer_right);
+	}
 	/* clear dirty flag */
 	if (disp_num < MDSS_BLOCK_DISP_NUM)
 		mdss_pp_res->pp_disp_flags[disp_num] = 0;
@@ -275,12 +575,31 @@
 		mutex_unlock(&mdss_pp_mutex);
 	}
 }
+static int pp_get_dspp_num(u32 disp_num, u32 *dspp_num)
+{
+	int i;
+	u32 mixer_cnt;
+	u32 mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+
+	if (!mixer_cnt)
+		return -EPERM;
+
+	/* only read the first mixer */
+	for (i = 0; i < mixer_cnt; i++) {
+		if (mixer_id[i] < MDSS_MDP_MAX_DSPP)
+			break;
+	}
+	if (i >= mixer_cnt)
+		return -EPERM;
+	*dspp_num = mixer_id[i];
+	return 0;
+}
 
 int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config, u32 *copyback)
 {
-	int i, ret = 0;
-	u32 pa_offset, disp_num, mixer_cnt;
-	u32 mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+	int ret = 0;
+	u32 pa_offset, disp_num, dspp_num = 0;
 
 	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(config->block >= MDP_BLOCK_MAX))
@@ -290,24 +609,15 @@
 	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
 
 	if (config->flags & MDP_PP_OPS_READ) {
-		mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
-		if (!mixer_cnt) {
-			ret = -EPERM;
-			goto pa_config_exit;
-		}
-		/* only read the first mixer */
-		for (i = 0; i < mixer_cnt; i++) {
-			if (mixer_id[i] < MDSS_MDP_MAX_DSPP)
-				break;
-		}
-		if (i >= mixer_cnt) {
-			ret = -EPERM;
+		ret = pp_get_dspp_num(disp_num, &dspp_num);
+		if (ret) {
+			pr_err("%s, no dspp connects to disp %d",
+				__func__, disp_num);
 			goto pa_config_exit;
 		}
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-		pa_offset = MDSS_MDP_REG_DSPP_OFFSET(mixer_id[i]) +
+		pa_offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
 			  MDSS_MDP_REG_DSPP_PA_BASE;
-
 		config->hue_adj = MDSS_MDP_REG_READ(pa_offset);
 		pa_offset += 4;
 		config->sat_adj = MDSS_MDP_REG_READ(pa_offset);
@@ -326,3 +636,910 @@
 	mutex_unlock(&mdss_pp_mutex);
 	return ret;
 }
+
+static void pp_read_pcc_regs(u32 offset,
+				struct mdp_pcc_cfg_data *cfg_ptr)
+{
+	cfg_ptr->r.c = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.c = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.c = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.r = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.r = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.r = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.g = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.g = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.g = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.b = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.b = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.b = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.rr = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.rr = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.rr = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.rg = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.rg = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.rg = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.rb = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.rb = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.rb = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.gg = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.gg = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.gg = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.gb = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.gb = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.gb = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.bb = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.bb = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.bb = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.rgb_0 = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.rgb_0 = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.rgb_0 = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.rgb_1 = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.rgb_1 = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.rgb_1 = MDSS_MDP_REG_READ(offset + 8);
+}
+
+static void pp_update_pcc_regs(u32 offset,
+				struct mdp_pcc_cfg_data *cfg_ptr)
+{
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.c);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.c);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.c);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.r);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.r);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.r);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.g);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.g);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.g);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.b);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.b);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.b);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rr);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rr);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rr);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rg);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rg);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rg);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rb);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rb);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rb);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.gg);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.gg);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.gg);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.gb);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.gb);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.gb);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.bb);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.bb);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.bb);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rgb_0);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rgb_0);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rgb_0);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rgb_1);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rgb_1);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rgb_1);
+}
+
+int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *config, u32 *copyback)
+{
+	int ret = 0;
+	u32 base, disp_num, dspp_num = 0;
+
+	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(config->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+
+	mutex_lock(&mdss_pp_mutex);
+	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+	if (config->ops & MDP_PP_OPS_READ) {
+		ret = pp_get_dspp_num(disp_num, &dspp_num);
+		if (ret) {
+			pr_err("%s, no dspp connects to disp %d",
+				__func__, disp_num);
+			goto pcc_config_exit;
+		}
+
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+		base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+			  MDSS_MDP_REG_DSPP_PCC_BASE;
+		pp_read_pcc_regs(base, config);
+		*copyback = 1;
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	} else {
+		mdss_pp_res->pcc_disp_cfg[disp_num] = *config;
+		mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_PCC;
+	}
+
+pcc_config_exit:
+	mutex_unlock(&mdss_pp_mutex);
+	return ret;
+
+}
+
+static void pp_read_igc_lut(struct mdp_igc_lut_data *cfg,
+				u32 offset, u32 blk_idx)
+{
+	int i;
+	u32 data;
+
+	/* INDEX_UPDATE & VALUE_UPDATEN */
+	data = (3 << 24) | (((~(1 << blk_idx)) & 0x7) << 28);
+	MDSS_MDP_REG_WRITE(offset, data);
+
+	for (i = 0; i < cfg->len; i++)
+		cfg->c0_c1_data[i] = MDSS_MDP_REG_READ(offset) & 0xFFF;
+
+	offset += 0x4;
+	MDSS_MDP_REG_WRITE(offset, data);
+	for (i = 0; i < cfg->len; i++)
+		cfg->c0_c1_data[i] |= (MDSS_MDP_REG_READ(offset) & 0xFFF) << 16;
+
+	offset += 0x4;
+	MDSS_MDP_REG_WRITE(offset, data);
+	for (i = 0; i < cfg->len; i++)
+		cfg->c2_data[i] = MDSS_MDP_REG_READ(offset) & 0xFFF;
+}
+
+static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
+				u32 offset, u32 blk_idx)
+{
+	int i;
+	u32 data;
+	/* INDEX_UPDATE */
+	data = (1 << 25) | (((~(1 << blk_idx)) & 0x7) << 28);
+	MDSS_MDP_REG_WRITE(offset, (cfg->c0_c1_data[0] & 0xFFF) | data);
+
+	/* disable index update */
+	data &= ~(1 << 25);
+	for (i = 1; i < cfg->len; i++)
+		MDSS_MDP_REG_WRITE(offset, (cfg->c0_c1_data[i] & 0xFFF) | data);
+
+	offset += 0x4;
+	data |= (1 << 25);
+	MDSS_MDP_REG_WRITE(offset, ((cfg->c0_c1_data[0] >> 16) & 0xFFF) | data);
+	data &= ~(1 << 25);
+	for (i = 1; i < cfg->len; i++)
+		MDSS_MDP_REG_WRITE(offset,
+		((cfg->c0_c1_data[i] >> 16) & 0xFFF) | data);
+
+	offset += 0x4;
+	data |= (1 << 25);
+	MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[0] & 0xFFF) | data);
+	data &= ~(1 << 25);
+	for (i = 1; i < cfg->len; i++)
+		MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[i] & 0xFFF) | data);
+}
+
+int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback)
+{
+	int ret = 0;
+	u32 tbl_idx, igc_offset, disp_num, dspp_num = 0;
+	struct mdp_igc_lut_data local_cfg;
+
+	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(config->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+
+	mutex_lock(&mdss_pp_mutex);
+	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+	if (config->ops & MDP_PP_OPS_READ) {
+		ret = pp_get_dspp_num(disp_num, &dspp_num);
+		if (ret) {
+			pr_err("%s, no dspp connects to disp %d",
+				__func__, disp_num);
+			goto igc_config_exit;
+		}
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		if (config->ops & MDP_PP_IGC_FLAG_ROM0)
+			tbl_idx = 1;
+		else if (config->ops & MDP_PP_IGC_FLAG_ROM1)
+			tbl_idx = 2;
+		else
+			tbl_idx = 0;
+		igc_offset = MDSS_MDP_REG_IGC_DSPP_BASE + (0x10 * tbl_idx);
+		local_cfg = *config;
+		local_cfg.c0_c1_data =
+			&mdss_pp_res->igc_lut_c0c1[disp_num][0];
+		local_cfg.c2_data =
+			&mdss_pp_res->igc_lut_c2[disp_num][0];
+		pp_read_igc_lut(&local_cfg, igc_offset, dspp_num);
+		if (copy_to_user(config->c0_c1_data, local_cfg.c2_data,
+			config->len * sizeof(u32))) {
+			ret = -EFAULT;
+			goto igc_config_exit;
+		}
+		if (copy_to_user(config->c2_data, local_cfg.c0_c1_data,
+			config->len * sizeof(u32))) {
+			ret = -EFAULT;
+			goto igc_config_exit;
+		}
+		*copyback = 1;
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	} else {
+		if (copy_from_user(&mdss_pp_res->igc_lut_c0c1[disp_num][0],
+			config->c0_c1_data, config->len * sizeof(u32))) {
+			ret = -EFAULT;
+			goto igc_config_exit;
+		}
+		if (copy_from_user(&mdss_pp_res->igc_lut_c2[disp_num][0],
+			config->c2_data, config->len * sizeof(u32))) {
+			ret = -EFAULT;
+			goto igc_config_exit;
+		}
+		mdss_pp_res->igc_disp_cfg[disp_num] = *config;
+		mdss_pp_res->igc_disp_cfg[disp_num].c0_c1_data =
+			&mdss_pp_res->igc_lut_c0c1[disp_num][0];
+		mdss_pp_res->igc_disp_cfg[disp_num].c2_data =
+			&mdss_pp_res->igc_lut_c2[disp_num][0];
+		mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_IGC;
+	}
+
+igc_config_exit:
+	mutex_unlock(&mdss_pp_mutex);
+	return ret;
+}
+static void pp_update_gc_one_lut(u32 offset,
+		struct mdp_ar_gc_lut_data *lut_data)
+{
+	int i, start_idx;
+
+	start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
+	for (i = start_idx; i < GC_LUT_SEGMENTS; i++)
+		MDSS_MDP_REG_WRITE(offset, lut_data[i].x_start);
+	for (i = 0; i < start_idx; i++)
+		MDSS_MDP_REG_WRITE(offset, lut_data[i].x_start);
+	offset += 4;
+	start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
+	for (i = start_idx; i < GC_LUT_SEGMENTS; i++)
+		MDSS_MDP_REG_WRITE(offset, lut_data[i].slope);
+	for (i = 0; i < start_idx; i++)
+		MDSS_MDP_REG_WRITE(offset, lut_data[i].slope);
+	offset += 4;
+	start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
+	for (i = start_idx; i < GC_LUT_SEGMENTS; i++)
+		MDSS_MDP_REG_WRITE(offset, lut_data[i].offset);
+	for (i = 0; i < start_idx; i++)
+		MDSS_MDP_REG_WRITE(offset, lut_data[i].offset);
+}
+static void pp_update_argc_lut(u32 offset, struct mdp_pgc_lut_data *config)
+{
+	pp_update_gc_one_lut(offset, config->r_data);
+	offset += 0x10;
+	pp_update_gc_one_lut(offset, config->g_data);
+	offset += 0x10;
+	pp_update_gc_one_lut(offset, config->b_data);
+}
+static void pp_read_gc_one_lut(u32 offset,
+		struct mdp_ar_gc_lut_data *gc_data)
+{
+	int i, start_idx, data;
+	data = MDSS_MDP_REG_READ(offset);
+	start_idx = (data >> 16) & 0xF;
+	gc_data[start_idx].x_start = data & 0xFFF;
+
+	for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
+		data = MDSS_MDP_REG_READ(offset);
+		gc_data[i].x_start = data & 0xFFF;
+	}
+	for (i = 0; i < start_idx; i++) {
+		data = MDSS_MDP_REG_READ(offset);
+		gc_data[i].x_start = data & 0xFFF;
+	}
+
+	offset += 4;
+	data = MDSS_MDP_REG_READ(offset);
+	start_idx = (data >> 16) & 0xF;
+	gc_data[start_idx].slope = data & 0x7FFF;
+	for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
+		data = MDSS_MDP_REG_READ(offset);
+		gc_data[i].slope = data & 0x7FFF;
+	}
+	for (i = 0; i < start_idx; i++) {
+		data = MDSS_MDP_REG_READ(offset);
+		gc_data[i].slope = data & 0x7FFF;
+	}
+	offset += 4;
+	data = MDSS_MDP_REG_READ(offset);
+	start_idx = (data >> 16) & 0xF;
+	gc_data[start_idx].offset = data & 0x7FFF;
+	for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
+		data = MDSS_MDP_REG_READ(offset);
+		gc_data[i].offset = data & 0x7FFF;
+	}
+	for (i = 0; i < start_idx; i++) {
+		data = MDSS_MDP_REG_READ(offset);
+		gc_data[i].offset = data & 0x7FFF;
+	}
+}
+
+static int pp_read_argc_lut(struct mdp_pgc_lut_data *config, u32 offset)
+{
+	int ret = 0;
+	pp_read_gc_one_lut(offset, config->r_data);
+	offset += 0x10;
+	pp_read_gc_one_lut(offset, config->g_data);
+	offset += 0x10;
+	pp_read_gc_one_lut(offset, config->b_data);
+	return ret;
+}
+int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback)
+{
+	int ret = 0;
+	u32 argc_offset, disp_num, dspp_num = 0;
+	struct mdp_pgc_lut_data local_cfg;
+	u32 tbl_size;
+
+	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(config->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+
+	mutex_lock(&mdss_pp_mutex);
+	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+	tbl_size = GC_LUT_SEGMENTS * sizeof(struct mdp_ar_gc_lut_data);
+	if (config->flags & MDP_PP_OPS_READ) {
+		ret = pp_get_dspp_num(disp_num, &dspp_num);
+		if (ret) {
+			pr_err("%s, no dspp connects to disp %d",
+				__func__, disp_num);
+			goto argc_config_exit;
+		}
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+		argc_offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) +
+				MDSS_MDP_REG_LM_GC_LUT_BASE;
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		local_cfg = *config;
+		local_cfg.r_data =
+			&mdss_pp_res->gc_lut_r[disp_num][0];
+		local_cfg.g_data =
+			&mdss_pp_res->gc_lut_g[disp_num][0];
+		local_cfg.b_data =
+			&mdss_pp_res->gc_lut_b[disp_num][0];
+		pp_read_argc_lut(&local_cfg, argc_offset);
+		if (copy_to_user(config->r_data,
+			&mdss_pp_res->gc_lut_r[disp_num][0], tbl_size)) {
+			ret = -EFAULT;
+			goto argc_config_exit;
+		}
+		if (copy_to_user(config->g_data,
+			&mdss_pp_res->gc_lut_g[disp_num][0], tbl_size)) {
+			ret = -EFAULT;
+			goto argc_config_exit;
+		}
+		if (copy_to_user(config->b_data,
+			&mdss_pp_res->gc_lut_b[disp_num][0], tbl_size)) {
+			ret = -EFAULT;
+			goto argc_config_exit;
+		}
+		*copyback = 1;
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	} else {
+		if (copy_from_user(&mdss_pp_res->gc_lut_r[disp_num][0],
+			config->r_data, tbl_size)) {
+			ret = -EFAULT;
+			goto argc_config_exit;
+		}
+		if (copy_from_user(&mdss_pp_res->gc_lut_g[disp_num][0],
+			config->g_data, tbl_size)) {
+			ret = -EFAULT;
+			goto argc_config_exit;
+		}
+		if (copy_from_user(&mdss_pp_res->gc_lut_b[disp_num][0],
+			config->b_data, tbl_size)) {
+			ret = -EFAULT;
+			goto argc_config_exit;
+		}
+		mdss_pp_res->pgc_disp_cfg[disp_num] = *config;
+		mdss_pp_res->pgc_disp_cfg[disp_num].r_data =
+			&mdss_pp_res->gc_lut_r[disp_num][0];
+		mdss_pp_res->pgc_disp_cfg[disp_num].g_data =
+			&mdss_pp_res->gc_lut_g[disp_num][0];
+		mdss_pp_res->pgc_disp_cfg[disp_num].b_data =
+			&mdss_pp_res->gc_lut_b[disp_num][0];
+		mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_ARGC;
+	}
+argc_config_exit:
+	mutex_unlock(&mdss_pp_mutex);
+	return ret;
+}
+int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback)
+{
+	int i, ret = 0;
+	u32 hist_offset, disp_num, dspp_num = 0;
+
+	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(config->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+
+	mutex_lock(&mdss_pp_mutex);
+	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+	if (config->ops & MDP_PP_OPS_READ) {
+		ret = pp_get_dspp_num(disp_num, &dspp_num);
+		if (ret) {
+			pr_err("%s, no dspp connects to disp %d",
+				__func__, disp_num);
+			goto enhist_config_exit;
+		}
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+		hist_offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+			  MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
+		for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
+			mdss_pp_res->enhist_lut[disp_num][i] =
+				MDSS_MDP_REG_READ(hist_offset);
+		if (copy_to_user(config->data,
+			&mdss_pp_res->enhist_lut[disp_num][0],
+			ENHIST_LUT_ENTRIES * sizeof(u32))) {
+			ret = -EFAULT;
+			goto enhist_config_exit;
+		}
+		*copyback = 1;
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	} else {
+		if (copy_from_user(&mdss_pp_res->enhist_lut[disp_num][0],
+			config->data, ENHIST_LUT_ENTRIES * sizeof(u32))) {
+			ret = -EFAULT;
+			goto enhist_config_exit;
+		}
+		mdss_pp_res->enhist_disp_cfg[disp_num] = *config;
+		mdss_pp_res->enhist_disp_cfg[disp_num].data =
+			&mdss_pp_res->enhist_lut[disp_num][0];
+		mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_ENHIST;
+	}
+enhist_config_exit:
+	mutex_unlock(&mdss_pp_mutex);
+	return ret;
+}
+
+int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback)
+{
+	u32 disp_num;
+	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(config->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+	if (config->flags & MDP_PP_OPS_READ)
+		return -ENOTSUPP;
+
+	mutex_lock(&mdss_pp_mutex);
+	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+	mdss_pp_res->dither_disp_cfg[disp_num] = *config;
+	mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_DITHER;
+	mutex_unlock(&mdss_pp_mutex);
+	return 0;
+}
+
+int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback)
+{
+	int i, j, size_total = 0, ret = 0;
+	u32 offset, disp_num, dspp_num = 0;
+	uint16_t *tbl_off;
+	struct mdp_gamut_cfg_data local_cfg;
+
+	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(config->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+	for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++)
+		size_total += config->tbl_size[i];
+	if (size_total != GAMUT_TOTAL_TABLE_SIZE)
+		return -EINVAL;
+
+	mutex_lock(&mdss_pp_mutex);
+	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+	if (config->flags & MDP_PP_OPS_READ) {
+		ret = pp_get_dspp_num(disp_num, &dspp_num);
+		if (ret) {
+			pr_err("%s, no dspp connects to disp %d",
+				__func__, disp_num);
+			goto gamut_config_exit;
+		}
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+		offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+			  MDSS_MDP_REG_DSPP_GAMUT_BASE;
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			for (j = 0; j < config->tbl_size[i]; j++)
+				config->r_tbl[i][j] =
+					(u16)MDSS_MDP_REG_READ(offset);
+			offset += 4;
+		}
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			for (j = 0; j < config->tbl_size[i]; j++)
+				config->g_tbl[i][j] =
+					(u16)MDSS_MDP_REG_READ(offset);
+			offset += 4;
+		}
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			for (j = 0; j < config->tbl_size[i]; j++)
+				config->b_tbl[i][j] =
+					(u16)MDSS_MDP_REG_READ(offset);
+			offset += 4;
+		}
+		*copyback = 1;
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	} else {
+		local_cfg = *config;
+		tbl_off = mdss_pp_res->gamut_tbl[disp_num];
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			local_cfg.r_tbl[i] = tbl_off;
+			if (copy_from_user(tbl_off, config->r_tbl[i],
+				config->tbl_size[i] * sizeof(uint16_t))) {
+				ret = -EFAULT;
+				goto gamut_config_exit;
+			}
+			tbl_off += local_cfg.tbl_size[i];
+		}
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			local_cfg.g_tbl[i] = tbl_off;
+			if (copy_from_user(tbl_off, config->g_tbl[i],
+				config->tbl_size[i] * sizeof(uint16_t))) {
+				ret = -EFAULT;
+				goto gamut_config_exit;
+			}
+			tbl_off += local_cfg.tbl_size[i];
+		}
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			local_cfg.b_tbl[i] = tbl_off;
+			if (copy_from_user(tbl_off, config->b_tbl[i],
+				config->tbl_size[i] * sizeof(uint16_t))) {
+				ret = -EFAULT;
+				goto gamut_config_exit;
+			}
+			tbl_off += local_cfg.tbl_size[i];
+		}
+		mdss_pp_res->gamut_disp_cfg[disp_num] = local_cfg;
+		mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_GAMUT;
+	}
+gamut_config_exit:
+	mutex_unlock(&mdss_pp_mutex);
+	return ret;
+}
+static void pp_hist_read(u32 v_base, struct pp_hist_col_info *hist_info)
+{
+	int i, i_start;
+	u32 data;
+	data = MDSS_MDP_REG_READ(v_base);
+	i_start = data >> 24;
+	hist_info->data[i_start] = data & 0xFFFFFF;
+	for (i = i_start + 1; i < HIST_V_SIZE; i++)
+		hist_info->data[i] = MDSS_MDP_REG_READ(v_base) & 0xFFFFFF;
+	for (i = 0; i < i_start - 1; i++)
+		hist_info->data[i] = MDSS_MDP_REG_READ(v_base) & 0xFFFFFF;
+	hist_info->hist_cnt_read++;
+}
+
+int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req)
+{
+	u32 ctl_base, done_shift_bit;
+	struct pp_hist_col_info *hist_info;
+	int i, ret = 0;
+	u32 disp_num, dspp_num = 0;
+	u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+
+	if ((req->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(req->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+
+	mutex_lock(&mdss_mdp_hist_mutex);
+	disp_num = req->block - MDP_LOGICAL_BLOCK_DISP_0;
+	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+
+	if (!mixer_cnt) {
+		pr_err("%s, no dspp connects to disp %d",
+			__func__, disp_num);
+		ret = -EPERM;
+		goto hist_start_exit;
+	}
+	if (mixer_cnt >= MDSS_MDP_MAX_DSPP) {
+		pr_err("%s, Too many dspp connects to disp %d",
+			__func__, mixer_cnt);
+		ret = -EPERM;
+		goto hist_start_exit;
+	}
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	for (i = 0; i < mixer_cnt; i++) {
+		dspp_num = mixer_id[i];
+		hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+		done_shift_bit = (dspp_num * 4) + 12;
+		/* check if it is idle */
+		if (hist_info->col_en) {
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+			pr_info("%s Hist collection has already been enabled %d",
+				__func__, dspp_num);
+			goto hist_start_exit;
+		}
+		spin_lock(&mdss_hist_lock);
+		hist_info->frame_cnt = req->frame_cnt;
+		init_completion(&hist_info->comp);
+		hist_info->hist_cnt_read = 0;
+		hist_info->hist_cnt_sent = 0;
+		hist_info->read_request = false;
+		hist_info->col_state = HIST_RESET;
+		hist_info->col_en = true;
+		spin_unlock(&mdss_hist_lock);
+		mdss_pp_res->hist_col[disp_num][i] =
+			&mdss_pp_res->dspp_hist[dspp_num];
+		mdss_mdp_hist_irq_enable(3 << done_shift_bit);
+		ctl_base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+			  MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
+		MDSS_MDP_REG_WRITE(ctl_base + 8, req->frame_cnt);
+		/* Kick out reset start */
+		MDSS_MDP_REG_WRITE(ctl_base + 4, 1);
+	}
+	for (i = mixer_cnt; i < MDSS_MDP_MAX_DSPP; i++)
+		mdss_pp_res->hist_col[disp_num][i] = 0;
+	mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_HIST_COL;
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+hist_start_exit:
+	mutex_unlock(&mdss_mdp_hist_mutex);
+	return ret;
+}
+
+int mdss_mdp_histogram_stop(u32 block)
+{
+	int i, ret = 0;
+	u32 dspp_num, disp_num, ctl_base, done_bit;
+	struct pp_hist_col_info *hist_info;
+	u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+
+	if ((block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+
+	mutex_lock(&mdss_mdp_hist_mutex);
+	disp_num = block - MDP_LOGICAL_BLOCK_DISP_0;
+	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+
+	if (!mixer_cnt) {
+		pr_err("%s, no dspp connects to disp %d",
+			__func__, disp_num);
+		ret = -EPERM;
+		goto hist_stop_exit;
+	}
+	if (mixer_cnt >= MDSS_MDP_MAX_DSPP) {
+		pr_err("%s, Too many dspp connects to disp %d",
+			__func__, mixer_cnt);
+		ret = -EPERM;
+		goto hist_stop_exit;
+	}
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	for (i = 0; i < mixer_cnt; i++) {
+		dspp_num = mixer_id[i];
+		hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+		done_bit = 3 << ((dspp_num * 4) + 12);
+		ctl_base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+			  MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
+		if (hist_info->col_en == false) {
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+			goto hist_stop_exit;
+		}
+		complete_all(&hist_info->comp);
+		spin_lock(&mdss_hist_lock);
+		hist_info->col_en = false;
+		hist_info->col_state = HIST_UNKNOWN;
+		spin_unlock(&mdss_hist_lock);
+		mdss_mdp_hist_irq_disable(done_bit);
+		MDSS_MDP_REG_WRITE(ctl_base, (1 << 1));/* cancel */
+	}
+	for (i = 0; i < MDSS_MDP_MAX_DSPP; i++)
+		mdss_pp_res->hist_col[disp_num][i] = 0;
+	mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_HIST_COL;
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+hist_stop_exit:
+	mutex_unlock(&mdss_mdp_hist_mutex);
+	return ret;
+}
+
+int mdss_mdp_hist_collect(struct fb_info *info,
+		  struct mdp_histogram_data *hist, u32 *hist_data_addr)
+{
+	int i, j, wait_ret, ret = 0;
+	u32 timeout, v_base;
+	struct pp_hist_col_info *hist_info;
+	u32 dspp_num, disp_num, ctl_base;
+	u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+
+	if ((hist->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(hist->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+
+	mutex_lock(&mdss_mdp_hist_mutex);
+	disp_num = hist->block - MDP_LOGICAL_BLOCK_DISP_0;
+	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+
+	if (!mixer_cnt) {
+		pr_err("%s, no dspp connects to disp %d",
+			__func__, disp_num);
+		ret = -EPERM;
+		goto hist_collect_exit;
+	}
+	if (mixer_cnt >= MDSS_MDP_MAX_DSPP) {
+		pr_err("%s, Too many dspp connects to disp %d",
+			__func__, mixer_cnt);
+		ret = -EPERM;
+		goto hist_collect_exit;
+	}
+	hist_info = &mdss_pp_res->dspp_hist[0];
+	for (i = 0; i < mixer_cnt; i++) {
+		dspp_num = mixer_id[i];
+		hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+		ctl_base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+			  MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
+		if ((hist_info->col_en == 0) ||
+			(hist_info->col_state == HIST_UNKNOWN)) {
+			ret = -EINVAL;
+			goto hist_collect_exit;
+		}
+		spin_lock(&mdss_hist_lock);
+		if ((hist_info->col_state == HIST_READY) ||
+			(hist_info->hist_cnt_read == 0)) {
+			/* wait for hist done if cache has no data */
+			if ((hist_info->col_state != HIST_READY) &&
+				(hist_info->hist_cnt_read == 0)) {
+				hist_info->read_request = true;
+				spin_unlock(&mdss_hist_lock);
+				timeout = HIST_WAIT_TIMEOUT *
+					hist_info->frame_cnt;
+				mutex_unlock(&mdss_mdp_hist_mutex);
+				wait_ret = wait_for_completion_killable_timeout(
+					&(hist_info->comp), timeout);
+
+				mutex_lock(&mdss_mdp_hist_mutex);
+				hist_info->read_request = false;
+				if (wait_ret == 0) {
+					ret = -ETIMEDOUT;
+					pr_debug("%s: bin collection timedout",
+						__func__);
+					goto hist_collect_exit;
+				} else if (wait_ret < 0) {
+					ret = -EINTR;
+					pr_debug("%s: bin collection interrupted",
+						__func__);
+					goto hist_collect_exit;
+				}
+				if (hist_info->col_state != HIST_READY) {
+					ret = -EBUSY;
+					pr_err("%s: collection state is not ready: %d",
+						__func__, hist_info->col_state);
+					goto hist_collect_exit;
+				}
+			} else {
+				spin_unlock(&mdss_hist_lock);
+			}
+			if (hist_info->col_state == HIST_READY) {
+				v_base = ctl_base + 0x1C;
+				mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+				pp_hist_read(v_base, hist_info);
+				mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+				spin_lock(&mdss_hist_lock);
+				hist_info->col_state = HIST_IDLE;
+				spin_unlock(&mdss_hist_lock);
+			}
+		} else {
+			spin_unlock(&mdss_hist_lock);
+		}
+		hist_info->hist_cnt_sent = hist_info->hist_cnt_read;
+	}
+	if (mixer_cnt > 1) {
+		memset(&mdss_pp_res->hist_data[disp_num][0],
+			0, HIST_V_SIZE * sizeof(u32));
+		for (i = 0; i < mixer_cnt; i++) {
+			dspp_num = mixer_id[i];
+			hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+			for (j = 0; j < HIST_V_SIZE; j++)
+				mdss_pp_res->hist_data[disp_num][i] +=
+					hist_info->data[i];
+		}
+		*hist_data_addr = (u32)&mdss_pp_res->hist_data[disp_num][0];
+	} else {
+		*hist_data_addr = (u32)hist_info->data;
+	}
+
+hist_collect_exit:
+	mutex_unlock(&mdss_mdp_hist_mutex);
+	return ret;
+}
+void mdss_mdp_hist_intr_done(u32 isr)
+{
+	u32 isr_blk, blk_idx;
+	struct pp_hist_col_info *hist_info;
+	isr &= 0x333333;
+	while (isr != 0) {
+		if (isr & 0xFFF000) {
+			if (isr & 0x3000) {
+				blk_idx = 0;
+				isr_blk = (isr >> 12) & 0x3;
+				isr &= ~0x3000;
+			} else if (isr & 0x30000) {
+				blk_idx = 1;
+				isr_blk = (isr >> 16) & 0x3;
+				isr &= ~0x30000;
+			} else {
+				blk_idx = 2;
+				isr_blk = (isr >> 20) & 0x3;
+				isr &= ~0x300000;
+			}
+			hist_info = &mdss_pp_res->dspp_hist[blk_idx];
+		} else {
+			if (isr & 0x3) {
+				blk_idx = 0;
+				isr_blk = isr & 0x3;
+				isr &= ~0x3;
+			} else if (isr & 0x30) {
+				blk_idx = 1;
+				isr_blk = (isr >> 4) & 0x3;
+				isr &= ~0x30;
+			} else {
+				blk_idx = 2;
+				isr_blk = (isr >> 8) & 0x3;
+				isr &= ~0x300;
+			}
+			/* SSPP block, not support yet*/
+			continue;
+		}
+		/* Histogram Done Interrupt */
+		if ((isr_blk & 0x1) &&
+			(hist_info->col_en)) {
+			spin_lock(&mdss_hist_lock);
+			hist_info->col_state = HIST_READY;
+			spin_unlock(&mdss_hist_lock);
+			if (hist_info->read_request)
+				complete(&hist_info->comp);
+		}
+		/* Histogram Reset Done Interrupt */
+		if ((isr_blk & 0x2) &&
+			(hist_info->col_en)) {
+				spin_lock(&mdss_hist_lock);
+				hist_info->col_state = HIST_IDLE;
+				spin_unlock(&mdss_hist_lock);
+		}
+	};
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 57e8441..aa65018 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -112,22 +112,22 @@
 
 irqreturn_t mdss_mdp_isr(int irq, void *ptr)
 {
-	u32 isr, mask;
+	u32 isr, mask, hist_isr, hist_mask;
 
 
 	isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_STATUS);
 
-	pr_debug("isr=%x\n", isr);
-
 	if (isr == 0)
-		goto done;
+		goto mdp_isr_done;
+
+	pr_debug("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;
+		goto mdp_isr_done;
 
 	if (isr & MDSS_MDP_INTR_PING_PONG_0_DONE)
 		mdss_mdp_intr_done(MDP_INTR_PING_PONG_0);
@@ -159,7 +159,17 @@
 	if (isr & MDSS_MDP_INTR_WB_2_DONE)
 		mdss_mdp_intr_done(MDP_INTR_WB_2);
 
-done:
+mdp_isr_done:
+	hist_isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_HIST_INTR_STATUS);
+	if (hist_isr == 0)
+		goto hist_isr_done;
+	hist_mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_HIST_INTR_EN);
+	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_HIST_INTR_CLEAR, hist_isr);
+	hist_isr &= hist_mask;
+	if (hist_isr == 0)
+		goto hist_isr_done;
+	mdss_mdp_hist_intr_done(hist_isr);
+hist_isr_done:
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index b0a67938..b18efbe 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -86,13 +86,13 @@
 
 
 		ihdl = ion_alloc(iclient, img_size, SZ_4K,
-				 ION_HEAP(ION_SF_HEAP_ID));
+				 ION_HEAP(ION_SF_HEAP_ID), 0);
 		if (IS_ERR_OR_NULL(ihdl)) {
 			pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
 			return NULL;
 		}
 
-		videomemory = ion_map_kernel(iclient, ihdl, 0);
+		videomemory = ion_map_kernel(iclient, ihdl);
 		ion_phys(iclient, ihdl, &mdss_wb_mem, &img_size);
 
 		if (is_mdss_iommu_attached()) {
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index 2b75193..60311dc 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -25,6 +25,7 @@
 #include <linux/uaccess.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
+#include <linux/iopoll.h>
 
 #include <asm/system.h>
 #include <asm/mach-types.h>
@@ -964,31 +965,30 @@
 
 	uint32 dsi_ctrl;
 	uint32 status;
-	int cnt;
+	u32 sleep_us = 1000;
+	u32 timeout_us = 16000;
 
-	cnt = 16;
-	while (cnt--) {
-		status = MIPI_INP(MIPI_DSI_BASE + 0x0004);
-		status &= 0x02;		/* CMD_MODE_DMA_BUSY */
-		if (status == 0)
-			break;
-		usleep(1000);
-	}
-	if (cnt == 0)
+	/* Check for CMD_MODE_DMA_BUSY */
+	if (readl_poll_timeout((MIPI_DSI_BASE + 0x0004),
+			   status,
+			   ((status & 0x02) == 0),
+			       sleep_us, timeout_us))
 		pr_info("%s: DSI status=%x failed\n", __func__, status);
 
-	cnt = 16;
-	while (cnt--) {
-		status = MIPI_INP(MIPI_DSI_BASE + 0x0008);
-		status &= 0x11111000;	/* x_HS_FIFO_EMPTY */
-		if (status == 0x11111000)	/* all empty */
-			break;
-		usleep(1000);
-	}
-
-	if (cnt == 0)
+	/* Check for x_HS_FIFO_EMPTY */
+	if (readl_poll_timeout((MIPI_DSI_BASE + 0x0008),
+			   status,
+			   ((status & 0x11111000) == 0x11111000),
+			       sleep_us, timeout_us))
 		pr_info("%s: FIFO status=%x failed\n", __func__, status);
 
+	/* Check for VIDEO_MODE_ENGINE_BUSY */
+	if (readl_poll_timeout((MIPI_DSI_BASE + 0x0004),
+			   status,
+			   ((status & 0x08) == 0),
+			       sleep_us, timeout_us))
+		pr_info("%s: DSI status=%x failed\n", __func__, status);
+
 	dsi_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0000);
 	if (enable)
 		dsi_ctrl |= 0x01;
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 2896349..7dc89ef 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -37,7 +37,6 @@
 #include <linux/fb.h>
 #include <linux/list.h>
 #include <linux/types.h>
-
 #include <linux/msm_mdp.h>
 #ifdef CONFIG_HAS_EARLYSUSPEND
 #include <linux/earlysuspend.h>
@@ -189,6 +188,7 @@
 	int cont_splash_done;
 	void *copy_splash_buf;
 	unsigned char *copy_splash_phys;
+	void *cpu_pm_hdl;
 };
 
 struct dentry *msm_fb_get_debugfs_root(void);
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index a2c3db1..7fc7a2f 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -168,7 +168,7 @@
 	__u32 frame_count;
 	__u32 is_3d_panel;
 	__u32 frame_rate;
-
+	__u32 frame_interval;
 
 	struct mddi_panel_info mddi;
 	struct lcd_panel_info lcd;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 400a3a7..2a850d8 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -292,6 +292,7 @@
 	u32  num_slices_comp;
 	struct vcd_property_slice_delivery_info slice_delivery_info;
 	struct ddl_batch_frame_data batch_frame;
+	u32 avc_delimiter_enable;
 };
 struct ddl_decoder_data {
 	struct ddl_codec_data_hdr  hdr;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index d4601f2..1782fd2 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -278,7 +278,8 @@
 				memset(frame[i].vcd_frm.virtual + luma_size,
 					 0x80808080,
 					frame[i].vcd_frm.alloc_len - luma_size);
-				if (frame[i].vcd_frm.ion_flag == CACHED) {
+				if (frame[i].vcd_frm.ion_flag
+					== ION_FLAG_CACHED) {
 					msm_ion_do_cache_op(
 					ddl_context->video_ion_client,
 					frame[i].vcd_frm.buff_ion_handle,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 931c1c8..d6558c3 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1047,6 +1047,20 @@
 	case VCD_REQ_PERF_LEVEL:
 		vcd_status = VCD_S_SUCCESS;
 		break;
+	case VCD_I_ENABLE_DELIMITER_FLAG:
+	{
+		struct vcd_property_avc_delimiter_enable *delimiter_enable =
+			(struct vcd_property_avc_delimiter_enable *)
+				property_value;
+		if (sizeof(struct vcd_property_avc_delimiter_enable) ==
+			property_hdr->sz &&
+			encoder->codec.codec == VCD_CODEC_H264) {
+			encoder->avc_delimiter_enable =
+			delimiter_enable->avc_delimiter_enable_flag;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
 	default:
 		DDL_MSG_ERROR("INVALID ID %d\n", (int)property_hdr->prop_id);
 		vcd_status = VCD_ERR_ILLEGAL_OP;
@@ -1530,6 +1544,15 @@
 			vcd_status = VCD_S_SUCCESS;
 		}
 		break;
+	case VCD_I_ENABLE_DELIMITER_FLAG:
+		if (sizeof(struct vcd_property_avc_delimiter_enable) ==
+			property_hdr->sz) {
+			((struct vcd_property_avc_delimiter_enable *)
+				property_value)->avc_delimiter_enable_flag =
+					encoder->avc_delimiter_enable;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
 	default:
 		vcd_status = VCD_ERR_ILLEGAL_OP;
 		break;
@@ -1691,6 +1714,7 @@
 	encoder->slice_delivery_info.enable = 0;
 	encoder->slice_delivery_info.num_slices = 0;
 	encoder->slice_delivery_info.num_slices_enc = 0;
+	encoder->avc_delimiter_enable = 0;
 }
 
 static void ddl_set_default_enc_profile(struct ddl_encoder_data *encoder)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index 8099234..40dc2aa 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -83,6 +83,8 @@
 #define VIDC_SM_ENC_EXT_CTRL_ADDR                    0x0028
 #define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_BMSK    0xffff0000
 #define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_SHFT    16
+#define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK    0x00000800
+#define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT    11
 #define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK  0x80
 #define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_SHFT  7
 #define VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_BMSK    0X100
@@ -446,10 +448,10 @@
 	*shared_mem, u32 hec_enable,
 	enum VIDC_SM_frame_skip frame_skip_mode,
 	u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable,
-	u32 sps_pps_control, u32 closed_gop_enable)
+	u32 sps_pps_control, u32 closed_gop_enable,
+	u32 au_delim_enable)
 {
 	u32 enc_ctrl;
-
 	enc_ctrl = VIDC_SETFIELD((hec_enable) ? 1 : 0,
 			VIDC_SM_ENC_EXT_CTRL_HEC_ENABLE_SHFT,
 			VIDC_SM_ENC_EXT_CTRL_HEC_ENABLE_BMSK) |
@@ -470,7 +472,11 @@
 			VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_BMSK) |
 			VIDC_SETFIELD(closed_gop_enable,
 			VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT,
-			VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK);
+			VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK) |
+			VIDC_SETFIELD((au_delim_enable) ? 1 : 0,
+			VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT,
+			VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK);
+
 	DDL_MEM_WRITE_32(shared_mem, VIDC_SM_ENC_EXT_CTRL_ADDR, enc_ctrl);
 }
 
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index 9cb1933..c4d577b 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -106,7 +106,7 @@
 	struct ddl_buf_addr *shared_mem, u32 hec_enable,
 	enum VIDC_SM_frame_skip  frame_skip_mode, u32 seq_hdr_in_band,
 	u32 vbv_buffer_size, u32 cpcfc_enable, u32 sps_pps_control,
-	u32 closed_gop_enable);
+	u32 closed_gop_enable, u32 au_delim_enable);
 void vidc_sm_set_encoder_param_change(struct ddl_buf_addr *shared_mem,
 	u32 bit_rate_chg, u32 frame_rate_chg, u32 i_period_chg);
 void vidc_sm_set_encoder_vop_time(struct ddl_buf_addr *shared_mem,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
index 5897a33..31f60e5 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
@@ -45,7 +45,6 @@
 	unsigned long iova = 0;
 	unsigned long buffer_size = 0;
 	unsigned long *kernel_vaddr = NULL;
-	unsigned long ionflag = 0;
 	unsigned long flags = 0;
 	int ret = 0;
 	ion_phys_addr_t phyaddr = 0;
@@ -71,20 +70,15 @@
 		alloc_size = (alloc_size+4095) & ~4095;
 		addr->alloc_handle = ion_alloc(
 		ddl_context->video_ion_client, alloc_size, SZ_4K,
-			res_trk_get_mem_type());
+			res_trk_get_mem_type(), 0);
 		if (IS_ERR_OR_NULL(addr->alloc_handle)) {
 			DDL_MSG_ERROR("%s() :DDL ION alloc failed\n",
 						 __func__);
 			goto bail_out;
 		}
-		if (res_trk_check_for_sec_session() ||
-			addr->mem_type == DDL_FW_MEM)
-			ionflag = UNCACHED;
-		else
-			ionflag = CACHED;
 		kernel_vaddr = (unsigned long *) ion_map_kernel(
 					ddl_context->video_ion_client,
-					addr->alloc_handle, ionflag);
+					addr->alloc_handle);
 		if (IS_ERR_OR_NULL(kernel_vaddr)) {
 				DDL_MSG_ERROR("%s() :DDL ION map failed\n",
 							 __func__);
@@ -111,7 +105,7 @@
 					0,
 					&iova,
 					&buffer_size,
-					UNCACHED, 0);
+					0, 0);
 			if (ret || !iova) {
 				DDL_MSG_ERROR(
 				"%s():DDL ION ion map iommu failed, ret = %d iova = 0x%lx\n",
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 4687915..5eed305 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -596,7 +596,7 @@
 		[ddl->command_channel], hdr_ext_control,
 		r_cframe_skip, false, 0,
 		h263_cpfc_enable, encoder->sps_pps.sps_pps_for_idr_enable_flag,
-		encoder->closed_gop);
+		encoder->closed_gop, encoder->avc_delimiter_enable);
 	vidc_sm_set_encoder_init_rc_value(&ddl->shared_mem
 		[ddl->command_channel],
 		encoder->target_bit_rate.target_bitrate);
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index 3ac396c..f68802e 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -69,7 +69,7 @@
 	if (res_trk_get_enable_ion() && addr->alloc_handle) {
 		kernel_vaddr = (unsigned long *) ion_map_kernel(
 					ddl_context->video_ion_client,
-					addr->alloc_handle, UNCACHED);
+					addr->alloc_handle);
 		if (IS_ERR_OR_NULL(kernel_vaddr)) {
 			DDL_MSG_ERROR("%s():DDL ION client map failed\n",
 						 __func__);
@@ -84,7 +84,7 @@
 				0,
 				&iova,
 				&buffer_size,
-				UNCACHED, 0);
+				0, 0);
 		if (ret || !iova) {
 			DDL_MSG_ERROR(
 			"%s():DDL ION client iommu map failed, ret = %d iova = 0x%lx\n",
@@ -209,7 +209,7 @@
 			addr->alloc_handle = ion_alloc(
 					ddl_context->video_ion_client,
 					 alloc_size, SZ_4K,
-					res_trk_get_mem_type());
+					res_trk_get_mem_type(), 0);
 			if (IS_ERR_OR_NULL(addr->alloc_handle)) {
 				DDL_MSG_ERROR("%s() :DDL ION alloc failed\n",
 						__func__);
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
index 21f01d1..3b40640 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
@@ -124,7 +124,7 @@
 					ddl_context->video_ion_client,
 					alloc_size,
 					SZ_4K,
-					buff_addr->mem_type);
+					buff_addr->mem_type, 0);
 		if (!buff_addr->alloc_handle) {
 			ERR("\n%s(): DDL ION alloc failed\n",
 					__func__);
@@ -142,8 +142,7 @@
 		buff_addr->physical_base_addr = (u32 *)phyaddr;
 		kernel_vaddr = (unsigned long *) ion_map_kernel(
 					ddl_context->video_ion_client,
-					buff_addr->alloc_handle,
-					UNCACHED);
+					buff_addr->alloc_handle);
 		if (IS_ERR_OR_NULL(kernel_vaddr)) {
 			ERR("\n%s(): DDL ION map failed\n", __func__);
 			goto unmap_ion_buffer;
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index 68bcd5c..59e19b7 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -347,7 +347,7 @@
 		ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
 				pmem_fd, kernel_vaddr, buffer_index,
 				&buff_handle);
-		if (ion_flag == CACHED && buff_handle) {
+		if (ion_flag == ION_FLAG_CACHED && buff_handle) {
 			DBG("%s: Cache invalidate: vaddr (%p), "\
 				"size %u\n", __func__,
 				(void *)kernel_vaddr,
@@ -908,8 +908,7 @@
 		}
 		vcd_h264_mv_buffer->kernel_virtual_addr = (u8 *) ion_map_kernel(
 			client_ctx->user_ion_client,
-			client_ctx->h264_mv_ion_handle,
-			ionflag);
+			client_ctx->h264_mv_ion_handle);
 		if (!vcd_h264_mv_buffer->kernel_virtual_addr) {
 			ERR("%s(): get_ION_kernel virtual addr failed\n",
 				 __func__);
@@ -935,7 +934,7 @@
 					VIDEO_DOMAIN, VIDEO_MAIN_POOL,
 					SZ_4K, 0, (unsigned long *)&iova,
 					(unsigned long *)&buffer_size,
-					UNCACHED, 0);
+					0, 0);
 			if (rc || !iova) {
 				ERR(
 				"%s():get_ION_kernel physical addr fail, rc = %d iova = 0x%lx\n",
@@ -1298,7 +1297,7 @@
 						kernel_vaddr,
 						buffer_index,
 						&buff_handle);
-			if (ion_flag == CACHED && buff_handle) {
+			if (ion_flag == ION_FLAG_CACHED && buff_handle) {
 				msm_ion_do_cache_op(client_ctx->user_ion_client,
 				buff_handle,
 				(unsigned long *)kernel_vaddr,
@@ -1812,7 +1811,7 @@
 			}
 			ker_vaddr = (unsigned long) ion_map_kernel(
 				client_ctx->user_ion_client,
-				client_ctx->seq_hdr_ion_handle, ionflag);
+				client_ctx->seq_hdr_ion_handle);
 			if (!ker_vaddr) {
 				ERR("%s():get_ION_kernel virtual addr fail\n",
 							 __func__);
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index 67917b9..c7237e4 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -267,7 +267,7 @@
 		ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
 					pmem_fd, kernel_vaddr, buffer_index,
 					&buff_handle);
-		if (ion_flag == CACHED && buff_handle) {
+		if (ion_flag == ION_FLAG_CACHED && buff_handle) {
 			msm_ion_do_cache_op(client_ctx->user_ion_client,
 				buff_handle,
 				(unsigned long *) kernel_vaddr,
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index 5ee0a3d..8779432 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -1688,7 +1688,7 @@
 				&buff_handle);
 
 		if (vcd_input_buffer.data_len > 0) {
-			if (ion_flag == CACHED && buff_handle) {
+			if (ion_flag == ION_FLAG_CACHED && buff_handle) {
 				msm_ion_do_cache_op(
 				client_ctx->user_ion_client,
 				buff_handle,
@@ -1837,8 +1837,7 @@
 		}
 		control->kernel_virtual_addr = (u8 *) ion_map_kernel(
 			client_ctx->user_ion_client,
-			client_ctx->recon_buffer_ion_handle[i],
-			ionflag);
+			client_ctx->recon_buffer_ion_handle[i]);
 		if (!control->kernel_virtual_addr) {
 			ERR("%s(): get_ION_kernel virtual addr fail\n",
 				 __func__);
@@ -1867,7 +1866,7 @@
 					0,
 					(unsigned long *)&iova,
 					(unsigned long *)&buffer_size,
-					UNCACHED, 0);
+					0, 0);
 			if (rc || !iova) {
 				ERR(
 				"%s():ION map iommu addr fail, rc = %d, iova = 0x%lx\n",
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index 221c154..65dde68 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -647,8 +647,7 @@
 			*kernel_vaddr = (unsigned long)
 				ion_map_kernel(
 				client_ctx->user_ion_client,
-				buff_ion_handle,
-				ionflag);
+				buff_ion_handle);
 			if (IS_ERR_OR_NULL((void *)*kernel_vaddr)) {
 				ERR("%s():ION virtual addr fail\n",
 				 __func__);
@@ -678,7 +677,7 @@
 						length,
 						(unsigned long *) &iova,
 						(unsigned long *) &buffer_size,
-						UNCACHED,
+						0,
 						ION_IOMMU_UNMAP_DELAYED);
 				if (ret || !iova) {
 					ERR(
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 71e8df8..6e332ef 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -92,7 +92,7 @@
 	} else {
 		map_buffer->alloc_handle = ion_alloc(
 			    cctxt->vcd_ion_client, sz, SZ_4K,
-			    memtype);
+			    memtype, 0);
 		if (!map_buffer->alloc_handle) {
 			pr_err("%s() ION alloc failed", __func__);
 			goto bailout;
@@ -105,8 +105,7 @@
 		}
 		*kernel_vaddr = (u8 *) ion_map_kernel(
 				cctxt->vcd_ion_client,
-				map_buffer->alloc_handle,
-				ionflag);
+				map_buffer->alloc_handle);
 		if (!(*kernel_vaddr)) {
 			pr_err("%s() ION map failed", __func__);
 			goto ion_free_bailout;
@@ -120,7 +119,7 @@
 				0,
 				(unsigned long *)&iova,
 				(unsigned long *)&buffer_size,
-				UNCACHED, 0);
+				0, 0);
 			if (ret || !iova) {
 				pr_err(
 				"%s() ION iommu map failed, ret = %d, iova = 0x%lx",
diff --git a/include/linux/epm_adc.h b/include/linux/epm_adc.h
index b7b7d90..ca1a425 100644
--- a/include/linux/epm_adc.h
+++ b/include/linux/epm_adc.h
@@ -13,6 +13,7 @@
 	int32_t physical;
 };
 
+#ifdef __KERNEL__
 struct epm_psoc_init_resp {
 	u8	cmd;
 	u8	version;
@@ -91,7 +92,6 @@
 	uint32_t	vadc_voltage;
 };
 
-#ifdef __KERNEL__
 struct epm_chan_properties {
 	uint32_t resistorvalue;
 	uint32_t gain;
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 6ac2835..85bb182 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -51,6 +51,14 @@
 #define ION_HEAP_CARVEOUT_MASK		(1 << ION_HEAP_TYPE_CARVEOUT)
 #define ION_HEAP_CP_MASK		(1 << ION_HEAP_TYPE_CP)
 
+/**
+ * heap flags - the lower 16 bits are used by core ion, the upper 16
+ * bits are reserved for use by the heaps themselves.
+ */
+#define ION_FLAG_CACHED 1		/* mappings of this buffer should be
+					   cached, ion will do cache
+					   maintenance when the buffer is
+					   mapped for dma */
 
 /**
  * These are the only ids that should be used for Ion heap ids.
@@ -115,14 +123,11 @@
 #define ION_QSECOM_HEAP_NAME	"qsecom"
 #define ION_FMEM_HEAP_NAME	"fmem"
 
-#define CACHED          1
-#define UNCACHED        0
+#define ION_SET_CACHED(__cache)		(__cache | ION_FLAG_CACHED)
+#define ION_SET_UNCACHED(__cache)	(__cache & ~ION_FLAG_CACHED)
 
-#define ION_CACHE_SHIFT 0
+#define ION_IS_CACHED(__flags)	((__flags) & ION_FLAG_CACHED)
 
-#define ION_SET_CACHE(__cache)  ((__cache) << ION_CACHE_SHIFT)
-
-#define ION_IS_CACHED(__flags)	((__flags) & (1 << ION_CACHE_SHIFT))
 
 /*
  * This flag allows clients when mapping into the IOMMU to specify to
@@ -305,14 +310,18 @@
  * @len:	size of the allocation
  * @align:	requested allocation alignment, lots of hardware blocks have
  *		alignment requirements of some kind
- * @flags:	mask of heaps to allocate from, if multiple bits are set
+ * @heap_mask:	mask of heaps to allocate from, if multiple bits are set
  *		heaps will be tried in order from lowest to highest order bit
+ * @flags:	heap flags, the low 16 bits are consumed by ion, the high 16
+ *		bits are passed on to the respective heap and can be heap
+ *		custom
  *
  * Allocate memory in one of the heaps provided in heap mask and return
  * an opaque handle to it.
  */
 struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
-			     size_t align, unsigned int flags);
+			     size_t align, unsigned int heap_mask,
+			     unsigned int flags);
 
 /**
  * ion_free - free a handle
@@ -363,8 +372,7 @@
  * can be used to access this address. If no flags are specified, this
  * will return a non-secure uncached mapping.
  */
-void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle,
-			unsigned long flags);
+void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle);
 
 /**
  * ion_unmap_kernel() - destroy a kernel mapping for a handle
@@ -418,7 +426,6 @@
  *		address space will be mapped to a dummy buffer.
  * @iova - pointer to store the iova address
  * @buffer_size - pointer to store the size of the buffer
- * @flags - flags for options to map
  * @iommu_flags - flags specific to the iommu.
  *
  * Maps the handle into the iova space specified via domain number. Iova
@@ -574,7 +581,9 @@
 static inline void ion_client_destroy(struct ion_client *client) { }
 
 static inline struct ion_handle *ion_alloc(struct ion_client *client,
-			size_t len, size_t align, unsigned int flags)
+					size_t len, size_t align,
+					unsigned int heap_mask,
+					unsigned int flags)
 {
 	return ERR_PTR(-ENODEV);
 }
@@ -695,6 +704,7 @@
  * struct ion_allocation_data - metadata passed from userspace for allocations
  * @len:	size of the allocation
  * @align:	required alignment of the allocation
+ * @heap_mask:	mask of heaps to allocate from
  * @flags:	flags passed to heap
  * @handle:	pointer that will be populated with a cookie to use to refer
  *		to this allocation
diff --git a/include/linux/mfd/pm8xxx/batterydata-lib.h b/include/linux/mfd/pm8xxx/batterydata-lib.h
new file mode 100644
index 0000000..c55e47e
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/batterydata-lib.h
@@ -0,0 +1,155 @@
+/* Copyright (c) 2012, The Linux Foundation. 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 __PM8XXX_BMS_BATTERYDATA_H
+#define __PM8XXX_BMS_BATTERYDATA_H
+
+#include <linux/errno.h>
+
+#define FCC_CC_COLS		5
+#define FCC_TEMP_COLS		8
+
+#define PC_CC_ROWS             29
+#define PC_CC_COLS             13
+
+#define PC_TEMP_ROWS		29
+#define PC_TEMP_COLS		8
+
+#define MAX_SINGLE_LUT_COLS	20
+
+struct single_row_lut {
+	int x[MAX_SINGLE_LUT_COLS];
+	int y[MAX_SINGLE_LUT_COLS];
+	int cols;
+};
+
+/**
+ * struct sf_lut -
+ * @rows:	number of percent charge entries should be <= PC_CC_ROWS
+ * @cols:	number of charge cycle entries should be <= PC_CC_COLS
+ * @row_entries:	the charge cycles/temperature at which sf data
+ *			is available in the table.
+ *		The charge cycles must be in increasing order from 0 to rows.
+ * @percent:	the percent charge at which sf data is available in the table
+ *		The  percentcharge must be in decreasing order from 0 to cols.
+ * @sf:		the scaling factor data
+ */
+struct sf_lut {
+	int rows;
+	int cols;
+	int row_entries[PC_CC_COLS];
+	int percent[PC_CC_ROWS];
+	int sf[PC_CC_ROWS][PC_CC_COLS];
+};
+
+/**
+ * struct pc_temp_ocv_lut -
+ * @rows:	number of percent charge entries should be <= PC_TEMP_ROWS
+ * @cols:	number of temperature entries should be <= PC_TEMP_COLS
+ * @temp:	the temperatures at which ocv data is available in the table
+ *		The temperatures must be in increasing order from 0 to rows.
+ * @percent:	the percent charge at which ocv data is available in the table
+ *		The  percentcharge must be in decreasing order from 0 to cols.
+ * @ocv:	the open circuit voltage
+ */
+struct pc_temp_ocv_lut {
+	int rows;
+	int cols;
+	int temp[PC_TEMP_COLS];
+	int percent[PC_TEMP_ROWS];
+	int ocv[PC_TEMP_ROWS][PC_TEMP_COLS];
+};
+
+enum battery_type {
+	BATT_UNKNOWN = 0,
+	BATT_PALLADIUM,
+	BATT_DESAY,
+};
+
+/**
+ * struct bms_battery_data -
+ * @fcc:		full charge capacity (mAmpHour)
+ * @fcc_temp_lut:	table to get fcc at a given temp
+ * @pc_temp_ocv_lut:	table to get percent charge given batt temp and cycles
+ * @pc_sf_lut:		table to get percent charge scaling factor given cycles
+ *			and percent charge
+ * @rbatt_sf_lut:	table to get battery resistance scaling factor given
+ *			temperature and percent charge
+ * @default_rbatt_mohm:	the default value of battery resistance to use when
+ *			readings from bms are not available.
+ * @delta_rbatt_mohm:	the resistance to be added towards lower soc to
+ *			compensate for battery capacitance.
+ */
+
+struct bms_battery_data {
+	unsigned int		fcc;
+	struct single_row_lut	*fcc_temp_lut;
+	struct single_row_lut	*fcc_sf_lut;
+	struct pc_temp_ocv_lut	*pc_temp_ocv_lut;
+	struct sf_lut		*pc_sf_lut;
+	struct sf_lut		*rbatt_sf_lut;
+	int			default_rbatt_mohm;
+	int			delta_rbatt_mohm;
+};
+
+#if defined(CONFIG_PM8921_BMS) || \
+	defined(CONFIG_PM8921_BMS_MODULE)
+extern struct bms_battery_data  palladium_1500_data;
+extern struct bms_battery_data  desay_5200_data;
+
+int interpolate_fcc(struct single_row_lut *fcc_temp_lut, int batt_temp);
+int interpolate_scalingfactor(struct sf_lut *sf_lut, int row_entry, int pc);
+int interpolate_scalingfactor_fcc(struct single_row_lut *fcc_sf_lut,
+				int cycles);
+int interpolate_pc(struct pc_temp_ocv_lut *pc_temp_ocv,
+				int batt_temp_degc, int ocv);
+int interpolate_ocv(struct pc_temp_ocv_lut *pc_temp_ocv,
+				int batt_temp_degc, int pc);
+int linear_interpolate(int y0, int x0, int y1, int x1, int x);
+int is_between(int left, int right, int value);
+#else
+static inline int interpolate_fcc(struct single_row_lut *fcc_temp_lut,
+			int batt_temp)
+{
+	return -EINVAL;
+}
+static inline int interpolate_scalingfactor(struct sf_lut *sf_lut,
+			int row_entry, int pc)
+{
+	return -EINVAL;
+}
+static inline int interpolate_scalingfactor_fcc(
+			struct single_row_lut *fcc_sf_lut, int cycles)
+{
+	return -EINVAL;
+}
+static inline int interpolate_pc(struct pc_temp_ocv_lut *pc_temp_ocv,
+			int batt_temp_degc, int ocv)
+{
+	return -EINVAL;
+}
+static inline int interpolate_ocv(struct pc_temp_ocv_lut *pc_temp_ocv,
+			int batt_temp_degc, int pc)
+{
+	return -EINVAL;
+}
+static inline int linear_interpolate(int y0, int x0, int y1, int x1, int x)
+{
+	return -EINVAL;
+}
+static inline int is_between(int left, int right, int value)
+{
+	return -EINVAL;
+}
+#endif
+
+#endif
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index a73a284..5f2fe9f 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -14,87 +14,10 @@
 #define __PM8XXX_BMS_H
 
 #include <linux/errno.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
 
 #define PM8921_BMS_DEV_NAME	"pm8921-bms"
 
-#define FCC_CC_COLS		5
-#define FCC_TEMP_COLS		8
-
-#define PC_CC_ROWS             29
-#define PC_CC_COLS             13
-
-#define PC_TEMP_ROWS		29
-#define PC_TEMP_COLS		8
-
-#define MAX_SINGLE_LUT_COLS	20
-
-struct single_row_lut {
-	int x[MAX_SINGLE_LUT_COLS];
-	int y[MAX_SINGLE_LUT_COLS];
-	int cols;
-};
-
-/**
- * struct sf_lut -
- * @rows:	number of percent charge entries should be <= PC_CC_ROWS
- * @cols:	number of charge cycle entries should be <= PC_CC_COLS
- * @row_entries:	the charge cycles/temperature at which sf data
- *			is available in the table.
- *		The charge cycles must be in increasing order from 0 to rows.
- * @percent:	the percent charge at which sf data is available in the table
- *		The  percentcharge must be in decreasing order from 0 to cols.
- * @sf:		the scaling factor data
- */
-struct sf_lut {
-	int rows;
-	int cols;
-	int row_entries[PC_CC_COLS];
-	int percent[PC_CC_ROWS];
-	int sf[PC_CC_ROWS][PC_CC_COLS];
-};
-
-/**
- * struct pc_temp_ocv_lut -
- * @rows:	number of percent charge entries should be <= PC_TEMP_ROWS
- * @cols:	number of temperature entries should be <= PC_TEMP_COLS
- * @temp:	the temperatures at which ocv data is available in the table
- *		The temperatures must be in increasing order from 0 to rows.
- * @percent:	the percent charge at which ocv data is available in the table
- *		The  percentcharge must be in decreasing order from 0 to cols.
- * @ocv:	the open circuit voltage
- */
-struct pc_temp_ocv_lut {
-	int rows;
-	int cols;
-	int temp[PC_TEMP_COLS];
-	int percent[PC_TEMP_ROWS];
-	int ocv[PC_TEMP_ROWS][PC_TEMP_COLS];
-};
-
-/**
- * struct pm8921_bms_battery_data -
- * @fcc:		full charge capacity (mAmpHour)
- * @fcc_temp_lut:	table to get fcc at a given temp
- * @pc_temp_ocv_lut:	table to get percent charge given batt temp and cycles
- * @pc_sf_lut:		table to get percent charge scaling factor given cycles
- *			and percent charge
- * @rbatt_sf_lut:	table to get battery resistance scaling factor given
- *			temperature and percent charge
- * @default_rbatt_mohm:	the default value of battery resistance to use when
- *			readings from bms are not available.
- * @delta_rbatt_mohm:	the resistance to be added towards lower soc to
- *			compensate for battery capacitance.
- */
-struct pm8921_bms_battery_data {
-	unsigned int		fcc;
-	struct single_row_lut	*fcc_temp_lut;
-	struct single_row_lut	*fcc_sf_lut;
-	struct pc_temp_ocv_lut	*pc_temp_ocv_lut;
-	struct sf_lut		*pc_sf_lut;
-	struct sf_lut		*rbatt_sf_lut;
-	int			default_rbatt_mohm;
-	int			delta_rbatt_mohm;
-};
 
 struct pm8xxx_bms_core_data {
 	unsigned int	batt_temp_channel;
@@ -104,12 +27,6 @@
 	unsigned int	batt_id_channel;
 };
 
-enum battery_type {
-	BATT_UNKNOWN = 0,
-	BATT_PALLADIUM,
-	BATT_DESAY,
-};
-
 /**
  * struct pm8921_bms_platform_data -
  * @batt_type:		allows to force chose battery calibration data
@@ -137,8 +54,6 @@
 };
 
 #if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
-extern struct pm8921_bms_battery_data  palladium_1500_data;
-extern struct pm8921_bms_battery_data  desay_5200_data;
 /**
  * pm8921_bms_get_vsense_avg - return the voltage across the sense
  *				resitor in microvolts
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index f6d164d..c306c75 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -37,6 +37,12 @@
 #define SITAR_IS_1P1(ver) \
 	((ver == SITAR_VERSION_1P1) ? 1 : 0)
 
+
+#define TAIKO_VERSION_1_0	0
+#define TAIKO_IS_1_0(ver) \
+	((ver == TAIKO_VERSION_1_0) ? 1 : 0)
+
+
 enum {
 	TABLA_IRQ_SLIMBUS = 0,
 	TABLA_IRQ_MBHC_REMOVAL,
diff --git a/include/linux/mfd/wcd9xxx/wcd9320_registers.h b/include/linux/mfd/wcd9xxx/wcd9320_registers.h
index 5725e6e..4b8626a 100644
--- a/include/linux/mfd/wcd9xxx/wcd9320_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9320_registers.h
@@ -701,45 +701,45 @@
 #define TAIKO_A_CDC_TX10_VOL_CTL_CFG			(0x26A)
 #define TAIKO_A_CDC_TX10_VOL_CTL_CFG__POR				(0x00)
 #define TAIKO_A_CDC_TX1_MUX_CTL			(0x223)
-#define TAIKO_A_CDC_TX1_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX1_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX2_MUX_CTL			(0x22B)
-#define TAIKO_A_CDC_TX2_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX2_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX3_MUX_CTL			(0x233)
-#define TAIKO_A_CDC_TX3_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX3_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX4_MUX_CTL			(0x23B)
-#define TAIKO_A_CDC_TX4_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX4_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX5_MUX_CTL			(0x243)
-#define TAIKO_A_CDC_TX5_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX5_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX6_MUX_CTL			(0x24B)
-#define TAIKO_A_CDC_TX6_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX6_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX7_MUX_CTL			(0x253)
-#define TAIKO_A_CDC_TX7_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX7_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX8_MUX_CTL			(0x25B)
-#define TAIKO_A_CDC_TX8_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX8_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX9_MUX_CTL			(0x263)
-#define TAIKO_A_CDC_TX9_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX9_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX10_MUX_CTL			(0x26B)
-#define TAIKO_A_CDC_TX10_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX10_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX1_CLK_FS_CTL			(0x224)
-#define TAIKO_A_CDC_TX1_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX1_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX2_CLK_FS_CTL			(0x22C)
-#define TAIKO_A_CDC_TX2_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX2_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX3_CLK_FS_CTL			(0x234)
-#define TAIKO_A_CDC_TX3_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX3_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX4_CLK_FS_CTL			(0x23C)
-#define TAIKO_A_CDC_TX4_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX4_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX5_CLK_FS_CTL			(0x244)
-#define TAIKO_A_CDC_TX5_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX5_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX6_CLK_FS_CTL			(0x24C)
-#define TAIKO_A_CDC_TX6_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX6_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX7_CLK_FS_CTL			(0x254)
-#define TAIKO_A_CDC_TX7_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX7_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX8_CLK_FS_CTL			(0x25C)
-#define TAIKO_A_CDC_TX8_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX8_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX9_CLK_FS_CTL			(0x264)
-#define TAIKO_A_CDC_TX9_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX9_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX10_CLK_FS_CTL			(0x26C)
-#define TAIKO_A_CDC_TX10_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX10_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX1_DMIC_CTL			(0x225)
 #define TAIKO_A_CDC_TX1_DMIC_CTL__POR				(0x00)
 #define TAIKO_A_CDC_TX2_DMIC_CTL			(0x22D)
@@ -779,9 +779,9 @@
 #define TAIKO_A_CDC_SRC2_PDA_CFG			(0x2A8)
 #define TAIKO_A_CDC_SRC2_PDA_CFG__POR				(0x00)
 #define TAIKO_A_CDC_SRC1_FS_CTL			(0x2A1)
-#define TAIKO_A_CDC_SRC1_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_SRC1_FS_CTL__POR				(0x1B)
 #define TAIKO_A_CDC_SRC2_FS_CTL			(0x2A9)
-#define TAIKO_A_CDC_SRC2_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_SRC2_FS_CTL__POR				(0x1B)
 #define TAIKO_A_CDC_RX1_B1_CTL			(0x2B0)
 #define TAIKO_A_CDC_RX1_B1_CTL__POR				(0x00)
 #define TAIKO_A_CDC_RX2_B1_CTL			(0x2B8)
@@ -839,33 +839,33 @@
 #define TAIKO_A_CDC_RX7_B4_CTL			(0x2E3)
 #define TAIKO_A_CDC_RX7_B4_CTL__POR				(0x00)
 #define TAIKO_A_CDC_RX1_B5_CTL			(0x2B4)
-#define TAIKO_A_CDC_RX1_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX1_B5_CTL__POR				(0x78)
 #define TAIKO_A_CDC_RX2_B5_CTL			(0x2BC)
-#define TAIKO_A_CDC_RX2_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX2_B5_CTL__POR				(0x78)
 #define TAIKO_A_CDC_RX3_B5_CTL			(0x2C4)
-#define TAIKO_A_CDC_RX3_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX3_B5_CTL__POR				(0x78)
 #define TAIKO_A_CDC_RX4_B5_CTL			(0x2CC)
-#define TAIKO_A_CDC_RX4_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX4_B5_CTL__POR				(0x78)
 #define TAIKO_A_CDC_RX5_B5_CTL			(0x2D4)
-#define TAIKO_A_CDC_RX5_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX5_B5_CTL__POR				(0x78)
 #define TAIKO_A_CDC_RX6_B5_CTL			(0x2DC)
-#define TAIKO_A_CDC_RX6_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX6_B5_CTL__POR				(0x78)
 #define TAIKO_A_CDC_RX7_B5_CTL			(0x2E4)
-#define TAIKO_A_CDC_RX7_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX7_B5_CTL__POR				(0x78)
 #define TAIKO_A_CDC_RX1_B6_CTL			(0x2B5)
-#define TAIKO_A_CDC_RX1_B6_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX1_B6_CTL__POR				(0x80)
 #define TAIKO_A_CDC_RX2_B6_CTL			(0x2BD)
-#define TAIKO_A_CDC_RX2_B6_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX2_B6_CTL__POR				(0x80)
 #define TAIKO_A_CDC_RX3_B6_CTL			(0x2C5)
-#define TAIKO_A_CDC_RX3_B6_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX3_B6_CTL__POR				(0x80)
 #define TAIKO_A_CDC_RX4_B6_CTL			(0x2CD)
-#define TAIKO_A_CDC_RX4_B6_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX4_B6_CTL__POR				(0x80)
 #define TAIKO_A_CDC_RX5_B6_CTL			(0x2D5)
-#define TAIKO_A_CDC_RX5_B6_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX5_B6_CTL__POR				(0x80)
 #define TAIKO_A_CDC_RX6_B6_CTL			(0x2DD)
-#define TAIKO_A_CDC_RX6_B6_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX6_B6_CTL__POR				(0x80)
 #define TAIKO_A_CDC_RX7_B6_CTL			(0x2E5)
-#define TAIKO_A_CDC_RX7_B6_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX7_B6_CTL__POR				(0x80)
 #define TAIKO_A_CDC_RX1_VOL_CTL_B1_CTL			(0x2B6)
 #define TAIKO_A_CDC_RX1_VOL_CTL_B1_CTL__POR				(0x00)
 #define TAIKO_A_CDC_RX2_VOL_CTL_B1_CTL			(0x2BE)
@@ -1041,9 +1041,9 @@
 #define TAIKO_A_CDC_IIR2_GAIN_B8_CTL			(0x357)
 #define TAIKO_A_CDC_IIR2_GAIN_B8_CTL__POR				(0x00)
 #define TAIKO_A_CDC_IIR1_CTL			(0x348)
-#define TAIKO_A_CDC_IIR1_CTL__POR				(0x00)
+#define TAIKO_A_CDC_IIR1_CTL__POR				(0x40)
 #define TAIKO_A_CDC_IIR2_CTL			(0x358)
-#define TAIKO_A_CDC_IIR2_CTL__POR				(0x00)
+#define TAIKO_A_CDC_IIR2_CTL__POR				(0x40)
 #define TAIKO_A_CDC_IIR1_GAIN_TIMER_CTL			(0x349)
 #define TAIKO_A_CDC_IIR1_GAIN_TIMER_CTL__POR				(0x00)
 #define TAIKO_A_CDC_IIR2_GAIN_TIMER_CTL			(0x359)
@@ -1059,35 +1059,35 @@
 #define TAIKO_A_CDC_TOP_GAIN_UPDATE			(0x360)
 #define TAIKO_A_CDC_TOP_GAIN_UPDATE__POR				(0x00)
 #define TAIKO_A_CDC_COMP0_B1_CTL			(0x368)
-#define TAIKO_A_CDC_COMP0_B1_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP0_B1_CTL__POR				(0x30)
 #define TAIKO_A_CDC_COMP1_B1_CTL			(0x370)
-#define TAIKO_A_CDC_COMP1_B1_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP1_B1_CTL__POR				(0x30)
 #define TAIKO_A_CDC_COMP2_B1_CTL			(0x378)
-#define TAIKO_A_CDC_COMP2_B1_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP2_B1_CTL__POR				(0x30)
 #define TAIKO_A_CDC_COMP0_B2_CTL			(0x369)
-#define TAIKO_A_CDC_COMP0_B2_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP0_B2_CTL__POR				(0xB5)
 #define TAIKO_A_CDC_COMP1_B2_CTL			(0x371)
-#define TAIKO_A_CDC_COMP1_B2_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP1_B2_CTL__POR				(0xB5)
 #define TAIKO_A_CDC_COMP2_B2_CTL			(0x379)
-#define TAIKO_A_CDC_COMP2_B2_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP2_B2_CTL__POR				(0xB5)
 #define TAIKO_A_CDC_COMP0_B3_CTL			(0x36A)
-#define TAIKO_A_CDC_COMP0_B3_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP0_B3_CTL__POR				(0x28)
 #define TAIKO_A_CDC_COMP1_B3_CTL			(0x372)
-#define TAIKO_A_CDC_COMP1_B3_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP1_B3_CTL__POR				(0x28)
 #define TAIKO_A_CDC_COMP2_B3_CTL			(0x37A)
-#define TAIKO_A_CDC_COMP2_B3_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP2_B3_CTL__POR				(0x28)
 #define TAIKO_A_CDC_COMP0_B4_CTL			(0x36B)
-#define TAIKO_A_CDC_COMP0_B4_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP0_B4_CTL__POR				(0x3C)
 #define TAIKO_A_CDC_COMP1_B4_CTL			(0x373)
-#define TAIKO_A_CDC_COMP1_B4_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP1_B4_CTL__POR				(0x3C)
 #define TAIKO_A_CDC_COMP2_B4_CTL			(0x37B)
-#define TAIKO_A_CDC_COMP2_B4_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP2_B4_CTL__POR				(0x3C)
 #define TAIKO_A_CDC_COMP0_B5_CTL			(0x36C)
-#define TAIKO_A_CDC_COMP0_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP0_B5_CTL__POR				(0x1F)
 #define TAIKO_A_CDC_COMP1_B5_CTL			(0x374)
-#define TAIKO_A_CDC_COMP1_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP1_B5_CTL__POR				(0x1F)
 #define TAIKO_A_CDC_COMP2_B5_CTL			(0x37C)
-#define TAIKO_A_CDC_COMP2_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP2_B5_CTL__POR				(0x1F)
 #define TAIKO_A_CDC_COMP0_B6_CTL			(0x36D)
 #define TAIKO_A_CDC_COMP0_B6_CTL__POR				(0x00)
 #define TAIKO_A_CDC_COMP1_B6_CTL			(0x375)
@@ -1095,17 +1095,17 @@
 #define TAIKO_A_CDC_COMP2_B6_CTL			(0x37D)
 #define TAIKO_A_CDC_COMP2_B6_CTL__POR				(0x00)
 #define TAIKO_A_CDC_COMP0_SHUT_DOWN_STATUS			(0x36E)
-#define TAIKO_A_CDC_COMP0_SHUT_DOWN_STATUS__POR				(0x00)
+#define TAIKO_A_CDC_COMP0_SHUT_DOWN_STATUS__POR				(0x03)
 #define TAIKO_A_CDC_COMP1_SHUT_DOWN_STATUS			(0x376)
-#define TAIKO_A_CDC_COMP1_SHUT_DOWN_STATUS__POR				(0x00)
+#define TAIKO_A_CDC_COMP1_SHUT_DOWN_STATUS__POR				(0x03)
 #define TAIKO_A_CDC_COMP2_SHUT_DOWN_STATUS			(0x37E)
-#define TAIKO_A_CDC_COMP2_SHUT_DOWN_STATUS__POR				(0x00)
+#define TAIKO_A_CDC_COMP2_SHUT_DOWN_STATUS__POR				(0x03)
 #define TAIKO_A_CDC_COMP0_FS_CFG			(0x36F)
-#define TAIKO_A_CDC_COMP0_FS_CFG__POR				(0x00)
+#define TAIKO_A_CDC_COMP0_FS_CFG__POR				(0x03)
 #define TAIKO_A_CDC_COMP1_FS_CFG			(0x377)
-#define TAIKO_A_CDC_COMP1_FS_CFG__POR				(0x00)
+#define TAIKO_A_CDC_COMP1_FS_CFG__POR				(0x03)
 #define TAIKO_A_CDC_COMP2_FS_CFG			(0x37F)
-#define TAIKO_A_CDC_COMP2_FS_CFG__POR				(0x00)
+#define TAIKO_A_CDC_COMP2_FS_CFG__POR				(0x03)
 #define TAIKO_A_CDC_CONN_RX1_B1_CTL			(0x380)
 #define TAIKO_A_CDC_CONN_RX1_B1_CTL__POR				(0x00)
 #define TAIKO_A_CDC_CONN_RX1_B2_CTL			(0x381)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index a80eb59..3b379ba 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -53,9 +53,6 @@
 	u8			part_config;
 	u8			cache_ctrl;
 	u8			rst_n_function;
-	u8			max_packed_writes;
-	u8			max_packed_reads;
-	u8			packed_event_en;
 	unsigned int		part_time;		/* Units: ms */
 	unsigned int		sa_timeout;		/* Units: 100ns */
 	unsigned int		generic_cmd6_time;	/* Units: 10ms */
@@ -79,10 +76,13 @@
 	bool			hpi_en;			/* HPI enablebit */
 	bool			hpi;			/* HPI support bit */
 	unsigned int		hpi_cmd;		/* cmd used as HPI */
+	bool			bkops;		/* background support bit */
+	bool			bkops_en;	/* background enable bit */
 	unsigned int            data_sector_size;       /* 512 bytes or 4KB */
 	unsigned int            data_tag_unit_size;     /* DATA TAG UNIT size */
 	unsigned int		boot_ro_lock;		/* ro lock support */
 	bool			boot_ro_lockable;
+	u8			raw_exception_status;	/* 53 */
 	u8			raw_partition_support;	/* 160 */
 	u8			raw_erased_mem_count;	/* 181 */
 	u8			raw_ext_csd_structure;	/* 194 */
@@ -96,6 +96,7 @@
 	u8			raw_sec_erase_mult;	/* 230 */
 	u8			raw_sec_feature_support;/* 231 */
 	u8			raw_trim_mult;		/* 232 */
+	u8			raw_bkops_status;	/* 246 */
 	u8			raw_sectors[4];		/* 212 - 4 bytes */
 
 	unsigned int            feature_support;
@@ -205,25 +206,6 @@
 #define MMC_BLK_DATA_AREA_GP	(1<<2)
 };
 
-enum mmc_packed_stop_reasons {
-	EXCEEDS_SEGMENTS = 0,
-	EXCEEDS_SECTORS,
-	WRONG_DATA_DIR,
-	FLUSH_OR_DISCARD,
-	EMPTY_QUEUE,
-	REL_WRITE,
-	THRESHOLD,
-	MAX_REASONS,
-};
-
-struct mmc_wr_pack_stats {
-	u32 *packing_events;
-	u32 pack_stop_reason[MAX_REASONS];
-	spinlock_t lock;
-	bool enabled;
-	bool print_in_read;
-};
-
 /*
  * MMC device
  */
@@ -247,6 +229,7 @@
 #define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
 #define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
 #define MMC_STATE_SLEEP		(1<<9)		/* card is in sleep state */
+#define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -297,7 +280,6 @@
 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
 	unsigned int    nr_parts;
 
-	struct mmc_wr_pack_stats wr_pack_stats; /* packed commands stats*/
 };
 
 /*
@@ -415,6 +397,7 @@
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 #define mmc_card_removed(c)	((c) && ((c)->state & MMC_CARD_REMOVED))
 #define mmc_card_is_sleep(c)	((c)->state & MMC_STATE_SLEEP)
+#define mmc_card_doing_bkops(c)	((c)->state & MMC_STATE_DOING_BKOPS)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
@@ -427,7 +410,9 @@
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
 #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 #define mmc_card_set_sleep(c)	((c)->state |= MMC_STATE_SLEEP)
+#define mmc_card_set_doing_bkops(c)	((c)->state |= MMC_STATE_DOING_BKOPS)
 
+#define mmc_card_clr_doing_bkops(c)	((c)->state &= ~MMC_STATE_DOING_BKOPS)
 #define mmc_card_clr_sleep(c)	((c)->state &= ~MMC_STATE_SLEEP)
 /*
  * Quirk add/remove for MMC products.
@@ -519,8 +504,4 @@
 extern void mmc_fixup_device(struct mmc_card *card,
 			     const struct mmc_fixup *table);
 
-extern struct mmc_wr_pack_stats *mmc_blk_get_packed_statistics(
-			struct mmc_card *card);
-extern void mmc_blk_init_packed_statistics(struct mmc_card *card);
-
 #endif /* LINUX_MMC_CARD_H */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 817862f..7a45622 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -18,9 +18,6 @@
 struct mmc_command {
 	u32			opcode;
 	u32			arg;
-#define MMC_CMD23_ARG_REL_WR	(1 << 31)
-#define MMC_CMD23_ARG_PACKED	((0 << 31) | (1 << 30))
-#define MMC_CMD23_ARG_TAG_REQ	(1 << 29)
 	u32			resp[4];
 	unsigned int		flags;		/* expected response type */
 #define MMC_RSP_PRESENT	(1 << 0)
@@ -138,6 +135,8 @@
 struct mmc_card;
 struct mmc_async_req;
 
+extern int mmc_stop_bkops(struct mmc_card *);
+extern int mmc_read_bkops_status(struct mmc_card *);
 extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
 					   struct mmc_async_req *, int *);
 extern int mmc_interrupt_hpi(struct mmc_card *);
@@ -146,8 +145,9 @@
 extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
 extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
 	struct mmc_command *, int);
+extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
+extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool);
 extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
-extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
 
 #define MMC_ERASE_ARG		0x00000000
 #define MMC_SECURE_ERASE_ARG	0x80000000
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index dcd9a6f..dcdcd58 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -241,12 +241,8 @@
 #define MMC_CAP2_BROKEN_VOLTAGE	(1 << 7)	/* Use the broken voltage */
 #define MMC_CAP2_DETECT_ON_ERR	(1 << 8)	/* On I/O err check card removal */
 #define MMC_CAP2_HC_ERASE_SZ	(1 << 9)	/* High-capacity erase size */
-#define MMC_CAP2_PACKED_RD	(1 << 10)	/* Allow packed read */
-#define MMC_CAP2_PACKED_WR	(1 << 11)	/* Allow packed write */
-#define MMC_CAP2_PACKED_CMD	(MMC_CAP2_PACKED_RD | \
-				 MMC_CAP2_PACKED_WR) /* Allow packed commands */
-#define MMC_CAP2_PACKED_WR_CONTROL (1 << 12) /* Allow write packing control */
 #define MMC_CAP2_SANITIZE	(1 << 13)		/* Support Sanitize */
+#define MMC_CAP2_INIT_BKOPS	    (1 << 15)	/* Need to set BKOPS_EN */
 #define MMC_CAP2_POWER_OFF_VCCQ_DURING_SUSPEND	(1 << 16)
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index ce4d3c2..2cf8119 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -139,8 +139,8 @@
 #define R1_CURRENT_STATE(x)	((x & 0x00001E00) >> 9)	/* sx, b (4 bits) */
 #define R1_READY_FOR_DATA	(1 << 8)	/* sx, a */
 #define R1_SWITCH_ERROR		(1 << 7)	/* sx, c */
+#define R1_EXCEPTION_EVENT	(1 << 6)	/* sx, a */
 #define R1_APP_CMD		(1 << 5)	/* sr, c */
-#define R1_EXP_EVENT		(1 << 6)	/* sr, a */
 
 #define R1_STATE_IDLE	0
 #define R1_STATE_READY	1
@@ -276,8 +276,6 @@
 #define EXT_CSD_FLUSH_CACHE		32      /* W */
 #define EXT_CSD_CACHE_CTRL		33      /* R/W */
 #define EXT_CSD_POWER_OFF_NOTIFICATION	34	/* R/W */
-#define EXT_CSD_PACKED_FAILURE_INDEX	35	/* RO */
-#define EXT_CSD_PACKED_CMD_STATUS	36	/* RO */
 #define EXT_CSD_EXP_EVENTS_STATUS	54	/* RO, 2 bytes */
 #define EXT_CSD_EXP_EVENTS_CTRL	56	/* R/W, 2 bytes */
 #define EXT_CSD_DATA_SECTOR_SIZE	61	/* R */
@@ -286,6 +284,8 @@
 #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
 #define EXT_CSD_HPI_MGMT		161	/* R/W */
 #define EXT_CSD_RST_N_FUNCTION		162	/* R/W */
+#define EXT_CSD_BKOPS_EN		163	/* R/W */
+#define EXT_CSD_BKOPS_START		164	/* W */
 #define EXT_CSD_SANITIZE_START		165     /* W */
 #define EXT_CSD_WR_REL_PARAM		166	/* RO */
 #define EXT_CSD_BOOT_WP			173	/* R/W */
@@ -319,13 +319,13 @@
 #define EXT_CSD_PWR_CL_200_360		237	/* RO */
 #define EXT_CSD_PWR_CL_DDR_52_195	238	/* RO */
 #define EXT_CSD_PWR_CL_DDR_52_360	239	/* RO */
+#define EXT_CSD_BKOPS_STATUS		246	/* RO */
 #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
 #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
 #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
-#define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
-#define EXT_CSD_MAX_PACKED_READS	501	/* RO */
+#define EXT_CSD_BKOPS_SUPPORT		502	/* RO */
 #define EXT_CSD_HPI_FEATURES		503	/* RO */
 
 /*
@@ -395,12 +395,17 @@
 #define EXT_CSD_PWR_CL_8BIT_SHIFT	4
 #define EXT_CSD_PWR_CL_4BIT_SHIFT	0
 
-#define EXT_CSD_PACKED_EVENT_EN	(1 << 3)
+/*
+ * EXCEPTION_EVENT_STATUS field
+ */
+#define EXT_CSD_URGENT_BKOPS		BIT(0)
+#define EXT_CSD_DYNCAP_NEEDED		BIT(1)
+#define EXT_CSD_SYSPOOL_EXHAUSTED	BIT(2)
 
-#define EXT_CSD_PACKED_FAILURE	(1 << 3)
-
-#define EXT_CSD_PACKED_GENERIC_ERROR	(1 << 0)
-#define EXT_CSD_PACKED_INDEXED_ERROR	(1 << 1)
+/*
+ * BKOPS status level
+ */
+#define EXT_CSD_BKOPS_LEVEL_2		0x2
 
 /*
  * MMC_SWITCH access modes
diff --git a/include/linux/msm_charm.h b/include/linux/msm_charm.h
index 44d2553..1d1f3bb 100644
--- a/include/linux/msm_charm.h
+++ b/include/linux/msm_charm.h
@@ -12,6 +12,7 @@
 #define WAIT_FOR_RESTART	_IOR(CHARM_CODE, 7, int)
 #define GET_DLOAD_STATUS	_IOR(CHARM_CODE, 8, int)
 #define IMAGE_UPGRADE		_IOW(CHARM_CODE, 9, int)
+#define SHUTDOWN_CHARM		_IOW(CHARM_CODE, 10, int)
 
 enum charm_boot_type {
 	CHARM_NORMAL_BOOT = 0,
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index 0e28e54..e7959d1 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -1,5 +1,4 @@
 /*
- * include/linux/ion.h
  *
  * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
  *
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index d03ecfa..861084a 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -276,6 +276,8 @@
 #define MDP_PP_OPS_READ 0x2
 #define MDP_PP_OPS_WRITE 0x4
 #define MDP_PP_OPS_DISABLE 0x8
+#define MDP_PP_IGC_FLAG_ROM0	0x10
+#define MDP_PP_IGC_FLAG_ROM1	0x20
 
 struct mdp_qseed_cfg {
 	uint32_t table_num;
@@ -405,7 +407,7 @@
 
 struct mdp_histogram_data {
 	uint32_t block;
-	uint8_t bin_cnt;
+	uint32_t bin_cnt;
 	uint32_t *c0;
 	uint32_t *c1;
 	uint32_t *c2;
@@ -422,6 +424,8 @@
 	struct mdp_pcc_coeff r, g, b;
 };
 
+#define MDP_GAMUT_TABLE_NUM		8
+
 enum {
 	mdp_lut_igc,
 	mdp_lut_pgc,
@@ -484,6 +488,24 @@
 	uint32_t cont_adj;
 };
 
+struct mdp_dither_cfg_data {
+	uint32_t block;
+	uint32_t flags;
+	uint32_t g_y_depth;
+	uint32_t r_cr_depth;
+	uint32_t b_cb_depth;
+};
+
+struct mdp_gamut_cfg_data {
+	uint32_t block;
+	uint32_t flags;
+	uint32_t gamut_first;
+	uint32_t tbl_size[MDP_GAMUT_TABLE_NUM];
+	uint16_t *r_tbl[MDP_GAMUT_TABLE_NUM];
+	uint16_t *g_tbl[MDP_GAMUT_TABLE_NUM];
+	uint16_t *b_tbl[MDP_GAMUT_TABLE_NUM];
+};
+
 enum {
 	mdp_op_pcc_cfg,
 	mdp_op_csc_cfg,
@@ -491,6 +513,8 @@
 	mdp_op_qseed_cfg,
 	mdp_bl_scale_cfg,
 	mdp_op_pa_cfg,
+	mdp_op_dither_cfg,
+	mdp_op_gamut_cfg,
 	mdp_op_max,
 };
 
@@ -503,6 +527,8 @@
 		struct mdp_qseed_cfg_data qseed_cfg_data;
 		struct mdp_bl_scale_data bl_scale_data;
 		struct mdp_pa_cfg_data pa_cfg_data;
+		struct mdp_dither_cfg_data dither_cfg_data;
+		struct mdp_gamut_cfg_data gamut_cfg_data;
 	} data;
 };
 
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 68a87bf..44c64e8 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -368,6 +368,15 @@
 	struct mon_bus *mon_bus;	/* non-null when associated */
 	int monitored;			/* non-zero when monitored */
 #endif
+	unsigned skip_resume:1;		/* All USB devices are brought into full
+					 * power state after system resume. It
+					 * is desirable for some buses to keep
+					 * their devices in suspend state even
+					 * after system resume. The devices
+					 * are resumed later when a remote
+					 * wakeup is detected or an interface
+					 * driver starts I/O.
+					 */
 };
 
 /* ----------------------------------------------------------------------- */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 8e6550f..920cf77 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -294,6 +294,8 @@
  * @xo_handle: TCXO buffer handle
  * @bus_perf_client: Bus performance client handle to request BUS bandwidth
  * @mhl_enabled: MHL driver registration successful and MHL enabled.
+ * @chg_check_timer: The timer used to implement the workaround to detect
+ *               very slow plug in of wall charger.
  */
 struct msm_otg {
 	struct usb_phy phy;
@@ -323,6 +325,7 @@
 #define A_CONN		15
 #define B_BUS_REQ	16
 #define MHL	        17
+#define B_FALSE_SDP	18
 	unsigned long inputs;
 	struct work_struct sm_work;
 	bool sm_work_pending;
@@ -345,6 +348,7 @@
 	struct msm_xo_voter *xo_handle;
 	uint32_t bus_perf_client;
 	bool mhl_enabled;
+	struct timer_list chg_check_timer;
 	/*
 	 * Allowing PHY power collpase turns off the HSUSB 3.3v and 1.8v
 	 * analog regulators while going to low power mode.
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index b265eb9..07beb50 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1798,6 +1798,12 @@
 	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0 = 7,
 };
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 22)
+enum v4l2_mpeg_vidc_video_h264_au_delimiter {
+	V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED = 0,
+	V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_ENABLED = 1
+};
 /*  Camera class control IDs */
 #define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
 #define V4L2_CID_CAMERA_CLASS 		(V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index d32bc57..7a194ca 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -58,6 +58,7 @@
 int wcnss_hardware_type(void);
 void *wcnss_prealloc_get(unsigned int size);
 int wcnss_prealloc_put(void *ptr);
+void wcnss_reset_intr(void);
 
 #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
 #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index 484d08f..180b38d 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -55,6 +55,7 @@
 #define VCD_I_SLICE_DELIVERY_MODE (VCD_START_BASE + 0x27)
 #define VCD_I_VOP_TIMING_CONSTANT_DELTA (VCD_START_BASE + 0x28)
 #define VCD_I_SET_TURBO_CLK (VCD_START_BASE + 0x29)
+#define VCD_I_ENABLE_DELIMITER_FLAG (VCD_START_BASE + 0x2A)
 
 #define VCD_START_REQ      (VCD_START_BASE + 0x1000)
 #define VCD_I_REQ_IFRAME   (VCD_START_REQ + 0x1)
@@ -373,4 +374,8 @@
 	u32 sps_pps_for_idr_enable_flag;
 };
 
+struct vcd_property_avc_delimiter_enable {
+	u32 avc_delimiter_enable_flag;
+};
+
 #endif
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 2918b94..a15d1f1 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -289,7 +289,6 @@
 	atomic_t			queued_count;
 	struct list_head		done_list;
 	spinlock_t			done_lock;
-	struct mutex		q_lock;
 	wait_queue_head_t		done_wq;
 
 	void				*alloc_ctx[VIDEO_MAX_PLANES];
diff --git a/include/sound/compress_params.h b/include/sound/compress_params.h
index 31d684b..54af7d6a 100644
--- a/include/sound/compress_params.h
+++ b/include/sound/compress_params.h
@@ -86,6 +86,7 @@
 #define SND_AUDIOCODEC_DTS_PASS_THROUGH      ((__u32) 0x00000012)
 #define SND_AUDIOCODEC_DTS_LBR               ((__u32) 0x00000013)
 #define SND_AUDIOCODEC_DTS_TRANSCODE_LOOPBACK ((__u32) 0x00000014)
+#define SND_AUDIOCODEC_PASS_THROUGH          ((__u32) 0x00000015)
 
 /*
  * Profile and modes are listed with bit masks. This allows for a
@@ -331,6 +332,10 @@
 	__u32 bw;	/* encoder bandwidth */
 	__s32 reserved[15];
 };
+struct snd_dec_dts {
+	__u32 modelIdLength;
+	__u8 *modelId;
+};
 
 union snd_codec_options {
 	struct snd_enc_wma wma;
@@ -338,6 +343,7 @@
 	struct snd_enc_real real;
 	struct snd_enc_flac flac;
 	struct snd_enc_generic generic;
+	struct snd_dec_dts dts;
 };
 
 /** struct snd_codec_desc - description of codec capabilities
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 4021d48..32d3aef 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -49,6 +49,7 @@
 #define FORMAT_MAT	0x0017
 #define FORMAT_AAC	0x0018
 #define FORMAT_DTS_LBR 0x0019
+#define FORMAT_PASS_THROUGH 0x0020
 
 #define ENCDEC_SBCBITRATE   0x0001
 #define ENCDEC_IMMEDIATE_DECODE 0x0002
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index a1d2849..5ba1770 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -418,6 +418,19 @@
 
 	  If in doubt, say N.
 
+config CPU_FREQ_SWITCH_PROFILER
+	bool "CPU frequency switch time profiler"
+	select GENERIC_TRACER
+	help
+	  This option enables the CPU frequency switch profiler. A file is
+	  created in debugfs called "cpu_freq_switch_profile_enabled", which
+	  defaults to zero. When a 1 is echoed into this file, profiling begins.
+	  When a zero is echoed, profiling stops. A "cpu_freq_switch" file is
+	  also created in the trace_stats directory; this file shows the
+	  switches that have occurred and duration statistics.
+
+	  If in doubt, say N.
+
 config FTRACE_MCOUNT_RECORD
 	def_bool y
 	depends on DYNAMIC_FTRACE
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 5f39a07..3c13931 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -36,6 +36,7 @@
 obj-$(CONFIG_IRQSOFF_TRACER) += trace_irqsoff.o
 obj-$(CONFIG_PREEMPT_TRACER) += trace_irqsoff.o
 obj-$(CONFIG_SCHED_TRACER) += trace_sched_wakeup.o
+obj-$(CONFIG_CPU_FREQ_SWITCH_PROFILER) += trace_cpu_freq_switch.o
 obj-$(CONFIG_NOP_TRACER) += trace_nop.o
 obj-$(CONFIG_STACK_TRACER) += trace_stack.o
 obj-$(CONFIG_MMIOTRACE) += trace_mmiotrace.o
diff --git a/kernel/trace/trace_cpu_freq_switch.c b/kernel/trace/trace_cpu_freq_switch.c
new file mode 100644
index 0000000..7e7b104
--- /dev/null
+++ b/kernel/trace/trace_cpu_freq_switch.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. 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/percpu.h>
+#include <linux/slab.h>
+#include <linux/rbtree.h>
+#include <linux/hrtimer.h>
+#include <linux/debugfs.h>
+#include <linux/ktime.h>
+#include <trace/events/power.h>
+#include "trace_stat.h"
+#include "trace.h"
+
+struct trans {
+	struct rb_node node;
+	unsigned int cpu;
+	unsigned int start_freq;
+	unsigned int end_freq;
+	unsigned int min_us;
+	unsigned int max_us;
+	ktime_t total_t;
+	unsigned int count;
+};
+static struct rb_root freq_trans_tree = RB_ROOT;
+
+static struct trans *tr_search(struct rb_root *root, unsigned int cpu,
+			       unsigned int start_freq, unsigned int end_freq)
+{
+	struct rb_node *node = root->rb_node;
+
+	while (node) {
+		struct trans *tr = container_of(node, struct trans, node);
+
+		if (cpu < tr->cpu)
+			node = node->rb_left;
+		else if (cpu > tr->cpu)
+			node = node->rb_right;
+		else if (start_freq < tr->start_freq)
+			node = node->rb_left;
+		else if (start_freq > tr->start_freq)
+			node = node->rb_right;
+		else if (end_freq < tr->end_freq)
+			node = node->rb_left;
+		else if (end_freq > tr->end_freq)
+			node = node->rb_right;
+		else
+			return tr;
+	}
+	return NULL;
+}
+
+static int tr_insert(struct rb_root *root, struct trans *tr)
+{
+	struct rb_node **new = &(root->rb_node), *parent = NULL;
+
+	while (*new) {
+		struct trans *this = container_of(*new, struct trans, node);
+
+		parent = *new;
+		if (tr->cpu < this->cpu)
+			new = &((*new)->rb_left);
+		else if (tr->cpu > this->cpu)
+			new = &((*new)->rb_right);
+		else if (tr->start_freq < this->start_freq)
+			new = &((*new)->rb_left);
+		else if (tr->start_freq > this->start_freq)
+			new = &((*new)->rb_right);
+		else if (tr->end_freq < this->end_freq)
+			new = &((*new)->rb_left);
+		else if (tr->end_freq > this->end_freq)
+			new = &((*new)->rb_right);
+		else
+			return -EINVAL;
+	}
+
+	rb_link_node(&tr->node, parent, new);
+	rb_insert_color(&tr->node, root);
+
+	return 0;
+}
+
+struct trans_state {
+	spinlock_t lock;
+	unsigned int start_freq;
+	unsigned int end_freq;
+	ktime_t start_t;
+	bool started;
+};
+static DEFINE_PER_CPU(struct trans_state, freq_trans_state);
+
+static DEFINE_SPINLOCK(state_lock);
+
+static void probe_start(void *ignore, unsigned int start_freq,
+			unsigned int end_freq, unsigned int cpu)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&state_lock, flags);
+	per_cpu(freq_trans_state, cpu).start_freq = start_freq;
+	per_cpu(freq_trans_state, cpu).end_freq = end_freq;
+	per_cpu(freq_trans_state, cpu).start_t = ktime_get();
+	per_cpu(freq_trans_state, cpu).started = true;
+	spin_unlock_irqrestore(&state_lock, flags);
+}
+
+static void probe_end(void *ignore, unsigned int cpu)
+{
+	unsigned long flags;
+	struct trans *tr;
+	s64 dur_us;
+	ktime_t dur_t, end_t = ktime_get();
+
+	spin_lock_irqsave(&state_lock, flags);
+
+	if (!per_cpu(freq_trans_state, cpu).started)
+		goto out;
+
+	dur_t = ktime_sub(end_t, per_cpu(freq_trans_state, cpu).start_t);
+	dur_us = ktime_to_us(dur_t);
+
+	tr = tr_search(&freq_trans_tree, cpu,
+		       per_cpu(freq_trans_state, cpu).start_freq,
+		       per_cpu(freq_trans_state, cpu).end_freq);
+	if (!tr) {
+		tr = kzalloc(sizeof(*tr), GFP_ATOMIC);
+		if (!tr) {
+			WARN_ONCE(1, "CPU frequency trace is now invalid!\n");
+			goto out;
+		}
+
+		tr->start_freq = per_cpu(freq_trans_state, cpu).start_freq;
+		tr->end_freq = per_cpu(freq_trans_state, cpu).end_freq;
+		tr->cpu = cpu;
+		tr->min_us = UINT_MAX;
+		tr_insert(&freq_trans_tree, tr);
+	}
+	tr->total_t = ktime_add(tr->total_t, dur_t);
+	tr->count++;
+
+	if (dur_us > tr->max_us)
+		tr->max_us = dur_us;
+	if (dur_us < tr->min_us)
+		tr->min_us = dur_us;
+
+	per_cpu(freq_trans_state, cpu).started = false;
+out:
+	spin_unlock_irqrestore(&state_lock, flags);
+}
+
+static void *freq_switch_stat_start(struct tracer_stat *trace)
+{
+	struct rb_node *n;
+	unsigned long flags;
+
+	spin_lock_irqsave(&state_lock, flags);
+	n = rb_first(&freq_trans_tree);
+	spin_unlock_irqrestore(&state_lock, flags);
+
+	return n;
+}
+
+static void *freq_switch_stat_next(void *prev, int idx)
+{
+	struct rb_node *n;
+	unsigned long flags;
+
+	spin_lock_irqsave(&state_lock, flags);
+	n = rb_next(prev);
+	spin_unlock_irqrestore(&state_lock, flags);
+
+	return n;
+}
+
+static int freq_switch_stat_show(struct seq_file *s, void *p)
+{
+	unsigned long flags;
+	struct trans *tr = p;
+
+	spin_lock_irqsave(&state_lock, flags);
+	seq_printf(s, "%3d %9d %8d %5d %6lld %6d %6d\n", tr->cpu,
+		   tr->start_freq, tr->end_freq, tr->count,
+		   div_s64(ktime_to_us(tr->total_t), tr->count),
+		   tr->min_us, tr->max_us);
+	spin_unlock_irqrestore(&state_lock, flags);
+
+	return 0;
+}
+
+static void freq_switch_stat_release(void *stat)
+{
+	struct trans *tr = stat;
+	unsigned long flags;
+
+	spin_lock_irqsave(&state_lock, flags);
+	rb_erase(&tr->node, &freq_trans_tree);
+	spin_unlock_irqrestore(&state_lock, flags);
+	kfree(tr);
+}
+
+static int freq_switch_stat_headers(struct seq_file *s)
+{
+	seq_printf(s, "CPU START_KHZ  END_KHZ COUNT AVG_US MIN_US MAX_US\n");
+	seq_printf(s, "  |         |        |     |      |      |      |\n");
+	return 0;
+}
+
+struct tracer_stat freq_switch_stats __read_mostly = {
+	.name = "cpu_freq_switch",
+	.stat_start = freq_switch_stat_start,
+	.stat_next = freq_switch_stat_next,
+	.stat_show = freq_switch_stat_show,
+	.stat_release = freq_switch_stat_release,
+	.stat_headers = freq_switch_stat_headers
+};
+
+static void trace_freq_switch_disable(void)
+{
+	unregister_stat_tracer(&freq_switch_stats);
+	unregister_trace_cpu_frequency_switch_end(probe_end, NULL);
+	unregister_trace_cpu_frequency_switch_start(probe_start, NULL);
+	pr_info("disabled cpu frequency switch time profiling\n");
+}
+
+static int trace_freq_switch_enable(void)
+{
+	int ret;
+
+	ret = register_trace_cpu_frequency_switch_start(probe_start, NULL);
+	if (ret)
+		goto out;
+
+	ret = register_trace_cpu_frequency_switch_end(probe_end, NULL);
+	if (ret)
+		goto err_register_switch_end;
+
+	ret = register_stat_tracer(&freq_switch_stats);
+	if (ret)
+		goto err_register_stat_tracer;
+
+	pr_info("enabled cpu frequency switch time profiling\n");
+	return 0;
+
+err_register_stat_tracer:
+	unregister_trace_cpu_frequency_switch_end(probe_end, NULL);
+err_register_switch_end:
+	register_trace_cpu_frequency_switch_start(probe_start, NULL);
+out:
+	pr_err("failed to enable cpu frequency switch time profiling\n");
+
+	return ret;
+}
+
+static DEFINE_MUTEX(debugfs_lock);
+static bool trace_freq_switch_enabled;
+
+static int debug_toggle_tracing(void *data, u64 val)
+{
+	int ret = 0;
+
+	mutex_lock(&debugfs_lock);
+
+	if (val == 1 && !trace_freq_switch_enabled)
+		ret = trace_freq_switch_enable();
+	else if (val == 0 && trace_freq_switch_enabled)
+		trace_freq_switch_disable();
+	else if (val > 1)
+		ret = -EINVAL;
+
+	if (!ret)
+		trace_freq_switch_enabled = val;
+
+	mutex_unlock(&debugfs_lock);
+
+	return ret;
+}
+
+static int debug_tracing_state_get(void *data, u64 *val)
+{
+	mutex_lock(&debugfs_lock);
+	*val = trace_freq_switch_enabled;
+	mutex_unlock(&debugfs_lock);
+
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debug_tracing_state_fops, debug_tracing_state_get,
+			debug_toggle_tracing, "%llu\n");
+
+static int __init trace_freq_switch_init(void)
+{
+	struct dentry *d_tracer = tracing_init_dentry();
+	if (!d_tracer)
+		return 0;
+
+	debugfs_create_file("cpu_freq_switch_profile_enabled",
+		S_IRUGO | S_IWUSR, d_tracer, NULL, &debug_tracing_state_fops);
+
+	return 0;
+}
+late_initcall(trace_freq_switch_init);
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index a47e446..deddbe8 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -6526,7 +6526,7 @@
 	s16 mb_v[num_det];
 	s32 mic_mv[num_det];
 	bool inval;
-	bool highdelta;
+	bool highdelta = false;
 	bool ahighv = false, highv;
 	bool gndmicswapped = false;
 
@@ -6587,26 +6587,29 @@
 			if (vddioswitch)
 				__tabla_codec_switch_micbias(tabla->codec, 0,
 							     false, false);
-			/* claim UNSUPPORTED plug insertion when
-			 * good headset is detected but HPHR GND switch makes
-			 * delta difference */
-			if (i == (num_det - 2) && highdelta && !ahighv)
-				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__,
 			 i + 1, mb_v[i] & 0xffff, mic_mv[i], scaled, gndswitch,
 			 vddioswitch, inval);
 		/* don't need to run further DCEs */
-		if (ahighv && inval)
+		if ((ahighv || !vddioswitch) && inval)
 			break;
 		mic_mv[i] = scaled;
+
+		/*
+		 * claim UNSUPPORTED plug insertion when
+		 * good headset is detected but HPHR GND switch makes
+		 * delta difference
+		 */
+		if (i == (num_det - 2) && highdelta && !ahighv)
+			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;
+		}
 	}
 
 	for (i = 0; (plug_type[0] != PLUG_TYPE_GND_MIC_SWAP && !inval) &&
diff --git a/sound/soc/codecs/wcd9320-tables.c b/sound/soc/codecs/wcd9320-tables.c
index 68a4670..c49c276 100644
--- a/sound/soc/codecs/wcd9320-tables.c
+++ b/sound/soc/codecs/wcd9320-tables.c
@@ -673,7 +673,7 @@
 	[TAIKO_A_CDC_MAD_BEACON_IIR_CTL_VAL] = 1,
 };
 
-const u8 taiko_reg_defaults[TAIKO_CACHE_SIZE] = {
+const u8 taiko_reset_reg_defaults[TAIKO_CACHE_SIZE] = {
 	[TAIKO_A_CHIP_CTL] = TAIKO_A_CHIP_CTL__POR,
 	[TAIKO_A_CHIP_STATUS] = TAIKO_A_CHIP_STATUS__POR,
 	[TAIKO_A_CHIP_ID_BYTE_0] = TAIKO_A_CHIP_ID_BYTE_0__POR,
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 136024c..e8bb652 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -685,7 +685,7 @@
 				u32 compander, u32 enable, int event)
 {
 	int value = 0;
-	int mask = 1 << 4;
+	int mask = 1 << 5;
 	int gain = 0;
 	int gain_offset;
 	if (compander >= COMPANDER_MAX) {
@@ -828,19 +828,23 @@
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		/* Halt the compander*/
-		snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B1_CTL +
-			w->shift * 8, 1 << 2, 1 << 2);
+		if (taiko->comp_enabled[w->shift] != 0) {
+			snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B1_CTL +
+				w->shift * 8, 1 << 2, 1 << 2);
+		}
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		/* Restore the gain */
-		taiko_config_gain_compander(codec, w->shift,
-				taiko->comp_enabled[w->shift], event);
-		/* Disable the compander*/
-		snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B1_CTL +
-			w->shift * 8, 0x03, 0x00);
-		/* Turn off the clock for compander in pair*/
-		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_B2_CTL,
-			0x03 << comp_shift[w->shift], 0);
+		if (taiko->comp_enabled[w->shift] != 0) {
+			taiko_config_gain_compander(codec, w->shift,
+					taiko->comp_enabled[w->shift], event);
+			/* Disable the compander*/
+			snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B1_CTL +
+					w->shift * 8, 0x03, 0x00);
+			/* Turn off the clock for compander in pair*/
+			snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_B2_CTL,
+				0x03 << comp_shift[w->shift], 0);
+		}
 		break;
 	}
 	return 0;
@@ -1716,7 +1720,7 @@
 		usleep_range(100, 100);
 		taiko_codec_enable_audio_mode_bandgap(codec);
 	} else if (choice == TAIKO_BANDGAP_OFF) {
-		snd_soc_write(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x00);
+		snd_soc_write(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x50);
 	} else {
 		pr_err("%s: Error, Invalid bandgap settings\n", __func__);
 	}
@@ -1730,7 +1734,7 @@
 	snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN2, 0x04, 0x00);
 	usleep_range(50, 50);
 	snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN2, 0x02, 0x02);
-	snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x05, 0x00);
+	snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x01, 0x00);
 	usleep_range(50, 50);
 	taiko->clock_active = false;
 }
@@ -1815,10 +1819,9 @@
 		/* switch to MCLK */
 		snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x08, 0x00);
 
-		if (taiko->mbhc_polling_active) {
+		if (taiko->mbhc_polling_active)
 			snd_soc_write(codec, TAIKO_A_CLK_BUFF_EN2, 0x02);
-			taiko_codec_enable_config_mode(codec, 0);
-		}
+		taiko_codec_enable_config_mode(codec, 0);
 	}
 
 	snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x01, 0x01);
@@ -2658,7 +2661,7 @@
 	return ret;
 }
 
-static int taiko_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
+static int taiko_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
@@ -4295,25 +4298,25 @@
 			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MIXER_E("RX1 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
-		0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 	SND_SOC_DAPM_MIXER_E("RX2 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
-		0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 	SND_SOC_DAPM_MIXER_E("RX7 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
-		0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 	SND_SOC_DAPM_MIXER_E("RX4 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
-		0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 	SND_SOC_DAPM_MIXER_E("RX5 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
-		0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 	SND_SOC_DAPM_MIXER_E("RX6 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
-		0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 	SND_SOC_DAPM_MIXER_E("RX7 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
-		0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 
 	SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -4321,11 +4324,11 @@
 	SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
 
 	SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TAIKO_A_CDC_CLK_RX_B1_CTL, 3, 0,
-		&rx4_dsm_mux, taiko_codec_reset_interpolator,
+		&rx4_dsm_mux, taiko_codec_enable_interpolator,
 		SND_SOC_DAPM_PRE_PMU),
 
 	SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TAIKO_A_CDC_CLK_RX_B1_CTL, 5, 0,
-		&rx6_dsm_mux, taiko_codec_reset_interpolator,
+		&rx6_dsm_mux, taiko_codec_enable_interpolator,
 		SND_SOC_DAPM_PRE_PMU),
 
 	SND_SOC_DAPM_MIXER("RX1 CHAIN", TAIKO_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
@@ -4381,10 +4384,10 @@
 	SND_SOC_DAPM_SUPPLY("CLASS_H_EAR", TAIKO_A_CDC_CLSH_B1_CTL, 4, 0,
 		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
 
-	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_R", TAIKO_A_CDC_CLSH_B1_CTL, 3, 0,
+	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_L", TAIKO_A_CDC_CLSH_B1_CTL, 3, 0,
 		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
 
-	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_L", TAIKO_A_CDC_CLSH_B1_CTL, 2, 0,
+	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_R", TAIKO_A_CDC_CLSH_B1_CTL, 2, 0,
 		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
 
 	SND_SOC_DAPM_SUPPLY("CP", TAIKO_A_NCP_EN, 0, 0,
@@ -7088,7 +7091,7 @@
 	return rc;
 }
 
-static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
+static const struct taiko_reg_mask_val taiko_reg_defaults[] = {
 
 	/* set MCLk to 9.6 */
 	TAIKO_REG_VAL(TAIKO_A_CHIP_CTL, 0x0A),
@@ -7096,14 +7099,10 @@
 
 	/* EAR PA deafults  */
 	TAIKO_REG_VAL(TAIKO_A_RX_EAR_CMBUFF, 0x05),
-	/* HPH PA */
-	TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
 
 	/** BUCK and NCP defaults for EAR and HS */
 	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_4, 0x50),
-	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_VCL_1, 0x08),
 	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_1, 0x5B),
-	TAIKO_REG_VAL(TAIKO_A_NCP_CLK, 0xFC),
 
 	/* CLASS-H defaults for EAR and HS */
 	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
@@ -7120,7 +7119,6 @@
 	 */
 	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B1_CTL, 0x26),
 
-
 	/* RX deafults */
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX1_B5_CTL, 0x78),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX2_B5_CTL, 0x78),
@@ -7142,20 +7140,50 @@
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
 };
 
+static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
+	/*
+	 * The following only need to be written for Taiko 1.0 parts.
+	 * Taiko 2.0 will have appropriate defaults for these registers.
+	 */
+	/* Choose max non-overlap time for NCP */
+	TAIKO_REG_VAL(TAIKO_A_NCP_CLK, 0xFC),
+	/* Use 25mV/50mV for deltap/m to reduce ripple */
+	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_VCL_1, 0x08),
+	/*
+	 * Set DISABLE_MODE_SEL<1:0> to 0b10 (disable PWM in auto mode).
+	 * Note that the other bits of this register will be changed during
+	 * Rx PA bring up.
+	 */
+	TAIKO_REG_VAL(TAIKO_A_BUCK_MODE_3, 0xCE),
+	/* Reduce HPH DAC bias to 70% */
+	TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
+	/*Reduce EAR DAC bias to 70% */
+	TAIKO_REG_VAL(TAIKO_A_RX_EAR_BIAS_PA, 0x76),
+	/* Reduce LINE DAC bias to 70% */
+	TAIKO_REG_VAL(TAIKO_A_RX_LINE_BIAS_PA, 0x78),
+};
+
 static void taiko_update_reg_defaults(struct snd_soc_codec *codec)
 {
 	u32 i;
+	struct wcd9xxx *taiko_core = dev_get_drvdata(codec->dev->parent);
 
-	for (i = 0; i < ARRAY_SIZE(taiko_1_0_reg_defaults); i++)
-		snd_soc_write(codec, taiko_1_0_reg_defaults[i].reg,
+	for (i = 0; i < ARRAY_SIZE(taiko_reg_defaults); i++)
+		snd_soc_write(codec, taiko_reg_defaults[i].reg,
+				taiko_reg_defaults[i].val);
+
+	if (TAIKO_IS_1_0(taiko_core->version)) {
+		for (i = 0; i < ARRAY_SIZE(taiko_1_0_reg_defaults); i++)
+			snd_soc_write(codec, taiko_1_0_reg_defaults[i].reg,
 				taiko_1_0_reg_defaults[i].val);
+	}
 }
 
 static const struct taiko_reg_mask_val taiko_codec_reg_init_val[] = {
 	/* Initialize current threshold to 350MA
 	 * number of wait and run cycles to 4096
 	 */
-	{TAIKO_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
+	{TAIKO_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
 	{TAIKO_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
 
 	/* Initialize gain registers to use register gain */
@@ -7185,7 +7213,7 @@
 
 	/* Use 16 bit sample size for RX */
 	{TAIKO_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
-	{TAIKO_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
+	{TAIKO_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0x2A},
 
 	/*enable HPF filter for TX paths */
 	{TAIKO_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
@@ -7601,7 +7629,7 @@
 	.volatile_register = taiko_volatile,
 
 	.reg_cache_size = TAIKO_CACHE_SIZE,
-	.reg_cache_default = taiko_reg_defaults,
+	.reg_cache_default = taiko_reset_reg_defaults,
 	.reg_word_size = 1,
 
 	.controls = taiko_snd_controls,
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index 739ab17..7ca8ff0 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -36,7 +36,7 @@
 				SND_JACK_BTN_6 | SND_JACK_BTN_7)
 
 extern const u8 taiko_reg_readable[TAIKO_CACHE_SIZE];
-extern const u8 taiko_reg_defaults[TAIKO_CACHE_SIZE];
+extern const u8 taiko_reset_reg_defaults[TAIKO_CACHE_SIZE];
 
 enum taiko_micbias_num {
 	TAIKO_MICBIAS1 = 0,
diff --git a/sound/soc/msm/apq8064-i2s.c b/sound/soc/msm/apq8064-i2s.c
index 162f39d..c489573 100644
--- a/sound/soc/msm/apq8064-i2s.c
+++ b/sound/soc/msm/apq8064-i2s.c
@@ -208,6 +208,7 @@
 
 static struct snd_soc_jack hs_jack;
 static struct snd_soc_jack button_jack;
+static atomic_t auxpcm_rsc_ref;
 
 static int apq8064_i2s_hs_detect_use_gpio = -1;
 module_param(apq8064_i2s_hs_detect_use_gpio, int, 0444);
@@ -952,14 +953,10 @@
 static int msm_mi2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 			struct snd_pcm_hw_params *params)
 {
-	struct snd_interval *rate = hw_param_interval(params,
-	SNDRV_PCM_HW_PARAM_RATE);
-
 	struct snd_interval *channels = hw_param_interval(params,
 			SNDRV_PCM_HW_PARAM_CHANNELS);
 
-	pr_debug("%s()\n", __func__);
-	rate->min = rate->max = 48000;
+	pr_debug("%s(): channels = %d\n", __func__, msm_mi2s_rx_ch);
 	channels->min = channels->max = msm_mi2s_rx_ch;
 
 	return 0;
@@ -968,15 +965,10 @@
 static int msm_mi2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 			struct snd_pcm_hw_params *params)
 {
-	struct snd_interval *rate = hw_param_interval(params,
-	SNDRV_PCM_HW_PARAM_RATE);
-
 	struct snd_interval *channels = hw_param_interval(params,
 			SNDRV_PCM_HW_PARAM_CHANNELS);
 
-	pr_debug("%s()\n", __func__);
-	rate->min = rate->max = 48000;
-
+	pr_debug("%s(): channels = %d\n", __func__, msm_mi2s_tx_ch);
 	channels->min = channels->max = msm_mi2s_tx_ch;
 
 	return 0;
@@ -986,14 +978,10 @@
 static int msm_i2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 			struct snd_pcm_hw_params *params)
 {
-	struct snd_interval *rate = hw_param_interval(params,
-	SNDRV_PCM_HW_PARAM_RATE);
-
 	struct snd_interval *channels = hw_param_interval(params,
 			SNDRV_PCM_HW_PARAM_CHANNELS);
 
-	pr_debug("%s()\n", __func__);
-	rate->min = rate->max = 48000;
+	pr_debug("%s(): channels = %d\n", __func__, msm_i2s_rx_ch);
 	channels->min = channels->max = msm_i2s_rx_ch;
 
 	return 0;
@@ -1002,15 +990,10 @@
 static int msm_i2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 			struct snd_pcm_hw_params *params)
 {
-	struct snd_interval *rate = hw_param_interval(params,
-	SNDRV_PCM_HW_PARAM_RATE);
-
 	struct snd_interval *channels = hw_param_interval(params,
 			SNDRV_PCM_HW_PARAM_CHANNELS);
 
-	pr_debug("%s()\n", __func__);
-	rate->min = rate->max = 48000;
-
+	pr_debug("%s(): channels = %d\n", __func__, msm_i2s_tx_ch);
 	channels->min = channels->max = msm_i2s_tx_ch;
 
 	return 0;
@@ -2095,8 +2078,10 @@
 {
 	int ret = 0;
 
-	pr_debug("%s(): substream = %s\n", __func__, substream->name);
-	ret = msm_aux_pcm_get_gpios();
+	pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+		__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+	if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
+		ret = msm_aux_pcm_get_gpios();
 	if (ret < 0) {
 		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
 		return -EINVAL;
@@ -2120,8 +2105,10 @@
 static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
 {
 
-	pr_debug("%s(): substream = %s\n", __func__, substream->name);
-	msm_aux_pcm_free_gpios();
+	pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+		__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+	if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+		msm_aux_pcm_free_gpios();
 }
 
 static void msm_shutdown(struct snd_pcm_substream *substream)
@@ -2710,6 +2697,7 @@
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
 		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+		.ops = &msm_auxpcm_be_ops,
 	},
 };
 
@@ -2785,6 +2773,7 @@
 
 	mutex_init(&cdc_mclk_mutex);
 	atomic_set(&mi2s_rsc_ref, 0);
+	atomic_set(&auxpcm_rsc_ref, 0);
 	return ret;
 
 }
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 80d6e5d..c8cf681 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -100,6 +100,7 @@
 
 static struct snd_soc_jack hs_jack;
 static struct snd_soc_jack button_jack;
+static atomic_t auxpcm_rsc_ref;
 
 static int apq8064_hs_detect_use_gpio = -1;
 module_param(apq8064_hs_detect_use_gpio, int, 0444);
@@ -1468,8 +1469,10 @@
 {
 	int ret = 0;
 
-	pr_debug("%s(): substream = %s\n", __func__, substream->name);
-	ret = msm_aux_pcm_get_gpios();
+	pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+		__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+	if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
+		ret = msm_aux_pcm_get_gpios();
 	if (ret < 0) {
 		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
 		return -EINVAL;
@@ -1493,8 +1496,10 @@
 static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
 {
 
-	pr_debug("%s(): substream = %s\n", __func__, substream->name);
-	msm_aux_pcm_free_gpios();
+	pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+		__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+	if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+		msm_aux_pcm_free_gpios();
 }
 
 static void msm_shutdown(struct snd_pcm_substream *substream)
@@ -1933,6 +1938,7 @@
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
 		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+		.ops = &msm_auxpcm_be_ops,
 	},
 	{
 		.name = LPASS_BE_STUB_RX,
@@ -2127,6 +2133,7 @@
 	}
 
 	mutex_init(&cdc_mclk_mutex);
+	atomic_set(&auxpcm_rsc_ref, 0);
 	return ret;
 
 }
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 499e4b6..957b656 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -134,7 +134,7 @@
 static int msm_slim_0_rx_ch = 1;
 static int msm_slim_0_tx_ch = 1;
 static int msm_hdmi_rx_ch = 8;
-
+static int mi2s_rate_variable;
 static struct clk *codec_clk;
 static int clk_users;
 
@@ -517,6 +517,7 @@
 static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
 static const char * const hdmi_rx_ch_text[] = {"Two", "Three", "Four",
 					"Five", "Six", "Seven", "Eight"};
+static const char * const mi2s_rate[] = {"Default", "Variable"};
 
 
 static const struct soc_enum msm_enum[] = {
@@ -524,6 +525,7 @@
 	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
 	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
 	SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(2, mi2s_rate),
 
 };
 
@@ -584,6 +586,20 @@
 	return 1;
 }
 
+static int msm_mi2s_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	mi2s_rate_variable = ucontrol->value.integer.value[0];
+	pr_debug("%s: mi2s_rate_variable = %d\n", __func__, mi2s_rate_variable);
+	return 0;
+}
+
+static int msm_mi2s_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = mi2s_rate_variable;
+	return 0;
+}
 
 static const struct snd_kcontrol_new tabla_msm_controls[] = {
 	SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_get_spk,
@@ -594,6 +610,9 @@
 		msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
 	SOC_ENUM_EXT("HDMI_RX Channels", msm_enum[3],
 		msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
+	SOC_ENUM_EXT("SEC RX Rate", msm_enum[4],
+					msm_mi2s_rate_get,
+					msm_mi2s_rate_put),
 
 };
 
@@ -813,11 +832,16 @@
 static int msm_be_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 			struct snd_pcm_hw_params *params)
 {
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
 
 	struct snd_interval *channels = hw_param_interval(params,
 					SNDRV_PCM_HW_PARAM_CHANNELS);
 
-	pr_debug("%s()\n", __func__);
+	pr_debug("%s mi2s_rate_variable = %d\n", __func__, mi2s_rate_variable);
+	/*Configure the sample rate as 48000 KHz for the LPCM playback*/
+	if (!mi2s_rate_variable)
+		rate->min = rate->max = 48000;
 	channels->min =  channels->max = 2;
 
 	return 0;
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 78b3abc..550a492 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -31,6 +31,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/android_pmem.h>
 #include <sound/timer.h>
+#include <mach/qdsp6v2/q6core.h>
 
 #include "msm-compr-q6.h"
 #include "msm-pcm-routing.h"
@@ -332,6 +333,7 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct compr_audio *compr = runtime->private_data;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct msm_audio *prtd = &compr->prtd;
 	struct asm_aac_cfg aac_cfg;
 	struct asm_wma_cfg wma_cfg;
@@ -373,11 +375,14 @@
 			pr_err("%s: CMD Format block failed\n", __func__);
 		break;
 	case SND_AUDIOCODEC_AC3_PASS_THROUGH:
-		pr_debug("compressd playback, no need to send"
-			" the decoder params\n");
-		break;
 	case SND_AUDIOCODEC_DTS_PASS_THROUGH:
-		pr_debug("compressd DTS playback,dont send the decoder params\n");
+		pr_debug("compressd playback, no need to send decoder params");
+		pr_debug("decoder id: %d\n",
+			compr->info.codec_param.codec.id);
+		msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream,
+					1);
 		break;
 	case SND_AUDIOCODEC_WMA:
 		pr_debug("SND_AUDIOCODEC_WMA\n");
@@ -470,6 +475,7 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct compr_audio *compr = runtime->private_data;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct msm_audio *prtd = &compr->prtd;
 	struct audio_buffer *buf = prtd->audio_client->port[OUT].buf;
 	struct snd_codec *codec = &compr->info.codec_param.codec;
@@ -499,6 +505,13 @@
 			pr_err("%s: CMD Format block" \
 				"failed: %d\n", __func__, ret);
 		break;
+	case SND_AUDIOCODEC_PCM:
+		pr_debug("SND_AUDIOCODEC_PCM\n");
+		ret = q6asm_enc_cfg_blk_multi_ch_pcm(prtd->audio_client,
+			 prtd->samp_rate, prtd->channel_mode);
+		if (ret < 0)
+			pr_info("%s: CMD Format block failed\n", __func__);
+		break;
 	default:
 		pr_debug("No config for codec %d\n", codec->id);
 	}
@@ -511,6 +524,7 @@
 		read_param.uid = i;
 		switch (codec->id) {
 		case SND_AUDIOCODEC_AMRWB:
+		case SND_AUDIOCODEC_PCM:
 			read_param.len = prtd->pcm_count
 					- COMPRE_CAPTURE_HEADER_SIZE;
 			read_param.paddr = (unsigned long)(buf[i].phys)
@@ -521,17 +535,30 @@
 					buf[i].data);
 			q6asm_async_read(prtd->audio_client, &read_param);
 			break;
-		default:
+		case SND_AUDIOCODEC_PASS_THROUGH:
 			read_param.paddr = (unsigned long)(buf[i].phys);
 			q6asm_async_read_compressed(prtd->audio_client,
 				&read_param);
 			break;
+		default:
+			pr_err("Invalid format");
+			ret = -EINVAL;
+			break;
 		}
 	}
 	prtd->periods = runtime->periods;
 
 	prtd->enabled = 1;
 
+	if (compr->info.codec_param.codec.id ==
+			SND_AUDIOCODEC_AC3_PASS_THROUGH ||
+			compr->info.codec_param.codec.id ==
+			SND_AUDIOCODEC_DTS_PASS_THROUGH)
+		msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream,
+					1);
+
 	return ret;
 }
 
@@ -539,7 +566,6 @@
 {
 	int ret = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct compr_audio *compr = runtime->private_data;
 	struct msm_audio *prtd = &compr->prtd;
 
@@ -547,28 +573,7 @@
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		prtd->pcm_irq_pos = 0;
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			if (compr->info.codec_param.codec.id ==
-				SND_AUDIOCODEC_AC3_PASS_THROUGH ||
-					compr->info.codec_param.codec.id ==
-					SND_AUDIOCODEC_DTS_PASS_THROUGH) {
-				msm_pcm_routing_reg_psthr_stream(
-					soc_prtd->dai_link->be_id,
-					prtd->session_id, substream->stream,
-					1);
-			}
-		} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			switch (compr->info.codec_param.codec.id) {
-			case SND_AUDIOCODEC_AMRWB:
-				break;
-			default:
-				msm_pcm_routing_reg_psthr_stream(
-					soc_prtd->dai_link->be_id,
-					prtd->session_id, substream->stream,
-					1);
-				break;
-			}
-		}
+		/* intentional fall-through */
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		pr_debug("%s: Trigger start\n", __func__);
@@ -576,29 +581,6 @@
 		atomic_set(&prtd->start, 1);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
-		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			if (compr->info.codec_param.codec.id ==
-					SND_AUDIOCODEC_AC3_PASS_THROUGH ||
-					compr->info.codec_param.codec.id ==
-					SND_AUDIOCODEC_DTS_PASS_THROUGH) {
-				msm_pcm_routing_reg_psthr_stream(
-					soc_prtd->dai_link->be_id,
-					prtd->session_id, substream->stream,
-					0);
-			}
-		} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			switch (compr->info.codec_param.codec.id) {
-			case SND_AUDIOCODEC_AMRWB:
-				break;
-			default:
-				msm_pcm_routing_reg_psthr_stream(
-					soc_prtd->dai_link->be_id,
-					prtd->session_id, substream->stream,
-					0);
-				break;
-			}
-		}
 		atomic_set(&prtd->start, 0);
 		break;
 	case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -620,7 +602,7 @@
 {
 	pr_debug("%s\n", __func__);
 	/* MP3 Block */
-	compr->info.compr_cap.num_codecs = 10;
+	compr->info.compr_cap.num_codecs = 12;
 	compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
 	compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
 	compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
@@ -635,6 +617,8 @@
 	compr->info.compr_cap.codecs[7] = SND_AUDIOCODEC_DTS_PASS_THROUGH;
 	compr->info.compr_cap.codecs[8] = SND_AUDIOCODEC_AMRWB;
 	compr->info.compr_cap.codecs[9] = SND_AUDIOCODEC_AMRWBPLUS;
+	compr->info.compr_cap.codecs[10] = SND_AUDIOCODEC_PASS_THROUGH;
+	compr->info.compr_cap.codecs[11] = SND_AUDIOCODEC_PCM;
 	/* Add new codecs here and update num_codecs*/
 }
 
@@ -753,11 +737,18 @@
 	compressed_audio.prtd = NULL;
 	q6asm_audio_client_buf_free_contiguous(dir,
 				prtd->audio_client);
-	if (!(compr->info.codec_param.codec.id ==
-			SND_AUDIOCODEC_AC3_PASS_THROUGH))
+	if ((compr->info.codec_param.codec.id !=
+			SND_AUDIOCODEC_AC3_PASS_THROUGH) &&
+			(compr->info.codec_param.codec.id !=
+			SND_AUDIOCODEC_DTS_PASS_THROUGH))
 		msm_pcm_routing_dereg_phy_stream(
 			soc_prtd->dai_link->be_id,
 			SNDRV_PCM_STREAM_PLAYBACK);
+	else
+		msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream,
+					0);
 	q6asm_audio_client_free(prtd->audio_client);
 	kfree(prtd);
 	return 0;
@@ -776,8 +767,17 @@
 	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
 	q6asm_audio_client_buf_free_contiguous(dir,
 				prtd->audio_client);
-	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
-				SNDRV_PCM_STREAM_CAPTURE);
+	if (compr->info.codec_param.codec.id ==
+			SND_AUDIOCODEC_AC3_PASS_THROUGH ||
+			compr->info.codec_param.codec.id ==
+			SND_AUDIOCODEC_DTS_PASS_THROUGH)
+		msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream,
+					0);
+	else
+		msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+					SNDRV_PCM_STREAM_CAPTURE);
 	q6asm_audio_client_free(prtd->audio_client);
 	kfree(prtd);
 
@@ -909,12 +909,30 @@
 					prtd->audio_client->perf_mode,
 					prtd->session_id, substream->stream);
 			break;
-		default:
+		case SND_AUDIOCODEC_PCM:
+			pr_debug("q6asm_open_read(FORMAT_PCM)\n");
+			ret = q6asm_open_read(prtd->audio_client,
+				FORMAT_MULTI_CHANNEL_LINEAR_PCM);
+			if (ret < 0) {
+				pr_err("%s: compressed Session open failed\n",
+					__func__);
+				return -ENOMEM;
+			}
+			pr_debug("msm_pcm_routing_reg_phy_stream\n");
+			msm_pcm_routing_reg_phy_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->audio_client->perf_mode,
+					prtd->session_id, substream->stream);
+			break;
+		case SND_AUDIOCODEC_PASS_THROUGH:
 			pr_debug("q6asm_open_read_compressed(COMPRESSED_META_DATA_MODE)\n");
 			ret = q6asm_open_read_compressed(prtd->audio_client,
 				MAX_NUM_FRAMES_PER_BUFFER,
 				COMPRESSED_META_DATA_MODE);
 			break;
+		default:
+			pr_err("Invalid codec for compressed session open\n");
+			return -EFAULT;
 		}
 
 		if (ret < 0) {
@@ -1047,13 +1065,37 @@
 			pr_debug("SND_AUDIOCODEC_DTS_PASS_THROUGH\n");
 			compr->codec = FORMAT_DTS;
 			break;
-		case SND_AUDIOCODEC_DTS:
+		case SND_AUDIOCODEC_DTS: {
+			char modelId[128];
+			struct snd_dec_dts opt_dts =
+				compr->info.codec_param.codec.options.dts;
+			int modelIdLength = opt_dts.modelIdLength;
 			pr_debug("SND_AUDIOCODEC_DTS\n");
+			if (copy_from_user(modelId, (void *)opt_dts.modelId,
+				modelIdLength))
+				pr_err("%s: ERROR: copy modelId\n", __func__);
+			modelId[modelIdLength] = '\0';
+			pr_debug("%s: Received modelId =%s,length=%d\n",
+				__func__, modelId, modelIdLength);
+			core_set_dts_model_id(modelIdLength, modelId);
 			compr->codec = FORMAT_DTS;
+			}
 			break;
-		case SND_AUDIOCODEC_DTS_LBR:
-			pr_debug("SND_AUDIOCODEC_DTS\n");
+		case SND_AUDIOCODEC_DTS_LBR:{
+			char modelId[128];
+			struct snd_dec_dts opt_dts =
+				compr->info.codec_param.codec.options.dts;
+			int modelIdLength = opt_dts.modelIdLength;
+			pr_debug("SND_AUDIOCODEC_DTS_LBR\n");
+			if (copy_from_user(modelId, (void *)opt_dts.modelId,
+					modelIdLength))
+				pr_err("%s: ERROR: copy modelId\n", __func__);
+			modelId[modelIdLength] = '\0';
+			pr_debug("%s: Received modelId =%s,length=%d\n",
+				__func__, modelId, modelIdLength);
+			core_set_dts_model_id(modelIdLength, modelId);
 			compr->codec = FORMAT_DTS_LBR;
+			}
 			break;
 		case SND_AUDIOCODEC_AMRWB:
 			pr_debug("msm_compr_ioctl SND_AUDIOCODEC_AMRWB\n");
@@ -1063,11 +1105,19 @@
 			pr_debug("msm_compr_ioctl SND_AUDIOCODEC_AMRWBPLUS\n");
 			compr->codec = FORMAT_AMR_WB_PLUS;
 			break;
-		default:
-			/*Needed for the HDMI IN compressed use case*/
-			pr_debug("FORMAT_LINEAR_PCM\n");
-			compr->codec = FORMAT_LINEAR_PCM;
+		case SND_AUDIOCODEC_PASS_THROUGH:
+			/* format pass through is used for HDMI IN compressed
+			   where the decoder format is indicated by LPASS */
+			pr_debug("msm_compr_ioctl SND_AUDIOCODEC_PASSTHROUGH\n");
+			compr->codec = FORMAT_PASS_THROUGH;
 			break;
+		case SND_AUDIOCODEC_PCM:
+			pr_debug("msm_compr_ioctl SND_AUDIOCODEC_PCM\n");
+			compr->codec = FORMAT_MULTI_CHANNEL_LINEAR_PCM;
+			break;
+		default:
+			pr_err("msm_compr_ioctl failed..unknown codec\n");
+			return -EFAULT;
 		}
 		return 0;
 	case SNDRV_PCM_IOCTL1_RESET:
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index c8d4b02..4725e8e 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -66,6 +66,7 @@
 
 static struct snd_soc_jack hs_jack;
 static struct snd_soc_jack button_jack;
+static atomic_t auxpcm_rsc_ref;
 
 static int msm8930_enable_codec_ext_clk(
 		struct snd_soc_codec *codec, int enable,
@@ -860,8 +861,10 @@
 {
 	int ret = 0;
 
-	pr_debug("%s(): substream = %s\n", __func__, substream->name);
-	ret = msm8930_aux_pcm_get_gpios();
+	pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+		__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+	if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
+		ret = msm8930_aux_pcm_get_gpios();
 	if (ret < 0) {
 		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
 		return -EINVAL;
@@ -872,8 +875,10 @@
 
 static void msm8930_auxpcm_shutdown(struct snd_pcm_substream *substream)
 {
-	pr_debug("%s(): substream = %s\n", __func__, substream->name);
-	msm8930_aux_pcm_free_gpios();
+	pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+		__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+	if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+		msm8930_aux_pcm_free_gpios();
 }
 
 static void msm8930_shutdown(struct snd_pcm_substream *substream)
@@ -1229,6 +1234,7 @@
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
 		.be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
+		.ops = &msm8930_auxpcm_be_ops,
 	},
 	/* Incall Music BACK END DAI Link */
 	{
@@ -1336,6 +1342,7 @@
 	} else
 		msm8930_headset_gpios_configured = 1;
 
+	atomic_set(&auxpcm_rsc_ref, 0);
 	return ret;
 
 }
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 1338e2f..59d118e 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -83,6 +83,7 @@
 
 static struct snd_soc_jack hs_jack;
 static struct snd_soc_jack button_jack;
+static atomic_t auxpcm_rsc_ref;
 
 static bool hs_detect_use_gpio;
 module_param(hs_detect_use_gpio, bool, 0444);
@@ -1131,8 +1132,11 @@
 {
 	int ret = 0;
 
-	pr_debug("%s(): substream = %s\n", __func__, substream->name);
-	ret = msm8960_aux_pcm_get_gpios();
+	pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+		__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+	if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
+		ret = msm8960_aux_pcm_get_gpios();
+
 	if (ret < 0) {
 		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
 		return -EINVAL;
@@ -1142,9 +1146,10 @@
 
 static void msm8960_auxpcm_shutdown(struct snd_pcm_substream *substream)
 {
-
-	pr_debug("%s(): substream = %s\n", __func__, substream->name);
-	msm8960_aux_pcm_free_gpios();
+	pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+		__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+	if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+		msm8960_aux_pcm_free_gpios();
 }
 
 static void msm8960_shutdown(struct snd_pcm_substream *substream)
@@ -1522,6 +1527,7 @@
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
 		.be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
+		.ops = &msm8960_auxpcm_be_ops,
 	},
 	/* Incall Music BACK END DAI Link */
 	{
@@ -1819,7 +1825,7 @@
 	}
 
 	mutex_init(&cdc_mclk_mutex);
-
+	atomic_set(&auxpcm_rsc_ref, 0);
 	return ret;
 
 }
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 7e56a42..92b7324 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -88,6 +88,7 @@
 static struct mutex cdc_mclk_mutex;
 static struct q_clkdiv *codec_clk;
 static int clk_users;
+static atomic_t auxpcm_rsc_ref;
 
 static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
 {
@@ -553,8 +554,10 @@
 {
 	int ret = 0;
 
-	pr_debug("%s(): substream = %s\n", __func__, substream->name);
-	ret = msm_aux_pcm_get_gpios();
+	pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+		__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+	if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
+		ret = msm_aux_pcm_get_gpios();
 	if (ret < 0) {
 		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
 		return -EINVAL;
@@ -565,8 +568,10 @@
 static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
 {
 
-	pr_debug("%s(): substream = %s\n", __func__, substream->name);
-	msm_aux_pcm_free_gpios();
+	pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+		__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+	if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+		msm_aux_pcm_free_gpios();
 }
 static struct snd_soc_ops msm_auxpcm_be_ops = {
 	.startup = msm_auxpcm_startup,
@@ -904,6 +909,7 @@
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
 		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+		.ops = &msm_auxpcm_be_ops,
 	},
 	/* Backend DAI Links */
 	{
@@ -1041,6 +1047,8 @@
 		goto err;
 	}
 	mutex_init(&cdc_mclk_mutex);
+	atomic_set(&auxpcm_rsc_ref, 0);
+
 	return 0;
 err:
 	devm_kfree(&pdev->dev, pdata);
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 3a226b4..b086b8e 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -529,7 +529,7 @@
 					}
 					buf[cnt].handle = ion_alloc
 						(buf[cnt].client, bufsz, SZ_4K,
-						(0x1 << ION_AUDIO_HEAP_ID));
+						(0x1 << ION_AUDIO_HEAP_ID), 0);
 					if (IS_ERR_OR_NULL((void *)
 						buf[cnt].handle)) {
 						pr_err("%s: ION memory allocation for AUDIO failed\n",
@@ -551,8 +551,7 @@
 					}
 
 					buf[cnt].data = ion_map_kernel
-					(buf[cnt].client, buf[cnt].handle,
-							 0);
+					(buf[cnt].client, buf[cnt].handle);
 					if (IS_ERR_OR_NULL((void *)
 						buf[cnt].data)) {
 						pr_err("%s: ION memory mapping for AUDIO failed\n",
@@ -665,7 +664,7 @@
 		goto fail;
 	}
 	buf[0].handle = ion_alloc(buf[0].client, bufsz * bufcnt, SZ_4K,
-				  (0x1 << ION_AUDIO_HEAP_ID));
+				  (0x1 << ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL((void *) buf[0].handle)) {
 		pr_err("%s: ION memory allocation for AUDIO failed\n",
 			__func__);
@@ -682,7 +681,7 @@
 		goto fail;
 	}
 
-	buf[0].data = ion_map_kernel(buf[0].client, buf[0].handle, 0);
+	buf[0].data = ion_map_kernel(buf[0].client, buf[0].handle);
 	if (IS_ERR_OR_NULL((void *) buf[0].data)) {
 		pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
 		mutex_unlock(&ac->cmd_lock);
@@ -876,8 +875,9 @@
 		case ASM_STREAM_CMD_OPEN_READ_COMPRESSED:
 			if (atomic_read(&ac->cmd_state) && wakeup_flag) {
 				atomic_set(&ac->cmd_state, 0);
-				if (payload[1] == ADSP_EUNSUPPORTED) {
-					pr_debug("paload[1]:%d unsupported",
+				if (payload[1] == ADSP_EUNSUPPORTED ||
+					payload[1] == ADSP_EFAILED) {
+					pr_debug("payload[1]:%d unsupported",
 								payload[1]);
 					atomic_set(&ac->cmd_response, 1);
 				}
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index 2a21dfa..cb2e39b 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -4061,7 +4061,7 @@
 
 	common.ion_handle = ion_alloc(common.ion_client,
 				TOTAL_VOICE_CAL_SIZE,
-				SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+				SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL((void *) common.ion_handle)) {
 		pr_err("%s: ION memory allocation failed\n",
 			__func__);
@@ -4076,8 +4076,7 @@
 		goto err_ion_handle;
 	}
 
-	kvptr = ion_map_kernel(common.ion_client,
-				common.ion_handle, 0);
+	kvptr = ion_map_kernel(common.ion_client, common.ion_handle);
 	if (IS_ERR_OR_NULL(kvptr)) {
 		pr_err("%s: ION memory mapping failed\n", __func__);
 		goto err_ion_handle;
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 6f3249a..bbd43f7 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -25,13 +25,25 @@
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/control.h>
+#include <sound/q6asm-v2.h>
+#include <sound/pcm_params.h>
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
 #include <linux/android_pmem.h>
+#include <sound/timer.h>
 
 #include "msm-compr-q6-v2.h"
 #include "msm-pcm-routing-v2.h"
 
+#define COMPRE_CAPTURE_NUM_PERIODS	16
+/* Allocate the worst case frame size for compressed audio */
+#define COMPRE_CAPTURE_HEADER_SIZE	(sizeof(struct snd_compr_audio_info))
+#define COMPRE_CAPTURE_MAX_FRAME_SIZE	(6144)
+#define COMPRE_CAPTURE_PERIOD_SIZE	((COMPRE_CAPTURE_MAX_FRAME_SIZE + \
+					  COMPRE_CAPTURE_HEADER_SIZE) * \
+					  MAX_NUM_FRAMES_PER_BUFFER)
+#define COMPRE_OUTPUT_METADATA_SIZE	(sizeof(struct output_meta_data_st))
+
 struct snd_msm {
 	struct msm_audio *prtd;
 	unsigned volume;
@@ -40,7 +52,7 @@
 
 static struct audio_locks the_locks;
 
-static struct snd_pcm_hardware msm_compr_hardware_playback = {
+static struct snd_pcm_hardware msm_compr_hardware_capture = {
 	.info =		 (SNDRV_PCM_INFO_MMAP |
 				SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				SNDRV_PCM_INFO_MMAP_VALID |
@@ -51,12 +63,33 @@
 	.rate_min =	     8000,
 	.rate_max =	     48000,
 	.channels_min =	 1,
-	.channels_max =	 2,
+	.channels_max =	 8,
+	.buffer_bytes_max =
+		COMPRE_CAPTURE_PERIOD_SIZE * COMPRE_CAPTURE_NUM_PERIODS ,
+	.period_bytes_min =	COMPRE_CAPTURE_PERIOD_SIZE,
+	.period_bytes_max = COMPRE_CAPTURE_PERIOD_SIZE,
+	.periods_min =	  COMPRE_CAPTURE_NUM_PERIODS,
+	.periods_max =	  COMPRE_CAPTURE_NUM_PERIODS,
+	.fifo_size =	    0,
+};
+
+static struct snd_pcm_hardware msm_compr_hardware_playback = {
+	.info =		 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =	      SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =		SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
+	.rate_min =	     8000,
+	.rate_max =	     48000,
+	.channels_min =	 1,
+	.channels_max =	 8,
 	.buffer_bytes_max =     1200 * 1024 * 2,
-	.period_bytes_min =	4800,
+	.period_bytes_min =	2400,
 	.period_bytes_max =     1200 * 1024,
 	.periods_min =	  2,
-	.periods_max =	  512,
+	.periods_max =	  1024,
 	.fifo_size =	    0,
 };
 
@@ -79,8 +112,13 @@
 	struct snd_pcm_substream *substream = prtd->substream;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct audio_aio_write_param param;
+	struct audio_aio_read_param read_param;
 	struct audio_buffer *buf = NULL;
+	struct output_meta_data_st output_meta_data;
+	uint32_t *ptrmem = (uint32_t *)payload;
 	int i = 0;
+	int time_stamp_flag = 0;
+	int buffer_length = 0;
 
 	pr_debug("%s opcode =%08x\n", __func__, opcode);
 	switch (opcode) {
@@ -91,6 +129,9 @@
 		prtd->pcm_irq_pos += prtd->pcm_count;
 		if (atomic_read(&prtd->start))
 			snd_pcm_period_elapsed(substream);
+		else
+			if (substream->timer_running)
+				snd_timer_interrupt(substream->timer, 1);
 		atomic_inc(&prtd->out_count);
 		wake_up(&the_locks.write_wait);
 		if (!atomic_read(&prtd->start)) {
@@ -98,9 +139,6 @@
 			break;
 		} else
 			atomic_set(&prtd->pending_buffer, 0);
-
-		if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
-			break;
 		buf = prtd->audio_client->port[IN].buf;
 		pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
 				__func__, prtd->pcm_count, prtd->out_head);
@@ -109,14 +147,38 @@
 				((unsigned int)buf[0].phys
 				+ (prtd->out_head * prtd->pcm_count)));
 
+		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
+			time_stamp_flag = SET_TIMESTAMP;
+			memcpy(&output_meta_data, (char *)(buf->data +
+			prtd->out_head * prtd->pcm_count),
+			COMPRE_OUTPUT_METADATA_SIZE);
+		} else {
+			time_stamp_flag = NO_TIMESTAMP;
+			memset(&output_meta_data, 0,
+				 COMPRE_OUTPUT_METADATA_SIZE);
+			output_meta_data.frame_size = prtd->pcm_count;
+		}
+		buffer_length = output_meta_data.frame_size;
+		pr_debug("meta_data_length: %d, frame_length: %d\n",
+			 output_meta_data.meta_data_length,
+			 output_meta_data.frame_size);
+		pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
+			 output_meta_data.timestamp_msw,
+			 output_meta_data.timestamp_lsw);
+		if (buffer_length == 0) {
+			pr_debug("Recieved a zero length buffer-break out");
+			break;
+		}
 		param.paddr = (unsigned long)buf[0].phys
-				+ (prtd->out_head * prtd->pcm_count);
-		param.len = prtd->pcm_count;
-		param.msw_ts = 0;
-		param.lsw_ts = 0;
-		param.flags = NO_TIMESTAMP;
+				+ (prtd->out_head * prtd->pcm_count)
+				+ output_meta_data.meta_data_length;
+		param.len = buffer_length;
+		param.msw_ts = output_meta_data.timestamp_msw;
+		param.lsw_ts = output_meta_data.timestamp_lsw;
+		param.flags = time_stamp_flag;
 		param.uid =  (unsigned long)buf[0].phys
-				+ (prtd->out_head * prtd->pcm_count);
+				+ (prtd->out_head * prtd->pcm_count
+				+ output_meta_data.meta_data_length);
 		for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
 					i++, ++ptrmem)
 			pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
@@ -131,12 +193,60 @@
 	}
 	case ASM_DATA_EVENT_RENDERED_EOS:
 		pr_debug("ASM_DATA_CMDRSP_EOS\n");
-		prtd->cmd_ack = 1;
-		wake_up(&the_locks.eos_wait);
+		if (atomic_read(&prtd->eos)) {
+			pr_debug("ASM_DATA_CMDRSP_EOS wake up\n");
+			prtd->cmd_ack = 1;
+			wake_up(&the_locks.eos_wait);
+			atomic_set(&prtd->eos, 0);
+		}
 		break;
+	case ASM_DATA_EVENT_READ_DONE_V2: {
+		pr_debug("ASM_DATA_EVENT_READ_DONE\n");
+		pr_debug("buf = %p, data = 0x%X, *data = %p,\n"
+			 "prtd->pcm_irq_pos = %d\n",
+				prtd->audio_client->port[OUT].buf,
+			 *(uint32_t *)prtd->audio_client->port[OUT].buf->data,
+				prtd->audio_client->port[OUT].buf->data,
+				prtd->pcm_irq_pos);
+
+		memcpy(prtd->audio_client->port[OUT].buf->data +
+			   prtd->pcm_irq_pos, (ptrmem + 2),
+			   COMPRE_CAPTURE_HEADER_SIZE);
+		pr_debug("buf = %p, updated data = 0x%X, *data = %p\n",
+				prtd->audio_client->port[OUT].buf,
+			*(uint32_t *)(prtd->audio_client->port[OUT].buf->data +
+				prtd->pcm_irq_pos),
+				prtd->audio_client->port[OUT].buf->data);
+		if (!atomic_read(&prtd->start))
+			break;
+		pr_debug("frame size=%d, buffer = 0x%X\n", ptrmem[2],
+				ptrmem[1]);
+		if (ptrmem[2] > COMPRE_CAPTURE_MAX_FRAME_SIZE) {
+			pr_err("Frame length exceeded the max length");
+			break;
+		}
+		buf = prtd->audio_client->port[OUT].buf;
+		pr_debug("pcm_irq_pos=%d, buf[0].phys = 0x%X\n",
+				prtd->pcm_irq_pos, (uint32_t)buf[0].phys);
+		read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE;
+		read_param.paddr = (unsigned long)(buf[0].phys) +
+			prtd->pcm_irq_pos + COMPRE_CAPTURE_HEADER_SIZE;
+		prtd->pcm_irq_pos += prtd->pcm_count;
+
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+
+		q6asm_async_read(prtd->audio_client, &read_param);
+		break;
+	}
 	case APR_BASIC_RSP_RESULT: {
 		switch (payload[0]) {
 		case ASM_SESSION_CMD_RUN_V2: {
+			if (substream->stream
+				!= SNDRV_PCM_STREAM_PLAYBACK) {
+				atomic_set(&prtd->start, 1);
+				break;
+			}
 			if (!atomic_read(&prtd->pending_buffer))
 				break;
 			pr_debug("%s:writing %d bytes of buffer[%d] to dsp\n",
@@ -146,12 +256,32 @@
 				__func__, prtd->out_head,
 				((unsigned int)buf[0].phys
 				+ (prtd->out_head * prtd->pcm_count)));
-			param.paddr = (unsigned long)buf[prtd->out_head].phys;
-			param.len = prtd->pcm_count;
-			param.msw_ts = 0;
-			param.lsw_ts = 0;
-			param.flags = NO_TIMESTAMP;
-			param.uid =  (unsigned long)buf[prtd->out_head].phys;
+			if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
+				time_stamp_flag = SET_TIMESTAMP;
+				memcpy(&output_meta_data, (char *)(buf->data +
+				prtd->out_head * prtd->pcm_count),
+				COMPRE_OUTPUT_METADATA_SIZE);
+			} else {
+				time_stamp_flag = NO_TIMESTAMP;
+				memset(&output_meta_data, 0,
+				 COMPRE_OUTPUT_METADATA_SIZE);
+				output_meta_data.frame_size = prtd->pcm_count;
+			}
+			buffer_length = output_meta_data.frame_size;
+			pr_debug("meta_data_length: %d, frame_length: %d\n",
+				 output_meta_data.meta_data_length,
+				 output_meta_data.frame_size);
+			pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
+				 output_meta_data.timestamp_msw,
+				 output_meta_data.timestamp_lsw);
+			param.paddr = (unsigned long)buf[prtd->out_head].phys
+					+ output_meta_data.meta_data_length;
+			param.len = buffer_length;
+			param.msw_ts = output_meta_data.timestamp_msw;
+			param.lsw_ts = output_meta_data.timestamp_lsw;
+			param.flags = time_stamp_flag;
+			param.uid =  (unsigned long)buf[prtd->out_head].phys
+					+ output_meta_data.meta_data_length;
 			if (q6asm_async_write(prtd->audio_client,
 						&param) < 0)
 				pr_err("%s:q6asm_async_write failed\n",
@@ -166,7 +296,7 @@
 		case ASM_STREAM_CMD_FLUSH:
 			pr_debug("ASM_STREAM_CMD_FLUSH\n");
 			prtd->cmd_ack = 1;
-			wake_up(&the_locks.eos_wait);
+			wake_up(&the_locks.flush_wait);
 			break;
 		default:
 			break;
@@ -187,7 +317,7 @@
 	struct asm_aac_cfg aac_cfg;
 	int ret;
 
-	pr_debug("%s\n", __func__);
+	pr_debug("compressed stream prepare\n");
 	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
 	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
 	prtd->pcm_irq_pos = 0;
@@ -205,7 +335,7 @@
 		/* No media format block for mp3 */
 		break;
 	case SND_AUDIOCODEC_AAC:
-		pr_debug("SND_AUDIOCODEC_AAC\n");
+		pr_debug("%s: SND_AUDIOCODEC_AAC\n", __func__);
 		memset(&aac_cfg, 0x0, sizeof(struct asm_aac_cfg));
 		aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
 		aac_cfg.format = 0x03;
@@ -226,10 +356,83 @@
 	return 0;
 }
 
+static int msm_compr_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct compr_audio *compr = runtime->private_data;
+	struct msm_audio *prtd = &compr->prtd;
+	struct audio_buffer *buf = prtd->audio_client->port[OUT].buf;
+	struct snd_codec *codec = &compr->info.codec_param.codec;
+	struct audio_aio_read_param read_param;
+	int ret = 0;
+	int i;
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+
+	if (prtd->enabled)
+		return ret;
+	read_param.len = prtd->pcm_count;
+
+	switch (codec->id) {
+	case SND_AUDIOCODEC_AMRWB:
+		pr_debug("SND_AUDIOCODEC_AMRWB\n");
+		ret = q6asm_enc_cfg_blk_amrwb(prtd->audio_client,
+			MAX_NUM_FRAMES_PER_BUFFER,
+			codec->options.generic.reserved[0] /*bitrate 0-8*/,
+			codec->options.generic.reserved[1] /*dtx mode 0/1*/);
+		if (ret < 0)
+			pr_err("%s: CMD Format block" \
+				"failed: %d\n", __func__, ret);
+		break;
+	default:
+		pr_debug("No config for codec %d\n", codec->id);
+	}
+	pr_debug("%s: Samp_rate = %d, Channel = %d, pcm_size = %d,\n"
+			 "pcm_count = %d, periods = %d\n",
+			 __func__, prtd->samp_rate, prtd->channel_mode,
+			 prtd->pcm_size, prtd->pcm_count, runtime->periods);
+
+	for (i = 0; i < runtime->periods; i++) {
+		read_param.uid = i;
+		switch (codec->id) {
+		case SND_AUDIOCODEC_AMRWB:
+			read_param.len = prtd->pcm_count
+					- COMPRE_CAPTURE_HEADER_SIZE;
+			read_param.paddr = (unsigned long)(buf[i].phys)
+					+ COMPRE_CAPTURE_HEADER_SIZE;
+			pr_debug("Push buffer [%d] to DSP, "\
+					"paddr: %p, vaddr: %p\n",
+					i, (void *) read_param.paddr,
+					buf[i].data);
+			q6asm_async_read(prtd->audio_client, &read_param);
+			break;
+		default:
+			read_param.paddr = (unsigned long)(buf[i].phys);
+			/*q6asm_async_read_compressed(prtd->audio_client,
+				&read_param);*/
+			pr_debug("%s: To add support for read compressed\n",
+								__func__);
+			ret = -EINVAL;
+			break;
+		}
+	}
+	prtd->periods = runtime->periods;
+
+	prtd->enabled = 1;
+
+	return ret;
+}
+
 static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	int ret = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct compr_audio *compr = runtime->private_data;
 	struct msm_audio *prtd = &compr->prtd;
 
@@ -237,6 +440,17 @@
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		prtd->pcm_irq_pos = 0;
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+			switch (compr->info.codec_param.codec.id) {
+			case SND_AUDIOCODEC_AMRWB:
+				break;
+			default:
+				msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream);
+				break;
+			}
+		}
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		pr_debug("%s: Trigger start\n", __func__);
@@ -245,6 +459,17 @@
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+			switch (compr->info.codec_param.codec.id) {
+			case SND_AUDIOCODEC_AMRWB:
+				break;
+			default:
+				msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream);
+				break;
+			}
+		}
 		atomic_set(&prtd->start, 0);
 		break;
 	case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -266,7 +491,7 @@
 {
 	pr_debug("%s\n", __func__);
 	/* MP3 Block */
-	compr->info.compr_cap.num_codecs = 1;
+	compr->info.compr_cap.num_codecs = 2;
 	compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
 	compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
 	compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
@@ -294,10 +519,6 @@
 		.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
 	};
 
-	/* Capture path */
-	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-		return -EINVAL;
-
 	pr_debug("%s\n", __func__);
 	compr = kzalloc(sizeof(struct compr_audio), GFP_KERNEL);
 	if (compr == NULL) {
@@ -313,12 +534,18 @@
 		kfree(prtd);
 		return -ENOMEM;
 	}
-	runtime->hw = msm_compr_hardware_playback;
 
 	pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
 
 	prtd->session_id = prtd->audio_client->session;
-	prtd->cmd_ack = 1;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		runtime->hw = msm_compr_hardware_playback;
+		prtd->cmd_ack = 1;
+	} else {
+		runtime->hw = msm_compr_hardware_capture;
+	}
+
 
 	ret = snd_pcm_hw_constraint_list(runtime, 0,
 			SNDRV_PCM_HW_PARAM_RATE,
@@ -333,9 +560,11 @@
 
 	prtd->dsp_cnt = 0;
 	atomic_set(&prtd->pending_buffer, 1);
-	compr->codec = FORMAT_MP3;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		compr->codec = FORMAT_MP3;
 	populate_codec_list(compr, runtime);
 	runtime->private_data = compr;
+	atomic_set(&prtd->eos, 0);
 	compressed_audio.prtd =  &compr->prtd;
 	ret = compressed_set_volume(compressed_audio.volume);
 	if (ret < 0)
@@ -382,13 +611,34 @@
 
 	dir = IN;
 	atomic_set(&prtd->pending_buffer, 0);
+	prtd->pcm_irq_pos = 0;
 	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
 	compressed_audio.prtd = NULL;
 	q6asm_audio_client_buf_free_contiguous(dir,
 				prtd->audio_client);
+		msm_pcm_routing_dereg_phy_stream(
+			soc_prtd->dai_link->be_id,
+			SNDRV_PCM_STREAM_PLAYBACK);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+	return 0;
+}
 
+static int msm_compr_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct compr_audio *compr = runtime->private_data;
+	struct msm_audio *prtd = &compr->prtd;
+	int dir = OUT;
+
+	pr_debug("%s\n", __func__);
+	atomic_set(&prtd->pending_buffer, 0);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
 	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
-	SNDRV_PCM_STREAM_PLAYBACK);
+				SNDRV_PCM_STREAM_CAPTURE);
 	q6asm_audio_client_free(prtd->audio_client);
 	kfree(prtd);
 	return 0;
@@ -401,7 +651,7 @@
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		ret = msm_compr_playback_close(substream);
 	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-		ret = EINVAL;
+		ret = msm_compr_capture_close(substream);
 	return ret;
 }
 static int msm_compr_prepare(struct snd_pcm_substream *substream)
@@ -411,7 +661,7 @@
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		ret = msm_compr_playback_prepare(substream);
 	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-		ret = EINVAL;
+		ret = msm_compr_capture_prepare(substream);
 	return ret;
 }
 
@@ -425,7 +675,10 @@
 	if (prtd->pcm_irq_pos >= prtd->pcm_size)
 		prtd->pcm_irq_pos = 0;
 
-	pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+	pr_debug("%s: pcm_irq_pos = %d, pcm_size = %d, sample_bits = %d,\n"
+			 "frame_bits = %d\n", __func__, prtd->pcm_irq_pos,
+			 prtd->pcm_size, runtime->sample_bits,
+			 runtime->frame_bits);
 	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
 }
 
@@ -467,22 +720,69 @@
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		dir = IN;
 	else
-		return -EINVAL;
+		dir = OUT;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			ret = q6asm_open_write(prtd->audio_client,
+					compr->codec);
+			if (ret < 0) {
+				pr_err("%s: Session out open failed\n",
+					__func__);
+				return -ENOMEM;
+			}
+			msm_pcm_routing_reg_phy_stream(
+				soc_prtd->dai_link->be_id,
+				prtd->session_id,
+				substream->stream);
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		switch (compr->info.codec_param.codec.id) {
+		case SND_AUDIOCODEC_AMRWB:
+			pr_debug("q6asm_open_read(FORMAT_AMRWB)\n");
+			ret = q6asm_open_read(prtd->audio_client,
+				FORMAT_AMRWB);
+			if (ret < 0) {
+				pr_err("%s: compressed Session out open failed\n",
+					__func__);
+				return -ENOMEM;
+			}
+			pr_debug("msm_pcm_routing_reg_phy_stream\n");
+			msm_pcm_routing_reg_phy_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream);
+			break;
+		default:
+			pr_debug("q6asm_open_read_compressed(COMPRESSED_META_DATA_MODE)\n");
+			/*
+			ret = q6asm_open_read_compressed(prtd->audio_client,
+				MAX_NUM_FRAMES_PER_BUFFER,
+				COMPRESSED_META_DATA_MODE);
+			*/
+			ret = -EINVAL;
+			break;
+		}
 
-	ret = q6asm_open_write(prtd->audio_client, compr->codec);
-	if (ret < 0) {
-		pr_err("%s: Session out open failed\n", __func__);
-		return -ENOMEM;
+		if (ret < 0) {
+			pr_err("%s: compressed Session out open failed\n",
+				__func__);
+			return -ENOMEM;
+		}
 	}
-	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
-			prtd->session_id, substream->stream);
 
 	ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
 	if (ret < 0) {
 		pr_err("%s: Set IO mode failed\n", __func__);
 		return -ENOMEM;
 	}
-
+	/* Modifying kernel hardware params based on userspace config */
+	if (params_periods(params) > 0 &&
+		(params_periods(params) != runtime->hw.periods_max)) {
+		runtime->hw.periods_max = params_periods(params);
+	}
+	if (params_period_bytes(params) > 0 &&
+		(params_period_bytes(params) != runtime->hw.period_bytes_min)) {
+		runtime->hw.period_bytes_min = params_period_bytes(params);
+	}
+	runtime->hw.buffer_bytes_max =
+			runtime->hw.period_bytes_min * runtime->hw.periods_max;
 	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
 			prtd->audio_client,
 			runtime->hw.period_bytes_min,
@@ -494,13 +794,17 @@
 	}
 	buf = prtd->audio_client->port[dir].buf;
 
-	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->area = buf[0].data;
 	dma_buf->addr =  buf[0].phys;
 	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+
+	pr_debug("%s: buf[%p]dma_buf->area[%p]dma_buf->addr[%p]\n"
+		 "dma_buf->bytes[%d]\n", __func__,
+		 (void *)buf, (void *)dma_buf->area,
+		 (void *)dma_buf->addr, dma_buf->bytes);
 	if (!dma_buf->area)
 		return -ENOMEM;
 
@@ -577,16 +881,47 @@
 		}
 		return 0;
 	case SNDRV_PCM_IOCTL1_RESET:
-		prtd->cmd_ack = 0;
-		rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
-		if (rc < 0)
-			pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
-		rc = wait_event_timeout(the_locks.eos_wait,
-			prtd->cmd_ack, 5 * HZ);
-		if (rc < 0)
-			pr_err("Flush cmd timeout\n");
-		prtd->pcm_irq_pos = 0;
+		pr_debug("SNDRV_PCM_IOCTL1_RESET\n");
+		/* Flush only when session is started during CAPTURE,
+		   while PLAYBACK has no such restriction. */
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+			  (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
+						atomic_read(&prtd->start))) {
+			if (atomic_read(&prtd->eos)) {
+				prtd->cmd_ack = 1;
+				wake_up(&the_locks.eos_wait);
+				atomic_set(&prtd->eos, 0);
+			}
+
+			/* A unlikely race condition possible with FLUSH
+			   DRAIN if ack is set by flush and reset by drain */
+			prtd->cmd_ack = 0;
+			rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+			if (rc < 0) {
+				pr_err("%s: flush cmd failed rc=%d\n",
+					__func__, rc);
+				return rc;
+			}
+			rc = wait_event_timeout(the_locks.flush_wait,
+				prtd->cmd_ack, 5 * HZ);
+			if (rc < 0)
+				pr_err("Flush cmd timeout\n");
+			prtd->pcm_irq_pos = 0;
+		}
 		break;
+	case SNDRV_COMPRESS_DRAIN:
+		pr_debug("%s: SNDRV_COMPRESS_DRAIN\n", __func__);
+		atomic_set(&prtd->eos, 1);
+		atomic_set(&prtd->pending_buffer, 0);
+		prtd->cmd_ack = 0;
+		q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+		/* Wait indefinitely for  DRAIN. Flush can also signal this*/
+		rc = wait_event_interruptible(the_locks.eos_wait,
+			prtd->cmd_ack);
+		if (rc < 0)
+			pr_err("EOS cmd interrupted\n");
+		pr_debug("%s: SNDRV_COMPRESS_DRAIN  out of wait\n", __func__);
+		return 0;
 	default:
 		break;
 	}
@@ -658,6 +993,7 @@
 	init_waitqueue_head(&the_locks.eos_wait);
 	init_waitqueue_head(&the_locks.write_wait);
 	init_waitqueue_head(&the_locks.read_wait);
+	init_waitqueue_head(&the_locks.flush_wait);
 
 	return platform_driver_register(&msm_compr_driver);
 }
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
index 22bf0cc..e25d356 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -49,6 +49,7 @@
 	wait_queue_head_t write_wait;
 	wait_queue_head_t eos_wait;
 	wait_queue_head_t enable_wait;
+	wait_queue_head_t flush_wait;
 };
 
 struct msm_audio {
@@ -76,10 +77,19 @@
 	atomic_t out_count;
 	atomic_t in_count;
 	atomic_t out_needed;
+	atomic_t eos;
 	int out_head;
 	int periods;
 	int mmap_flag;
 	atomic_t pending_buffer;
 };
 
+struct output_meta_data_st {
+	uint32_t meta_data_length;
+	uint32_t frame_size;
+	uint32_t timestamp_lsw;
+	uint32_t timestamp_msw;
+	uint32_t reserved[12];
+};
+
 #endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index 492569b..c7a8031 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -32,8 +32,9 @@
 #include "q6voice.h"
 #include "audio_ocmem.h"
 
+#define SHARED_MEM_BUF 2
 #define VOIP_MAX_Q_LEN 10
-#define VOIP_MAX_VOC_PKT_SIZE 640
+#define VOIP_MAX_VOC_PKT_SIZE 4096
 #define VOIP_MIN_VOC_PKT_SIZE 320
 
 /* Length of the DSP frame info header added to the voc packet. */
@@ -259,8 +260,8 @@
 
 /* capture path */
 static void voip_process_ul_pkt(uint8_t *voc_pkt,
-					uint32_t pkt_len,
-					void *private_data)
+				uint32_t pkt_len,
+				void *private_data)
 {
 	struct voip_buf_node *buf_node = NULL;
 	struct voip_drv_info *prtd = private_data;
@@ -315,8 +316,8 @@
 		default: {
 			buf_node->frame.len = pkt_len;
 			memcpy(&buf_node->frame.voc_pkt[0],
-				voc_pkt,
-				buf_node->frame.len);
+			       voc_pkt,
+			       buf_node->frame.len);
 			list_add_tail(&buf_node->list, &prtd->out_queue);
 		}
 		}
@@ -334,15 +335,12 @@
 }
 
 /* playback path */
-static void voip_process_dl_pkt(uint8_t *voc_pkt,
-					uint32_t *pkt_len,
-					void *private_data)
+static void voip_process_dl_pkt(uint8_t *voc_pkt, void *private_data)
 {
 	struct voip_buf_node *buf_node = NULL;
 	struct voip_drv_info *prtd = private_data;
 	unsigned long dsp_flags;
 
-
 	if (prtd->playback_substream == NULL)
 		return;
 
@@ -355,14 +353,18 @@
 		switch (prtd->mode) {
 		case MODE_AMR:
 		case MODE_AMR_WB: {
-			/* Add the DSP frame info header. Header format:
+			*((uint32_t *)voc_pkt) = buf_node->frame.len +
+							DSP_FRAME_HDR_LEN;
+			/* Advance to the header of voip packet */
+			voc_pkt = voc_pkt + sizeof(uint32_t);
+			/*
+			 * Add the DSP frame info header. Header format:
 			 * Bits 0-3: Frame rate
 			 * Bits 4-7: Frame type
 			 */
 			*voc_pkt = ((buf_node->frame.header.frame_type &
 					0x0F) << 4) | (prtd->rate_type & 0x0F);
 			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
-			*pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
 			memcpy(voc_pkt,
 				&buf_node->frame.voc_pkt[0],
 				buf_node->frame.len);
@@ -372,12 +374,16 @@
 		case MODE_IS127:
 		case MODE_4GV_NB:
 		case MODE_4GV_WB: {
-			/* Add the DSP frame info header. Header format:
+			*((uint32_t *)voc_pkt) = buf_node->frame.len +
+							 DSP_FRAME_HDR_LEN;
+			/* Advance to the header of voip packet */
+			voc_pkt = voc_pkt + sizeof(uint32_t);
+			/*
+			 * Add the DSP frame info header. Header format:
 			 * Bits 0-3 : Frame rate
-			*/
+			 */
 			*voc_pkt = buf_node->frame.header.packet_rate & 0x0F;
 			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
-			*pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
 
 			memcpy(voc_pkt,
 				&buf_node->frame.voc_pkt[0],
@@ -387,22 +393,19 @@
 			break;
 		}
 		default: {
-			*pkt_len = buf_node->frame.len;
-
+			*((uint32_t *)voc_pkt) = buf_node->frame.len;
+			voc_pkt = voc_pkt + sizeof(uint32_t);
 			memcpy(voc_pkt,
-				&buf_node->frame.voc_pkt[0],
-				buf_node->frame.len);
-
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.len);
 			list_add_tail(&buf_node->list, &prtd->free_in_queue);
 		}
 		}
-		pr_debug("dl_pkt: pkt_len=%d, frame_len=%d\n", *pkt_len,
-			buf_node->frame.len);
 		prtd->pcm_playback_irq_pos += prtd->pcm_count;
 		spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
 		snd_pcm_period_elapsed(prtd->playback_substream);
 	} else {
-		*pkt_len = 0;
+		*((uint32_t *)voc_pkt) = 0;
 		spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
 		pr_err("DL data not available\n");
 	}
@@ -556,7 +559,7 @@
 		pr_err("%s: No free DL buffs\n", __func__);
 		ret = -ETIMEDOUT;
 	} else {
-		pr_err("%s: playback copy  was interrupted\n", __func__);
+		pr_err("%s: playback copy was interrupted %d\n", __func__, ret);
 	}
 
 	return  ret;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 714b2ce..9f98c1b 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -632,7 +632,7 @@
 					}
 					buf[cnt].handle = ion_alloc
 						(buf[cnt].client, bufsz, SZ_4K,
-						(0x1 << ION_AUDIO_HEAP_ID));
+						(0x1 << ION_AUDIO_HEAP_ID), 0);
 					if (IS_ERR_OR_NULL((void *)
 						buf[cnt].handle)) {
 						pr_err("%s: ION memory allocation for AUDIO failed\n",
@@ -652,8 +652,7 @@
 					}
 
 					buf[cnt].data = ion_map_kernel
-					(buf[cnt].client, buf[cnt].handle,
-							 0);
+					(buf[cnt].client, buf[cnt].handle);
 					if (IS_ERR_OR_NULL((void *)
 						buf[cnt].data)) {
 						pr_err("%s: ION memory mapping for AUDIO failed\n",
@@ -729,7 +728,7 @@
 		goto fail;
 	}
 	buf[0].handle = ion_alloc(buf[0].client, bufsz * bufcnt, SZ_4K,
-				  (0x1 << ION_AUDIO_HEAP_ID));
+				  (0x1 << ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL((void *) buf[0].handle)) {
 		pr_err("%s: ION memory allocation for AUDIO failed\n",
 			__func__);
@@ -744,7 +743,7 @@
 		goto fail;
 	}
 
-	buf[0].data = ion_map_kernel(buf[0].client, buf[0].handle, 0);
+	buf[0].data = ion_map_kernel(buf[0].client, buf[0].handle);
 	if (IS_ERR_OR_NULL((void *) buf[0].data)) {
 		pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
 		goto fail;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index f84b456..1f6dbf1 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -50,6 +50,15 @@
 static int voice_send_set_device_cmd(struct voice_data *v);
 static int voice_send_disable_vocproc_cmd(struct voice_data *v);
 static int voice_send_vol_index_cmd(struct voice_data *v);
+static int voice_send_mvm_map_memory_physical_cmd(struct voice_data *v);
+static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
+						    unsigned int bufcnt);
+static int voice_send_mvm_cal_network_cmd(struct voice_data *v);
+static int voice_send_mvm_media_type_cmd(struct voice_data *v);
+static int voice_send_cvs_data_exchange_mode_cmd(struct voice_data *v);
+static int voice_send_cvs_packet_exchange_config_cmd(struct voice_data *v);
+static int voice_set_packet_exchange_mode_and_config(uint16_t session_id,
+						     uint32_t mode);
 static int voice_cvs_stop_playback(struct voice_data *v);
 static int voice_cvs_start_playback(struct voice_data *v);
 static int voice_cvs_start_record(struct voice_data *v, uint32_t rec_mode);
@@ -594,7 +603,6 @@
 		detach_stream.detach_stream.handle = cvs_handle;
 
 		v->mvm_state = CMD_STATUS_FAIL;
-
 		ret = apr_send_pkt(apr_mvm, (uint32_t *) &detach_stream);
 		if (ret < 0) {
 			pr_err("%s: Error %d sending DETACH_STREAM\n",
@@ -608,6 +616,7 @@
 			pr_err("%s: wait event timeout\n", __func__);
 			goto fail;
 		}
+
 		/* Destroy CVS. */
 		pr_debug("%s: CVS destroy session\n", __func__);
 
@@ -622,7 +631,6 @@
 		cvs_destroy.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
 
 		v->cvs_state = CMD_STATUS_FAIL;
-
 		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_destroy);
 		if (ret < 0) {
 			pr_err("%s: Error %d sending CVS DESTROY\n",
@@ -640,6 +648,13 @@
 		cvs_handle = 0;
 		voice_set_cvs_handle(v, cvs_handle);
 
+		ret = voice_send_mvm_unmap_memory_physical_cmd(v,
+							       NUM_OF_BUFFERS);
+		if (ret < 0) {
+			pr_err("%s CMD Memory_unmap_regions failed %d\n",
+				__func__, ret);
+		}
+
 		/* Destroy MVM. */
 		pr_debug("MVM destroy session\n");
 
@@ -667,7 +682,6 @@
 					 msecs_to_jiffies(TIMEOUT_MS));
 		if (!ret) {
 			pr_err("%s: wait event timeout\n", __func__);
-
 			goto fail;
 		}
 		mvm_handle = 0;
@@ -788,6 +802,58 @@
 	return 0;
 }
 
+static int voice_send_mvm_media_type_cmd(struct voice_data *v)
+{
+	struct vss_imvm_cmd_set_cal_media_type_t mvm_set_cal_media_type;
+	int ret = 0;
+	void *apr_mvm;
+	u16 mvm_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_mvm = common.apr_q6_mvm;
+
+	if (!apr_mvm) {
+		pr_err("%s: apr_mvm is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	mvm_handle = voice_get_mvm_handle(v);
+
+	mvm_set_cal_media_type.hdr.hdr_field =
+					APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE),
+					APR_PKT_VER);
+	mvm_set_cal_media_type.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(mvm_set_cal_media_type) -
+					APR_HDR_SIZE);
+	mvm_set_cal_media_type.hdr.src_port = v->session_id;
+	mvm_set_cal_media_type.hdr.dest_port = mvm_handle;
+	mvm_set_cal_media_type.hdr.token = 0;
+	mvm_set_cal_media_type.hdr.opcode = VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE;
+	mvm_set_cal_media_type.media_id = common.mvs_info.media_type;
+	pr_debug("%s: setting media_id as %x\n",
+		 __func__ , mvm_set_cal_media_type.media_id);
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_cal_media_type);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending media type\n", __func__, ret);
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->mvm_wait,
+				(v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout %d\n", __func__, ret);
+		goto fail;
+	}
+	return 0;
+fail:
+	return -EINVAL;
+}
 static int voice_config_cvs_vocoder(struct voice_data *v)
 {
 	int ret = 0;
@@ -813,7 +879,8 @@
 						APR_HDR_LEN(APR_HDR_SIZE),
 						APR_PKT_VER);
 	cvs_set_media_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				      sizeof(cvs_set_media_cmd) - APR_HDR_SIZE);
+						sizeof(cvs_set_media_cmd) -
+						APR_HDR_SIZE);
 	cvs_set_media_cmd.hdr.src_port = v->session_id;
 	cvs_set_media_cmd.hdr.dest_port = cvs_handle;
 	cvs_set_media_cmd.hdr.token = 0;
@@ -826,7 +893,7 @@
 	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_media_cmd);
 	if (ret < 0) {
 		pr_err("%s: Error %d sending SET_MEDIA_TYPE\n",
-		       __func__, ret);
+			__func__, ret);
 
 		goto fail;
 	}
@@ -1196,6 +1263,102 @@
 	return -EINVAL;
 }
 
+static int voice_send_mvm_map_memory_physical_cmd(struct voice_data *v)
+{
+	struct vss_imemory_cmd_map_physical_t mvm_map_phys_cmd;
+	uint32_t *memtable;
+	int ret = 0;
+	void *apr_mvm;
+	u16 mvm_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	apr_mvm = common.apr_q6_mvm;
+
+	if (!apr_mvm) {
+		pr_err("%s: apr_mvm is NULL.\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!v->shmem_info.memtbl.data) {
+		pr_err("%s: shmem_info.memtbl.data is NULL.\n", __func__);
+		return -EINVAL;
+	}
+
+	memtable = (uint32_t *)v->shmem_info.memtbl.data;
+
+	/*
+	 * Store next table descriptor's address(64 bit) as NULL as there
+	 * is only one memory block
+	 */
+	memtable[0] = (uint32_t)NULL;
+	memtable[1] = (uint32_t)NULL;
+
+	/* Store next table descriptor's size */
+	memtable[2] = 0;
+
+	/* Store shared mem add */
+	memtable[3] = v->shmem_info.sh_buf.buf[0].phys;
+	memtable[4] = 0;
+
+	/* Store shared memory size */
+	memtable[5] = v->shmem_info.sh_buf.buf[0].size * NUM_OF_BUFFERS;
+
+	mvm_handle = voice_get_mvm_handle(v);
+
+	mvm_map_phys_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mvm_map_phys_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mvm_map_phys_cmd) - APR_HDR_SIZE);
+	mvm_map_phys_cmd.hdr.src_port = v->session_id;
+	mvm_map_phys_cmd.hdr.dest_port = mvm_handle;
+	mvm_map_phys_cmd.hdr.token = 0;
+	mvm_map_phys_cmd.hdr.opcode = VSS_IMEMORY_CMD_MAP_PHYSICAL;
+
+	mvm_map_phys_cmd.table_descriptor.mem_address =
+						v->shmem_info.memtbl.phys;
+	mvm_map_phys_cmd.table_descriptor.mem_size =
+			sizeof(struct vss_imemory_block_t) +
+			sizeof(struct vss_imemory_table_descriptor_t);
+	mvm_map_phys_cmd.is_cached = true;
+	mvm_map_phys_cmd.cache_line_size = 128;
+	mvm_map_phys_cmd.access_mask = 3;
+	mvm_map_phys_cmd.page_align = 4096;
+	mvm_map_phys_cmd.min_data_width = 8;
+	mvm_map_phys_cmd.max_data_width = 64;
+
+	pr_debug("%s: ntd->add: %lld, ntd->size: %d, table->add: 0x%x\n",
+		__func__,
+		*((uint64_t *)v->shmem_info.memtbl.data),
+		*(((uint32_t *)(v->shmem_info.memtbl.data)) + 2),
+		*(((uint32_t *)(v->shmem_info.memtbl.data)) + 3));
+	pr_debug("%s: table->size: %d, pkt_size: %d, mvm_handle: 0x%x\n",
+		__func__,
+		*(((uint32_t *)(v->shmem_info.memtbl.data)) + 5),
+		mvm_map_phys_cmd.hdr.pkt_size, mvm_handle);
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_map_phys_cmd);
+	if (ret < 0) {
+		pr_err("Fail: sending mvm map phy cmd %d\n", ret);
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->mvm_wait,
+			(v->mvm_state == CMD_STATUS_SUCCESS),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout %d\n", __func__, ret);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
 
 static int voice_setup_vocproc(struct voice_data *v)
 {
@@ -1225,7 +1388,7 @@
 	cvp_session_cmd.hdr.dest_port = 0;
 	cvp_session_cmd.hdr.token = 0;
 	cvp_session_cmd.hdr.opcode =
-			VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION;
+			VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2;
 
 	/* Use default topology if invalid value in ACDB */
 	cvp_session_cmd.cvp_session.tx_topology_id =
@@ -1241,16 +1404,24 @@
 			VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
 
 	cvp_session_cmd.cvp_session.direction = 2; /*tx and rx*/
-	cvp_session_cmd.cvp_session.network_id = VSS_NETWORK_ID_DEFAULT;
 	cvp_session_cmd.cvp_session.tx_port_id = v->dev_tx.port_id;
 	cvp_session_cmd.cvp_session.rx_port_id = v->dev_rx.port_id;
+	cvp_session_cmd.cvp_session.profile_id =
+					 VSS_ICOMMON_CAL_NETWORK_ID_NONE;
+	cvp_session_cmd.cvp_session.vocproc_mode =
+				 VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING;
+	cvp_session_cmd.cvp_session.ec_ref_port_id =
+						 VSS_IVOCPROC_PORT_ID_NONE;
 
-	pr_debug("topology=%d net_id=%d, dir=%d tx_port_id=%d, rx_port_id=%d\n",
+	pr_debug("tx_topology: %d tx_port_id=%d, rx_port_id=%d, mode: 0x%x\n",
 		cvp_session_cmd.cvp_session.tx_topology_id,
-		cvp_session_cmd.cvp_session.network_id,
-		cvp_session_cmd.cvp_session.direction,
 		cvp_session_cmd.cvp_session.tx_port_id,
-		cvp_session_cmd.cvp_session.rx_port_id);
+		cvp_session_cmd.cvp_session.rx_port_id,
+		cvp_session_cmd.cvp_session.vocproc_mode);
+	pr_debug("rx_topology: %d, profile_id: 0x%x, pkt_size: %d\n",
+		cvp_session_cmd.cvp_session.rx_topology_id,
+		cvp_session_cmd.cvp_session.profile_id,
+		cvp_session_cmd.hdr.pkt_size);
 
 	v->cvp_state = CMD_STATUS_FAIL;
 	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_session_cmd);
@@ -1266,7 +1437,6 @@
 		goto fail;
 	}
 
-
 	/* enable vocproc */
 	ret = voice_send_enable_vocproc_cmd(v);
 	if (ret < 0)
@@ -1280,9 +1450,19 @@
 	/* send tty mode if tty device is used */
 	voice_send_tty_mode_cmd(v);
 
+	if (is_voip_session(v->session_id)) {
+		ret = voice_send_mvm_cal_network_cmd(v);
+		if (ret < 0)
+			pr_err("%s: voice_send_mvm_cal_network_cmd: %d\n",
+				__func__, ret);
 
-	if (is_voip_session(v->session_id))
+		ret = voice_send_mvm_media_type_cmd(v);
+		if (ret < 0)
+			pr_err("%s: voice_send_mvm_media_type_cmd: %d\n",
+				__func__, ret);
+
 		voice_send_netid_timing_cmd(v);
+	}
 
 	/* Start in-call music delivery if this feature is enabled */
 	if (v->music_info.play_enable)
@@ -1350,6 +1530,55 @@
 	return -EINVAL;
 }
 
+static int voice_send_mvm_cal_network_cmd(struct voice_data *v)
+{
+	struct vss_imvm_cmd_set_cal_network_t mvm_set_cal_network;
+	int ret = 0;
+	void *apr_mvm;
+	u16 mvm_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_mvm = common.apr_q6_mvm;
+
+	if (!apr_mvm) {
+		pr_err("%s: apr_mvm is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	mvm_handle = voice_get_mvm_handle(v);
+
+	mvm_set_cal_network.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	mvm_set_cal_network.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mvm_set_cal_network) - APR_HDR_SIZE);
+	mvm_set_cal_network.hdr.src_port = v->session_id;
+	mvm_set_cal_network.hdr.dest_port = mvm_handle;
+	mvm_set_cal_network.hdr.token = 0;
+	mvm_set_cal_network.hdr.opcode = VSS_IMVM_CMD_SET_CAL_NETWORK;
+	mvm_set_cal_network.network_id = VSS_ICOMMON_CAL_NETWORK_ID_NONE;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_cal_network);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_NETWORK\n", __func__, ret);
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->mvm_wait,
+				(v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout %d\n", __func__, ret);
+		goto fail;
+	}
+	return 0;
+fail:
+	return -EINVAL;
+}
+
 static int voice_send_netid_timing_cmd(struct voice_data *v)
 {
 	int ret = 0;
@@ -1590,10 +1819,177 @@
 
 	cvp_handle = 0;
 	voice_set_cvp_handle(v, cvp_handle);
+	return 0;
+fail:
+	return -EINVAL;
+}
 
+static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
+							 unsigned int bufcnt)
+{
+	struct vss_imemory_cmd_unmap_t mem_unmap;
+	int ret = 0;
+	void *apr_mvm;
+	u16 mvm_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_mvm = common.apr_q6_mvm;
+
+	if (!apr_mvm) {
+		pr_err("%s: apr_mvm is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	mvm_handle = voice_get_mvm_handle(v);
+
+	mem_unmap.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	mem_unmap.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mem_unmap) - APR_HDR_SIZE);
+	mem_unmap.hdr.src_port = v->session_id;
+	mem_unmap.hdr.dest_port = mvm_handle;
+	mem_unmap.hdr.token = 0;
+	mem_unmap.hdr.opcode = VSS_IMEMORY_CMD_UNMAP;
+	mem_unmap.mem_handle = v->shmem_info.mem_handle;
+
+	pr_debug("%s: mem_handle: ox%x\n", __func__, mem_unmap.mem_handle);
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mem_unmap);
+	if (ret < 0) {
+		pr_err("mem_unmap op[0x%x]ret[%d]\n",
+			mem_unmap.hdr.opcode, ret);
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->mvm_wait,
+				 (v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout %d\n", __func__, ret);
+		goto fail;
+	}
 	return 0;
 
 fail:
+	return ret;
+}
+
+static int voice_send_cvs_packet_exchange_config_cmd(struct voice_data *v)
+{
+	struct vss_istream_cmd_set_oob_packet_exchange_config_t
+						 packet_exchange_config_pkt;
+	int ret = 0;
+	uint64_t *dec_buf;
+	uint64_t *enc_buf;
+	void *apr_cvs;
+	u16 cvs_handle;
+	dec_buf = (uint64_t *)v->shmem_info.sh_buf.buf[0].phys;
+	enc_buf = (uint64_t *)v->shmem_info.sh_buf.buf[1].phys;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvs = common.apr_q6_cvs;
+
+	if (!apr_cvs) {
+		pr_err("%s: apr_cvs is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	cvs_handle = voice_get_cvs_handle(v);
+
+	packet_exchange_config_pkt.hdr.hdr_field = APR_HDR_FIELD(
+						APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	packet_exchange_config_pkt.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(packet_exchange_config_pkt) -
+					 APR_HDR_SIZE);
+	packet_exchange_config_pkt.hdr.src_port = v->session_id;
+	packet_exchange_config_pkt.hdr.dest_port = cvs_handle;
+	packet_exchange_config_pkt.hdr.token = 0;
+	packet_exchange_config_pkt.hdr.opcode =
+			 VSS_ISTREAM_CMD_SET_OOB_PACKET_EXCHANGE_CONFIG;
+	packet_exchange_config_pkt.mem_handle = v->shmem_info.mem_handle;
+	packet_exchange_config_pkt.dec_buf_addr = (uint32_t)dec_buf;
+	packet_exchange_config_pkt.dec_buf_size = 4096;
+	packet_exchange_config_pkt.enc_buf_addr = (uint32_t)enc_buf;
+	packet_exchange_config_pkt.enc_buf_size = 4096;
+
+	pr_debug("%s: dec buf: add %p, size %d, enc buf: add %p, size %d\n",
+		__func__,
+		dec_buf,
+		packet_exchange_config_pkt.dec_buf_size,
+		enc_buf,
+		packet_exchange_config_pkt.enc_buf_size);
+
+	v->cvs_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &packet_exchange_config_pkt);
+	if (ret < 0) {
+		pr_err("Failed to send packet exchange config cmd %d\n", ret);
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret)
+		pr_err("%s: wait_event timeout %d\n", __func__, ret);
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_cvs_data_exchange_mode_cmd(struct voice_data *v)
+{
+	struct vss_istream_cmd_set_packet_exchange_mode_t data_exchange_pkt;
+	int ret = 0;
+	void *apr_cvs;
+	u16 cvs_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvs = common.apr_q6_cvs;
+
+	if (!apr_cvs) {
+		pr_err("%s: apr_cvs is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	cvs_handle = voice_get_cvs_handle(v);
+
+	data_exchange_pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	data_exchange_pkt.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(data_exchange_pkt) - APR_HDR_SIZE);
+	data_exchange_pkt.hdr.src_port = v->session_id;
+	data_exchange_pkt.hdr.dest_port = cvs_handle;
+	data_exchange_pkt.hdr.token = 0;
+	data_exchange_pkt.hdr.opcode = VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE;
+	data_exchange_pkt.mode = VSS_ISTREAM_PACKET_EXCHANGE_MODE_OUT_OF_BAND;
+
+	v->cvs_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &data_exchange_pkt);
+	if (ret < 0) {
+		pr_err("Failed to send data exchange mode %d\n", ret);
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret)
+		pr_err("%s: wait_event timeout %d\n", __func__, ret);
+
+	return 0;
+fail:
 	return -EINVAL;
 }
 
@@ -1878,7 +2274,6 @@
 	return 0;
 
 fail:
-
 	return ret;
 }
 
@@ -2202,16 +2597,54 @@
 			pr_err("%s:  set device failed\n", __func__);
 			goto fail;
 		}
-		/* send tty mode if tty device is used */
-		voice_send_tty_mode_cmd(v);
 
-		v->voc_state = VOC_RUN;
+	ret = voice_send_enable_vocproc_cmd(v);
+	if (ret < 0) {
+		pr_err("%s: enable vocproc failed %d\n", __func__, ret);
+		goto fail;
+	}
+
+	/* Send tty mode if tty device is used */
+	voice_send_tty_mode_cmd(v);
+
+	v->voc_state = VOC_RUN;
 	}
 
 fail:
 	mutex_unlock(&v->lock);
+	return ret;
+}
+
+static int voice_set_packet_exchange_mode_and_config(uint16_t session_id,
+						 uint32_t mode)
+{
+	struct voice_data *v = voice_get_session(session_id);
+	int ret = 0;
+
+	if (v == NULL) {
+		pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+		return -EINVAL;
+	}
+
+	if (v->voc_state != VOC_RUN)
+		ret = voice_send_cvs_data_exchange_mode_cmd(v);
+
+	if (ret) {
+		pr_err("%s: Error voice_send_data_exchange_mode_cmd %d\n",
+			__func__, ret);
+		goto fail;
+	}
+
+	ret = voice_send_cvs_packet_exchange_config_cmd(v);
+	if (ret) {
+		pr_err("%s: Error: voice_send_packet_exchange_config_cmd %d\n",
+			__func__, ret);
+		goto fail;
+	}
 
 	return ret;
+fail:
+	return -EINVAL;
 }
 
 int voc_set_tx_mute(uint16_t session_id, uint32_t dir, uint32_t mute)
@@ -2552,6 +2985,22 @@
 			pr_err("create mvm and cvs failed\n");
 			goto fail;
 		}
+		if (is_voip_session(session_id)) {
+			ret = voice_send_mvm_map_memory_physical_cmd(v);
+			if (ret) {
+				pr_err("%s: mvm_map_memory_phy failed %d\n",
+					__func__, ret);
+				goto fail;
+			}
+			ret = voice_set_packet_exchange_mode_and_config(
+				session_id,
+				VSS_ISTREAM_PACKET_EXCHANGE_MODE_OUT_OF_BAND);
+			if (ret) {
+				pr_err("%s: Err: exchange_mode_and_config  %d\n",
+					__func__, ret);
+				goto fail;
+			}
+		}
 		ret = voice_send_dual_control_cmd(v);
 		if (ret < 0) {
 			pr_err("Err Dual command failed\n");
@@ -2570,7 +3019,8 @@
 
 		v->voc_state = VOC_RUN;
 	}
-fail:	mutex_unlock(&v->lock);
+fail:
+	mutex_unlock(&v->lock);
 	return ret;
 }
 
@@ -2638,6 +3088,7 @@
 		if (data->payload_size) {
 			ptr = data->payload;
 
+			pr_info("%x %x\n", ptr[0], ptr[1]);
 			/* ping mvm service ACK */
 			switch (ptr[0]) {
 			case VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION:
@@ -2666,6 +3117,9 @@
 			case VSS_ICOMMON_CMD_SET_VOICE_TIMING:
 			case VSS_IWIDEVOICE_CMD_SET_WIDEVOICE:
 			case VSS_IMVM_CMD_SET_POLICY_DUAL_CONTROL:
+			case VSS_IMVM_CMD_SET_CAL_NETWORK:
+			case VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE:
+			case VSS_IMEMORY_CMD_UNMAP:
 				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
 				v->mvm_state = CMD_STATUS_SUCCESS;
 				wake_up(&v->mvm_wait);
@@ -2676,8 +3130,19 @@
 				break;
 			}
 		}
+	} else if (data->opcode == VSS_IMEMORY_RSP_MAP) {
+		pr_debug("%s, Revd VSS_IMEMORY_RSP_MAP response\n", __func__);
+		if (data->payload_size) {
+			ptr = data->payload;
+			if (ptr[0]) {
+				v->shmem_info.mem_handle = ptr[0];
+				pr_debug("%s: shared mem_handle: 0x[%x]\n",
+					 __func__, v->shmem_info.mem_handle);
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			}
+		}
 	}
-
 	return 0;
 }
 
@@ -2725,6 +3190,7 @@
 		if (data->payload_size) {
 			ptr = data->payload;
 
+			pr_info("%x %x\n", ptr[0], ptr[1]);
 			/*response from  CVS */
 			switch (ptr[0]) {
 			case VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION:
@@ -2754,6 +3220,8 @@
 			case VSS_ISTREAM_CMD_STOP_PLAYBACK:
 			case VSS_ISTREAM_CMD_START_RECORD:
 			case VSS_ISTREAM_CMD_STOP_RECORD:
+			case VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE:
+			case VSS_ISTREAM_CMD_SET_OOB_PACKET_EXCHANGE_CONFIG:
 				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
 				v->cvs_state = CMD_STATUS_SUCCESS;
 				wake_up(&v->cvs_wait);
@@ -2765,63 +3233,117 @@
 				break;
 			}
 		}
-	} else if (data->opcode == VSS_ISTREAM_EVT_SEND_ENC_BUFFER) {
-		uint32_t *voc_pkt = data->payload;
-		uint32_t pkt_len = data->payload_size;
-
-		if (voc_pkt != NULL && c->mvs_info.ul_cb != NULL) {
-			pr_debug("%s: Media type is 0x%x\n",
-				 __func__, voc_pkt[0]);
-
-			/* Remove media ID from payload. */
-			voc_pkt++;
-			pkt_len = pkt_len - 4;
-
-			c->mvs_info.ul_cb((uint8_t *)voc_pkt,
-					  pkt_len,
-					  c->mvs_info.private_data);
-		} else
-			pr_err("%s: voc_pkt is 0x%x ul_cb is 0x%x\n",
-			       __func__, (unsigned int)voc_pkt,
-			       (unsigned int) c->mvs_info.ul_cb);
-	} else if (data->opcode == VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER) {
-		struct cvs_send_dec_buf_cmd send_dec_buf;
+	} else if (data->opcode ==
+			 VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_READY) {
 		int ret = 0;
-		uint32_t pkt_len = 0;
+		u16 cvs_handle;
+		uint32_t *cvs_voc_pkt;
+		struct cvs_enc_buffer_consumed_cmd send_enc_buf_consumed_cmd;
+		void *apr_cvs;
 
-		if (c->mvs_info.dl_cb != NULL) {
-			send_dec_buf.dec_buf.media_id = c->mvs_info.media_type;
+		pr_debug("Encoder buffer is ready\n");
 
-			c->mvs_info.dl_cb(
-				(uint8_t *)&send_dec_buf.dec_buf.packet_data,
-				&pkt_len,
-				c->mvs_info.private_data);
+		apr_cvs = common.apr_q6_cvs;
+		if (!apr_cvs) {
+			pr_err("%s: apr_cvs is NULL\n", __func__);
+			return -EINVAL;
+		}
+		cvs_handle = voice_get_cvs_handle(v);
 
-			send_dec_buf.hdr.hdr_field =
-					APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-					APR_HDR_LEN(APR_HDR_SIZE),
-					APR_PKT_VER);
-			send_dec_buf.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-			       sizeof(send_dec_buf.dec_buf.media_id) + pkt_len);
-			send_dec_buf.hdr.src_port = v->session_id;
-			send_dec_buf.hdr.dest_port = voice_get_cvs_handle(v);
-			send_dec_buf.hdr.token = 0;
-			send_dec_buf.hdr.opcode =
-					VSS_ISTREAM_EVT_SEND_DEC_BUFFER;
+		send_enc_buf_consumed_cmd.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE),
+				APR_PKT_VER);
+		send_enc_buf_consumed_cmd.hdr.pkt_size =
+			APR_PKT_SIZE(APR_HDR_SIZE,
+			sizeof(send_enc_buf_consumed_cmd) - APR_HDR_SIZE);
 
-			ret = apr_send_pkt(c->apr_q6_cvs,
-					   (uint32_t *) &send_dec_buf);
+		send_enc_buf_consumed_cmd.hdr.src_port = v->session_id;
+		send_enc_buf_consumed_cmd.hdr.dest_port = cvs_handle;
+		send_enc_buf_consumed_cmd.hdr.token = 0;
+		send_enc_buf_consumed_cmd.hdr.opcode =
+			VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_CONSUMED;
+
+		cvs_voc_pkt = v->shmem_info.sh_buf.buf[1].data;
+		if (cvs_voc_pkt != NULL &&  common.mvs_info.ul_cb != NULL) {
+			common.mvs_info.ul_cb((uint8_t *)&cvs_voc_pkt[3],
+					      cvs_voc_pkt[2],
+					      common.mvs_info.private_data);
+		} else
+			pr_err("%s: cvs_voc_pkt or ul_cb is NULL\n", __func__);
+
+		ret = apr_send_pkt(apr_cvs,
+			(uint32_t *) &send_enc_buf_consumed_cmd);
+		if (ret < 0) {
+			pr_err("%s: Err send ENC_BUF_CONSUMED_NOTIFY %d\n",
+				__func__, ret);
+			goto fail;
+		}
+	} else if (data->opcode == VSS_ISTREAM_EVT_SEND_ENC_BUFFER) {
+		pr_debug("Recd VSS_ISTREAM_EVT_SEND_ENC_BUFFER\n");
+	} else if (data->opcode ==
+			 VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_REQUEST) {
+		int ret = 0;
+		u16 cvs_handle;
+		uint32_t *cvs_voc_pkt;
+		struct cvs_dec_buffer_ready_cmd send_dec_buf;
+		void *apr_cvs;
+		apr_cvs = common.apr_q6_cvs;
+
+		if (!apr_cvs) {
+			pr_err("%s: apr_cvs is NULL\n", __func__);
+			return -EINVAL;
+		}
+		cvs_handle = voice_get_cvs_handle(v);
+
+		send_dec_buf.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE),
+				APR_PKT_VER);
+
+		send_dec_buf.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(send_dec_buf) - APR_HDR_SIZE);
+
+		send_dec_buf.hdr.src_port = v->session_id;
+		send_dec_buf.hdr.dest_port = cvs_handle;
+		send_dec_buf.hdr.token = 0;
+		send_dec_buf.hdr.opcode =
+				 VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_READY;
+
+		cvs_voc_pkt = (uint32_t *)(v->shmem_info.sh_buf.buf[0].data);
+		if (cvs_voc_pkt != NULL && common.mvs_info.dl_cb != NULL) {
+			/* Set timestamp to 0 and advance the pointer */
+			cvs_voc_pkt[0] = 0;
+			/* Set media_type and advance the pointer */
+			cvs_voc_pkt[1] = common.mvs_info.media_type;
+			common.mvs_info.dl_cb(
+					      (uint8_t *)&cvs_voc_pkt[2],
+					      common.mvs_info.private_data);
+			ret = apr_send_pkt(apr_cvs, (uint32_t *) &send_dec_buf);
 			if (ret < 0) {
-				pr_err("%s: Error %d sending DEC_BUF\n",
-				       __func__, ret);
+				pr_err("%s: Err send DEC_BUF_READY_NOTIFI %d\n",
+					__func__, ret);
 				goto fail;
 			}
-		} else
-			pr_debug("%s: dl_cb is NULL\n", __func__);
+		} else {
+			pr_debug("%s: voc_pkt or dl_cb is NULL\n", __func__);
+			goto fail;
+		}
+	} else if (data->opcode == VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER) {
+		pr_debug("Recd VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER\n");
 	} else if (data->opcode == VSS_ISTREAM_EVT_SEND_DEC_BUFFER) {
 		pr_debug("Send dec buf resp\n");
+	} else if (data->opcode == APR_RSP_ACCEPTED) {
+		ptr = data->payload;
+		if (ptr[0])
+			pr_debug("%s: APR_RSP_ACCEPTED for 0x%x:\n",
+				 __func__, ptr[0]);
+	} else if (data->opcode == VSS_ISTREAM_EVT_NOT_READY) {
+		pr_debug("Recd VSS_ISTREAM_EVT_NOT_READY\n");
+	} else if (data->opcode == VSS_ISTREAM_EVT_READY) {
+		pr_debug("Recd VSS_ISTREAM_EVT_READY\n");
 	} else
-		pr_debug("Unknown opcode 0x%x\n", data->opcode);
+		pr_err("Unknown opcode 0x%x\n", data->opcode);
 
 fail:
 	return 0;
@@ -2869,13 +3391,15 @@
 		if (data->payload_size) {
 			ptr = data->payload;
 
+			pr_info("%x %x\n", ptr[0], ptr[1]);
 			switch (ptr[0]) {
-			case VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION:
+			case VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2:
 			/*response from  CVP */
 				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
 				if (!ptr[1]) {
 					voice_set_cvp_handle(v, data->src_port);
-					pr_debug("cvphdl=%d\n", data->src_port);
+					pr_debug("status: %d, cvphdl=%d\n",
+						 ptr[1], data->src_port);
 				} else
 					pr_err("got NACK from CVP create session response\n");
 				v->cvp_state = CMD_STATUS_SUCCESS;
@@ -2908,6 +3432,137 @@
 	return 0;
 }
 
+static int voice_alloc_oob_shared_mem(void)
+{
+	int cnt = 0;
+	int rc = 0;
+	int len;
+	void *mem_addr;
+	dma_addr_t phys;
+	int bufsz = BUFFER_BLOCK_SIZE;
+	int bufcnt = NUM_OF_BUFFERS;
+	struct voice_data *v = voice_get_session(
+				common.voice[VOC_PATH_FULL].session_id);
+
+	v->shmem_info.sh_buf.client = msm_ion_client_create(UINT_MAX,
+							    "voip_client");
+	if (IS_ERR_OR_NULL((void *)v->shmem_info.sh_buf.client)) {
+		pr_err("%s: ION create client failed\n", __func__);
+		goto err;
+	}
+
+	v->shmem_info.sh_buf.handle = ion_alloc(v->shmem_info.sh_buf.client,
+						bufsz * bufcnt, SZ_4K,
+						(0x1 << ION_AUDIO_HEAP_ID), 0);
+	if (IS_ERR_OR_NULL((void *)v->shmem_info.sh_buf.handle)) {
+		pr_err("%s: ION memory allocation failed\n",
+			__func__);
+		goto err_ion_client;
+	}
+
+	rc = ion_phys(v->shmem_info.sh_buf.client, v->shmem_info.sh_buf.handle,
+		  (ion_phys_addr_t *)&phys, (size_t *)&len);
+	if (rc) {
+		pr_err("%s: ION Get Physical failed, rc = %d\n",
+			__func__, rc);
+		goto err_ion_handle;
+	}
+
+	mem_addr = ion_map_kernel(v->shmem_info.sh_buf.client,
+				  v->shmem_info.sh_buf.handle);
+	if (IS_ERR_OR_NULL(mem_addr)) {
+		pr_err("%s: ION memory mapping failed\n", __func__);
+		goto err_ion_handle;
+	}
+
+	while (cnt < bufcnt) {
+		v->shmem_info.sh_buf.buf[cnt].data =  mem_addr  + (cnt * bufsz);
+		v->shmem_info.sh_buf.buf[cnt].phys =  phys + (cnt * bufsz);
+		v->shmem_info.sh_buf.buf[cnt].size = bufsz;
+		cnt++;
+	}
+
+	pr_debug("%s buf[0].data:[%p], buf[0].phys:[%p], &buf[0].phys:[%p],\n",
+		 __func__,
+		(void *)v->shmem_info.sh_buf.buf[0].data,
+		(void *)v->shmem_info.sh_buf.buf[0].phys,
+		(void *)&v->shmem_info.sh_buf.buf[0].phys);
+	pr_debug("%s: buf[1].data:[%p], buf[1].phys[%p], &buf[1].phys[%p]\n",
+		__func__,
+		(void *)v->shmem_info.sh_buf.buf[1].data,
+		(void *)v->shmem_info.sh_buf.buf[1].phys,
+		(void *)&v->shmem_info.sh_buf.buf[1].phys);
+
+	memset((void *)v->shmem_info.sh_buf.buf[0].data, 0, (bufsz * bufcnt));
+
+	return 0;
+
+err_ion_handle:
+	ion_free(v->shmem_info.sh_buf.client, v->shmem_info.sh_buf.handle);
+err_ion_client:
+	ion_client_destroy(v->shmem_info.sh_buf.client);
+err:
+	return -EINVAL;
+}
+
+static int voice_alloc_oob_mem_table(void)
+{
+	int rc = 0;
+	int len;
+	struct voice_data *v = voice_get_session(
+				common.voice[VOC_PATH_FULL].session_id);
+
+	v->shmem_info.memtbl.client = msm_ion_client_create(UINT_MAX,
+							      "voip_client");
+	if (IS_ERR_OR_NULL((void *)v->shmem_info.memtbl.client)) {
+		pr_err("%s: ION create client for memtbl failed\n", __func__);
+		goto err;
+	}
+
+	v->shmem_info.memtbl.handle = ion_alloc(v->shmem_info.memtbl.client,
+				sizeof(struct vss_imemory_table_t), SZ_4K,
+				(0x1 << ION_AUDIO_HEAP_ID), 0);
+	if (IS_ERR_OR_NULL((void *) v->shmem_info.memtbl.handle)) {
+		pr_err("%s: ION memory allocation for memtbl failed\n",
+			__func__);
+		goto err_ion_client;
+	}
+
+	rc = ion_phys(v->shmem_info.memtbl.client, v->shmem_info.memtbl.handle,
+		(ion_phys_addr_t *)&v->shmem_info.memtbl.phys, (size_t *)&len);
+	if (rc) {
+		pr_err("%s: ION Get Physical for memtbl failed, rc = %d\n",
+			__func__, rc);
+		goto err_ion_handle;
+	}
+
+	v->shmem_info.memtbl.data = ion_map_kernel(v->shmem_info.memtbl.client,
+						   v->shmem_info.memtbl.handle);
+	if (IS_ERR_OR_NULL((void *)v->shmem_info.memtbl.data)) {
+		pr_err("%s: ION memory mapping for memtbl failed\n",
+				__func__);
+		goto err_ion_handle;
+	}
+
+	memset(v->shmem_info.memtbl.data, 0,
+	       sizeof(struct vss_imemory_table_t));
+
+	v->shmem_info.memtbl.size = sizeof(struct vss_imemory_table_t);
+
+	pr_debug("%s data[%p]phys[%p][%p]\n", __func__,
+		 (void *)v->shmem_info.memtbl.data,
+		 (void *)v->shmem_info.memtbl.phys,
+		 (void *)&v->shmem_info.memtbl.phys);
+
+	return 0;
+
+err_ion_handle:
+	ion_free(v->shmem_info.memtbl.client, v->shmem_info.memtbl.handle);
+err_ion_client:
+	ion_client_destroy(v->shmem_info.memtbl.client);
+err:
+	return -EINVAL;
+}
 
 static int __init voice_init(void)
 {
@@ -2946,6 +3601,17 @@
 		mutex_init(&common.voice[i].lock);
 	}
 
+	/* Allocate shared memory for OOB Voip */
+	rc = voice_alloc_oob_shared_mem();
+	if (rc < 0)
+		pr_err("failed to alloc shared memory for OOB %d\n", rc);
+	else {
+		/* Allocate mem map table for OOB */
+		rc = voice_alloc_oob_mem_table();
+		if (rc < 0)
+			pr_err("failed to alloc mem map talbe %d\n", rc);
+	}
+
 	return rc;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 8bafe04..df0cbec 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -17,6 +17,13 @@
 
 #define MAX_VOC_PKT_SIZE 642
 #define SESSION_NAME_LEN 20
+#define NUM_OF_MEMORY_BLOCKS 1
+#define NUM_OF_BUFFERS 2
+/*
+ * BUFFER BLOCK SIZE based on
+ * the supported page size
+ */
+#define BUFFER_BLOCK_SIZE       4096
 
 #define VOC_REC_UPLINK		0x00
 #define VOC_REC_DOWNLINK	0x01
@@ -60,6 +67,26 @@
 	VOC_RELEASE,
 };
 
+struct mem_buffer {
+	dma_addr_t		phys;
+	void			*data;
+	uint32_t		size; /* size of buffer */
+};
+
+struct share_mem_buf {
+	struct ion_handle	*handle;
+	struct ion_client	*client;
+	struct mem_buffer	buf[NUM_OF_BUFFERS];
+};
+
+struct mem_map_table {
+	dma_addr_t		phys;
+	void			*data;
+	uint32_t		size; /* size of buffer */
+	struct ion_handle	*handle;
+	struct ion_client	*client;
+};
+
 /* Common */
 #define VSS_ICOMMON_CMD_SET_UI_PROPERTY 0x00011103
 /* Set a UI property */
@@ -119,8 +146,6 @@
 #define VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION	0x000110FE
 /* Create a new full control MVM session. */
 
-#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2	0x000112BF
-
 #define APRV2_IBASIC_CMD_DESTROY_SESSION		0x0001003C
 /**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
 
@@ -165,6 +190,12 @@
 #define VSS_IWIDEVOICE_CMD_SET_WIDEVOICE                0x00011243
 /* Enable/disable WideVoice */
 
+#define VSS_IMEMORY_CMD_MAP_PHYSICAL			0x00011334
+#define VSS_IMEMORY_RSP_MAP				0x00011336
+#define VSS_IMEMORY_CMD_UNMAP				0x00011337
+#define VSS_IMVM_CMD_SET_CAL_NETWORK			0x0001137A
+#define VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE		0x0001137B
+
 enum msm_audio_voc_rate {
 		VOC_0_RATE, /* Blank frame */
 		VOC_8_RATE, /* 1/8 rate    */
@@ -311,6 +342,92 @@
 	struct vss_iwidevoice_cmd_set_widevoice_t vss_set_wv;
 } __packed;
 
+struct vss_imemory_table_descriptor_t {
+	uint64_t mem_address;
+	/*
+	 * Base physical address of the table. The address must be aligned
+	 * to LCM( cache_line_size, page_align, max_data_width ), where the
+	 * attributes are specified in #VSS_IMEMORY_CMD_MAP_PHYSICAL, and
+	 * LCM = Least Common Multiple. The table at the address must have
+	 * the format specified by #vss_imemory_table_t.
+	 */
+	uint32_t mem_size;
+	/* Size in bytes of the table. */
+} __packed;
+
+struct vss_imemory_block_t {
+	uint64_t mem_address;
+	/*
+	 * Base address of the memory block. The address is virtual for virtual
+	 * memory and physical for physical memory. The address must be aligned
+	 * to LCM( cache_line_size, page_align, max_data_width ), where the
+	 * attributes are specified in VSS_IMEMORY_CMD_MAP_VIRTUAL or
+	 * VSS_IMEMORY_CMD_MAP_PHYSICAL, and LCM = Least Common Multiple.
+	 */
+	uint32_t mem_size;
+	/*
+	 * Size in bytes of the memory block. The size must be multiple of
+	 * page_align, where page_align is specified in
+	 * VSS_IMEMORY_CMD_MAP_VIRTUAL or #VSS_IMEMORY_CMD_MAP_PHYSICAL.
+	 */
+} __packed;
+
+struct vss_imemory_table_t {
+	struct vss_imemory_table_descriptor_t next_table_descriptor;
+	/*
+	 * Specifies the next table. If there is no next table,
+	 * set the size of the table to 0 and the table address is ignored.
+	 */
+	struct vss_imemory_block_t blocks[NUM_OF_MEMORY_BLOCKS];
+	/* Specifies one ore more memory blocks. */
+} __packed;
+
+struct vss_imemory_cmd_map_physical_t {
+	struct apr_hdr hdr;
+	struct vss_imemory_table_descriptor_t table_descriptor;
+	bool is_cached;
+	/*
+	 * Indicates cached or uncached memory. Supported values:
+	 * TRUE - Cached.
+	 */
+	uint16_t cache_line_size;
+	/* Cache line size in bytes. Supported values: 128 */
+	uint32_t access_mask;
+	/*
+	 * CVD's access permission to the memory while it is mapped.
+	 * Supported values:
+	 * bit 0 - If set, the memory is readable.
+	 * bit 1 - If set, the memory is writable.
+	 */
+	uint32_t page_align;
+	/* Page frame alignment in bytes. Supported values: 4096 */
+	uint8_t min_data_width;
+	/*
+	 * Minimum native data type width in bits that can be accessed.
+	 * Supported values: 8
+	 */
+	uint8_t max_data_width;
+	/*
+	 * Maximum native data type width in bits that can be accessed.
+	 * Supported values: 64
+	 */
+} __packed;
+
+struct vss_imvm_cmd_set_cal_network_t {
+	struct apr_hdr hdr;
+	uint32_t network_id;
+} __packed;
+
+struct vss_imvm_cmd_set_cal_media_type_t {
+	struct apr_hdr hdr;
+	uint32_t media_id;
+} __packed;
+
+struct vss_imemory_cmd_unmap_t {
+	struct apr_hdr hdr;
+	uint32_t mem_handle;
+} __packed;
+
 /* TO CVS commands */
 #define VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION	0x00011140
 /**< Wait for APRV2_IBASIC_RSP_RESULT response. */
@@ -337,6 +454,8 @@
  * The client should respond with a VSS_ISTREAM_EVT_SEND_DEC_BUFFER event.
  */
 
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_REQUEST	0x0001136E
+
 #define VSS_ISTREAM_EVT_SEND_DEC_BUFFER			0x00011016
 /* Event sent by the client to the stream in response to a
  * VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER event, providing a decoder packet.
@@ -376,6 +495,29 @@
 #define VSS_TAP_POINT_STREAM_END                        0x00010F79
 /* Indicates that specified path should be tapped at the end of the stream. */
 
+#define VSS_ISTREAM_EVT_NOT_READY			0x000110FD
+
+#define VSS_ISTREAM_EVT_READY				0x000110FC
+
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_READY	0x0001136F
+/*notify dsp that decoder buffer is ready*/
+
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_READY	0x0001136C
+/*dsp notifying client that encoder buffer is ready*/
+
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_CONSUMED	0x0001136D
+/*notify dsp that encoder buffer is consumed*/
+
+#define VSS_ISTREAM_CMD_SET_OOB_PACKET_EXCHANGE_CONFIG	0x0001136B
+
+#define VSS_ISTREAM_PACKET_EXCHANGE_MODE_INBAND	0
+/* In-band packet exchange mode. */
+
+#define VSS_ISTREAM_PACKET_EXCHANGE_MODE_OUT_OF_BAND	1
+/* Out-of-band packet exchange mode. */
+
+#define VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE	0x0001136A
+
 struct vss_istream_cmd_start_record_t {
 	uint32_t rx_tap_point;
 	/* Tap point to use on the Rx path. Supported values are:
@@ -614,6 +756,28 @@
 	struct vss_istream_cmd_start_record_t rec_mode;
 } __packed;
 
+struct cvs_dec_buffer_ready_cmd {
+	struct apr_hdr hdr;
+} __packed;
+
+struct cvs_enc_buffer_consumed_cmd {
+	struct apr_hdr hdr;
+} __packed;
+
+struct vss_istream_cmd_set_oob_packet_exchange_config_t {
+	struct apr_hdr hdr;
+	uint32_t mem_handle;
+	uint64_t enc_buf_addr;
+	uint32_t enc_buf_size;
+	uint64_t dec_buf_addr;
+	uint32_t dec_buf_size;
+} __packed;
+
+struct vss_istream_cmd_set_packet_exchange_mode_t {
+	struct apr_hdr hdr;
+	uint32_t mode;
+} __packed;
+
 /* TO CVP commands */
 
 #define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION	0x000100C3
@@ -646,6 +810,17 @@
 #define VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT		0x00010F77
 
 /* Newtwork IDs */
+#define VSS_ICOMMON_CAL_NETWORK_ID_NONE		0x0001135E
+
+/* Select internal mixing mode. */
+#define VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING	0x00010F7C
+
+/* Select external mixing mode. */
+#define VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING	0x00010F7D
+
+/* Default AFE port ID. Applicable to Tx and Rx. */
+#define VSS_IVOCPROC_PORT_ID_NONE			0xFFFF
+
 #define VSS_NETWORK_ID_DEFAULT				0x00010037
 #define VSS_NETWORK_ID_VOIP_NB				0x00011240
 #define VSS_NETWORK_ID_VOIP_WB				0x00011241
@@ -678,73 +853,92 @@
 #define VOICE_CMD_GET_PARAM				0x00011007
 #define VOICE_EVT_GET_PARAM_ACK				0x00011008
 
-struct vss_ivocproc_cmd_create_full_control_session_t {
+#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2	0x000112BF
+
+struct vss_ivocproc_cmd_create_full_control_session_v2_t {
 	uint16_t direction;
 	/*
-	 * stream direction.
-	 * 0 : TX only
-	 * 1 : RX only
-	 * 2 : TX and RX
+	 * Vocproc direction. The supported values:
+	 * VSS_IVOCPROC_DIRECTION_RX
+	 * VSS_IVOCPROC_DIRECTION_TX
+	 * VSS_IVOCPROC_DIRECTION_RX_TX
 	 */
-	uint32_t tx_port_id;
+	uint16_t tx_port_id;
 	/*
-	 * TX device port ID which vocproc will connect to. If not supplying a
-	 * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+	 * Tx device port ID to which the vocproc connects. If a port ID is
+	 * not being supplied, set this to #VSS_IVOCPROC_PORT_ID_NONE.
 	 */
 	uint32_t tx_topology_id;
 	/*
-	 * Tx leg topology ID. If not supplying a topology ID set to
-	 * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+	 * Tx path topology ID. If a topology ID is not being supplied, set
+	 * this to #VSS_IVOCPROC_TOPOLOGY_ID_NONE.
 	 */
-	uint32_t rx_port_id;
+	uint16_t rx_port_id;
 	/*
-	 * RX device port ID which vocproc will connect to. If not supplying a
-	 * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+	 * Rx device port ID to which the vocproc connects. If a port ID is
+	 * not being supplied, set this to #VSS_IVOCPROC_PORT_ID_NONE.
 	 */
 	uint32_t rx_topology_id;
 	/*
-	 * Rx leg topology ID. If not supplying a topology ID set to
-	 * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+	 * Rx path topology ID. If a topology ID is not being supplied, set
+	 * this to #VSS_IVOCPROC_TOPOLOGY_ID_NONE.
 	 */
-	int32_t network_id;
+	uint32_t profile_id;
+	/* Voice calibration profile ID. */
+	uint32_t vocproc_mode;
 	/*
-	 * Network ID. (Refer to VSS_NETWORK_ID_XXX). If not supplying a network
-	 * ID set to VSS_NETWORK_ID_DEFAULT.
+	 * Vocproc mode. The supported values:
+	 * VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING
+	 * VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING
+	 */
+	uint16_t ec_ref_port_id;
+	/*
+	 * Port ID to which the vocproc connects for receiving echo
+	 * cancellation reference signal. If a port ID is not being supplied,
+	 * set this to #VSS_IVOCPROC_PORT_ID_NONE. This parameter value is
+	 * ignored when the vocproc_mode parameter is set to
+	 * VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING.
+	 */
+	char name[SESSION_NAME_LEN];
+	/*
+	 * Session name string used to identify a session that can be shared
+	 * with passive controllers (optional). The string size, including the
+	 * NULL termination character, is limited to 31 characters.
 	 */
 } __packed;
 
 struct vss_ivocproc_cmd_set_volume_index_t {
 	uint16_t vol_index;
-	/**<
-	* Volume index utilized by the vocproc to index into the volume table
-	* provided in VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE and set
-	* volume on the VDSP.
-	*/
+	/*
+	 * Volume index utilized by the vocproc to index into the volume table
+	 * provided in VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE and set
+	 * volume on the VDSP.
+	 */
 } __packed;
 
 struct vss_ivocproc_cmd_set_device_t {
 	uint32_t tx_port_id;
-	/**<
-	* TX device port ID which vocproc will connect to.
-	* VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
-	*/
+	/*
+	 * TX device port ID which vocproc will connect to.
+	 * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+	 */
 	uint32_t tx_topology_id;
-	/**<
-	* TX leg topology ID.
-	* VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
-	* pre/post-processing blocks and is pass-through.
-	*/
+	/*
+	 * TX leg topology ID.
+	 * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+	 * pre/post-processing blocks and is pass-through.
+	 */
 	int32_t rx_port_id;
-	/**<
-	* RX device port ID which vocproc will connect to.
-	* VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
-	*/
+	/*
+	 * RX device port ID which vocproc will connect to.
+	 * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+	 */
 	uint32_t rx_topology_id;
-	/**<
-	* RX leg topology ID.
-	* VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
-	* pre/post-processing blocks and is pass-through.
-	*/
+	/*
+	 * RX leg topology ID.
+	 * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+	 * pre/post-processing blocks and is pass-through.
+	 */
 } __packed;
 
 struct vss_ivocproc_cmd_register_calibration_data_t {
@@ -784,7 +978,7 @@
 
 struct cvp_create_full_ctl_session_cmd {
 	struct apr_hdr hdr;
-	struct vss_ivocproc_cmd_create_full_control_session_t cvp_session;
+	struct vss_ivocproc_cmd_create_full_control_session_v2_t cvp_session;
 } __packed;
 
 struct cvp_command {
@@ -835,7 +1029,6 @@
 
 /* CB for down-link packets. */
 typedef void (*dl_cb_fn)(uint8_t *voc_pkt,
-			 uint32_t *pkt_len,
 			 void *private_data);
 
 
@@ -862,9 +1055,18 @@
 	int force;
 };
 
+struct share_memory_info {
+	u32			mem_handle;
+	struct share_mem_buf	sh_buf;
+	struct mem_map_table	memtbl;
+};
+
 struct voice_data {
 	int voc_state;/*INIT, CHANGE, RELEASE, RUN */
 
+	/* Shared mem to store decoder and encoder packets */
+	struct share_memory_info	shmem_info;
+
 	wait_queue_head_t mvm_wait;
 	wait_queue_head_t cvs_wait;
 	wait_queue_head_t cvp_wait;
@@ -959,7 +1161,8 @@
 };
 
 /* called  by alsa driver */
-int voc_set_pp_enable(uint16_t session_id, uint32_t module_id, uint32_t enable);
+int voc_set_pp_enable(uint16_t session_id, uint32_t module_id,
+		      uint32_t enable);
 int voc_get_pp_enable(uint16_t session_id, uint32_t module_id);
 int voc_set_widevoice_enable(uint16_t session_id, uint32_t wv_enable);
 uint32_t voc_get_widevoice_enable(uint16_t session_id);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 2d2b333..4c6a5a4 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -308,7 +308,7 @@
 {
 	static char buf[32];
 
-	if (type == PERF_TYPE_RAW) {
+	if (!pmu_name && type == PERF_TYPE_RAW) {
 		sprintf(buf, "raw 0x%" PRIx64, config);
 		return buf;
 	}
@@ -684,6 +684,7 @@
 {
 	struct perf_event_attr attr;
 	struct perf_pmu *pmu;
+	char *ev_name;
 
 	pmu = perf_pmu__find(name);
 	if (!pmu)
@@ -700,7 +701,9 @@
 	if (perf_pmu__config(pmu, &attr, head_config))
 		return -EINVAL;
 
-	return add_event(list, idx, &attr, pmu->name);
+	ev_name = (char *) __event_name(attr.type, attr.config, pmu->name);
+
+	return add_event(list, idx, &attr, ev_name);
 }
 
 void parse_events_update_lists(struct list_head *list_event,