Merge "msm: mdss: move vsync pending logic for faster panel on"
diff --git a/Documentation/devicetree/bindings/arm/msm/debug-pc-cntr.txt b/Documentation/devicetree/bindings/arm/msm/debug-pc-cntr.txt
deleted file mode 100644
index 01301be..0000000
--- a/Documentation/devicetree/bindings/arm/msm/debug-pc-cntr.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-* MSM PC Debug Counters
-
-MSM PC debug counter reserves 16 registers in the IMEM memory space which
-maintains a count on the state of power collapse on each core. This count
-will be useful to debug the power collapse state on each core.
-
-The required nodes for MSM PC Debug Counters are:
-
-- compatible: "qcom,pc-cntr"
-- reg: physical IMEM address reserved for PC counters
-
-Example:
-
-qcom,pc-cntr@fe800000 {
-		compatible = "qcom,pc-cntr";
-		reg = <0xfe800664 0x40>;
-	};
-
diff --git a/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt b/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt
new file mode 100644
index 0000000..e62b9ec
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt
@@ -0,0 +1,17 @@
+* MSM Timetick counter (mpm-v2)
+
+The MPM provides a timetick that starts when the device is powered up and
+is not reset by any of the boot loaders or the HLOS. The MPM timetick counter
+driver provides an api to get this value.
+
+The required nodes for the MPM timetick counter driver are:
+
+- compatible: "qcom,mpm-counter"
+- reg: Specifies the physical address of the timetick count register.
+
+Example:
+	qcom,mpm-counter@fc4a3000 {
+		compatible = "qcom,mpm-counter";
+		reg = <0xfc4a3000 0x1000>;
+	};
+
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
index b429072..a372912 100644
--- a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
+++ b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
@@ -5,6 +5,9 @@
 the kernel to be notified of idle and suspend states and when called, follows
 through the set of instructions in putting the application cores to the lowest
 power mode possible.
+The PC debug counter reserves 16 registers in the IMEM memory space which maintains
+a count on the state of power collapse on each core. This count will be useful to
+debug the power collapse state on each core.
 
 The required properties for PM-8x60 are:
 
@@ -12,17 +15,22 @@
 
 The optional properties are:
 
+- reg: physical IMEM address reserved for PC counters and the size
 - qcom,use-sync-timer: Indicates whether the target uses the synchronized QTimer.
 - qcom,pc-mode: Indicates the type of power collapse used by the target. The
-           valid values for this are:
+	valid values for this are:
 	0  (Power collapse terminates in TZ; integrated L2 cache controller)
 	1, (Power collapse doesn't terminate in TZ; external L2 cache controller)
 	2  (Power collapse terminates in TZ; external L2 cache controller)
+- qcom,saw-turns-off-pll: Version of SAW2.1 or can turn off the HFPLL, when
+	doing power collapse and so the core need to switch to Global PLL before
+	PC.
 
 Example:
 
-qcom,pm-8x60 {
+qcom,pm-8x60@fe800664 {
 		compatible = "qcom,pm-8x60";
+		reg = <0xfe800664 0x40>;
 		qcom,pc-mode = <0>;
 		qcom,use-sync-timer;
 	};
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index b1f6717..8f602b6 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -21,8 +21,6 @@
 		      images and self-authentication is not desired;
 		      <1> if the hardware requires self-authenticating images.
 - qcom,is-loadable:   if PIL is required to load the modem image
-- qcom,gpio-err-fatal: GPIO used by the modem to indicate error fatal to the apps.
-- qcom,gpio-force-stop: GPIO used by the apps to force the modem to shutdown.
 
 Optional properties:
 - vdd_pll-supply:     Reference to the regulator that supplies the PLL's rail.
@@ -46,10 +44,4 @@
 		qcom,is-loadable;
 		qcom,firmware-name = "mba";
 		qcom,pil-self-auth = <1>;
-
-		/* GPIO inputs from mss */
-		gpio_err_fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
-
-		/* GPIO output to mss */
-		gpio_force_stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
 	};
diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt
index 939f77b..4b912f3 100644
--- a/Documentation/devicetree/bindings/spi/spi_qsd.txt
+++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt
@@ -1,25 +1,51 @@
 Qualcomm Serial Peripheral Interface (SPI)
 
 Required properties:
-- compatible : should be "qcom,spi-qup-v2".
-- reg : offset and length of the QUP register map.
-- interrupts : should contain the QUP core interrupt.
-- spi-max-frequency : specifies maximum SPI clock frequency, Units - Hz.
+- compatible : Should be "qcom,spi-qup-v2".
+- reg : Offset and length of the register regions for the device
+- reg-names : Register region names referenced in reg above.
+	Required register resource entries are:
+	"spi_physical" : Physical address of controller register blocks.
+- interrupts : Interrupt numbers used by this controller
+- interrupt-names : Interrupt resource names referenced in interrupts above.
+	Required interrupt resource entries are:
+	"spi_irq" : QUP-core interrupt.
+- spi-max-frequency : Specifies maximum SPI clock frequency, Units - Hz.
+
+Required alias:
+- The desired bus-number is specified via an alias with the following format
+	'spi{n}' where n is the bus number.
 
 Optional properties:
-- gpios : specifies the gpio pins to be used for SPI CLK, MISO, MOSI in
+- gpios : Specifies the gpio pins to be used for SPI CLK, MISO, MOSI in
   that order.
-- cs-gpios : specifies the gpio pins to be used for chipselects.
+- cs-gpios : Specifies the gpio pins to be used for chipselects.
+- qcom,infinite-mode: When missing or set to zero, QUP uses infinite-mode. When
+  value is non-zero, the value is the number of words in maximum transfer
+  length.
 
-SPI slave nodes must be children of the SPI master node and contain
+Optional properties which are required for support of BAM-mode:
+- qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW
+  version support latest features (e.g. BAM) and then enable them. Should be
+  removed for legacy HW.
+- qcom,use-bam : Boolean. When present, enables BAM-mode.
+- qcom,bam-consumer-pipe-index : BAM consumer-pipe index.
+- qcom,bam-producer-pipe-index : BAM producer-pipe index.
+- reg-names : register region names referenced in reg.
+	Required register resource for BAM are:
+	"spi_bam_physical" : Physical address of BAM for this controller.
+- interrupt-names : interrupt resource names referenced in interrupts.
+	Required interrupt resource from BAM are:
+	"spi_bam_irq" : BAM interrupt used by the controller.
+
+Optional SPI slave nodes must be children of the SPI master node and contain
 the following properties.
-- reg : (required) chip select address of device.
-- compatible : (required) name of SPI device following generic names
-  recommended practice
+- reg: (required) chip-select address of the device.
+- compatible : (required) Name of SPI device following generic names.
 - spi-max-frequency : (required) Maximum SPI clocking speed of device in Hz
-- interrupts : (recommended) should contain the SPI slave interrupt number
+- interrupts : (recommended) Should contain the SPI slave interrupt number
   encoded depending on the type of the interrupt controller.
-- interrupt-parent : (recommended) the phandle for the interrupt controller
+- interrupt-parent : (recommended) The phandle for the interrupt controller
   that services interrupts for this device.
 - spi-cpol : (optional) Empty property indicating device requires inverse
   clock polarity (CPOL) mode
@@ -29,18 +55,30 @@
   chip select active high
 
 Example:
-	spi@f9924000 {
-		compatible = "qcom,spi-qup-v2";
-		reg = <0xf9924000 0x1000>;
-		interrupts = <0 96 0>;
-		spi-max-frequency = <24000000>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		device@0 {
-			compatible = "spidev";
-			reg = <0>;
-			spi-max-frequency = <5000000>;
-		};
+	aliases {
+		spi0 = &spi_0;
 	};
 
+	spi_0: spi@f9923000 {
+		compatible = "qcom,spi-qup-v2";
+
+		reg-names = "spi_physical", "spi_bam_physical";
+		reg = <0xf9923000 0x1000>,
+			<0xf9904000 0x10000>;
+		interrupt-names = "spi_irq", "spi_bam_irq";
+		interrupts = <0 95 0>, <0 238 0>;
+
+		spi-max-frequency = <19200000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		gpios = <&msmgpio 3 0>, /* CLK  */
+			<&msmgpio 1 0>, /* MISO */
+			<&msmgpio 0 0>; /* MOSI */
+		cs-gpios = <&msmgpio 9 0>;
+
+		qcom,infinite-mode = <0>;
+		qcom,use-bam;
+		qcom,bam-consumer-pipe-index = <12>;
+		qcom,bam-producer-pipe-index = <13>;
+		qcom,ver-reg-exists;
+	};
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 0e06ac5..ce4513b 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -16,6 +16,113 @@
 	interrupt-controller;
 	#interrupt-cells = <3>;
 
+	qcom,pm8226@0 {
+		spmi-slave-container;
+		reg = <0x0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		pm8226_gpios: gpios {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-pin";
+			gpio-controller;
+			#gpio-cells = <2>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			label = "pm8226-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>;
+			};
+
+			gpio@c600 {
+				reg = <0xc600 0x100>;
+				qcom,pin-num = <7>;
+			};
+
+			gpio@c700 {
+				reg = <0xc700 0x100>;
+				qcom,pin-num = <8>;
+			};
+		};
+
+		pm8226_mpps: mpps {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-pin";
+			gpio-controller;
+			#gpio-cells = <2>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			label = "pm8226-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>;
+			};
+
+			mpp@a600 {
+				reg = <0xa600 0x100>;
+				qcom,pin-num = <7>;
+			};
+
+			mpp@a700 {
+				reg = <0xa700 0x100>;
+				qcom,pin-num = <8>;
+			};
+		};
+	};
+
 	qcom,pm8226@1 {
 		spmi-slave-container;
 		reg = <0x1>;
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index f2269d5..50d2dba 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -10,275 +10,300 @@
  * GNU General Public License for more details.
  */
 
- /* Stub Regulators */
+/* Stub Regulators */
 
- / {
-	pm8026_s1: regulator-s1 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_s1";
-		qcom,hpm-min-load = <100000>;
-		regulator-min-microvolt = <1150000>;
-		regulator-max-microvolt = <1150000>;
-	};
-
+/ {
 	pm8026_s1_corner: regulator-s1-corner {
 		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_s1_corner";
+		regulator-name = "8226_s1_corner";
 		qcom,hpm-min-load = <100000>;
 		regulator-min-microvolt = <1>;
 		regulator-max-microvolt = <7>;
 		qcom,consumer-supplies = "vdd_dig", "";
 	};
+};
 
-	pm8026_s2: regulator-s2 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_s2";
-		qcom,hpm-min-load = <100000>;
-		regulator-min-microvolt = <1050000>;
-		regulator-max-microvolt = <1050000>;
-	};
+/* QPNP controlled regulators: */
 
-	pm8026_s3: regulator-s3 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_s3";
-		qcom,hpm-min-load = <100000>;
-		regulator-min-microvolt = <1300000>;
-		regulator-max-microvolt = <1300000>;
-	};
+&spmi_bus {
 
-	pm8026_s4: regulator-s4 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_s4";
-		qcom,hpm-min-load = <100000>;
-		regulator-min-microvolt = <2100000>;
-		regulator-max-microvolt = <2100000>;
-	};
+	qcom,pm8226@1 {
 
-	pm8026_s5: regulator-s5 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_s5";
-		qcom,hpm-min-load = <100000>;
-		regulator-min-microvolt = <1150000>;
-		regulator-max-microvolt = <1150000>;
-	};
+		pm8226_s1: regulator@1400 {
+			status = "okay";
+			regulator-name = "8226_s1";
+			qcom,enable-time = <500>;
+			qcom,system-load = <100000>;
+			regulator-always-on;
+			regulator-min-microvolt = <1287500>;
+			regulator-max-microvolt = <1287500>;
+		};
 
-	pm8026_l1: regulator-l1 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l1";
-		parent-supply = <&pm8026_s3>;
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <1225000>;
-		regulator-max-microvolt = <1225000>;
-	};
+		pm8226_s2: regulator@1700 {
+			status = "okay";
+			regulator-name = "8226_s2";
+			qcom,enable-time = <500>;
+			qcom,system-load = <100000>;
+			regulator-always-on;
+			regulator-min-microvolt = <1150000>;
+			regulator-max-microvolt = <1150000>;
+		};
 
-	pm8026_l2: regulator-l2 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l2";
-		parent-supply = <&pm8026_s3>;
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <1200000>;
-		regulator-max-microvolt = <1200000>;
-	};
+		pm8226_s3: regulator@1a00 {
+			status = "okay";
+			regulator-name = "8226_s3";
+			qcom,enable-time = <500>;
+			qcom,system-load = <100000>;
+			regulator-always-on;
+			regulator-min-microvolt = <1300000>;
+			regulator-max-microvolt = <1300000>;
+		};
 
-	pm8026_l3: regulator-l3 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l3";
-		parent-supply = <&pm8026_s3>;
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <1150000>;
-		regulator-max-microvolt = <1150000>;
-	};
+		pm8226_s4: regulator@1d00 {
+			status = "okay";
+			regulator-name = "8226_s4";
+			qcom,enable-time = <500>;
+			qcom,system-load = <100000>;
+			regulator-always-on;
+			regulator-min-microvolt = <2100000>;
+			regulator-max-microvolt = <2100000>;
+		};
 
-	pm8026_l4: regulator-l4 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l4";
-		parent-supply = <&pm8026_s3>;
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <1200000>;
-		regulator-max-microvolt = <1200000>;
-	};
+		pm8226_s5: regulator@2000 {
+			status = "okay";
+			regulator-name = "8226_s5";
+			qcom,enable-time = <500>;
+			regulator-min-microvolt = <1150000>;
+			regulator-max-microvolt = <1150000>;
+		};
 
-	pm8026_l5: regulator-l5 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l5";
-		parent-supply = <&pm8026_s3>;
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <1200000>;
-		regulator-max-microvolt = <1200000>;
-	};
+		pm8226_l1: regulator@4000 {
+			status = "okay";
+			regulator-name = "8226_l1";
+			parent-supply = <&pm8226_s3>;
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+		};
 
-	pm8026_l6: regulator-l6 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l6";
-		parent-supply = <&pm8026_s4>;
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <1800000>;
-	};
+		pm8226_l2: regulator@4100 {
+			status = "okay";
+			regulator-name = "8226_l2";
+			parent-supply = <&pm8226_s3>;
+			regulator-always-on;
+			qcom,enable-time = <200>;
+			qcom,system-load = <10000>;
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+		};
 
-	pm8026_l7: regulator-l7 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l7";
-		parent-supply = <&pm8026_s4>;
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <1850000>;
-		regulator-max-microvolt = <1850000>;
-	};
+		pm8226_l3: regulator@4200 {
+			status = "okay";
+			regulator-name = "8226_l3";
+			parent-supply = <&pm8226_s3>;
+			qcom,system-load = <10000>;
+			regulator-always-on;
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <1287500>;
+			regulator-max-microvolt = <1287500>;
+		};
 
-	pm8026_l8: regulator-l8 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l8";
-		parent-supply = <&pm8026_s4>;
-		qcom,hpm-min-load = <5000>;
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <1800000>;
-		qcom,consumer-supplies = "vdd_sr2_pll", "";
-	};
+		pm8226_l4: regulator@4300 {
+			status = "okay";
+			regulator-name = "8226_l4";
+			parent-supply = <&pm8226_s3>;
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+		};
 
-	pm8026_l9: regulator-l9 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l9";
-		parent-supply = <&pm8026_s4>;
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <2050000>;
-		regulator-max-microvolt = <2050000>;
-	};
+		pm8226_l5: regulator@4400 {
+			status = "okay";
+			regulator-name = "8226_l5";
+			parent-supply = <&pm8226_s3>;
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+		};
 
-	pm8026_l10: regulator-l10 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l10";
-		parent-supply = <&pm8026_s4>;
-		qcom,hpm-min-load = <5000>;
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <1800000>;
-	};
+		pm8226_l6: regulator@4500 {
+			status = "okay";
+			regulator-name = "8226_l6";
+			parent-supply = <&pm8226_s4>;
+			qcom,system-load = <10000>;
+			regulator-always-on;
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+		};
 
-	pm8026_l12: regulator-l12 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l12";
-		qcom,hpm-min-load = <5000>;
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <1800000>;
-	};
+		pm8226_l7: regulator@4600 {
+			status = "okay";
+			regulator-name = "8226_l7";
+			parent-supply = <&pm8226_s4>;
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <1850000>;
+			regulator-max-microvolt = <1850000>;
+		};
 
-	pm8026_l14: regulator-l14 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l14";
-		qcom,hpm-min-load = <5000>;
-		regulator-min-microvolt = <2750000>;
-		regulator-max-microvolt = <2750000>;
-	};
+		pm8226_l8: regulator@4700 {
+			status = "okay";
+			regulator-name = "8226_l8";
+			parent-supply = <&pm8226_s4>;
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,consumer-supplies = "vdd_sr2_pll", "";
+		};
 
-	pm8026_l15: regulator-l15 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l15";
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <2800000>;
-		regulator-max-microvolt = <2800000>;
-	};
+		pm8226_l9: regulator@4800 {
+			status = "okay";
+			regulator-name = "8226_l9";
+			parent-supply = <&pm8226_s4>;
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <2050000>;
+			regulator-max-microvolt = <2050000>;
+		};
 
-	pm8026_l16: regulator-l16 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l16";
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <3000000>;
-		regulator-max-microvolt = <3000000>;
-	};
+		pm8226_l10: regulator@4900 {
+			status = "okay";
+			regulator-name = "8226_l10";
+			parent-supply = <&pm8226_s4>;
+			qcom,enable-time = <200>;
+			qcom,system-load = <5000>;
+			regulator-always-on;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+		};
 
-	pm8026_l17: regulator-l17 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l17";
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <2950000>;
-		regulator-max-microvolt = <2950000>;
-	};
+		pm8226_l12: regulator@4b00 {
+			status = "okay";
+			regulator-name = "8226_l12";
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+		};
 
-	pm8026_l18: regulator-l18 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l18";
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <2950000>;
-		regulator-max-microvolt = <2950000>;
-	};
+		pm8226_l14: regulator@4d00 {
+			status = "okay";
+			regulator-name = "8226_l14";
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <2750000>;
+			regulator-max-microvolt = <2750000>;
+		};
 
-	pm8026_l19: regulator-l19 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l19";
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <2850000>;
-		regulator-max-microvolt = <2850000>;
-	};
+		pm8226_l15: regulator@4e00 {
+			status = "okay";
+			regulator-name = "8226_l15";
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+		};
 
-	pm8026_l20: regulator-l20 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l20";
-		qcom,hpm-min-load = <5000>;
-		regulator-min-microvolt = <3075000>;
-		regulator-max-microvolt = <3075000>;
-	};
+		pm8226_l16: regulator@4f00 {
+			status = "okay";
+			regulator-name = "8226_l16";
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <3000000>;
+			regulator-max-microvolt = <3300000>;
+		};
 
-	pm8026_l21: regulator-l21 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l21";
-		qcom,hpm-min-load = <5000>;
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <2950000>;
-	};
+		pm8226_l17: regulator@5000 {
+			status = "okay";
+			regulator-name = "8226_l17";
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <2950000>;
+			regulator-max-microvolt = <2950000>;
+		};
 
-	pm8026_l22: regulator-l22 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l22";
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <2950000>;
-	};
+		pm8226_l18: regulator@5100 {
+			status = "okay";
+			regulator-name = "8226_l18";
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <2950000>;
+			regulator-max-microvolt = <2950000>;
+		};
 
-	pm8026_l23: regulator-l23 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l23";
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <2950000>;
-	};
+		pm8226_l19: regulator@5200 {
+			status = "okay";
+			regulator-name = "8226_l19";
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <2850000>;
+			regulator-max-microvolt = <2850000>;
+		};
 
-	pm8026_l24: regulator-l24 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l24";
-		parent-supply = <&pm8026_s3>;
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <1300000>;
-		regulator-max-microvolt = <1300000>;
-	};
+		pm8226_l20: regulator@5300 {
+			status = "okay";
+			regulator-name = "8226_l20";
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <3075000>;
+			regulator-max-microvolt = <3075000>;
+		};
 
-	pm8026_l26: regulator-l26 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l26";
-		parent-supply = <&pm8026_s3>;
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <1225000>;
-		regulator-max-microvolt = <1225000>;
-	};
+		pm8226_l21: regulator@5400 {
+			status = "okay";
+			regulator-name = "8226_l21";
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+		};
 
-	pm8026_l27: regulator-l27 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l27";
-		parent-supply = <&pm8026_s4>;
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <2050000>;
-		regulator-max-microvolt = <2050000>;
-	};
+		pm8226_l22: regulator@5500 {
+			status = "okay";
+			regulator-name = "8226_l22";
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+		};
 
-	pm8026_l28: regulator-l28 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_l28";
-		qcom,hpm-min-load = <10000>;
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <2950000>;
-	};
+		pm8226_l23: regulator@5600 {
+			status = "okay";
+			regulator-name = "8226_l23";
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+		};
 
-	 pm8026_lvs1: regulator-lvs1 {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8026_lvs1";
-		parent-supply = <&pm8026_l6>;
+		pm8226_l24: regulator@5700 {
+			status = "okay";
+			regulator-name = "8226_l24";
+			parent-supply = <&pm8226_s3>;
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <1300000>;
+			regulator-max-microvolt = <1300000>;
+		};
+
+		pm8226_l26: regulator@5900 {
+			status = "okay";
+			regulator-name = "8226_l26";
+			parent-supply = <&pm8226_s3>;
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+		};
+
+		pm8226_l27: regulator@5a00 {
+			status = "okay";
+			regulator-name = "8226_l27";
+			parent-supply = <&pm8226_s4>;
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <2050000>;
+			regulator-max-microvolt = <2050000>;
+		};
+
+		pm8226_l28: regulator@5b00 {
+			status = "okay";
+			regulator-name = "8226_l28";
+			qcom,enable-time = <200>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+		};
+
+		pm8226_lvs1: regulator@8000 {
+			status = "okay";
+			regulator-name = "8226_lvs1";
+			parent-supply = <&pm8226_l6>;
+			qcom,enable-time = <200>;
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226-sim.dts b/arch/arm/boot/dts/msm8226-sim.dts
index 9a0ec17..f9ab957 100644
--- a/arch/arm/boot/dts/msm8226-sim.dts
+++ b/arch/arm/boot/dts/msm8226-sim.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -39,8 +39,8 @@
 	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
-	vdd-supply = <&pm8026_l17>;
-	vdd-io-supply = <&pm8026_l6>;
+	vdd-supply = <&pm8226_l17>;
+	vdd-io-supply = <&pm8226_l6>;
 	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
 	qcom,sup-voltages = <2950 2950>;
 
@@ -50,8 +50,8 @@
 };
 
 &sdcc2 {
-	vdd-supply = <&pm8026_l18>;
-	vdd-io-supply = <&pm8026_l21>;
+	vdd-supply = <&pm8226_l18>;
+	vdd-io-supply = <&pm8226_l21>;
 	qcom,vdd-voltage-level = <2950000 2950000>;
 	qcom,vdd-current-level = <9000 800000>;
 
@@ -74,3 +74,57 @@
 
 	status = "ok";
 };
+
+&pm8226_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 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+};
+
+&pm8226_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 */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
+};
+
+
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 5227004..3ae69fd 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -81,9 +81,9 @@
 		reg = <0xf9a55000 0x400>;
 		interrupts = <0 134 0>, <0 140 0>;
 		interrupt-names = "core_irq", "async_irq";
-		HSUSB_VDDCX-supply = <&pm8026_s1>;
-		HSUSB_1p8-supply = <&pm8026_l10>;
-		HSUSB_3p3-supply = <&pm8026_l20>;
+		HSUSB_VDDCX-supply = <&pm8226_s1>;
+		HSUSB_1p8-supply = <&pm8226_l10>;
+		HSUSB_3p3-supply = <&pm8226_l20>;
 
 		qcom,hsusb-otg-phy-type = <2>;
 		qcom,hsusb-otg-mode = <1>;
@@ -123,23 +123,23 @@
 					17 18 19 20 21 22 23 24 25 26 27 28>;
 			qcom,cdc-reset-gpio = <&msmgpio 72 0>;
 
-			cdc-vdd-buck-supply = <&pm8026_s4>;
+			cdc-vdd-buck-supply = <&pm8226_s4>;
 			qcom,cdc-vdd-buck-voltage = <2100000 2100000>;
 			qcom,cdc-vdd-buck-current = <650000>;
 
-			cdc-vdd-h-supply = <&pm8026_l6>;
+			cdc-vdd-h-supply = <&pm8226_l6>;
 			qcom,cdc-vdd-h-voltage = <1800000 1800000>;
 			qcom,cdc-vdd-h-current = <25000>;
 
-			cdc-vdd-px-supply = <&pm8026_l6>;
+			cdc-vdd-px-supply = <&pm8226_l6>;
 			qcom,cdc-vdd-px-voltage = <1800000 1800000>;
 			qcom,cdc-vdd-px-current = <25000>;
 
-			cdc-vdd-a-1p2v-supply = <&pm8026_l4>;
+			cdc-vdd-a-1p2v-supply = <&pm8226_l4>;
 			qcom,cdc-vdd-a-1p2v-voltage = <1200000 1200000>;
 			qcom,cdc-vdd-a-1p2v-current = <10000>;
 
-			cdc-vdd-cx-supply = <&pm8026_l4>;
+			cdc-vdd-cx-supply = <&pm8226_l4>;
 			qcom,cdc-vdd-cx-voltage = <1200000 1200000>;
 			qcom,cdc-vdd-cx-current = <10000>;
 
@@ -466,8 +466,8 @@
 		compatible = "qcom,acpuclk-a7";
 		reg = <0xf9011050 0x8>;
 		reg-names = "rcg_base";
-		a7_cpu-supply = <&pm8026_s2>;
-		a7_mem-supply = <&pm8026_l3>;
+		a7_cpu-supply = <&pm8226_s2>;
+		a7_mem-supply = <&pm8226_l3>;
 	};
 
 	qcom,ocmem@fdd00000 {
@@ -510,7 +510,7 @@
 		      <0xfd485300 0xc>;
 		reg-names = "pmu_base", "clk_base", "halt_base";
 		interrupts = <0 149 1>;
-		vdd_pronto_pll-supply = <&pm8026_l8>;
+		vdd_pronto_pll-supply = <&pm8226_l8>;
 
 		qcom,firmware-name = "wcnss";
 	};
@@ -566,5 +566,5 @@
 	status = "ok";
 };
 
-/include/ "msm8226-regulator.dtsi"
 /include/ "msm-pm8226.dtsi"
+/include/ "msm8226-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 12804fb..16883ef 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -534,3 +534,11 @@
 	mpp@a300 { /* MPP 4 */
 	};
 };
+
+&slim_msm {
+	taiko_codec {
+		qcom,cdc-micbias1-ext-cap;
+		qcom,cdc-micbias3-ext-cap;
+		qcom,cdc-micbias4-ext-cap;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 7cc10e2..11c835f 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -207,7 +207,10 @@
 
 &slim_msm {
 	taiko_codec {
+		qcom,cdc-micbias1-ext-cap;
 		qcom,cdc-micbias2-ext-cap;
+		qcom,cdc-micbias3-ext-cap;
+		qcom,cdc-micbias4-ext-cap;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 76b23a1..e97678a 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -585,6 +585,7 @@
 &slim_msm {
 	taiko_codec {
 		qcom,cdc-micbias2-ext-cap;
+		qcom,cdc-micbias3-ext-cap;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index ea57389..e21610b 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -512,7 +512,9 @@
 
 &slim_msm {
 	taiko_codec {
+		qcom,cdc-micbias1-ext-cap;
 		qcom,cdc-micbias2-ext-cap;
+		qcom,cdc-micbias4-ext-cap;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8974-smp2p.dtsi b/arch/arm/boot/dts/msm8974-smp2p.dtsi
index 60f63a8..511f91f 100644
--- a/arch/arm/boot/dts/msm8974-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8974-smp2p.dtsi
@@ -103,29 +103,6 @@
 		gpios = <&smp2pgpio_smp2p_1_out 0 0>;
 	};
 
-	/* SMP2P SSR Driver for inbound entry from modem. */
-	smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
-		compatible = "qcom,smp2pgpio";
-		qcom,entry-name = "slave-kernel";
-		qcom,remote-pid = <1>;
-		qcom,is-inbound;
-		gpio-controller;
-		#gpio-cells = <2>;
-		interrupt-controller;
-		#interrupt-cells = <2>;
-	};
-
-	/* SMP2P SSR Driver for outbound entry to modem */
-	smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
-		compatible = "qcom,smp2pgpio";
-		qcom,entry-name = "master-kernel";
-		qcom,remote-pid = <1>;
-		gpio-controller;
-		#gpio-cells = <2>;
-		interrupt-controller;
-		#interrupt-cells = <2>;
-	};
-
 	/* SMP2P Test Driver for adsp inbound */
 	smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
 		compatible = "qcom,smp2pgpio";
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index f9b9e33..2de5fad 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -419,13 +419,9 @@
 			<40  95>;
 	};
 
-	qcom,pc-cntr@fe805664 {
-		compatible = "qcom,pc-cntr";
-		reg = <0xfe805664 0x40>;
-	};
-
-	qcom,pm-8x60 {
+	qcom,pm-8x60@fe805664 {
 		compatible = "qcom,pm-8x60";
+		reg = <0xfe805664 0x40>;
 		qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
 		qcom,use-sync-timer;
 	};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 6b0d446..e6376d4 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -25,6 +25,11 @@
 	compatible = "qcom,msm8974";
 	interrupt-parent = <&intc>;
 
+	aliases {
+		spi0 = &spi_0;
+		spi7 = &spi_7;
+	};
+
 	intc: interrupt-controller@F9000000 {
 		compatible = "qcom,msm-qgic2";
 		interrupt-controller;
@@ -60,6 +65,11 @@
 		clock-frequency = <19200000>;
 	};
 
+	qcom,mpm-counter@fc4a3000 {
+		compatible = "qcom,mpm-counter";
+		reg = <0xfc4a3000 0x1000>;
+	};
+
 	qcom,vidc@fdc00000 {
 		compatible = "qcom,msm-vidc";
 		reg = <0xfdc00000 0xff000>;
@@ -376,9 +386,8 @@
 		qcom,bam-dma-res-pipes = <6>;
 	};
 
-	spi_epm: spi@f9966000 {
+	spi_7: spi_epm: spi@f9966000 {
 		compatible = "qcom,spi-qup-v2";
-		cell-index = <7>;
 		reg = <0xf9966000 0x1000>;
 		interrupts = <0 104 0>;
 		spi-max-frequency = <19200000>;
@@ -567,8 +576,7 @@
 		qcom,i2c-src-freq = <19200000>;
 	};
 
-	spi@f9923000 {
-		cell-index = <0>;
+	spi_0: spi@f9923000 {
 		compatible = "qcom,spi-qup-v2";
 		reg = <0xf9923000 0x1000>;
 		interrupts = <0 95 0>;
@@ -883,12 +891,6 @@
 		qcom,is-loadable;
 		qcom,firmware-name = "mba";
 		qcom,pil-self-auth = <1>;
-
-		/* GPIO input from mss */
-		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
-
-		/* GPIO output to mss */
-		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
 	};
 
 	qcom,pronto@fb21b000 {
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 793d27b..a735609 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -189,8 +189,38 @@
 
 		qcom,gic-parent = <&intc>;
 		qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
-			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
-			<0xff 208>; /* summary_irq_kpss */
+			<41 180>,   /* usb_async_wakeup_irq */
+			<62 222>,   /* ee0_krait_hlos_spmi_periph_irq */
+			<0xff 57>,  /* mss_to_apps_irq(0) */
+			<0xff 58>,  /* mss_to_apps_irq(1) */
+			<0xff 59>,  /* mss_to_apps_irq(2) */
+			<0xff 60>,  /* mss_to_apps_irq(3) */
+			<0xff 173>, /* o_wcss_apss_smd_hi */
+			<0xff 174>, /* o_wcss_apss_smd_med */
+			<0xff 175>, /* o_wcss_apss_smd_lo */
+			<0xff 176>, /* o_wcss_apss_smsm_irq */
+			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
+			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
+			<0xff 179>, /* o_wcss_apss_asic_intr */
+			<0xff 188>, /* q6ss_irq_out(4) */
+			<0xff 189>, /* q6ss_irq_out(5) */
+			<0xff 190>, /* q6ss_irq_out(6) */
+			<0xff 191>, /* q6ss_irq_out(7) */
+			<0xff 192>, /* audio_out0_irq */
+			<0xff 193>, /* midi_arm_irq */
+			<0xff 194>, /* q6ss_wdog_exp_irq */
+			<0xff 195>, /* slimbus_core_ee1_irq */
+			<0xff 196>, /* bam_irq(1) */
+			<0xff 197>, /* qdss_irq_out(7) */
+			<0xff 200>, /* rpm_ipc(4) */
+			<0xff 201>, /* rpm_ipc(5) */
+			<0xff 202>, /* rpm_ipc(6) */
+			<0xff 203>, /* rpm_ipc(7)   */
+			<0xff 204>, /* rpm_ipc(24)   */
+			<0xff 205>, /* rpm_ipc(25)   */
+			<0xff 206>, /* rpm_ipc(26)   */
+			<0xff 207>, /* rpm_ipc(27)   */
+			<0xff 240>; /* summary_irq_kpss */
 
 		qcom,gpio-parent = <&msmgpio>;
 		qcom,gpio-map = <4  1>,
diff --git a/arch/arm/boot/dts/msm9625-v2-1-cdp.dts b/arch/arm/boot/dts/msm9625-v2-1-cdp.dts
new file mode 100644
index 0000000..8702184
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2-1-cdp.dts
@@ -0,0 +1,99 @@
+/* Copyright (c) 2013, 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm9625-v2-1.dtsi"
+
+/ {
+	model = "Qualcomm MSM 9625V2.1 CDP";
+	compatible = "qcom,msm9625-cdp", "qcom,msm9625";
+	qcom,msm-id = <134 1 0x20001>, <152 1 0x20001>, <149 1 0x20001>,
+		      <150 1 0x20001>, <151 1 0x20001>, <148 1 0x20001>,
+		      <173 1 0x20001>, <174 1 0x20001>, <175 1 0x20001>;
+
+	i2c@f9925000 {
+		charger@57 {
+			compatible = "summit,smb137c";
+			reg = <0x57>;
+			summit,chg-current-ma = <1500>;
+			summit,term-current-ma = <50>;
+			summit,pre-chg-current-ma = <100>;
+			summit,float-voltage-mv = <4200>;
+			summit,thresh-voltage-mv = <3000>;
+			summit,recharge-thresh-mv = <75>;
+			summit,system-voltage-mv = <4250>;
+			summit,charging-timeout = <382>;
+			summit,pre-charge-timeout = <48>;
+			summit,therm-current-ua = <10>;
+			summit,temperature-min = <4>; /*  0 C */
+			summit,temperature-max = <3>; /* 45 C */
+		};
+	};
+
+	wlan0: qca,wlan {
+		cell-index = <0>;
+		compatible = "qca,ar6004-sdio";
+		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
+		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
+		qca,ar6004-vdd-io-supply = <&pm8019_l11>;
+	};
+};
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+		/* ext_2p95v regulator enable config */
+		qcom,mode = <1>; /* Digital output */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,invert = <0>; /* Output low */
+		qcom,out-strength = <1>; /* Low */
+		qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
+		qcom,src-sel = <0>; /* Constant */
+		qcom,master-en = <1>; /* Enable GPIO */
+	};
+
+	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-v2-1-mtp.dts b/arch/arm/boot/dts/msm9625-v2-1-mtp.dts
new file mode 100644
index 0000000..2dc040c
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2-1-mtp.dts
@@ -0,0 +1,99 @@
+/* Copyright (c) 2013, 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm9625-v2-1.dtsi"
+
+/ {
+	model = "Qualcomm MSM 9625V2.1 MTP";
+	compatible = "qcom,msm9625-mtp", "qcom,msm9625";
+	qcom,msm-id = <134 7 0x20001>, <152 7 0x20001>, <149 7 0x20001>,
+		      <150 7 0x20001>, <151 7 0x20001>, <148 7 0x20001>,
+		      <173 7 0x20001>, <174 7 0x20001>, <175 7 0x20001>;
+
+	i2c@f9925000 {
+		charger@57 {
+			compatible = "summit,smb137c";
+			reg = <0x57>;
+			summit,chg-current-ma = <1500>;
+			summit,term-current-ma = <50>;
+			summit,pre-chg-current-ma = <100>;
+			summit,float-voltage-mv = <4200>;
+			summit,thresh-voltage-mv = <3000>;
+			summit,recharge-thresh-mv = <75>;
+			summit,system-voltage-mv = <4250>;
+			summit,charging-timeout = <382>;
+			summit,pre-charge-timeout = <48>;
+			summit,therm-current-ua = <10>;
+			summit,temperature-min = <4>; /*  0 C */
+			summit,temperature-max = <3>; /* 45 C */
+		};
+	};
+
+	wlan0: qca,wlan {
+		cell-index = <0>;
+		compatible = "qca,ar6004-sdio";
+		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
+		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
+		qca,ar6004-vdd-io-supply = <&pm8019_l11>;
+	};
+};
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+		/* ext_2p95v regulator enable config */
+		qcom,mode = <1>; /* Digital output */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,invert = <0>; /* Output low */
+		qcom,out-strength = <1>; /* Low */
+		qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
+		qcom,src-sel = <0>; /* Constant */
+		qcom,master-en = <1>; /* Enable GPIO */
+	};
+
+	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-v2-1.dtsi b/arch/arm/boot/dts/msm9625-v2-1.dtsi
new file mode 100644
index 0000000..c3c2c49
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2-1.dtsi
@@ -0,0 +1,36 @@
+/* Copyright (c) 2013, 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.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm9625.dtsi file.
+ */
+
+/include/ "msm9625.dtsi"
+
+/ {
+	qcom,msm-imem@fe807800 {
+		compatible = "qcom,msm-imem";
+		reg = <0xfe807800 0x1000>; /* Address and size of IMEM */
+	};
+
+	android_usb@fe8078c8 {
+		compatible = "qcom,android-usb";
+		reg = <0xfe8078c8 0xc8>;
+		qcom,android-usb-swfi-latency = <100>;
+	};
+};
+
+&ipa_hw {
+	qcom,ipa-hw-ver = <2>; /* IPA h-w revision */
+};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index d5a33ee..922616c 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -21,6 +21,10 @@
 	compatible = "qcom,msm9625";
 	interrupt-parent = <&intc>;
 
+	aliases {
+		spi0 = &spi_0;
+	};
+
 	intc: interrupt-controller@F9000000 {
 		compatible = "qcom,msm-qgic2";
 		interrupt-controller;
@@ -186,8 +190,7 @@
 		interrupt-names = "bam_irq";
 	};
 
-	spi@f9924000 {
-		cell-index = <0>;
+	spi_0: spi@f9924000 {
 		compatible = "qcom,spi-qup-v2";
 		reg = <0xf9924000 0x1000>;
 		interrupts = <0 96 0>;
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 1623d45..2bf4630 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -139,6 +139,7 @@
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
 CONFIG_WCD9306_CODEC=y
+CONFIG_GPIO_QPNP_PIN=y
 # CONFIG_HWMON is not set
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_STUB=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 2f2e0b3..6780761 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -308,6 +308,7 @@
 CONFIG_SENSORS_QPNP_ADC_CURRENT=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_MONITOR=y
 CONFIG_THERMAL_QPNP=y
 CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_WCD9320_CODEC=y
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index ecea32b..cb5e712 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -411,3 +411,5 @@
 
 obj-$(CONFIG_MSM_SMCMOD) += smcmod.o
 obj-$(CONFIG_MSM_CPU_PWRCTL) +=  msm_cpu_pwrctl.o
+
+obj-$(CONFIG_ARCH_MSM8974) += msm_mpmctr.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index b451d08..202b8dd 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -68,6 +68,8 @@
         dtb-$(CONFIG_ARCH_MSM9625)	+= msm9625-v1-rumi.dtb
 	dtb-$(CONFIG_ARCH_MSM9625)      += msm9625-v2-cdp.dtb
 	dtb-$(CONFIG_ARCH_MSM9625)      += msm9625-v2-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM9625)      += msm9625-v2-1-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM9625)      += msm9625-v2-1-cdp.dtb
 
 # MSM8226
    zreladdr-$(CONFIG_ARCH_MSM8226)	:= 0x00008000
diff --git a/arch/arm/mach-msm/bms-batterydata-desay.c b/arch/arm/mach-msm/bms-batterydata-desay.c
index 5b72a3f..dd3f346 100644
--- a/arch/arm/mach-msm/bms-batterydata-desay.c
+++ b/arch/arm/mach-msm/bms-batterydata-desay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -83,4 +83,5 @@
 	.pc_temp_ocv_lut	= &desay_5200_pc_temp_ocv,
 	.pc_sf_lut		= &desay_5200_pc_sf,
 	.default_rbatt_mohm	= 156,
+	.rbatt_capacitive_mohm	= 50,
 };
diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
index 824cf6b..0c39df6 100644
--- a/arch/arm/mach-msm/bms-batterydata.c
+++ b/arch/arm/mach-msm/bms-batterydata.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -105,4 +105,5 @@
 	.pc_temp_ocv_lut	= &pc_temp_ocv,
 	.rbatt_sf_lut		= &rbatt_sf,
 	.default_rbatt_mohm	= 236,
+	.rbatt_capacitive_mohm	= 50,
 };
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index a89ea61..beb064b 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2723,7 +2723,6 @@
 	&apq8064_device_uart_gsbi1,
 	&apq8064_device_uart_gsbi4,
 	&msm_device_sps_apq8064,
-	&msm8064_pc_cntr,
 };
 
 static struct platform_device *common_i2s_devices[] __initdata = {
@@ -2888,7 +2887,6 @@
 #ifdef CONFIG_MSM_ROTATOR
 	&msm_rotator_device,
 #endif
-	&msm8064_pc_cntr,
 };
 
 static struct platform_device
@@ -3861,11 +3859,13 @@
 	if (cpu_is_apq8064ab())
 		apq8064ab_update_krait_spm();
 	if (cpu_is_krait_v3()) {
-		msm_pm_set_tz_retention_flag(0);
+		struct msm_pm_init_data_type *pdata =
+			msm8064_pm_8x60.dev.platform_data;
+		pdata->retention_calls_tz = false;
 		apq8064ab_update_retention_spm();
-	} else {
-		msm_pm_set_tz_retention_flag(1);
 	}
+	platform_device_register(&msm8064_pm_8x60);
+
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	msm_spm_l2_init(msm_spm_l2_data);
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index a8e117f..25ba1aa 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -2473,7 +2473,6 @@
 	&msm8930_iommu_domain_device,
 	&msm_tsens_device,
 	&msm8930_cache_dump_device,
-	&msm8930_pc_cntr,
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
@@ -2955,11 +2954,14 @@
 	msm8930_i2c_init();
 	msm8930_init_gpu();
 	if (cpu_is_krait_v3()) {
-		msm_pm_set_tz_retention_flag(0);
+		struct msm_pm_init_data_type *pdata =
+			msm8930_pm_8x60.dev.platform_data;
+		pdata->retention_calls_tz = false;
 		msm8930ab_update_retention_spm();
-	} else {
-		msm_pm_set_tz_retention_flag(1);
 	}
+
+	platform_device_register(&msm8930_pm_8x60);
+
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	msm_spm_l2_init(msm_spm_l2_data);
 	msm8930_init_buses();
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 6524832..95f618a 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -2955,7 +2955,6 @@
 	&msm8960_cache_dump_device,
 	&msm8960_iommu_domain_device,
 	&msm_tsens_device,
-	&msm8960_pc_cntr,
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
@@ -3488,11 +3487,13 @@
 	if (cpu_is_msm8960ab())
 		msm8960ab_update_krait_spm();
 	if (cpu_is_krait_v3()) {
-		msm_pm_set_tz_retention_flag(0);
+		struct msm_pm_init_data_type *pdata =
+			msm8960_pm_8x60.dev.platform_data;
+		pdata->retention_calls_tz = false;
 		msm8960ab_update_retention_spm();
-	} else {
-		msm_pm_set_tz_retention_flag(1);
 	}
+	platform_device_register(&msm8960_pm_8x60);
+
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	msm_spm_l2_init(msm_spm_l2_data);
 
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index eb99073..b3cc9b7 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -258,12 +258,6 @@
 	.dir = GPIOMUX_OUT_HIGH,
 };
 
-static struct gpiomux_setting mhl_active_2_cfg = {
-	.func = GPIOMUX_FUNC_1,
-	.drv = GPIOMUX_DRV_2MA,
-	.pull = GPIOMUX_PULL_UP,
-};
-
 static struct gpiomux_setting hdmi_suspend_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_2MA,
@@ -299,14 +293,6 @@
 			[GPIOMUX_ACTIVE]    = &mhl_active_1_cfg,
 		},
 	},
-	{
-		/* mhl-sii8334 reset */
-		.gpio = 8,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &mhl_suspend_config,
-			[GPIOMUX_ACTIVE]    = &mhl_active_2_cfg,
-		},
-	},
 };
 
 
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index c45cf11..02a753a 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -5299,6 +5299,7 @@
 	&msm_device_tz_log,
 	&msm_rtb_device,
 	&msm8660_iommu_domain_device,
+	&msm8660_pm_8x60,
 };
 
 #ifdef CONFIG_ION_MSM
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 887f7cc..d26b4b2 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -526,7 +526,6 @@
 #define mm_gnd_source_val 6
 #define gpll1_hsic_source_val 4
 #define cxo_lpass_source_val 0
-#define lpapll0_lpass_source_val 1
 #define gpll0_lpass_source_val 5
 #define edppll_270_mm_source_val 4
 #define edppll_350_mm_source_val 4
@@ -742,21 +741,6 @@
 	},
 };
 
-static struct pll_vote_clk lpapll0_clk_src = {
-	.en_reg = (void __iomem *)LPASS_LPA_PLL_VOTE_APPS_REG,
-	.en_mask = BIT(0),
-	.status_reg = (void __iomem *)LPAPLL_STATUS_REG,
-	.status_mask = BIT(17),
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &cxo_clk_src.c,
-		.rate = 491520000,
-		.dbg_name = "lpapll0_clk_src",
-		.ops = &clk_ops_pll_vote,
-		CLK_INIT(lpapll0_clk_src.c),
-	},
-};
-
 static struct pll_vote_clk mmpll0_clk_src = {
 	.en_reg = (void __iomem *)MMSS_PLL_VOTE_APCS_REG,
 	.en_mask = BIT(0),
@@ -4350,411 +4334,6 @@
 	},
 };
 
-static struct clk_freq_tbl ftbl_audio_core_slimbus_core_clock[] = {
-	F_LPASS(24576000, lpapll0, 4, 1, 5),
-	F_END
-};
-
-static struct rcg_clk audio_core_slimbus_core_clk_src = {
-	.cmd_rcgr_reg = SLIMBUS_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_slimbus_core_clock,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_slimbus_core_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 70000000, NOMINAL, 140000000),
-		CLK_INIT(audio_core_slimbus_core_clk_src.c),
-	},
-};
-
-static struct branch_clk audio_core_slimbus_core_clk = {
-	.cbcr_reg = AUDIO_CORE_SLIMBUS_CORE_CBCR,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_slimbus_core_clk_src.c,
-		.dbg_name = "audio_core_slimbus_core_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_slimbus_core_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_slimbus_lfabif_clk = {
-	.cbcr_reg = AUDIO_CORE_SLIMBUS_LFABIF_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_slimbus_lfabif_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_slimbus_lfabif_clk.c),
-	},
-};
-
-static struct clk_freq_tbl ftbl_audio_core_lpaif_clock[] = {
-	F_LPASS(  512000, lpapll0, 16, 1, 60),
-	F_LPASS(  768000, lpapll0, 16, 1, 40),
-	F_LPASS( 1024000, lpapll0, 16, 1, 30),
-	F_LPASS( 1536000, lpapll0, 16, 1, 20),
-	F_LPASS( 2048000, lpapll0, 16, 1, 15),
-	F_LPASS( 3072000, lpapll0, 16, 1, 10),
-	F_LPASS( 4096000, lpapll0, 15, 1,  8),
-	F_LPASS( 6144000, lpapll0, 10, 1,  8),
-	F_LPASS( 8192000, lpapll0, 15, 1,  4),
-	F_LPASS(12288000, lpapll0, 10, 1,  4),
-	F_END
-};
-
-static struct rcg_clk audio_core_lpaif_codec_spkr_clk_src = {
-	.cmd_rcgr_reg = LPAIF_SPKR_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clock,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
-		CLK_INIT(audio_core_lpaif_codec_spkr_clk_src.c),
-	},
-};
-
-static struct rcg_clk audio_core_lpaif_pri_clk_src = {
-	.cmd_rcgr_reg = LPAIF_PRI_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clock,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_pri_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
-		CLK_INIT(audio_core_lpaif_pri_clk_src.c),
-	},
-};
-
-static struct rcg_clk audio_core_lpaif_sec_clk_src = {
-	.cmd_rcgr_reg = LPAIF_SEC_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clock,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_sec_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
-		CLK_INIT(audio_core_lpaif_sec_clk_src.c),
-	},
-};
-
-static struct rcg_clk audio_core_lpaif_ter_clk_src = {
-	.cmd_rcgr_reg = LPAIF_TER_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clock,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_ter_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
-		CLK_INIT(audio_core_lpaif_ter_clk_src.c),
-	},
-};
-
-static struct rcg_clk audio_core_lpaif_quad_clk_src = {
-	.cmd_rcgr_reg = LPAIF_QUAD_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clock,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_quad_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
-		CLK_INIT(audio_core_lpaif_quad_clk_src.c),
-	},
-};
-
-static struct rcg_clk audio_core_lpaif_pcm0_clk_src = {
-	.cmd_rcgr_reg = LPAIF_PCM0_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clock,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_pcm0_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
-		CLK_INIT(audio_core_lpaif_pcm0_clk_src.c),
-	},
-};
-
-static struct rcg_clk audio_core_lpaif_pcm1_clk_src = {
-	.cmd_rcgr_reg = LPAIF_PCM1_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clock,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_pcm1_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
-		CLK_INIT(audio_core_lpaif_pcm1_clk_src.c),
-	},
-};
-
-struct rcg_clk audio_core_lpaif_pcmoe_clk_src = {
-	.cmd_rcgr_reg = LPAIF_PCMOE_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clock,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_pcmoe_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP1(LOW, 12290000),
-		CLK_INIT(audio_core_lpaif_pcmoe_clk_src.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_osr_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_lpaif_codec_spkr_clk_src.c,
-		.dbg_name = "audio_core_lpaif_codec_spkr_osr_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_codec_spkr_osr_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_codec_spkr_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_codec_spkr_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR,
-	.has_sibling = 1,
-	.max_div = 15,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_lpaif_codec_spkr_clk_src.c,
-		.dbg_name = "audio_core_lpaif_codec_spkr_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_codec_spkr_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pri_osr_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_OSR_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_lpaif_pri_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pri_osr_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pri_osr_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pri_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_EBIT_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_pri_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pri_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pri_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_IBIT_CBCR,
-	.has_sibling = 1,
-	.max_div = 15,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_lpaif_pri_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pri_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pri_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_sec_osr_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_OSR_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_lpaif_sec_clk_src.c,
-		.dbg_name = "audio_core_lpaif_sec_osr_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_sec_osr_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_sec_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_EBIT_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_sec_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_sec_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_sec_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_IBIT_CBCR,
-	.has_sibling = 1,
-	.max_div = 15,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_lpaif_sec_clk_src.c,
-		.dbg_name = "audio_core_lpaif_sec_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_sec_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_ter_osr_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_TER_OSR_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_lpaif_ter_clk_src.c,
-		.dbg_name = "audio_core_lpaif_ter_osr_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_ter_osr_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_ter_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_TER_EBIT_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_ter_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_ter_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_ter_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_TER_IBIT_CBCR,
-	.has_sibling = 1,
-	.max_div = 15,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_lpaif_ter_clk_src.c,
-		.dbg_name = "audio_core_lpaif_ter_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_ter_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_quad_osr_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_OSR_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_lpaif_quad_clk_src.c,
-		.dbg_name = "audio_core_lpaif_quad_osr_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_quad_osr_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_quad_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_quad_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_quad_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_quad_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR,
-	.has_sibling = 1,
-	.max_div = 15,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_lpaif_quad_clk_src.c,
-		.dbg_name = "audio_core_lpaif_quad_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_quad_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pcm0_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_pcm0_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pcm0_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pcm0_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_lpaif_pcm0_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pcm0_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pcm0_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pcm1_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_lpaif_pcm1_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pcm1_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pcm1_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pcm1_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_lpaif_pcm1_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pcm1_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pcm1_ibit_clk.c),
-	},
-};
-
-struct branch_clk audio_core_lpaif_pcmoe_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PCM_DATA_OE_CBCR,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_lpaif_pcmoe_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pcmoe_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pcmoe_clk.c),
-	},
-};
-
 static struct branch_clk q6ss_ahb_lfabif_clk = {
 	.cbcr_reg = LPASS_Q6SS_AHB_LFABIF_CBCR,
 	.has_sibling = 1,
@@ -4766,16 +4345,6 @@
 	},
 };
 
-static struct branch_clk audio_core_ixfabric_clk = {
-	.cbcr_reg = AUDIO_CORE_IXFABRIC_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_ixfabric_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_ixfabric_clk.c),
-	},
-};
 
 static struct branch_clk gcc_lpass_q6_axi_clk = {
 	.cbcr_reg = LPASS_Q6_AXI_CBCR,
@@ -4811,17 +4380,6 @@
 	},
 };
 
-static struct branch_clk audio_wrapper_br_clk = {
-	.cbcr_reg = AUDIO_WRAPPER_BR_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_wrapper_br_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_wrapper_br_clk.c),
-	},
-};
-
 static DEFINE_CLK_MEASURE(l2_m_clk);
 static DEFINE_CLK_MEASURE(krait0_m_clk);
 static DEFINE_CLK_MEASURE(krait1_m_clk);
@@ -5004,20 +4562,9 @@
 	{&mdss_hdmi_ahb_clk.c,			MMSS_BASE, 0x0023},
 	{&mdss_pclk0_clk.c,			MMSS_BASE, 0x0016},
 	{&mdss_pclk1_clk.c,			MMSS_BASE, 0x0017},
-	{&audio_core_lpaif_pri_clk_src.c,	LPASS_BASE, 0x0017},
-	{&audio_core_lpaif_sec_clk_src.c,	LPASS_BASE, 0x0016},
-	{&audio_core_lpaif_ter_clk_src.c,	LPASS_BASE, 0x0015},
-	{&audio_core_lpaif_quad_clk_src.c,	LPASS_BASE, 0x0014},
-	{&audio_core_lpaif_pcm0_clk_src.c,	LPASS_BASE, 0x0013},
-	{&audio_core_lpaif_pcm1_clk_src.c,	LPASS_BASE, 0x0012},
-	{&audio_core_lpaif_pcmoe_clk_src.c,	LPASS_BASE, 0x000f},
-	{&audio_core_slimbus_core_clk.c,	LPASS_BASE, 0x003d},
-	{&audio_core_slimbus_lfabif_clk.c,	LPASS_BASE, 0x003e},
 	{&q6ss_xo_clk.c,			LPASS_BASE, 0x002b},
 	{&q6ss_ahb_lfabif_clk.c,		LPASS_BASE, 0x001e},
 	{&q6ss_ahbm_clk.c,			LPASS_BASE, 0x001d},
-	{&audio_core_ixfabric_clk.c,		LPASS_BASE, 0x0059},
-	{&audio_wrapper_br_clk.c,		LPASS_BASE, 0x0022},
 
 	{&krait0_m_clk,				APCS_BASE, M_ACPU0},
 	{&krait1_m_clk,				APCS_BASE, M_ACPU1},
@@ -5590,6 +5137,20 @@
 						"fda20000.qcom,jpeg"),
 	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
 						"fda24000.qcom,jpeg"),
+	CLK_LOOKUP("micro_iface_clk", camss_micro_ahb_clk.c,
+		"fda04000.qcom,cpp"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+		"fda04000.qcom,cpp"),
+	CLK_LOOKUP("cpp_iface_clk", camss_vfe_cpp_ahb_clk.c,
+		"fda04000.qcom,cpp"),
+	CLK_LOOKUP("cpp_core_clk", camss_vfe_cpp_clk.c, "fda04000.qcom,cpp"),
+	CLK_LOOKUP("cpp_bus_clk", camss_vfe_vfe_axi_clk.c, "fda04000.qcom,cpp"),
+	CLK_LOOKUP("vfe_clk_src", vfe0_clk_src.c,	 "fda04000.qcom,cpp"),
+	CLK_LOOKUP("camss_vfe_vfe_clk", camss_vfe_vfe0_clk.c,
+					"fda04000.qcom,cpp"),
+	CLK_LOOKUP("iface_clk", camss_vfe_vfe_ahb_clk.c, "fda04000.qcom,cpp"),
+
+
 	CLK_LOOKUP("iface_clk", camss_micro_ahb_clk.c, ""),
 	CLK_LOOKUP("iface_clk", camss_vfe_vfe_ahb_clk.c, "fda44000.qcom,iommu"),
 	CLK_LOOKUP("core_clk", camss_vfe_vfe_axi_clk.c, "fda44000.qcom,iommu"),
@@ -5625,57 +5186,6 @@
 
 
 	/* LPASS clocks */
-	CLK_LOOKUP("bus_clk", audio_core_ixfabric_clk.c, ""),
-	CLK_LOOKUP("core_clk", audio_core_slimbus_core_clk.c, "fe12f000.slim"),
-	CLK_LOOKUP("iface_clk", audio_core_slimbus_lfabif_clk.c,
-			"fe12f000.slim"),
-	CLK_LOOKUP("core_clk", audio_core_lpaif_codec_spkr_clk_src.c, ""),
-	CLK_LOOKUP("osr_clk", audio_core_lpaif_codec_spkr_osr_clk.c, ""),
-	CLK_LOOKUP("ebit_clk", audio_core_lpaif_codec_spkr_ebit_clk.c, ""),
-	CLK_LOOKUP("ibit_clk", audio_core_lpaif_codec_spkr_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk", audio_core_lpaif_pri_clk_src.c, ""),
-	CLK_LOOKUP("osr_clk", audio_core_lpaif_pri_osr_clk.c, ""),
-	CLK_LOOKUP("ebit_clk", audio_core_lpaif_pri_ebit_clk.c, ""),
-	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pri_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk", audio_core_lpaif_sec_clk_src.c, ""),
-	CLK_LOOKUP("osr_clk", audio_core_lpaif_sec_osr_clk.c, ""),
-	CLK_LOOKUP("ebit_clk", audio_core_lpaif_sec_ebit_clk.c, ""),
-	CLK_LOOKUP("ibit_clk", audio_core_lpaif_sec_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk", audio_core_lpaif_ter_clk_src.c, ""),
-	CLK_LOOKUP("osr_clk", audio_core_lpaif_ter_osr_clk.c, ""),
-	CLK_LOOKUP("ebit_clk", audio_core_lpaif_ter_ebit_clk.c, ""),
-	CLK_LOOKUP("ibit_clk", audio_core_lpaif_ter_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk", audio_core_lpaif_quad_clk_src.c,
-			"msm-dai-q6-mi2s.3"),
-	CLK_LOOKUP("osr_clk", audio_core_lpaif_quad_osr_clk.c,
-			"msm-dai-q6-mi2s.3"),
-	CLK_LOOKUP("ebit_clk", audio_core_lpaif_quad_ebit_clk.c,
-			"msm-dai-q6-mi2s.3"),
-	CLK_LOOKUP("ibit_clk", audio_core_lpaif_quad_ibit_clk.c,
-			"msm-dai-q6-mi2s.3"),
-	CLK_LOOKUP("pcm_clk", audio_core_lpaif_pcm0_clk_src.c,
-						"msm-dai-q6.4106"),
-	CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm0_ebit_clk.c, ""),
-	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c,
-						"msm-dai-q6.4106"),
-	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk", audio_core_lpaif_pcm1_clk_src.c, ""),
-	CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
-	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
-	CLK_LOOKUP("core_oe_src_clk", audio_core_lpaif_pcmoe_clk_src.c,
-						"msm-dai-q6.4106"),
-	CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
-						"msm-dai-q6.4106"),
-	CLK_LOOKUP("pcm_clk", audio_core_lpaif_pcm0_clk_src.c,
-						"msm-dai-q6.4107"),
-	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c,
-						"msm-dai-q6.4107"),
-	CLK_LOOKUP("core_oe_src_clk", audio_core_lpaif_pcmoe_clk_src.c,
-						"msm-dai-q6.4107"),
-	CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
-						"msm-dai-q6.4107"),
-	CLK_LOOKUP("br_clk", audio_wrapper_br_clk.c, "fdd00000.qcom,ocmem"),
-
 	CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
 	CLK_LOOKUP("iface_clk", gcc_mss_cfg_ahb_clk.c, "fc880000.qcom,mss"),
 	CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c,  "fc880000.qcom,mss"),
@@ -5866,32 +5376,6 @@
 	.main_output_mask = BIT(0),
 };
 
-static struct pll_config_regs lpapll0_regs __initdata = {
-	.l_reg = (void __iomem *)LPAPLL_L_REG,
-	.m_reg = (void __iomem *)LPAPLL_M_REG,
-	.n_reg = (void __iomem *)LPAPLL_N_REG,
-	.config_reg = (void __iomem *)LPAPLL_USER_CTL_REG,
-	.mode_reg = (void __iomem *)LPAPLL_MODE_REG,
-	.base = &virt_bases[LPASS_BASE],
-};
-
-/* LPAPLL0 at 491.52 MHz, main output enabled. */
-static struct pll_config lpapll0_config __initdata = {
-	.l = 0x33,
-	.m = 0x1,
-	.n = 0x5,
-	.vco_val = 0x0,
-	.vco_mask = BM(21, 20),
-	.pre_div_val = BVAL(14, 12, 0x1),
-	.pre_div_mask = BM(14, 12),
-	.post_div_val = 0x0,
-	.post_div_mask = BM(9, 8),
-	.mn_ena_val = BIT(24),
-	.mn_ena_mask = BIT(24),
-	.main_output_val = BIT(0),
-	.main_output_mask = BIT(0),
-};
-
 #define PWR_ON_MASK		BIT(31)
 #define EN_REST_WAIT_MASK	(0xF << 20)
 #define EN_FEW_WAIT_MASK	(0xF << 16)
@@ -5908,8 +5392,7 @@
 
 static void __init reg_init(void)
 {
-	u32 regval, status;
-	int ret;
+	u32 regval;
 
 	configure_sr_hpm_lp_pll(&mmpll0_config, &mmpll0_regs, 1);
 
@@ -5920,7 +5403,6 @@
 		configure_sr_hpm_lp_pll(&mmpll1_config, &mmpll1_regs, 1);
 		configure_sr_hpm_lp_pll(&mmpll3_config, &mmpll3_regs, 0);
 	}
-	configure_sr_hpm_lp_pll(&lpapll0_config, &lpapll0_regs, 1);
 
 	/* Vote for GPLL0 to turn on. Needed by acpuclock. */
 	regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE_REG));
@@ -5943,31 +5425,6 @@
 	 * register.
 	 */
 	writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
-
-	/*
-	 * TODO: The following sequence enables the LPASS audio core GDSC.
-	 * Remove when this becomes unnecessary.
-	 */
-
-	/*
-	 * Disable HW trigger: collapse/restore occur based on registers writes.
-	 * Disable SW override: Use hardware state-machine for sequencing.
-	 */
-	regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-	regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);
-
-	/* Configure wait time between states. */
-	regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
-	regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
-	writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-
-	regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-	regval &= ~BIT(0);
-	writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-
-	ret = readl_poll_timeout(LPASS_REG_BASE(AUDIO_CORE_GDSCR), status,
-				status & PWR_ON_MASK, 50, GDSC_TIMEOUT_US);
-	WARN(ret, "LPASS Audio Core GDSC did not power on.\n");
 }
 
 static void __init mdss_clock_setup(void)
@@ -6007,11 +5464,6 @@
 	 */
 	clk_prepare_enable(&cxo_a_clk_src.c);
 
-	/* TODO: Temporarily enable a clock to allow access to LPASS core
-	 * registers.
-	 */
-	clk_prepare_enable(&audio_core_ixfabric_clk.c);
-
 	/*
 	 * TODO: Temporarily enable NOC configuration AHB clocks. Remove when
 	 * the bus driver is ready.
@@ -6046,8 +5498,6 @@
 	clk_set_rate(&esc1_clk_src.c, esc1_clk_src.freq_tbl[0].freq_hz);
 	clk_set_rate(&hdmi_clk_src.c, hdmi_clk_src.freq_tbl[0].freq_hz);
 	clk_set_rate(&vsync_clk_src.c, vsync_clk_src.freq_tbl[0].freq_hz);
-	clk_set_rate(&audio_core_slimbus_core_clk_src.c,
-			audio_core_slimbus_core_clk_src.freq_tbl[0].freq_hz);
 }
 
 #define GCC_CC_PHYS		0xFC400000
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index c1cc27b..ee91a34 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -245,6 +245,14 @@
 	return rc;
 }
 
+static int rpm_branch_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (rate == clk->rate)
+		return 0;
+
+	return -EPERM;
+}
+
 static unsigned long rpm_clk_get_rate(struct clk *clk)
 {
 	struct rpm_clk *r = to_rpm_clk(clk);
@@ -335,6 +343,7 @@
 struct clk_ops clk_ops_rpm_branch = {
 	.prepare = rpm_clk_prepare,
 	.unprepare = rpm_clk_unprepare,
+	.set_rate = rpm_branch_clk_set_rate,
 	.is_local = rpm_clk_is_local,
 	.handoff = rpm_clk_handoff,
 };
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index 1e3f8a0..e87c7b5 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -72,16 +72,19 @@
 	struct cpuidle_device *dev, struct cpuidle_driver *drv, int index)
 {
 	int ret = 0;
-	int i = 0;
+	int i;
 	enum msm_pm_sleep_mode pm_mode;
-	struct cpuidle_state_usage *st_usage = NULL;
 
 	cpu_pm_enter();
+
 	pm_mode = msm_pm_idle_enter(dev, drv, index);
+
 	for (i = 0; i < dev->state_count; i++) {
-		st_usage = &dev->states_usage[i];
-		if ((enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage)
-		    == pm_mode) {
+		struct cpuidle_state_usage *st_usage = &dev->states_usage[i];
+		enum msm_pm_sleep_mode last_mode =
+			(enum msm_pm_sleep_mode)cpuidle_get_statedata(st_usage);
+
+		if (last_mode == pm_mode) {
 			ret = i;
 			break;
 		}
@@ -93,7 +96,7 @@
 	return ret;
 }
 
-static void __init msm_cpuidle_set_states(void)
+static void __devinit msm_cpuidle_set_states(void)
 {
 	int i = 0;
 	int state_count = 0;
@@ -149,7 +152,7 @@
 	dev->state_count = state_count; /* Per cpu state count */
 }
 
-int __init msm_cpuidle_init(void)
+int __devinit msm_cpuidle_init(void)
 {
 	unsigned int cpu = 0;
 	int ret = 0;
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index f87c540..10ee1e3 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -49,6 +49,7 @@
 #include <mach/mpm.h>
 #include <mach/iommu_domains.h>
 #include <mach/msm_cache_dump.h>
+#include "pm.h"
 
 /* Address of GSBI blocks */
 #define MSM_GSBI1_PHYS		0x12440000
@@ -120,11 +121,24 @@
 	},
 };
 
-struct platform_device msm8064_pc_cntr = {
-	.name		= "pc-cntr",
+static uint32_t msm_pm_cp15_regs[] = {0x4501, 0x5501, 0x6501, 0x7501, 0x0500};
+
+static struct msm_pm_init_data_type msm_pm_data = {
+	.retention_calls_tz = true,
+	.cp15_data.save_cp15 = true,
+	.cp15_data.qsb_pc_vdd = 0x98,
+	.cp15_data.reg_data = &msm_pm_cp15_regs[0],
+	.cp15_data.reg_saved_state_size = ARRAY_SIZE(msm_pm_cp15_regs),
+};
+
+struct platform_device msm8064_pm_8x60 = {
+	.name		= "pm-8x60",
 	.id		= -1,
 	.num_resources	= ARRAY_SIZE(msm8064_resources_pccntr),
 	.resource	= msm8064_resources_pccntr,
+	.dev = {
+		.platform_data = &msm_pm_data,
+	},
 };
 
 static struct msm_watchdog_pdata msm_watchdog_pdata = {
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index aad512e..6fe8ccb 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -32,6 +32,7 @@
 #include "rpm_rbcpr_stats.h"
 #include "footswitch.h"
 #include "acpuclock-krait.h"
+#include "pm.h"
 
 #ifdef CONFIG_MSM_MPM
 #include <mach/mpm.h>
@@ -48,11 +49,18 @@
 	},
 };
 
-struct platform_device msm8930_pc_cntr = {
-	.name		= "pc-cntr",
+static struct msm_pm_init_data_type msm_pm_data = {
+	.retention_calls_tz = true,
+};
+
+struct platform_device msm8930_pm_8x60 = {
+	.name		= "pm-8x60",
 	.id		= -1,
 	.num_resources	= ARRAY_SIZE(msm8930_resources_pccntr),
 	.resource	= msm8930_resources_pccntr,
+	.dev = {
+		.platform_data = &msm_pm_data,
+	},
 };
 
 struct msm_rpm_platform_data msm8930_rpm_data __initdata = {
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index c3748fa..6a344be 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -53,6 +53,7 @@
 #include <mach/msm_dcvs.h>
 #include <mach/iommu_domains.h>
 #include <mach/socinfo.h>
+#include "pm.h"
 
 #ifdef CONFIG_MSM_MPM
 #include <mach/mpm.h>
@@ -116,11 +117,18 @@
 	},
 };
 
-struct platform_device msm8960_pc_cntr = {
-	.name		= "pc-cntr",
+static struct msm_pm_init_data_type msm_pm_data = {
+	.retention_calls_tz = true,
+};
+
+struct platform_device msm8960_pm_8x60 = {
+	.name		= "pm-8x60",
 	.id		= -1,
 	.num_resources	= ARRAY_SIZE(msm8960_resources_pccntr),
 	.resource	= msm8960_resources_pccntr,
+	.dev = {
+		.platform_data = &msm_pm_data,
+	},
 };
 
 static struct resource resources_otg[] = {
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 58416c7..cfa9281 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -3181,3 +3181,9 @@
 		.platform_data = &msm8660_iommu_domain_pdata,
 	}
 };
+
+struct platform_device msm8660_pm_8x60 = {
+	.name		= "pm-8x60",
+	.id		= -1,
+};
+
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index d3810a2..53eca3e 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-msm/devices.h
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -113,11 +113,11 @@
 extern struct platform_device msm_device_sdc3;
 extern struct platform_device msm_device_sdc4;
 
+extern struct platform_device msm8960_pm_8x60;
+extern struct platform_device msm8064_pm_8x60;
+extern struct platform_device msm8930_pm_8x60;
 extern struct platform_device msm9615_pm_8x60;
-
-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 msm8660_pm_8x60;
 
 extern struct platform_device msm_device_gadget_peripheral;
 extern struct platform_device msm_device_hsusb_host;
diff --git a/arch/arm/mach-msm/include/mach/msm_mpmctr.h b/arch/arm/mach-msm/include/mach/msm_mpmctr.h
new file mode 100644
index 0000000..d3d853f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_mpmctr.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013, 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 __MSM_MPMCTR_H__
+#define __MSM_MPMCTR_H__
+
+/*
+ * returns the count value of the mpm timetick.
+ */
+uint32_t msm_mpm_get_count(void);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
index cd70457..92ae6b6 100644
--- a/arch/arm/mach-msm/include/mach/ocmem.h
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -136,6 +136,9 @@
 int ocmem_unmap(int client_id, struct ocmem_buf *buffer,
 			struct ocmem_map_list *list);
 
+int ocmem_drop(int client_id, struct ocmem_buf *buffer,
+			struct ocmem_map_list *list);
+
 int ocmem_dump(int client_id, struct ocmem_buf *buffer,
 				unsigned long dst_phys_addr);
 
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 205f917..abb5653 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -213,6 +213,7 @@
 			unsigned long, bool, bool);
 int process_free(int, struct ocmem_handle *);
 int process_xfer(int, struct ocmem_handle *, struct ocmem_map_list *, int);
+int process_drop(int, struct ocmem_handle *, struct ocmem_map_list *);
 int process_evict(int);
 int process_restore(int);
 int process_shrink(int, struct ocmem_handle *, unsigned long);
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 52aa43a..0c1e279 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -291,6 +291,11 @@
 
 int krait_power_mdd_enable(int cpu_num, bool on)
 {
+	/*
+	 * Expected to be called when the cpu goes to retention mode as a part
+	 * of idle power collapse. IT is guaranteed that cpu won't be put in
+	 * retention while being hotplugged out
+	 */
 	struct krait_power_vreg *kvreg = per_cpu(krait_vregs, cpu_num);
 
 	if (!on && kvreg->mode == LDO_MODE) {
@@ -298,7 +303,7 @@
 		return -EINVAL;
 	}
 
-	if ((on && kvreg->mode == LDO_MODE) || (!on && kvreg->mode == HS_MODE))
+	if (on && kvreg->mode == LDO_MODE)
 		return 0;
 
 	__krait_power_mdd_enable(kvreg, on);
@@ -801,6 +806,8 @@
 	int rc;
 
 	mutex_lock(&pvreg->krait_power_vregs_lock);
+	if (kvreg->mode == LDO_MODE)
+		__krait_power_mdd_enable(kvreg, true);
 	kvreg->online = true;
 	rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load_uA);
 	if (rc < 0)
@@ -830,6 +837,8 @@
 		goto dis_err;
 
 	rc = _set_voltage(rdev, kvreg->uV, kvreg->uV);
+	if (kvreg->mode == LDO_MODE)
+		__krait_power_mdd_enable(kvreg, false);
 dis_err:
 	mutex_unlock(&pvreg->krait_power_vregs_lock);
 	return rc;
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 8571bda..539a4fe 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -57,6 +57,8 @@
 		bool from_idle, bool notify_rpm)
 {
 	int ret = 0;
+	int debug_mask;
+	struct msm_rpmrs_limits *l = (struct msm_rpmrs_limits *)limits;
 	struct msm_lpm_sleep_data sleep_data;
 
 	sleep_data.limits = limits;
@@ -64,33 +66,34 @@
 	atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
 		MSM_LPM_STATE_ENTER, &sleep_data);
 
-	if (notify_rpm) {
-		int debug_mask;
-		struct msm_rpmrs_limits *l = (struct msm_rpmrs_limits *)limits;
+	if (from_idle)
+		debug_mask = msm_lpm_lvl_dbg_msk &
+			MSM_LPM_LVL_DBG_IDLE_LIMITS;
+	else
+		debug_mask = msm_lpm_lvl_dbg_msk &
+			MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
 
-		ret = msm_rpm_enter_sleep();
+	if (debug_mask)
+		pr_info("%s(): pxo:%d l2:%d mem:0x%x(0x%x) dig:0x%x(0x%x)\n",
+				__func__, l->pxo, l->l2_cache,
+				l->vdd_mem_lower_bound,
+				l->vdd_mem_upper_bound,
+				l->vdd_dig_lower_bound,
+				l->vdd_dig_upper_bound);
+
+	ret = msm_lpmrs_enter_sleep(sclk_count, l, from_idle, notify_rpm);
+	if (ret) {
+		pr_warn("%s() LPM resources failed to enter sleep\n",
+				__func__);
+		goto bail;
+	}
+	if (notify_rpm) {
+		ret = msm_rpm_enter_sleep(debug_mask);
 		if (ret) {
 			pr_warn("%s(): RPM failed to enter sleep err:%d\n",
 					__func__, ret);
 			goto bail;
 		}
-		if (from_idle)
-			debug_mask = msm_lpm_lvl_dbg_msk &
-					MSM_LPM_LVL_DBG_IDLE_LIMITS;
-		else
-			debug_mask = msm_lpm_lvl_dbg_msk &
-					MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
-
-		if (debug_mask)
-			pr_info("%s(): pxo:%d l2:%d mem:0x%x(0x%x) dig:0x%x(0x%x)\n",
-					__func__, l->pxo, l->l2_cache,
-					l->vdd_mem_lower_bound,
-					l->vdd_mem_upper_bound,
-					l->vdd_dig_lower_bound,
-					l->vdd_dig_upper_bound);
-
-		ret = msm_lpmrs_enter_sleep(sclk_count, l, from_idle,
-				notify_rpm);
 	}
 bail:
 	return ret;
@@ -99,9 +102,11 @@
 static void msm_lpm_exit_sleep(void *limits, bool from_idle,
 		bool notify_rpm, bool collapsed)
 {
-	msm_rpm_exit_sleep();
+
 	msm_lpmrs_exit_sleep((struct msm_rpmrs_limits *)limits,
 				from_idle, notify_rpm, collapsed);
+	if (notify_rpm)
+		msm_rpm_exit_sleep();
 	atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
 			MSM_LPM_STATE_EXIT, NULL);
 }
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index 5d7fc94..a62ee92 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -668,7 +668,8 @@
 	}
 	msm_lpm_get_rpm_notif = true;
 
-	msm_mpm_enter_sleep(sclk_count, from_idle);
+	if (notify_rpm)
+		msm_mpm_enter_sleep(sclk_count, from_idle);
 
 	return ret;
 }
diff --git a/arch/arm/mach-msm/msm_mpmctr.c b/arch/arm/mach-msm/msm_mpmctr.c
new file mode 100644
index 0000000..4ab82ab
--- /dev/null
+++ b/arch/arm/mach-msm/msm_mpmctr.c
@@ -0,0 +1,99 @@
+/* Copyright (c) 2013, 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/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/smp.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/sched.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <mach/msm_mpmctr.h>
+
+static void __iomem *mpm_timer_base;
+
+uint32_t msm_mpm_get_count(void)
+{
+	uint32_t count;
+	if (!mpm_timer_base)
+		return 0;
+
+	count = __raw_readl_no_log(mpm_timer_base);
+	pr_debug("mpm sclk sync:(%u)", count);
+	return count;
+}
+EXPORT_SYMBOL(msm_mpm_get_count);
+
+static inline void msm_mpmctr_show_count(void)
+{
+	unsigned long long t;
+	unsigned long nsec_rem;
+
+	t = sched_clock();
+
+	nsec_rem = do_div(t, 1000000000)/1000;
+
+	printk(KERN_INFO "mpm_counter: [%5lu.%06lu]:(%u)\n",
+		   (unsigned long)t, nsec_rem,
+		   msm_mpm_get_count());
+
+}
+
+static struct of_device_id msm_mpmctr_of_match[] = {
+	{.compatible = "qcom,mpm-counter"},
+	{}
+};
+
+static struct platform_driver msm_mpmctr_driver = {
+	.driver         = {
+		.name = "msm_mpctr",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_mpmctr_of_match,
+	},
+};
+
+static int __init mpmctr_set_register(struct device_node *np)
+{
+	if (of_get_address(np, 0, NULL, NULL)) {
+		mpm_timer_base = of_iomap(np, 0);
+		if (!mpm_timer_base) {
+			pr_err("%s: cannot map timer base\n", __func__);
+			return -ENOMEM;
+		}
+	}
+	return 0;
+}
+
+static int __init msm_mpmctr_probe(struct platform_device *pdev)
+{
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	if (mpmctr_set_register(pdev->dev.of_node))
+		return -ENODEV;
+
+	msm_mpmctr_show_count();
+
+	return 0;
+}
+
+static int __init mpmctr_init(void)
+{
+	return platform_driver_probe(&msm_mpmctr_driver, msm_mpmctr_probe);
+}
+
+module_init(mpmctr_init)
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
index e5a5b7b..16dd8b8 100644
--- a/arch/arm/mach-msm/ocmem_api.c
+++ b/arch/arm/mach-msm/ocmem_api.c
@@ -401,6 +401,40 @@
 }
 EXPORT_SYMBOL(ocmem_unmap);
 
+int ocmem_drop(int client_id, struct ocmem_buf *buffer,
+			   struct ocmem_map_list *list)
+{
+	int ret = 0;
+	struct ocmem_handle *handle = NULL;
+
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return -EINVAL;
+	}
+
+	if (!zone_active(client_id)) {
+		pr_err("ocmem: Client id: %s (id: %d) not allowed to use OCMEM\n",
+					get_name(client_id), client_id);
+		return -EINVAL;
+	}
+
+	if (!buffer) {
+		pr_err("ocmem: Invalid buffer\n");
+		return -EINVAL;
+	}
+
+	if (pre_validate_chunk_list(list) != 0)
+		return -EINVAL;
+
+	handle = buffer_to_handle(buffer);
+	mutex_lock(&handle->handle_mutex);
+	ret = process_drop(client_id, handle, list);
+	mutex_unlock(&handle->handle_mutex);
+	return ret;
+}
+EXPORT_SYMBOL(ocmem_drop);
+
+
 int ocmem_dump(int client_id, struct ocmem_buf *buffer,
 			unsigned long dst_phys_addr)
 {
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 906bd4a..868fd1a 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -532,6 +532,9 @@
 	struct ocmem_req *matched_req = NULL;
 	struct ocmem_region *matched_region = NULL;
 
+	if (!TEST_STATE(req, R_MAPPED))
+		goto invalid_op_error;
+
 	matched_region = find_region_match(req->req_start, req->req_end);
 	matched_req = find_req_match(req->req_id, matched_region);
 
@@ -1501,22 +1504,25 @@
 		mutex_unlock(&sched_mutex);
 	}
 
-	if (TEST_STATE(req, R_MAPPED)) {
-		/* unmap the interval and clear the memory */
-		rc = process_unmap(req, req->req_start, req->req_end);
+	if (!TEST_STATE(req, R_FREE)) {
 
-		if (rc < 0) {
-			pr_err("ocmem: Failed to unmap %p\n", req);
-			goto free_fail;
-		}
+		if (TEST_STATE(req, R_MAPPED)) {
+			/* unmap the interval and clear the memory */
+			rc = process_unmap(req, req->req_start, req->req_end);
 
-		rc = do_free(req);
-		if (rc < 0) {
-			pr_err("ocmem: Failed to free %p\n", req);
-			goto free_fail;
-		}
-	} else
+			if (rc < 0) {
+				pr_err("ocmem: Failed to unmap %p\n", req);
+				goto free_fail;
+			}
+
+			rc = do_free(req);
+			if (rc < 0) {
+				pr_err("ocmem: Failed to free %p\n", req);
+				goto free_fail;
+			}
+		} else
 			pr_debug("request %p was already shrunk to 0\n", req);
+	}
 
 	/* Turn off the memory */
 	if (req->req_sz != 0) {
@@ -1603,6 +1609,42 @@
 	return 0;
 }
 
+int process_drop(int id, struct ocmem_handle *handle,
+				 struct ocmem_map_list *list)
+{
+	struct ocmem_req *req = NULL;
+	struct ocmem_buf *buffer = NULL;
+	int rc = 0;
+
+	if (is_blocked(id)) {
+		pr_err("Client %d cannot request drop\n", id);
+		return -EINVAL;
+	}
+
+	if (is_tcm(id))
+		pr_err("Client %d cannot request drop\n", id);
+
+	req = handle_to_req(handle);
+	buffer = handle_to_buffer(handle);
+
+	if (!req)
+		return -EINVAL;
+
+	if (req->req_start != core_address(id, buffer->addr)) {
+		pr_err("Invalid buffer handle passed for drop\n");
+		return -EINVAL;
+	}
+
+	if (TEST_STATE(req, R_MAPPED)) {
+		rc = process_unmap(req, req->req_start, req->req_end);
+		if (rc < 0)
+			return -EINVAL;
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+
 int process_xfer_out(int id, struct ocmem_handle *handle,
 			struct ocmem_map_list *list)
 {
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index e85831a..c1d4ab4 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, The Linux Foundation. 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
@@ -24,7 +24,6 @@
 #include <linux/of.h>
 #include <linux/regulator/consumer.h>
 #include <linux/interrupt.h>
-#include <linux/of_gpio.h>
 
 #include <mach/subsystem_restart.h>
 #include <mach/clk.h>
@@ -88,8 +87,6 @@
 	bool crash_shutdown;
 	bool ignore_errors;
 	int is_loadable;
-	int err_fatal_irq;
-	int force_stop_gpio;
 };
 
 static int pbl_mba_boot_timeout_ms = 100;
@@ -445,17 +442,18 @@
 	subsystem_restart_dev(drv->subsys);
 }
 
-static irqreturn_t modem_err_fatal_intr_handler(int irq, void *dev_id)
+static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
 {
-	struct mba_data *drv = dev_id;
+	struct mba_data *drv = data;
 
-	/* Ignore if we're the one that set the force stop GPIO */
+	/* Ignore if we're the one that set SMSM_RESET */
 	if (drv->crash_shutdown)
-		return IRQ_HANDLED;
+		return;
 
-	pr_err("Fatal error on the modem.\n");
-	restart_modem(drv);
-	return IRQ_HANDLED;
+	if (new_state & SMSM_RESET) {
+		pr_err("Probable fatal error on the modem.\n");
+		restart_modem(drv);
+	}
 }
 
 static int modem_shutdown(const struct subsys_desc *subsys)
@@ -495,7 +493,7 @@
 {
 	struct mba_data *drv = subsys_to_drv(subsys);
 	drv->crash_shutdown = true;
-	gpio_set_value(drv->force_stop_gpio, 1);
+	smsm_reset_modem(SMSM_RESET);
 }
 
 static struct ramdump_segment smem_segments[] = {
@@ -632,11 +630,10 @@
 		goto err_irq;
 	}
 
-	ret = devm_request_irq(&pdev->dev, drv->err_fatal_irq,
-			modem_err_fatal_intr_handler,
-			IRQF_TRIGGER_RISING, "pil-mss", drv);
+	ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
+		smsm_state_cb, drv);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "Unable to register SMP2P err fatal handler!\n");
+		dev_err(&pdev->dev, "Unable to register SMSM callback!\n");
 		goto err_irq;
 	}
 
@@ -646,11 +643,14 @@
 		ret = PTR_ERR(drv->adsp_state_notifier);
 		dev_err(&pdev->dev, "%s: Registration with the SSR notification driver failed (%d)",
 			__func__, ret);
-		goto err_irq;
+		goto err_smsm;
 	}
 
 	return 0;
 
+err_smsm:
+	smsm_state_cb_deregister(SMSM_MODEM_STATE, SMSM_RESET, smsm_state_cb,
+			drv);
 err_irq:
 	destroy_ramdump_device(drv->smem_ramdump_dev);
 err_ramdump_smem:
@@ -759,7 +759,7 @@
 static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
 {
 	struct mba_data *drv;
-	int ret, err_fatal_gpio;
+	int ret;
 
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
@@ -774,22 +774,6 @@
 			return ret;
 	}
 
-	/* Get the IRQ from the GPIO for registering inbound handler */
-	err_fatal_gpio = of_get_named_gpio(pdev->dev.of_node,
-			"qcom,gpio-err-fatal", 0);
-	if (err_fatal_gpio < 0)
-		return err_fatal_gpio;
-
-	drv->err_fatal_irq = gpio_to_irq(err_fatal_gpio);
-	if (drv->err_fatal_irq < 0)
-		return drv->err_fatal_irq;
-
-	/* Get the GPIO pin for writing the outbound bits: add more as needed */
-	drv->force_stop_gpio = of_get_named_gpio(pdev->dev.of_node,
-			"qcom,gpio-force-stop", 0);
-	if (drv->force_stop_gpio < 0)
-		return drv->force_stop_gpio;
-
 	return pil_subsys_init(drv, pdev);
 }
 
@@ -799,6 +783,8 @@
 
 	subsys_notif_unregister_notifier(drv->adsp_state_notifier,
 						&adsp_state_notifier_block);
+	smsm_state_cb_deregister(SMSM_MODEM_STATE, SMSM_RESET,
+			smsm_state_cb, drv);
 	subsys_unregister(drv->subsys);
 	destroy_ramdump_device(drv->smem_ramdump_dev);
 	destroy_ramdump_device(drv->ramdump_dev);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index f7f2fef..b52d284 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -11,6 +11,7 @@
  *
  */
 
+#include <linux/debugfs.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -40,7 +41,6 @@
 #ifdef CONFIG_VFP
 #include <asm/vfp.h>
 #endif
-
 #include "acpuclock.h"
 #include "clock.h"
 #include "avs.h"
@@ -54,9 +54,27 @@
 #include <mach/event_timer.h>
 #define CREATE_TRACE_POINTS
 #include "trace_msm_low_power.h"
-/******************************************************************************
- * Debug Definitions
- *****************************************************************************/
+
+#define SCM_L2_RETENTION	(0x2)
+#define SCM_CMD_TERMINATE_PC	(0x2)
+
+#define GET_CPU_OF_ATTR(attr) \
+	(container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
+
+#define SCLK_HZ (32768)
+#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
+
+#define NUM_OF_COUNTERS 3
+#define MAX_BUF_SIZE  512
+
+static int msm_pm_debug_mask = 1;
+module_param_named(
+	debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+static int msm_pm_sleep_time_override;
+module_param_named(sleep_time_override,
+	msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
 enum {
 	MSM_PM_DEBUG_SUSPEND = BIT(0),
@@ -70,24 +88,12 @@
 	MSM_PM_DEBUG_HOTPLUG = BIT(8),
 };
 
-static int msm_pm_debug_mask = 1;
-module_param_named(
-	debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
-);
-static int msm_pm_retention_tz_call;
-
-/******************************************************************************
- * Sleep Modes and Parameters
- *****************************************************************************/
 enum {
 	MSM_PM_MODE_ATTR_SUSPEND,
 	MSM_PM_MODE_ATTR_IDLE,
 	MSM_PM_MODE_ATTR_NR,
 };
 
-#define SCM_L2_RETENTION	(0x2)
-#define SCM_CMD_TERMINATE_PC	(0x2)
-
 static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
 	[MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
 	[MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
@@ -98,9 +104,6 @@
 	struct kobj_attribute ka;
 };
 
-#define GET_CPU_OF_ATTR(attr) \
-	(container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
-
 struct msm_pm_sysfs_sleep_mode {
 	struct kobject *kobj;
 	struct attribute_group attr_group;
@@ -116,10 +119,15 @@
 		"standalone_power_collapse",
 };
 
-static struct msm_pm_init_data_type msm_pm_init_data;
 static struct hrtimer pm_hrtimer;
 static struct msm_pm_sleep_ops pm_sleep_ops;
 static bool msm_pm_ldo_retention_enabled = true;
+static bool msm_pm_use_sync_timer;
+static struct msm_pm_cp15_save_data cp15_data;
+static bool msm_pm_retention_calls_tz;
+static uint32_t msm_pm_max_sleep_time;
+static bool msm_no_ramp_down_pc;
+
 /*
  * Write out the attribute.
  */
@@ -166,9 +174,6 @@
 	return ret;
 }
 
-/*
- * Read in the new attribute value.
- */
 static ssize_t msm_pm_mode_attr_store(struct kobject *kobj,
 	struct kobj_attribute *attr, const char *buf, size_t count)
 {
@@ -205,10 +210,7 @@
 	return ret ? ret : count;
 }
 
-/*
- * Add sysfs entries for one cpu.
- */
-static int __init msm_pm_mode_sysfs_add_cpu(
+static int __devinit msm_pm_mode_sysfs_add_cpu(
 	unsigned int cpu, struct kobject *modes_kobj)
 {
 	char cpu_name[8];
@@ -291,10 +293,7 @@
 	return ret;
 }
 
-/*
- * Add sysfs entries for the sleep modes.
- */
-static int __init msm_pm_mode_sysfs_add(void)
+int __devinit msm_pm_mode_sysfs_add(void)
 {
 	struct kobject *module_kobj;
 	struct kobject *modes_kobj;
@@ -328,10 +327,6 @@
 	return ret;
 }
 
-/******************************************************************************
- * Configure Hardware before/after Low Power Mode
- *****************************************************************************/
-
 /*
  * Configure hardware registers in preparation for Apps power down.
  */
@@ -374,22 +369,6 @@
 	return;
 }
 
-
-/******************************************************************************
- * Suspend Max Sleep Time
- *****************************************************************************/
-
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
-static int msm_pm_sleep_time_override;
-module_param_named(sleep_time_override,
-	msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
-#endif
-
-#define SCLK_HZ (32768)
-#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
-
-static uint32_t msm_pm_max_sleep_time;
-
 /*
  * Convert time from nanoseconds to slow clock ticks, then cap it to the
  * specified limit
@@ -408,36 +387,21 @@
 	if (max_sleep_time_ns == 0) {
 		msm_pm_max_sleep_time = 0;
 	} else {
-		msm_pm_max_sleep_time = (uint32_t)msm_pm_convert_and_cap_time(
+		msm_pm_max_sleep_time =
+			(uint32_t)msm_pm_convert_and_cap_time(
 			max_sleep_time_ns, MSM_PM_SLEEP_TICK_LIMIT);
 
 		if (msm_pm_max_sleep_time == 0)
 			msm_pm_max_sleep_time = 1;
 	}
 
-	if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
+	if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 		pr_info("%s: Requested %lld ns Giving %u sclk ticks\n",
-			__func__, max_sleep_time_ns, msm_pm_max_sleep_time);
+			__func__, max_sleep_time_ns,
+			msm_pm_max_sleep_time);
 }
 EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
 
-struct reg_data {
-	uint32_t reg;
-	uint32_t val;
-};
-
-static struct reg_data reg_saved_state[] = {
-	{ .reg = 0x4501, },
-	{ .reg = 0x5501, },
-	{ .reg = 0x6501, },
-	{ .reg = 0x7501, },
-	{ .reg = 0x0500, },
-};
-
-static unsigned int active_vdd;
-static bool msm_pm_save_cp15;
-static const unsigned int pc_vdd = 0x98;
-
 static void msm_pm_save_cpu_reg(void)
 {
 	int i;
@@ -455,11 +419,12 @@
 	 * rate. Then restore the active vdd before switching the acpuclk rate.
 	 */
 	if (msm_pm_get_l2_flush_flag() == 1) {
-		active_vdd = msm_spm_get_vdd(0);
-		for (i = 0; i < ARRAY_SIZE(reg_saved_state); i++)
-			reg_saved_state[i].val =
-				get_l2_indirect_reg(reg_saved_state[i].reg);
-		msm_spm_set_vdd(0, pc_vdd);
+		cp15_data.active_vdd = msm_spm_get_vdd(0);
+		for (i = 0; i < cp15_data.reg_saved_state_size; i++)
+			cp15_data.reg_val[i] =
+				get_l2_indirect_reg(
+					cp15_data.reg_data[i]);
+		msm_spm_set_vdd(0, cp15_data.qsb_pc_vdd);
 	}
 }
 
@@ -472,10 +437,11 @@
 		return;
 
 	if (msm_pm_get_l2_flush_flag() == 1) {
-		for (i = 0; i < ARRAY_SIZE(reg_saved_state); i++)
-			set_l2_indirect_reg(reg_saved_state[i].reg,
-					reg_saved_state[i].val);
-		msm_spm_set_vdd(0, active_vdd);
+		for (i = 0; i < cp15_data.reg_saved_state_size; i++)
+			set_l2_indirect_reg(
+					cp15_data.reg_data[i],
+					cp15_data.reg_val[i]);
+		msm_spm_set_vdd(0, cp15_data.active_vdd);
 	}
 }
 
@@ -485,7 +451,6 @@
 	msm_arch_idle();
 }
 
-
 static void msm_pm_retention(void)
 {
 	int ret = 0;
@@ -494,7 +459,7 @@
 	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
 	WARN_ON(ret);
 
-	if (msm_pm_retention_tz_call)
+	if (msm_pm_retention_calls_tz)
 		scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
 					SCM_L2_RETENTION);
 	else
@@ -565,7 +530,7 @@
 static bool msm_pm_power_collapse(bool from_idle)
 {
 	unsigned int cpu = smp_processor_id();
-	unsigned long saved_acpuclk_rate;
+	unsigned long saved_acpuclk_rate = 0;
 	unsigned int avsdscr;
 	unsigned int avscsr;
 	bool collapsed;
@@ -582,28 +547,28 @@
 	avscsr = avs_get_avscsr();
 	avs_set_avscsr(0); /* Disable AVS */
 
-	if (cpu_online(cpu))
+	if (cpu_online(cpu) && !msm_no_ramp_down_pc)
 		saved_acpuclk_rate = acpuclk_power_collapse();
-	else
-		saved_acpuclk_rate = 0;
 
 	if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: change clock rate (old rate = %lu)\n",
 			cpu, __func__, saved_acpuclk_rate);
 
-	if (msm_pm_save_cp15)
+	if (cp15_data.save_cp15)
 		msm_pm_save_cpu_reg();
 
 	collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
 
-	if (msm_pm_save_cp15)
+	if (cp15_data.save_cp15)
 		msm_pm_restore_cpu_reg();
 
 	if (cpu_online(cpu)) {
 		if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
 			pr_info("CPU%u: %s: restore clock rate to %lu\n",
 				cpu, __func__, saved_acpuclk_rate);
-		if (acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC) < 0)
+		if (!msm_no_ramp_down_pc &&
+			acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC)
+				< 0)
 			pr_err("CPU%u: %s: failed to restore clock rate(%lu)\n",
 				cpu, __func__, saved_acpuclk_rate);
 	} else {
@@ -633,15 +598,9 @@
 	return collapsed;
 }
 
-static void msm_pm_target_init(void)
-{
-	if (cpu_is_apq8064())
-		msm_pm_save_cp15 = true;
-}
-
 static int64_t msm_pm_timer_enter_idle(void)
 {
-	if (msm_pm_init_data.use_sync_timer)
+	if (msm_pm_use_sync_timer)
 		return ktime_to_ns(tick_nohz_get_sleep_length());
 
 	return msm_timer_enter_idle();
@@ -649,7 +608,7 @@
 
 static void msm_pm_timer_exit_idle(bool timer_halted)
 {
-	if (msm_pm_init_data.use_sync_timer)
+	if (msm_pm_use_sync_timer)
 		return;
 
 	msm_timer_exit_idle((int) timer_halted);
@@ -659,7 +618,7 @@
 {
 	int64_t time = 0;
 
-	if (msm_pm_init_data.use_sync_timer)
+	if (msm_pm_use_sync_timer)
 		return ktime_to_ns(ktime_get());
 
 	time = msm_timer_get_sclk_time(period);
@@ -671,7 +630,7 @@
 
 static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
 {
-	if (msm_pm_init_data.use_sync_timer)
+	if (msm_pm_use_sync_timer)
 		return ktime_to_ns(ktime_get()) - time;
 
 	if (time != 0) {
@@ -794,6 +753,7 @@
 		bool allow;
 		uint32_t power;
 		int idx;
+		void *rs_limits = NULL;
 
 		mode = (enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage);
 		idx = MSM_PM_MODE(dev->cpu, mode);
@@ -803,11 +763,9 @@
 
 		switch (mode) {
 		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
-			if (num_online_cpus() > 1) {
+			if (num_online_cpus() > 1)
 				allow = false;
-				break;
-			}
-			/* fall through */
+			break;
 		case MSM_PM_SLEEP_MODE_RETENTION:
 			/*
 			 * The Krait BHS regulator doesn't have enough head
@@ -815,63 +773,41 @@
 			 * has disabled retention
 			 */
 			if (!msm_pm_ldo_retention_enabled)
-				break;
-
-			if (!allow)
-				break;
-
-			if (msm_pm_retention_tz_call &&
-				num_online_cpus() > 1) {
 				allow = false;
-				break;
-			}
-			/* fall through */
 
-		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
-			if (!allow)
-				break;
-			/* fall through */
-
-		case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
-			if (!allow)
-				break;
-			/* fall through */
-
-			if (pm_sleep_ops.lowest_limits)
-				*msm_pm_idle_rs_limits =
-					pm_sleep_ops.lowest_limits(
-						true, mode,
-						&time_param, &power);
-
-			if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
-				pr_info("CPU%u: %s: %s, latency %uus, "
-					"sleep %uus, limit %p\n",
-					dev->cpu, __func__, state->desc,
-					time_param.latency_us,
-					time_param.sleep_us,
-					*msm_pm_idle_rs_limits);
-
-			if (!*msm_pm_idle_rs_limits)
+			if (msm_pm_retention_calls_tz && num_online_cpus() > 1)
 				allow = false;
 			break;
-
+		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+		case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+			break;
 		default:
 			allow = false;
 			break;
 		}
 
+		if (!allow)
+			continue;
+
+		if (pm_sleep_ops.lowest_limits)
+			rs_limits = pm_sleep_ops.lowest_limits(true,
+					mode, &time_param, &power);
+
 		if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
-			pr_info("CPU%u: %s: allow %s: %d\n",
-				dev->cpu, __func__, state->desc, (int)allow);
+			pr_info("CPU%u:%s:%s, latency %uus, slp %uus, lim %p\n",
+					dev->cpu, __func__, state->desc,
+					time_param.latency_us,
+					time_param.sleep_us, rs_limits);
+		if (!rs_limits)
+			continue;
 
-		if (allow) {
-			if (power < power_usage) {
-				power_usage = power;
-				modified_time_us = time_param.modified_time_us;
-				ret = mode;
-			}
-
+		if (power < power_usage) {
+			power_usage = power;
+			modified_time_us = time_param.modified_time_us;
+			ret = mode;
+			*msm_pm_idle_rs_limits = rs_limits;
 		}
+
 	}
 
 	if (modified_time_us && !dev->cpu)
@@ -924,67 +860,64 @@
 
 	if (pm_sleep_ops.enter_sleep)
 		ret = pm_sleep_ops.enter_sleep(sleep_delay,
-			msm_pm_idle_rs_limits,
-			true, notify_rpm);
-	if (!ret) {
+			msm_pm_idle_rs_limits, true, notify_rpm);
+	if (ret)
+		goto cpuidle_enter_bail;
 
-		switch (sleep_mode) {
-		case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
-			msm_pm_swfi();
-			exit_stat = MSM_PM_STAT_IDLE_WFI;
-			break;
+	switch (sleep_mode) {
+	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+		msm_pm_swfi();
+		exit_stat = MSM_PM_STAT_IDLE_WFI;
+		break;
 
-		case MSM_PM_SLEEP_MODE_RETENTION:
-			msm_pm_retention();
-			exit_stat = MSM_PM_STAT_RETENTION;
-			break;
+	case MSM_PM_SLEEP_MODE_RETENTION:
+		msm_pm_retention();
+		exit_stat = MSM_PM_STAT_RETENTION;
+		break;
 
-		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
-			collapsed = msm_pm_power_collapse_standalone(true);
-			exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
-			break;
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+		collapsed = msm_pm_power_collapse_standalone(true);
+		exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
+		break;
 
-		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
-			if (MSM_PM_DEBUG_IDLE_CLK & msm_pm_debug_mask)
-				clock_debug_print_enabled();
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+		if (MSM_PM_DEBUG_IDLE_CLK & msm_pm_debug_mask)
+			clock_debug_print_enabled();
 
-			collapsed = msm_pm_power_collapse(true);
-			timer_halted = true;
+		collapsed = msm_pm_power_collapse(true);
+		timer_halted = true;
 
-			exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
-			msm_pm_timer_exit_idle(timer_halted);
-			break;
-
-		case MSM_PM_SLEEP_MODE_NOT_SELECTED:
-			goto cpuidle_enter_bail;
-			break;
-
-		default:
-			__WARN();
-			goto cpuidle_enter_bail;
-			break;
-		}
-		if (pm_sleep_ops.exit_sleep)
-			pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits,
-					true, notify_rpm, collapsed);
-
-		time = ktime_to_ns(ktime_get()) - time;
-		msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode,
-					collapsed);
-		if (exit_stat >= 0)
-			msm_pm_add_stat(exit_stat, time);
-		do_div(time, 1000);
-		dev->last_residency = (int) time;
-		return sleep_mode;
-
-	} else if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
+		exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
 		msm_pm_timer_exit_idle(timer_halted);
-		sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
-	} else
-		sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
+		break;
+
+	case MSM_PM_SLEEP_MODE_NOT_SELECTED:
+		goto cpuidle_enter_bail;
+		break;
+
+	default:
+		__WARN();
+		goto cpuidle_enter_bail;
+		break;
+	}
+
+	if (pm_sleep_ops.exit_sleep)
+		pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits, true,
+				notify_rpm, collapsed);
+
+	time = ktime_to_ns(ktime_get()) - time;
+	msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode, collapsed);
+	if (exit_stat >= 0)
+		msm_pm_add_stat(exit_stat, time);
+	do_div(time, 1000);
+	dev->last_residency = (int) time;
+	return sleep_mode;
 
 cpuidle_enter_bail:
 	dev->last_residency = 0;
+	if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
+		msm_pm_timer_exit_idle(timer_halted);
+	sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
 	return sleep_mode;
 }
 
@@ -1079,17 +1012,16 @@
 
 		clock_debug_print_enabled();
 
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
 		if (msm_pm_sleep_time_override > 0) {
 			int64_t ns = NSEC_PER_SEC *
 				(int64_t) msm_pm_sleep_time_override;
 			msm_pm_set_max_sleep_time(ns);
 			msm_pm_sleep_time_override = 0;
 		}
-#endif /* CONFIG_MSM_SLEEP_TIME_OVERRIDE */
+
 		if (pm_sleep_ops.lowest_limits)
 			rs_limits = pm_sleep_ops.lowest_limits(false,
-			MSM_PM_SLEEP_MODE_POWER_COLLAPSE, &time_param, &power);
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE, &time_param, &power);
 
 		if (rs_limits) {
 			if (pm_sleep_ops.enter_sleep)
@@ -1123,7 +1055,6 @@
 		msm_pm_swfi();
 	}
 
-
 enter_exit:
 	if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 		pr_info("%s: return\n", __func__);
@@ -1131,66 +1062,18 @@
 	return 0;
 }
 
-static struct platform_suspend_ops msm_pm_ops = {
-	.enter = msm_pm_enter,
-	.valid = suspend_valid_only_mem,
-};
-
-/******************************************************************************
- * Initialization routine
- *****************************************************************************/
 void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops)
 {
 	if (ops)
 		pm_sleep_ops = *ops;
 }
 
-void __init msm_pm_set_tz_retention_flag(unsigned int flag)
-{
-	msm_pm_retention_tz_call = flag;
-}
-
-static int __devinit msm_pc_debug_probe(struct platform_device *pdev)
-{
-	struct resource *res = NULL;
-	int i ;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		goto fail;
-
-	msm_pc_debug_counters_phys = res->start;
-	WARN_ON(resource_size(res) < SZ_64);
-	msm_pc_debug_counters = devm_ioremap_nocache(&pdev->dev, res->start,
-					resource_size(res));
-
-	if (!msm_pc_debug_counters)
-		goto fail;
-
-	for (i = 0; i < resource_size(res)/4; i++)
-		__raw_writel(0, msm_pc_debug_counters + i * 4);
-	return 0;
-fail:
-	msm_pc_debug_counters = 0;
-	msm_pc_debug_counters_phys = 0;
-	return -EFAULT;
-}
-
-static struct of_device_id msm_pc_debug_table[] = {
-	{.compatible = "qcom,pc-cntr"},
-	{},
+static const struct platform_suspend_ops msm_pm_ops = {
+	.enter = msm_pm_enter,
+	.valid = suspend_valid_only_mem,
 };
 
-static struct platform_driver msm_pc_counter_driver = {
-	.probe = msm_pc_debug_probe,
-	.driver = {
-		.name = "pc-cntr",
-		.owner = THIS_MODULE,
-		.of_match_table = msm_pc_debug_table,
-	},
-};
-
-static int __init msm_pm_init(void)
+static int __devinit msm_pm_init(void)
 {
 	pgd_t *pc_pgd;
 	pmd_t *pmd;
@@ -1205,7 +1088,6 @@
 	unsigned long exit_phys;
 
 	/* Page table for cores to come back up safely. */
-
 	pc_pgd = pgd_alloc(&init_mm);
 	if (!pc_pgd)
 		return -ENOMEM;
@@ -1244,18 +1126,13 @@
 
 	msm_pm_mode_sysfs_add();
 	msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
-
 	suspend_set_ops(&msm_pm_ops);
-	msm_pm_target_init();
 	hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
 	msm_cpuidle_init();
-	platform_driver_register(&msm_pc_counter_driver);
 
 	return 0;
 }
 
-late_initcall(msm_pm_init);
-
 static void __devinit msm_pm_set_flush_fn(uint32_t pc_mode)
 {
 	msm_pm_disable_l2_fn = NULL;
@@ -1268,41 +1145,203 @@
 	}
 }
 
+struct msm_pc_debug_counters_buffer {
+	void __iomem *reg;
+	u32 len;
+	char buf[MAX_BUF_SIZE];
+};
+
+static inline u32 msm_pc_debug_counters_read_register(
+		void __iomem *reg, int index , int offset)
+{
+	return readl_relaxed(reg + (index * 4 + offset) * 4);
+}
+
+static char *counter_name[] = {
+		"PC Entry Counter",
+		"Warmboot Entry Counter",
+		"PC Bailout Counter"
+};
+
+static int msm_pc_debug_counters_copy(
+		struct msm_pc_debug_counters_buffer *data)
+{
+	int j;
+	u32 stat;
+	unsigned int cpu;
+
+	for_each_possible_cpu(cpu) {
+		data->len += scnprintf(data->buf + data->len,
+				sizeof(data->buf)-data->len,
+				"CPU%d\n", cpu);
+
+			for (j = 0; j < NUM_OF_COUNTERS; j++) {
+				stat = msm_pc_debug_counters_read_register(
+						data->reg, cpu, j);
+				data->len += scnprintf(data->buf + data->len,
+					sizeof(data->buf)-data->len,
+					"\t%s : %d\n", counter_name[j],
+					stat);
+		}
+
+	}
+
+	return data->len;
+}
+
+static int msm_pc_debug_counters_file_read(struct file *file,
+		char __user *bufu, size_t count, loff_t *ppos)
+{
+	struct msm_pc_debug_counters_buffer *data;
+
+	data = file->private_data;
+
+	if (!data)
+		return -EINVAL;
+
+	if (!bufu || count < 0)
+		return -EINVAL;
+
+	if (!access_ok(VERIFY_WRITE, bufu, count))
+		return -EFAULT;
+
+	if (*ppos >= data->len && data->len == 0)
+		data->len = msm_pc_debug_counters_copy(data);
+
+	return simple_read_from_buffer(bufu, count, ppos,
+			data->buf, data->len);
+}
+
+static int msm_pc_debug_counters_file_open(struct inode *inode,
+		struct file *file)
+{
+	struct msm_pc_debug_counters_buffer *buf;
+	void __iomem *msm_pc_debug_counters_reg;
+
+	msm_pc_debug_counters_reg = inode->i_private;
+
+	if (!msm_pc_debug_counters_reg)
+		return -EINVAL;
+
+	file->private_data = kzalloc(
+		sizeof(struct msm_pc_debug_counters_buffer), GFP_KERNEL);
+
+	if (!file->private_data) {
+		pr_err("%s: ERROR kmalloc failed to allocate %d bytes\n",
+		__func__, sizeof(struct msm_pc_debug_counters_buffer));
+
+		return -ENOMEM;
+	}
+
+	buf = file->private_data;
+	buf->reg = msm_pc_debug_counters_reg;
+
+	return 0;
+}
+
+static int msm_pc_debug_counters_file_close(struct inode *inode,
+		struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+static const struct file_operations msm_pc_debug_counters_fops = {
+	.open = msm_pc_debug_counters_file_open,
+	.read = msm_pc_debug_counters_file_read,
+	.release = msm_pc_debug_counters_file_close,
+	.llseek = no_llseek,
+};
+
 static int __devinit msm_pm_8x60_probe(struct platform_device *pdev)
 {
 	char *key = NULL;
+	struct dentry *dent = NULL;
 	uint32_t val = 0;
+	struct resource *res = NULL;
+	int i ;
+	struct msm_pm_init_data_type pdata_local;
 	int ret = 0;
 
+	memset(&pdata_local, 0, sizeof(struct msm_pm_init_data_type));
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res) {
+		msm_pc_debug_counters_phys = res->start;
+		WARN_ON(resource_size(res) < SZ_64);
+		msm_pc_debug_counters = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+		if (msm_pc_debug_counters)
+			for (i = 0; i < resource_size(res)/4; i++)
+				__raw_writel(0, msm_pc_debug_counters + i * 4);
+
+	}
+
+	if (!msm_pc_debug_counters) {
+		msm_pc_debug_counters = 0;
+		msm_pc_debug_counters_phys = 0;
+	} else {
+		dent = debugfs_create_file("pc_debug_counter", S_IRUGO, NULL,
+				msm_pc_debug_counters,
+				&msm_pc_debug_counters_fops);
+		if (!dent)
+			pr_err("%s: ERROR debugfs_create_file failed\n",
+					__func__);
+	}
+
 	if (!pdev->dev.of_node) {
 		struct msm_pm_init_data_type *d = pdev->dev.platform_data;
 
 		if (!d)
 			goto pm_8x60_probe_done;
 
-		msm_pm_init_data.pc_mode = d->pc_mode;
-		msm_pm_set_flush_fn(msm_pm_init_data.pc_mode);
-		msm_pm_init_data.use_sync_timer = d->use_sync_timer;
+		memcpy(&pdata_local, d, sizeof(struct msm_pm_init_data_type));
+
 	} else {
 		key = "qcom,pc-mode";
 		ret = of_property_read_u32(pdev->dev.of_node, key, &val);
-
 		if (ret) {
 			pr_debug("%s: Cannot read %s,defaulting to 0",
 					__func__, key);
 			val = MSM_PM_PC_TZ_L2_INT;
 			ret = 0;
 		}
-
-		msm_pm_init_data.pc_mode = val;
-		msm_pm_set_flush_fn(msm_pm_init_data.pc_mode);
+		pdata_local.pc_mode = val;
 
 		key = "qcom,use-sync-timer";
-		msm_pm_init_data.use_sync_timer =
+		pdata_local.use_sync_timer =
 			of_property_read_bool(pdev->dev.of_node, key);
+
+		key = "qcom,saw-turns-off-pll";
+		msm_no_ramp_down_pc = of_property_read_bool(pdev->dev.of_node,
+					key);
 	}
 
+	if (pdata_local.cp15_data.reg_data &&
+		pdata_local.cp15_data.reg_saved_state_size > 0) {
+		cp15_data.reg_data = kzalloc(sizeof(uint32_t) *
+				pdata_local.cp15_data.reg_saved_state_size,
+				GFP_KERNEL);
+		if (!cp15_data.reg_data)
+			return -ENOMEM;
+
+		cp15_data.reg_val = kzalloc(sizeof(uint32_t) *
+				pdata_local.cp15_data.reg_saved_state_size,
+				GFP_KERNEL);
+		if (cp15_data.reg_val)
+			return -ENOMEM;
+
+		memcpy(cp15_data.reg_data, pdata_local.cp15_data.reg_data,
+			pdata_local.cp15_data.reg_saved_state_size *
+			sizeof(uint32_t));
+	}
+
+	msm_pm_set_flush_fn(pdata_local.pc_mode);
+	msm_pm_use_sync_timer = pdata_local.use_sync_timer;
+	msm_pm_retention_calls_tz = pdata_local.retention_calls_tz;
+
 pm_8x60_probe_done:
+	msm_pm_init();
 	return ret;
 }
 
@@ -1324,4 +1363,4 @@
 {
 	return platform_driver_register(&msm_pm_8x60_driver);
 }
-module_init(msm_pm_8x60_init);
+device_initcall(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 43bb7de..af0744c 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -97,8 +97,19 @@
 					external L2 cache controller */
 };
 
+struct msm_pm_cp15_save_data {
+	bool save_cp15;
+	uint32_t active_vdd;
+	uint32_t qsb_pc_vdd;
+	uint32_t reg_saved_state_size;
+	uint32_t *reg_data;
+	uint32_t *reg_val;
+};
+
 struct msm_pm_init_data_type {
 	enum msm_pm_pc_mode_type pc_mode;
+	bool retention_calls_tz;
+	struct msm_pm_cp15_save_data cp15_data;
 	bool use_sync_timer;
 };
 
diff --git a/arch/arm/mach-msm/rpm-notifier.h b/arch/arm/mach-msm/rpm-notifier.h
index b9815a5..16de77e 100644
--- a/arch/arm/mach-msm/rpm-notifier.h
+++ b/arch/arm/mach-msm/rpm-notifier.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -40,8 +40,12 @@
 
 /**
  * msm_rpm_enter_sleep - Notify RPM driver to prepare for entering sleep
+ *
+ * @bool - flag to enable print contents of sleep buffer.
+ *
+ * return 0 on success errno on failure.
  */
-int msm_rpm_enter_sleep(void);
+int msm_rpm_enter_sleep(bool print);
 
 /**
  * msm_rpm_exit_sleep - Notify RPM driver about resuming from power collapse
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 4295fd4..b84ade9 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -32,6 +32,7 @@
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#include <linux/rbtree.h>
 #include <mach/socinfo.h>
 #include <mach/msm_smd.h>
 #include <mach/rpm-smd.h>
@@ -62,6 +63,9 @@
 };
 
 #define DEFAULT_BUFFER_SIZE 256
+#define DEBUG_PRINT_BUFFER_SIZE 512
+#define MAX_SLEEP_BUFFER 128
+
 #define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_KERNEL)
 #define INV_RSC "resource does not exist"
 #define ERR "err\0"
@@ -106,6 +110,11 @@
 	uint32_t data_len;
 };
 
+struct kvp {
+	unsigned int k;
+	unsigned int s;
+};
+
 struct msm_rpm_kvp_data {
 	uint32_t key;
 	uint32_t nbytes; /* number of bytes */
@@ -113,6 +122,301 @@
 	bool valid;
 };
 
+struct slp_buf {
+	struct rb_node node;
+	char ubuf[MAX_SLEEP_BUFFER];
+	char *buf;
+	bool valid;
+};
+static struct rb_root tr_root = RB_ROOT;
+
+static int msm_rpm_send_smd_buffer(char *buf, int size, bool noirq);
+static uint32_t msm_rpm_get_next_msg_id(void);
+
+static inline unsigned int get_rsc_type(char *buf)
+{
+	struct rpm_message_header *h;
+	h = (struct rpm_message_header *)
+		(buf + sizeof(struct rpm_request_header));
+	return h->resource_type;
+}
+
+static inline unsigned int get_rsc_id(char *buf)
+{
+	struct rpm_message_header *h;
+	h = (struct rpm_message_header *)
+		(buf + sizeof(struct rpm_request_header));
+	return h->resource_id;
+}
+
+#define get_data_len(buf) \
+	(((struct rpm_message_header *) \
+	  (buf + sizeof(struct rpm_request_header)))->data_len)
+
+#define get_req_len(buf) \
+	(((struct rpm_request_header *)(buf))->request_len)
+
+#define get_msg_id(buf) \
+	(((struct rpm_message_header *) \
+	  (buf + sizeof(struct rpm_request_header)))->msg_id)
+
+
+static inline int get_buf_len(char *buf)
+{
+	return get_req_len(buf) + sizeof(struct rpm_request_header);
+}
+
+static inline struct kvp *get_first_kvp(char *buf)
+{
+	return (struct kvp *)(buf + sizeof(struct rpm_request_header)
+			+ sizeof(struct rpm_message_header));
+}
+
+static inline struct kvp *get_next_kvp(struct kvp *k)
+{
+	return (struct kvp *)((void *)k + sizeof(*k) + k->s);
+}
+
+static inline void *get_data(struct kvp *k)
+{
+	return (void *)k + sizeof(*k);
+}
+
+
+static void delete_kvp(char *msg, struct kvp *d)
+{
+	struct kvp *n;
+	int dec, size;
+
+	n = get_next_kvp(d);
+	dec = (void *)n - (void *)d;
+	size = get_data_len(msg) - ((void *)n - (void *)get_first_kvp(msg));
+
+	memcpy((void *)d, (void *)n, size);
+
+	get_data_len(msg) -= dec;
+	get_req_len(msg) -= dec;
+}
+
+static inline void update_kvp_data(struct kvp *dest, struct kvp *src)
+{
+	memcpy(get_data(dest), get_data(src), src->s);
+}
+
+static void add_kvp(char *buf, struct kvp *n)
+{
+	int inc = sizeof(*n) + n->s;
+	BUG_ON((get_req_len(buf) + inc) > MAX_SLEEP_BUFFER);
+
+	memcpy(buf + get_buf_len(buf), n, inc);
+
+	get_data_len(buf) += inc;
+	get_req_len(buf) += inc;
+}
+
+static struct slp_buf *tr_search(struct rb_root *root, char *slp)
+{
+	unsigned int type = get_rsc_type(slp);
+	unsigned int id = get_rsc_id(slp);
+
+	struct rb_node *node = root->rb_node;
+
+	while (node) {
+		struct slp_buf *cur = rb_entry(node, struct slp_buf, node);
+		unsigned int ctype = get_rsc_type(cur->buf);
+		unsigned int cid = get_rsc_id(cur->buf);
+
+		if (type < ctype)
+			node = node->rb_left;
+		else if (type > ctype)
+			node = node->rb_right;
+		else if (id < cid)
+			node = node->rb_left;
+		else if (id > cid)
+			node = node->rb_right;
+		else
+			return cur;
+	}
+	return NULL;
+}
+
+static int tr_insert(struct rb_root *root, struct slp_buf *slp)
+{
+	unsigned int type = get_rsc_type(slp->buf);
+	unsigned int id = get_rsc_id(slp->buf);
+
+	struct rb_node **node = &(root->rb_node), *parent = NULL;
+
+	while (*node) {
+		struct slp_buf *curr = rb_entry(*node, struct slp_buf, node);
+		unsigned int ctype = get_rsc_type(curr->buf);
+		unsigned int cid = get_rsc_id(curr->buf);
+
+		parent = *node;
+
+		if (type < ctype)
+			node = &((*node)->rb_left);
+		else if (type > ctype)
+			node = &((*node)->rb_right);
+		else if (id < cid)
+			node = &((*node)->rb_left);
+		else if (id > cid)
+			node = &((*node)->rb_right);
+		else
+			return -EINVAL;
+	}
+
+	rb_link_node(&slp->node, parent, node);
+	rb_insert_color(&slp->node, root);
+	slp->valid = true;
+	return 0;
+}
+
+#define for_each_kvp(buf, k) \
+	for (k = (struct kvp *)get_first_kvp(buf); \
+		((void *)k - (void *)get_first_kvp(buf)) < get_data_len(buf);\
+		k = get_next_kvp(k))
+
+
+static void tr_update(struct slp_buf *s, char *buf)
+{
+	struct kvp *e, *n;
+
+	for_each_kvp(buf, n) {
+		for_each_kvp(s->buf, e) {
+			if (n->k == e->k) {
+				if (n->s == e->s) {
+					void *e_data = get_data(e);
+					void *n_data = get_data(n);
+					if (memcmp(e_data, n_data, n->s)) {
+						update_kvp_data(e, n);
+						s->valid = true;
+					}
+				} else {
+					delete_kvp(s->buf, e);
+					add_kvp(s->buf, n);
+					s->valid = true;
+				}
+				break;
+			}
+		}
+	}
+}
+
+int msm_rpm_smd_buffer_request(char *buf, int size, gfp_t flag)
+{
+	struct slp_buf *slp;
+	static DEFINE_SPINLOCK(slp_buffer_lock);
+	unsigned long flags;
+
+	if (size > MAX_SLEEP_BUFFER)
+		return -ENOMEM;
+
+	spin_lock_irqsave(&slp_buffer_lock, flags);
+	slp = tr_search(&tr_root, buf);
+
+	if (!slp) {
+		slp = kzalloc(sizeof(struct slp_buf), GFP_ATOMIC);
+		if (!slp) {
+			spin_unlock_irqrestore(&slp_buffer_lock, flags);
+			return -ENOMEM;
+		}
+		slp->buf = PTR_ALIGN(&slp->ubuf[0], sizeof(u32));
+		memcpy(slp->buf, buf, size);
+		if (tr_insert(&tr_root, slp))
+			pr_err("%s(): Error updating sleep request\n",
+					__func__);
+	} else {
+		/* handle unsent requests */
+		tr_update(slp, buf);
+	}
+
+	spin_unlock_irqrestore(&slp_buffer_lock, flags);
+
+	return 0;
+}
+static void msm_rpm_print_sleep_buffer(struct slp_buf *s)
+{
+	char buf[DEBUG_PRINT_BUFFER_SIZE] = {0};
+	int pos;
+	int buflen = DEBUG_PRINT_BUFFER_SIZE;
+	char ch[5] = {0};
+	u32 type;
+	struct kvp *e;
+
+	if (!s)
+		return;
+
+	if (!s->valid)
+		return;
+
+	type = get_rsc_type(s->buf);
+	memcpy(ch, &type, sizeof(u32));
+
+	pos = scnprintf(buf, buflen,
+			"Sleep request type = 0x%08x(%s)",
+			get_rsc_type(s->buf), ch);
+	pos += scnprintf(buf + pos, buflen - pos, " id = 0%x",
+			get_rsc_id(s->buf));
+	for_each_kvp(s->buf, e) {
+		int i;
+		char *data = get_data(e);
+
+		memcpy(ch, &e->k, sizeof(u32));
+
+		pos += scnprintf(buf + pos, buflen - pos,
+				"\n\t\tkey = 0x%08x(%s)",
+				e->k, ch);
+		pos += scnprintf(buf + pos, buflen - pos,
+				" sz= %d data =", e->s);
+
+		for (i = 0; i < e->s; i++)
+			pos += scnprintf(buf + pos, buflen - pos,
+					" 0x%02X", data[i]);
+	}
+	pos += scnprintf(buf + pos, buflen - pos, "\n");
+	printk(buf);
+}
+
+static int msm_rpm_flush_requests(bool print)
+{
+	struct rb_node *t;
+	int ret;
+
+	for (t = rb_first(&tr_root); t; t = rb_next(t)) {
+
+		struct slp_buf *s = rb_entry(t, struct slp_buf, node);
+
+		if (!s->valid)
+			continue;
+
+		if (print)
+			msm_rpm_print_sleep_buffer(s);
+
+		get_msg_id(s->buf) = msm_rpm_get_next_msg_id();
+		ret = msm_rpm_send_smd_buffer(s->buf,
+				get_buf_len(s->buf), true);
+		/* By not adding the message to a wait list we can reduce
+		 * latency involved in waiting for a ACK from RPM. The ACK
+		 * messages will be processed when we wakeup from sleep but
+		 * processing should be minimal
+		 * msm_rpm_wait_for_ack_noirq(get_msg_id(s->buf));
+		 */
+
+		WARN_ON(ret != get_buf_len(s->buf));
+
+		trace_rpm_send_message(true, MSM_RPM_CTX_SLEEP_SET,
+				get_rsc_type(s->buf),
+				get_rsc_id(s->buf),
+				get_msg_id(s->buf));
+
+		s->valid = false;
+	}
+	return 0;
+
+}
+
+
 static atomic_t msm_rpm_msg_id = ATOMIC_INIT(0);
 
 static struct msm_rpm_driver_data msm_rpm_data;
@@ -450,7 +754,12 @@
 		}
 		elem = NULL;
 	}
-	WARN_ON(!elem);
+	/* Special case where the sleep driver doesn't
+	 * wait for ACKs. This would decrease the latency involved with
+	 * entering RPM assisted power collapse.
+	 */
+	if (!elem)
+		trace_rpm_ack_recd(0, msg_id);
 
 	spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
 }
@@ -544,8 +853,6 @@
 	}
 }
 
-#define DEBUG_PRINT_BUFFER_SIZE 512
-
 static void msm_rpm_log_request(struct msm_rpm_request *cdata)
 {
 	char buf[DEBUG_PRINT_BUFFER_SIZE];
@@ -677,13 +984,42 @@
 	pos += scnprintf(buf + pos, buflen - pos, "\n");
 	printk(buf);
 }
+static int msm_rpm_send_smd_buffer(char *buf, int size, bool noirq)
+{
+	unsigned long flags;
+	int ret;
 
+	spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
+	ret = smd_write_avail(msm_rpm_data.ch_info);
+
+	while ((ret = smd_write_avail(msm_rpm_data.ch_info)) < size) {
+		if (ret < 0)
+			break;
+		if (!noirq) {
+			spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write,
+					flags);
+			cpu_relax();
+			spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
+		} else
+			udelay(5);
+	}
+
+	if (ret < 0) {
+		pr_err("%s(): SMD not initialized\n", __func__);
+		spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+		return ret;
+	}
+
+	ret = smd_write(msm_rpm_data.ch_info, buf, size);
+	spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+	return ret;
+
+}
 static int msm_rpm_send_data(struct msm_rpm_request *cdata,
 		int msg_type, bool noirq)
 {
 	uint8_t *tmpbuff;
 	int i, ret, msg_size;
-	unsigned long flags;
 
 	int req_hdr_sz, msg_hdr_sz;
 
@@ -695,8 +1031,6 @@
 
 	cdata->req_hdr.service_type = msm_rpm_request_service[msg_type];
 
-	cdata->msg_hdr.msg_id = msm_rpm_get_next_msg_id();
-
 	cdata->req_hdr.request_len = cdata->msg_hdr.data_len + msg_hdr_sz;
 	msg_size = cdata->req_hdr.request_len + req_hdr_sz;
 
@@ -714,8 +1048,6 @@
 
 	tmpbuff = cdata->buf;
 
-	memcpy(tmpbuff, &cdata->req_hdr, req_hdr_sz + msg_hdr_sz);
-
 	tmpbuff += req_hdr_sz + msg_hdr_sz;
 
 	for (i = 0; (i < cdata->write_idx); i++) {
@@ -740,6 +1072,17 @@
 
 	}
 
+	memcpy(cdata->buf, &cdata->req_hdr, req_hdr_sz + msg_hdr_sz);
+
+	if ((cdata->msg_hdr.set == MSM_RPM_CTX_SLEEP_SET) &&
+		!msm_rpm_smd_buffer_request(cdata->buf, msg_size,
+			GFP_FLAG(noirq)))
+		return 1;
+
+	cdata->msg_hdr.msg_id = msm_rpm_get_next_msg_id();
+
+	memcpy(cdata->buf + req_hdr_sz, &cdata->msg_hdr, msg_hdr_sz);
+
 	if (msm_rpm_debug_mask
 	    & (MSM_RPM_LOG_REQUEST_PRETTY | MSM_RPM_LOG_REQUEST_RAW))
 		msm_rpm_log_request(cdata);
@@ -755,29 +1098,7 @@
 
 	msm_rpm_add_wait_list(cdata->msg_hdr.msg_id);
 
-	spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
-
-	ret = smd_write_avail(msm_rpm_data.ch_info);
-
-	if (ret < 0) {
-		pr_err("%s(): SMD not initialized\n", __func__);
-		spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
-		return 0;
-	}
-
-	while ((ret < msg_size)) {
-		if (!noirq) {
-			spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write,
-					flags);
-			cpu_relax();
-			spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
-		} else
-			udelay(5);
-		ret = smd_write_avail(msm_rpm_data.ch_info);
-	}
-
-	ret = smd_write(msm_rpm_data.ch_info, &cdata->buf[0], msg_size);
-	spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+	ret = msm_rpm_send_smd_buffer(&cdata->buf[0], msg_size, noirq);
 
 	if (ret == msg_size) {
 		trace_rpm_send_message(noirq, cdata->msg_hdr.set,
@@ -958,11 +1279,13 @@
  * During power collapse, the rpm driver disables the SMD interrupts to make
  * sure that the interrupt doesn't wakes us from sleep.
  */
-int msm_rpm_enter_sleep(void)
+int msm_rpm_enter_sleep(bool print)
 {
 	if (standalone)
 		return 0;
 
+	msm_rpm_flush_requests(print);
+
 	return smd_mask_receive_interrupt(msm_rpm_data.ch_info, true);
 }
 EXPORT_SYMBOL(msm_rpm_enter_sleep);
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index 0a14979..2c0e5ae 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -262,8 +262,9 @@
 
 	extra_iova_addr = data->iova_addr + buffer->size;
 	if (extra) {
-		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, SZ_4K,
-						prot);
+		unsigned long phys_addr = sg_phys(table->sgl);
+		ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
+					extra, SZ_4K, prot);
 		if (ret)
 			goto out2;
 	}
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 11f351c..3fdc68f 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -125,6 +125,7 @@
 #define QPNP_BIT_SHIFT_8				8
 #define QPNP_RSENSE_MSB_SIGN_CHECK			0x80
 #define QPNP_ADC_COMPLETION_TIMEOUT			HZ
+#define QPNP_IADC_ERR_CHK_RATELIMIT			3
 
 struct qpnp_iadc_drv {
 	struct qpnp_adc_drv			*adc;
@@ -134,6 +135,9 @@
 	bool					iadc_initialized;
 	int64_t					die_temp_calib_offset;
 	struct delayed_work			iadc_work;
+	struct mutex				iadc_vadc_lock;
+	bool					iadc_mode_sel;
+	uint32_t				iadc_err_cnt;
 	struct sensor_device_attribute		sens_attr[0];
 };
 
@@ -292,7 +296,7 @@
 }
 
 static int32_t qpnp_iadc_configure(enum qpnp_iadc_channels channel,
-						uint16_t *raw_code)
+					uint16_t *raw_code, uint32_t mode_sel)
 {
 	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0;
@@ -303,7 +307,11 @@
 
 	qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
 					QPNP_IADC_DEC_RATIO_SEL;
-	qpnp_iadc_mode_reg |= QPNP_ADC_TRIM_EN;
+	if (iadc->iadc_mode_sel)
+		qpnp_iadc_mode_reg |= (QPNP_ADC_TRIM_EN | QPNP_VADC_SYNCH_EN);
+	else
+		qpnp_iadc_mode_reg |= QPNP_ADC_TRIM_EN;
+
 	qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;
 
 	rc = qpnp_iadc_write_reg(QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
@@ -403,8 +411,10 @@
 	uint8_t rslt_lsb, rslt_msb;
 	int32_t rc = 0;
 	uint16_t raw_data;
+	uint32_t mode_sel = 0;
 
-	rc = qpnp_iadc_configure(GAIN_CALIBRATION_17P857MV, &raw_data);
+	rc = qpnp_iadc_configure(GAIN_CALIBRATION_17P857MV,
+						&raw_data, mode_sel);
 	if (rc < 0) {
 		pr_err("qpnp adc result read failed with %d\n", rc);
 		goto fail;
@@ -412,8 +422,8 @@
 
 	iadc->adc->calib.gain_raw = raw_data;
 
-	rc = qpnp_iadc_configure(OFFSET_CALIBRATION_SHORT_CADC_LEADS,
-								&raw_data);
+	rc = qpnp_iadc_configure(OFFSET_CALIBRATION_CSP2_CSN2,
+						&raw_data, mode_sel);
 	if (rc < 0) {
 		pr_err("qpnp adc result read failed with %d\n", rc);
 		goto fail;
@@ -470,12 +480,15 @@
 	mutex_lock(&iadc->adc->adc_lock);
 
 	rc = qpnp_iadc_calibrate_for_trim();
-	if (rc)
+	if (rc) {
 		pr_err("periodic IADC calibration failed\n");
+		iadc->iadc_err_cnt++;
+	}
 
 	mutex_unlock(&iadc->adc->adc_lock);
 
-	schedule_delayed_work(&iadc->iadc_work,
+	if (iadc->iadc_err_cnt < QPNP_IADC_ERR_CHK_RATELIMIT)
+		schedule_delayed_work(&iadc->iadc_work,
 			round_jiffies_relative(msecs_to_jiffies
 					(QPNP_IADC_CALIB_SECONDS)));
 
@@ -568,22 +581,24 @@
 				struct qpnp_iadc_result *result)
 {
 	struct qpnp_iadc_drv *iadc = qpnp_iadc;
-	int32_t rc, rsense_n_ohms, sign = 0, num;
+	int32_t rc, rsense_n_ohms, sign = 0, num, mode_sel = 0;
 	int64_t result_current;
 	uint16_t raw_data;
 
 	if (!iadc || !iadc->iadc_initialized)
 		return -EPROBE_DEFER;
 
-	rc = qpnp_check_pmic_temp();
-	if (rc) {
-		pr_err("Error checking pmic therm temp\n");
-		return rc;
+	if (!iadc->iadc_mode_sel) {
+		rc = qpnp_check_pmic_temp();
+		if (rc) {
+			pr_err("Error checking pmic therm temp\n");
+			return rc;
+		}
 	}
 
 	mutex_lock(&iadc->adc->adc_lock);
 
-	rc = qpnp_iadc_configure(channel, &raw_data);
+	rc = qpnp_iadc_configure(channel, &raw_data, mode_sel);
 	if (rc < 0) {
 		pr_err("qpnp adc result read failed with %d\n", rc);
 		goto fail;
@@ -644,6 +659,50 @@
 }
 EXPORT_SYMBOL(qpnp_iadc_get_gain_and_offset);
 
+int32_t qpnp_iadc_vadc_sync_read(
+	enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
+	enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
+{
+	struct qpnp_iadc_drv *iadc = qpnp_iadc;
+	int rc = 0;
+
+	if (!iadc || !iadc->iadc_initialized)
+		return -EPROBE_DEFER;
+
+	mutex_lock(&iadc->iadc_vadc_lock);
+
+	rc = qpnp_check_pmic_temp();
+	if (rc) {
+		pr_err("PMIC die temp check failed\n");
+		goto fail;
+	}
+
+	iadc->iadc_mode_sel = true;
+
+	rc = qpnp_vadc_iadc_sync_request(v_channel);
+	if (rc) {
+		pr_err("Configuring VADC failed\n");
+		goto fail;
+	}
+
+	rc = qpnp_iadc_read(i_channel, i_result);
+	if (rc)
+		pr_err("Configuring IADC failed\n");
+	/* Intentional fall through to release VADC */
+
+	rc = qpnp_vadc_iadc_sync_complete_request(v_channel,
+							v_result);
+	if (rc)
+		pr_err("Releasing VADC failed\n");
+fail:
+	iadc->iadc_mode_sel = false;
+
+	mutex_unlock(&iadc->iadc_vadc_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_iadc_vadc_sync_read);
+
 static ssize_t qpnp_iadc_show(struct device *dev,
 			struct device_attribute *devattr, char *buf)
 {
@@ -786,6 +845,8 @@
 	schedule_delayed_work(&iadc->iadc_work,
 			round_jiffies_relative(msecs_to_jiffies
 					(QPNP_IADC_CALIB_SECONDS)));
+	mutex_init(&iadc->iadc_vadc_lock);
+	iadc->iadc_err_cnt = 0;
 	iadc->iadc_initialized = true;
 
 	return 0;
@@ -801,6 +862,7 @@
 	struct device_node *child;
 	int i = 0;
 
+	mutex_destroy(&iadc->iadc_vadc_lock);
 	for_each_child_of_node(node, child) {
 		device_remove_file(&spmi->dev,
 			&iadc->sens_attr[i].dev_attr);
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 3df19d7..edbde44 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -98,6 +98,7 @@
 	bool				vadc_init_calib;
 	bool				vadc_initialized;
 	int				max_channels_available;
+	bool				vadc_iadc_sync_lock;
 	struct sensor_device_attribute		sens_attr[0];
 };
 
@@ -304,11 +305,14 @@
 	if (rc)
 		return rc;
 
-	/* Request conversion */
-	rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_REQ, QPNP_VADC_CONV_REQ_SET);
-	if (rc < 0) {
-		pr_err("Request conversion failed\n");
-		return rc;
+	if (!vadc->vadc_iadc_sync_lock) {
+		/* Request conversion */
+		rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_REQ,
+					QPNP_VADC_CONV_REQ_SET);
+		if (rc < 0) {
+			pr_err("Request conversion failed\n");
+			return rc;
+		}
 	}
 
 	return 0;
@@ -734,6 +738,121 @@
 }
 EXPORT_SYMBOL_GPL(qpnp_vadc_read);
 
+static void qpnp_vadc_lock(void)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+
+	mutex_lock(&vadc->adc->adc_lock);
+}
+
+static void qpnp_vadc_unlock(void)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+
+	mutex_unlock(&vadc->adc->adc_lock);
+}
+
+int32_t qpnp_vadc_iadc_sync_request(enum qpnp_vadc_channels channel)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+	int rc = 0, dt_index = 0;
+
+	if (!vadc || !vadc->vadc_initialized)
+		return -EPROBE_DEFER;
+
+	qpnp_vadc_lock();
+
+	if (!vadc->vadc_init_calib) {
+		rc = qpnp_vadc_version_check();
+		if (rc)
+			goto fail;
+
+		rc = qpnp_vadc_calib_device();
+		if (rc) {
+			pr_err("Calibration failed\n");
+			goto fail;
+		} else
+			vadc->vadc_init_calib = true;
+	}
+
+	vadc->adc->amux_prop->amux_channel = channel;
+
+	while ((vadc->adc->adc_channels[dt_index].channel_num
+		!= channel) && (dt_index < vadc->max_channels_available))
+		dt_index++;
+
+	if (dt_index >= vadc->max_channels_available) {
+		pr_err("not a valid VADC channel\n");
+		rc = -EINVAL;
+		goto fail;
+	}
+
+	vadc->adc->amux_prop->decimation =
+			vadc->adc->adc_channels[dt_index].adc_decimation;
+	vadc->adc->amux_prop->hw_settle_time =
+			vadc->adc->adc_channels[dt_index].hw_settle_time;
+	vadc->adc->amux_prop->fast_avg_setup =
+			vadc->adc->adc_channels[dt_index].fast_avg_setup;
+	vadc->adc->amux_prop->mode_sel = (ADC_OP_NORMAL_MODE
+					<< QPNP_VADC_OP_MODE_SHIFT);
+	vadc->vadc_iadc_sync_lock = true;
+
+	rc = qpnp_vadc_configure(vadc->adc->amux_prop);
+	if (rc) {
+		pr_err("qpnp vadc configure failed with %d\n", rc);
+		goto fail;
+	}
+
+	return rc;
+fail:
+	vadc->vadc_iadc_sync_lock = false;
+	qpnp_vadc_unlock();
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_vadc_iadc_sync_request);
+
+int32_t qpnp_vadc_iadc_sync_complete_request(enum qpnp_vadc_channels channel,
+						struct qpnp_vadc_result *result)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+	int rc = 0, scale_type, amux_prescaling, dt_index = 0;
+
+	vadc->adc->amux_prop->amux_channel = channel;
+
+	while ((vadc->adc->adc_channels[dt_index].channel_num
+		!= channel) && (dt_index < vadc->max_channels_available))
+		dt_index++;
+
+	rc = qpnp_vadc_read_conversion_result(&result->adc_code);
+	if (rc) {
+		pr_err("qpnp vadc read adc code failed with %d\n", rc);
+		goto fail;
+	}
+
+	amux_prescaling =
+		vadc->adc->adc_channels[dt_index].chan_path_prescaling;
+
+	vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
+		qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
+	vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
+		 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
+
+	scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
+	if (scale_type >= SCALE_NONE) {
+		rc = -EBADF;
+		goto fail;
+	}
+
+	vadc_scale_fn[scale_type].chan(result->adc_code,
+		vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
+
+fail:
+	vadc->vadc_iadc_sync_lock = false;
+	qpnp_vadc_unlock();
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_vadc_iadc_sync_complete_request);
+
 static ssize_t qpnp_adc_show(struct device *dev,
 			struct device_attribute *devattr, char *buf)
 {
@@ -857,6 +976,7 @@
 	vadc->vadc_init_calib = false;
 	vadc->max_channels_available = count_adc_channel_list;
 	vadc->vadc_initialized = true;
+	vadc->vadc_iadc_sync_lock = false;
 
 	return 0;
 fail:
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 717f763..eaf3519 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -128,6 +128,7 @@
 };
 
 #define QUP_MAX_CLK_STATE_RETRIES	300
+#define DEFAULT_CLK_RATE		(19200000)
 
 static char const * const i2c_rsrcs[] = {"i2c_clk", "i2c_sda"};
 
@@ -1235,18 +1236,26 @@
 	dev->clk_ctl = 0;
 	dev->pos = 0;
 
+	if (dev->pdata->src_clk_rate <= 0) {
+		dev_info(&pdev->dev,
+			"No src_clk_rate specified in platfrom data or "
+						"qcom,i2c-src-freq in DT\n");
+		dev_info(&pdev->dev, "Using default clock rate %dHz\n",
+							DEFAULT_CLK_RATE);
+		dev->pdata->src_clk_rate = DEFAULT_CLK_RATE;
+	}
+
+	ret = clk_set_rate(dev->clk, dev->pdata->src_clk_rate);
+	if (ret)
+		dev_info(&pdev->dev, "clk_set_rate(core_clk, %dHz):%d\n",
+					dev->pdata->src_clk_rate, ret);
+
+	clk_prepare_enable(dev->clk);
+	clk_prepare_enable(dev->pclk);
 	/*
 	 * If bootloaders leave a pending interrupt on certain GSBI's,
 	 * then we reset the core before registering for interrupts.
 	 */
-
-	if (dev->pdata->src_clk_rate > 0)
-		clk_set_rate(dev->clk, dev->pdata->src_clk_rate);
-	else
-		dev->pdata->src_clk_rate = 19200000;
-
-	clk_prepare_enable(dev->clk);
-	clk_prepare_enable(dev->pclk);
 	writel_relaxed(1, dev->base + QUP_SW_RESET);
 	if (qup_i2c_poll_state(dev, 0, true) != 0)
 		goto err_reset_failed;
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index bea6842..fb1882c 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -27,6 +27,7 @@
 #define WLED_MOD_EN_REG(base, n)	(base + 0x60 + n*0x10)
 #define WLED_IDAC_DLY_REG(base, n)	(WLED_MOD_EN_REG(base, n) + 0x01)
 #define WLED_FULL_SCALE_REG(base, n)	(WLED_IDAC_DLY_REG(base, n) + 0x01)
+#define WLED_MOD_SRC_SEL_REG(base, n)	(WLED_FULL_SCALE_REG(base, n) + 0x01)
 
 /* wled control registers */
 #define WLED_BRIGHTNESS_CNTL_LSB(base, n)	(base + 0x40 + 2*n)
@@ -83,7 +84,7 @@
 #define FLASH_LED_1_CURR(base)		(base + 0x43)
 #define FLASH_CLAMP_CURR(base)		(base + 0x44)
 #define FLASH_LED_TMR_CTRL(base)	(base + 0x48)
-#define FLASH_HEADROOM(base)		(base + 0x49)
+#define FLASH_HEADROOM(base)		(base + 0x4A)
 #define FLASH_STARTUP_DELAY(base)	(base + 0x4B)
 #define FLASH_MASK_ENABLE(base)		(base + 0x4C)
 #define FLASH_VREG_OK_FORCE(base)	(base + 0x4F)
@@ -111,7 +112,7 @@
 #define FLASH_ENABLE_MODULE		0x80
 #define FLASH_ENABLE_MODULE_MASK	0x80
 #define FLASH_DISABLE_ALL		0x00
-#define FLASH_ENABLE_MASK		0x60
+#define FLASH_ENABLE_MASK		0xE0
 #define FLASH_ENABLE_LED_0		0x40
 #define FLASH_ENABLE_LED_1		0x20
 #define FLASH_INIT_MASK			0xE0
@@ -454,6 +455,14 @@
 
 	/* Set led current */
 	if (val > 0) {
+		rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
+			FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Enable reg write failed(%d)\n", rc);
+			return rc;
+		}
+
 		rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
 			FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
 		if (rc) {
@@ -487,6 +496,13 @@
 				"LED %d flash write failed(%d)\n", led->id, rc);
 			return rc;
 		}
+		rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
+			FLASH_VREG_MASK, FLASH_HW_VREG_OK);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Vreg OK reg write failed(%d)\n", rc);
+			return rc;
+		}
 	} else {
 		rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
 			FLASH_ENABLE_MASK,
@@ -755,7 +771,7 @@
 
 		if (led->wled_cfg->dig_mod_gen_en) {
 			rc = qpnp_led_masked_write(led,
-				WLED_MOD_EN_REG(led->base, i),
+				WLED_MOD_SRC_SEL_REG(led->base, i),
 				WLED_NO_MASK, WLED_USE_EXT_GEN_MOD_SRC);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
@@ -883,7 +899,7 @@
 	}
 
 	rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
-		FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+		FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
 	if (rc) {
 		dev_err(&led->spmi_dev->dev,
 			"Enable reg write failed(%d)\n", rc);
diff --git a/drivers/media/platform/msm/camera_v2/Makefile b/drivers/media/platform/msm/camera_v2/Makefile
index 25dfd37..a1c5ea5 100644
--- a/drivers/media/platform/msm/camera_v2/Makefile
+++ b/drivers/media/platform/msm/camera_v2/Makefile
@@ -2,7 +2,7 @@
 ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor
 ccflags-y += -Idrivers/media/platform/msm/camera_v2/codecs
 ccflags-y += -Idrivers/media/platform/msm/camera_v2/isps
-ccflags-y += -Idrivers/media/platform/msm/camera_v2/pps
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/pproc
 ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_vb2
 ccflags-y += -Idrivers/media/platform/msm/camera_v2/camera
 ccflags-y += -Idrivers/media/platform/msm/camera_v2/jpeg_10
@@ -15,3 +15,4 @@
 obj-$(CONFIG_MSMB_CAMERA) += ispif/
 obj-$(CONFIG_MSMB_JPEG) += jpeg_10/
 obj-$(CONFIG_MSMB_CAMERA) += msm_buf_mgr/
+obj-$(CONFIG_MSMB_CAMERA) += pproc/
diff --git a/drivers/media/platform/msm/camera_v2/pproc/Makefile b/drivers/media/platform/msm/camera_v2/pproc/Makefile
new file mode 100644
index 0000000..854e4e7
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MSMB_CAMERA) += cpp/
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/Makefile b/drivers/media/platform/msm/camera_v2/pproc/cpp/Makefile
new file mode 100644
index 0000000..2f969d2
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/Makefile
@@ -0,0 +1,3 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+obj-$(CONFIG_MSM_CPP) += msm_cpp.o
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
new file mode 100644
index 0000000..4b1b1c7
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -0,0 +1,1025 @@
+/* Copyright (c) 2013, 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) "MSM-CPP %s:%d " fmt, __func__, __LINE__
+
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/ion.h>
+#include <linux/proc_fs.h>
+#include <linux/debugfs.h>
+#include <linux/msm_ion.h>
+#include <linux/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/iommu.h>
+#include <mach/vreg.h>
+#include <media/msm_isp.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/msmb_camera.h>
+#include <media/msmb_pproc.h>
+#include "msm_cpp.h"
+#include "msm_camera_io_util.h"
+
+#define MSM_CPP_DRV_NAME "msm_cpp"
+
+#define CONFIG_MSM_CPP_DBG 0
+
+#if CONFIG_MSM_CPP_DBG
+#define CPP_DBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CPP_DBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+#define ERR_USER_COPY(to) pr_err("copy %s user\n", \
+			((to) ? "to" : "from"))
+#define ERR_COPY_FROM_USER() ERR_USER_COPY(0)
+
+#define msm_dequeue(queue, member) ({	   \
+	unsigned long flags;		  \
+	struct msm_device_queue *__q = (queue);	 \
+	struct msm_queue_cmd *qcmd = 0;	   \
+	spin_lock_irqsave(&__q->lock, flags);	 \
+	if (!list_empty(&__q->list)) {		\
+		__q->len--;		 \
+		qcmd = list_first_entry(&__q->list,   \
+		struct msm_queue_cmd, member);  \
+		list_del_init(&qcmd->member);	 \
+	}			 \
+	spin_unlock_irqrestore(&__q->lock, flags);  \
+	qcmd;			 \
+})
+
+static void msm_queue_init(struct msm_device_queue *queue, const char *name)
+{
+	CPP_DBG("E\n");
+	spin_lock_init(&queue->lock);
+	queue->len = 0;
+	queue->max = 0;
+	queue->name = name;
+	INIT_LIST_HEAD(&queue->list);
+	init_waitqueue_head(&queue->wait);
+}
+
+static void msm_enqueue(struct msm_device_queue *queue,
+			struct list_head *entry)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&queue->lock, flags);
+	queue->len++;
+	if (queue->len > queue->max) {
+		queue->max = queue->len;
+		pr_info("queue %s new max is %d\n", queue->name, queue->max);
+	}
+	list_add_tail(entry, &queue->list);
+	wake_up(&queue->wait);
+	CPP_DBG("woke up %s\n", queue->name);
+	spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+static struct msm_cam_clk_info cpp_clk_info[] = {
+	{"camss_top_ahb_clk", -1},
+	{"vfe_clk_src", 266670000},
+	{"camss_vfe_vfe_clk", -1},
+	{"iface_clk", -1},
+	{"cpp_core_clk", 266670000},
+	{"cpp_iface_clk", -1},
+	{"cpp_bus_clk", -1},
+	{"micro_iface_clk", -1},
+};
+static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev);
+
+static void msm_cpp_write(u32 data, void __iomem *cpp_base)
+{
+	writel_relaxed((data), cpp_base + MSM_CPP_MICRO_FIFO_RX_DATA);
+}
+
+static uint32_t msm_cpp_read(void __iomem *cpp_base)
+{
+	uint32_t tmp, retry = 0;
+	do {
+		tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_TX_STAT);
+	} while (((tmp & 0x2) == 0x0) && (retry++ < 10)) ;
+	if (retry < 10) {
+		tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_TX_DATA);
+		CPP_DBG("Read data: 0%x\n", tmp);
+	} else {
+		CPP_DBG("Read failed\n");
+		tmp = 0xDEADBEEF;
+	}
+	return tmp;
+}
+
+static void msm_cpp_poll(void __iomem *cpp_base, u32 val)
+{
+	uint32_t tmp, retry = 0;
+	do {
+		usleep_range(1000, 2000);
+		tmp = msm_cpp_read(cpp_base);
+		if (tmp != 0xDEADBEEF)
+			CPP_DBG("poll: 0%x\n", tmp);
+	} while ((tmp != val) && (retry++ < MSM_CPP_POLL_RETRIES));
+	if (retry < MSM_CPP_POLL_RETRIES)
+		CPP_DBG("Poll finished\n");
+	else
+		pr_err("Poll failed: expect: 0x%x\n", val);
+}
+
+void cpp_release_ion_client(struct kref *ref)
+{
+	struct cpp_device *cpp_dev = container_of(ref,
+		struct cpp_device, refcount);
+	pr_err("Calling ion_client_destroy\n");
+	ion_client_destroy(cpp_dev->client);
+}
+
+static int cpp_init_mem(struct cpp_device *cpp_dev)
+{
+	int rc = 0;
+
+	kref_init(&cpp_dev->refcount);
+	kref_get(&cpp_dev->refcount);
+	cpp_dev->client = msm_ion_client_create(-1, "cpp");
+
+	CPP_DBG("E\n");
+	if (!cpp_dev->domain) {
+		pr_err("domain / iommu context not found\n");
+		return  -ENODEV;
+	}
+
+	CPP_DBG("X\n");
+	return rc;
+}
+
+static void cpp_deinit_mem(struct cpp_device *cpp_dev)
+{
+	CPP_DBG("E\n");
+	kref_put(&cpp_dev->refcount, cpp_release_ion_client);
+	CPP_DBG("X\n");
+}
+
+static irqreturn_t msm_cpp_irq(int irq_num, void *data)
+{
+	uint32_t tx_level;
+	uint32_t irq_status;
+	uint32_t msg_id, cmd_len;
+	uint32_t i;
+	uint32_t tx_fifo[16];
+	struct cpp_device *cpp_dev = data;
+	irq_status = msm_camera_io_r(cpp_dev->base + MSM_CPP_MICRO_IRQGEN_STAT);
+	CPP_DBG("status: 0x%x\n", irq_status);
+	if (irq_status & 0x8) {
+		tx_level = msm_camera_io_r(cpp_dev->base +
+			MSM_CPP_MICRO_FIFO_TX_STAT) >> 2;
+		for (i = 0; i < tx_level; i++) {
+			tx_fifo[i] = msm_camera_io_r(cpp_dev->base +
+				MSM_CPP_MICRO_FIFO_TX_DATA);
+		}
+
+		for (i = 0; i < tx_level; i++) {
+			if (tx_fifo[i] == MSM_CPP_MSG_ID_CMD) {
+				cmd_len = tx_fifo[i+1];
+				msg_id = tx_fifo[i+2];
+				if (msg_id == MSM_CPP_MSG_ID_FRAME_ACK) {
+					CPP_DBG("Frame done!!\n");
+					msm_cpp_notify_frame_done(cpp_dev);
+				}
+				i += cmd_len + 2;
+			}
+		}
+	}
+	msm_camera_io_w(irq_status, cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR);
+	return IRQ_HANDLED;
+}
+
+static int cpp_init_hardware(struct cpp_device *cpp_dev)
+{
+	int rc = 0;
+
+	if (cpp_dev->fs_cpp == NULL) {
+		cpp_dev->fs_cpp =
+			regulator_get(&cpp_dev->pdev->dev, "vdd");
+		if (IS_ERR(cpp_dev->fs_cpp)) {
+			pr_err("Regulator cpp vdd get failed %ld\n",
+				PTR_ERR(cpp_dev->fs_cpp));
+			cpp_dev->fs_cpp = NULL;
+			goto fs_failed;
+		} else if (regulator_enable(cpp_dev->fs_cpp)) {
+			pr_err("Regulator cpp vdd enable failed\n");
+			regulator_put(cpp_dev->fs_cpp);
+			cpp_dev->fs_cpp = NULL;
+			goto fs_failed;
+		}
+	}
+
+	rc = msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info,
+			cpp_dev->cpp_clk, ARRAY_SIZE(cpp_clk_info), 1);
+	if (rc < 0) {
+		pr_err("clk enable failed\n");
+		goto clk_failed;
+	}
+
+	cpp_dev->base = ioremap(cpp_dev->mem->start,
+		resource_size(cpp_dev->mem));
+	if (!cpp_dev->base) {
+		rc = -ENOMEM;
+		pr_err("ioremap failed\n");
+		goto remap_failed;
+	}
+
+	cpp_dev->vbif_base = ioremap(cpp_dev->vbif_mem->start,
+		resource_size(cpp_dev->vbif_mem));
+	if (!cpp_dev->vbif_base) {
+		rc = -ENOMEM;
+		pr_err("ioremap failed\n");
+		goto vbif_remap_failed;
+	}
+
+	if (cpp_dev->state != CPP_STATE_BOOT) {
+		rc = request_irq(cpp_dev->irq->start, msm_cpp_irq,
+			IRQF_TRIGGER_RISING, "cpp", cpp_dev);
+		if (rc < 0) {
+			pr_err("irq request fail\n");
+			rc = -EBUSY;
+			goto req_irq_fail;
+		}
+	}
+
+	msm_camera_io_w(0x1, cpp_dev->vbif_base + 0x4);
+
+	return rc;
+req_irq_fail:
+	iounmap(cpp_dev->vbif_base);
+vbif_remap_failed:
+	iounmap(cpp_dev->base);
+remap_failed:
+	msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info,
+		cpp_dev->cpp_clk, ARRAY_SIZE(cpp_clk_info), 0);
+clk_failed:
+	regulator_disable(cpp_dev->fs_cpp);
+	regulator_put(cpp_dev->fs_cpp);
+fs_failed:
+	return rc;
+}
+
+static void cpp_release_hardware(struct cpp_device *cpp_dev)
+{
+	if (cpp_dev->state != CPP_STATE_BOOT)
+		free_irq(cpp_dev->irq->start, cpp_dev);
+
+	iounmap(cpp_dev->base);
+	msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info,
+		cpp_dev->cpp_clk, ARRAY_SIZE(cpp_clk_info), 0);
+	if (0) {
+		regulator_disable(cpp_dev->fs_cpp);
+		regulator_put(cpp_dev->fs_cpp);
+		cpp_dev->fs_cpp = NULL;
+	}
+}
+
+static void cpp_load_fw(struct cpp_device *cpp_dev)
+{
+	uint32_t i;
+	uint32_t *ptr_bin = NULL;
+	int32_t rc = -EFAULT;
+	const struct firmware *fw = NULL;
+	char *fw_name_bin = "cpp_firmware_v1_1_1.fw";
+	struct device *dev = &cpp_dev->pdev->dev;
+
+	rc = request_firmware(&fw, fw_name_bin, dev);
+	if (rc) {
+		dev_err(dev, "Failed to locate blob %s from device %p, Error: %d\n",
+				fw_name_bin, dev, rc);
+	}
+
+	CPP_DBG("HW Ver:0x%x\n",
+		msm_camera_io_r(cpp_dev->base +
+		MSM_CPP_MICRO_HW_VERSION));
+
+	msm_camera_io_w(0x1, cpp_dev->base +
+					   MSM_CPP_MICRO_BOOT_START);
+	/*Enable MC clock*/
+	msm_camera_io_w(0x1, cpp_dev->base +
+					   MSM_CPP_MICRO_CLKEN_CTL);
+
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+
+	/*Start firmware loading*/
+	msm_cpp_write(MSM_CPP_CMD_FW_LOAD, cpp_dev->base);
+	msm_cpp_write(MSM_CPP_END_ADDRESS, cpp_dev->base);
+	msm_cpp_write(MSM_CPP_START_ADDRESS, cpp_dev->base);
+	if (NULL != fw)
+		ptr_bin = (uint32_t *)fw->data;
+
+	for (i = 0; i < fw->size/4; i++) {
+		if (ptr_bin) {
+			msm_cpp_write(*ptr_bin, cpp_dev->base);
+			ptr_bin++;
+		}
+	}
+	if (fw)
+		release_firmware(fw);
+
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_OK);
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+
+	/*Trigger MC to jump to start address*/
+	msm_cpp_write(MSM_CPP_CMD_EXEC_JUMP, cpp_dev->base);
+	msm_cpp_write(MSM_CPP_JUMP_ADDRESS, cpp_dev->base);
+
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+	msm_cpp_poll(cpp_dev->base, 0x1);
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_JUMP_ACK);
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
+
+	/*Get Bootloader Version*/
+	msm_cpp_write(MSM_CPP_CMD_GET_BOOTLOADER_VER, cpp_dev->base);
+	pr_info("MC Bootloader Version: 0x%x\n",
+		   msm_cpp_read(cpp_dev->base));
+
+	/*Get Firmware Version*/
+	msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base);
+	msm_cpp_write(MSM_CPP_MSG_ID_CMD, cpp_dev->base);
+	msm_cpp_write(0x1, cpp_dev->base);
+	msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base);
+	msm_cpp_write(MSM_CPP_MSG_ID_TRAILER, cpp_dev->base);
+
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+	msm_cpp_poll(cpp_dev->base, 0x2);
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_FW_VER);
+	pr_info("CPP FW Version: 0x%x\n", msm_cpp_read(cpp_dev->base));
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
+
+}
+
+static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	uint32_t i;
+	struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
+	CPP_DBG("E\n");
+
+	mutex_lock(&cpp_dev->mutex);
+	if (cpp_dev->cpp_open_cnt == MAX_ACTIVE_CPP_INSTANCE) {
+		pr_err("No free CPP instance\n");
+		mutex_unlock(&cpp_dev->mutex);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
+		if (cpp_dev->cpp_subscribe_list[i].active == 0) {
+			cpp_dev->cpp_subscribe_list[i].active = 1;
+			cpp_dev->cpp_subscribe_list[i].vfh = &fh->vfh;
+			break;
+		}
+	}
+	if (i == MAX_ACTIVE_CPP_INSTANCE) {
+		pr_err("No free instance\n");
+		mutex_unlock(&cpp_dev->mutex);
+		return -ENODEV;
+	}
+
+	CPP_DBG("open %d %p\n", i, &fh->vfh);
+	cpp_dev->cpp_open_cnt++;
+	if (cpp_dev->cpp_open_cnt == 1) {
+		cpp_init_hardware(cpp_dev);
+		cpp_init_mem(cpp_dev);
+		disable_irq(cpp_dev->irq->start);
+
+		cpp_load_fw(cpp_dev);
+
+		enable_irq(cpp_dev->irq->start);
+
+		msm_camera_io_w_mb(0x8, cpp_dev->base +
+			MSM_CPP_MICRO_IRQGEN_MASK);
+		msm_camera_io_w_mb(0xFFFF, cpp_dev->base +
+			MSM_CPP_MICRO_IRQGEN_CLR);
+		cpp_dev->state = CPP_STATE_IDLE;
+	}
+	mutex_unlock(&cpp_dev->mutex);
+	return 0;
+}
+
+static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	uint32_t i;
+	struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
+	mutex_lock(&cpp_dev->mutex);
+	for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
+		if (cpp_dev->cpp_subscribe_list[i].vfh == &fh->vfh) {
+			cpp_dev->cpp_subscribe_list[i].active = 0;
+			cpp_dev->cpp_subscribe_list[i].vfh = NULL;
+			break;
+		}
+	}
+	if (i == MAX_ACTIVE_CPP_INSTANCE) {
+		pr_err("Invalid close\n");
+		mutex_unlock(&cpp_dev->mutex);
+		return -ENODEV;
+	}
+
+	CPP_DBG("close %d %p\n", i, &fh->vfh);
+	cpp_dev->cpp_open_cnt--;
+	if (cpp_dev->cpp_open_cnt == 0) {
+		msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
+		cpp_deinit_mem(cpp_dev);
+		cpp_release_hardware(cpp_dev);
+		cpp_dev->state = CPP_STATE_OFF;
+	}
+	mutex_unlock(&cpp_dev->mutex);
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops msm_cpp_internal_ops = {
+	.open = cpp_open_node,
+	.close = cpp_close_node,
+};
+
+static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev)
+{
+	struct v4l2_event v4l2_evt;
+	struct msm_queue_cmd *frame_qcmd;
+	struct msm_queue_cmd *event_qcmd;
+	struct msm_cpp_frame_info_t *processed_frame;
+	struct msm_device_queue *queue = &cpp_dev->processing_q;
+
+	if (queue->len > 0) {
+		frame_qcmd = msm_dequeue(queue, list_frame);
+		processed_frame = frame_qcmd->command;
+		kfree(frame_qcmd);
+		event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
+		if (!event_qcmd) {
+			pr_err("Insufficient memory. return");
+			return -ENOMEM;
+		}
+		atomic_set(&event_qcmd->on_heap, 1);
+		event_qcmd->command = processed_frame;
+		CPP_DBG("fid %d\n", processed_frame->frame_id);
+		msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata);
+
+		v4l2_evt.id = processed_frame->inst_id;
+		v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE;
+		v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt);
+	}
+	return 0;
+}
+
+static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev)
+{
+	uint32_t i;
+	struct msm_queue_cmd *frame_qcmd;
+	struct msm_cpp_frame_info_t *process_frame;
+	struct msm_device_queue *queue;
+
+	if (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) {
+		while (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) {
+			if (cpp_dev->realtime_q.len != 0) {
+				queue = &cpp_dev->realtime_q;
+			} else if (cpp_dev->offline_q.len != 0) {
+				queue = &cpp_dev->offline_q;
+			} else {
+				pr_debug("All frames queued\n");
+				break;
+			}
+			frame_qcmd = msm_dequeue(queue, list_frame);
+			process_frame = frame_qcmd->command;
+			msm_enqueue(&cpp_dev->processing_q,
+						&frame_qcmd->list_frame);
+			msm_cpp_write(0x6, cpp_dev->base);
+			for (i = 0; i < process_frame->msg_len; i++)
+				msm_cpp_write(process_frame->cpp_cmd_msg[i],
+					cpp_dev->base);
+		}
+	}
+	return 0;
+}
+
+static int msm_cpp_cfg(struct cpp_device *cpp_dev,
+	struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+	int rc = 0;
+	struct msm_queue_cmd *frame_qcmd = NULL;
+	struct msm_cpp_frame_info_t *new_frame =
+		kzalloc(sizeof(struct msm_cpp_frame_info_t), GFP_KERNEL);
+	uint32_t *cpp_frame_msg;
+	struct ion_handle *src_ion_handle = NULL;
+	struct ion_handle *dest_ion_handle = NULL;
+	unsigned long len;
+	unsigned long in_phyaddr, out_phyaddr;
+	uint16_t num_stripes = 0;
+
+	int i = 0;
+	if (!new_frame) {
+		pr_err("Insufficient memory. return\n");
+		return -ENOMEM;
+	}
+
+	rc = (copy_from_user(new_frame, (void __user *)ioctl_ptr->ioctl_ptr,
+		sizeof(struct msm_cpp_frame_info_t)) ? -EFAULT : 0);
+	if (rc) {
+		ERR_COPY_FROM_USER();
+		rc = -EINVAL;
+		goto ERROR1;
+	}
+
+	cpp_frame_msg = kzalloc(sizeof(uint32_t)*new_frame->msg_len,
+		GFP_KERNEL);
+	if (!cpp_frame_msg) {
+		pr_err("Insufficient memory. return");
+		rc = -ENOMEM;
+		goto ERROR1;
+	}
+
+	rc = (copy_from_user(cpp_frame_msg,
+		(void __user *)new_frame->cpp_cmd_msg,
+		sizeof(uint32_t)*new_frame->msg_len) ? -EFAULT : 0);
+	if (rc) {
+		ERR_COPY_FROM_USER();
+		rc = -EINVAL;
+		goto ERROR2;
+	}
+
+	new_frame->cpp_cmd_msg = cpp_frame_msg;
+
+	CPP_DBG("CPP in_fd: %d out_fd: %d\n", new_frame->src_fd,
+		new_frame->dst_fd);
+
+	src_ion_handle = ion_import_dma_buf(cpp_dev->client,
+		new_frame->src_fd);
+	if (IS_ERR_OR_NULL(src_ion_handle)) {
+		pr_err("ION import failed\n");
+		rc = PTR_ERR(src_ion_handle);
+		goto ERROR2;
+	}
+	rc = ion_map_iommu(cpp_dev->client, src_ion_handle,
+		cpp_dev->domain_num, 0, SZ_4K, 0,
+		(unsigned long *)&in_phyaddr, &len, 0, 0);
+	if (rc < 0) {
+		pr_err("ION import failed\n");
+		rc = PTR_ERR(src_ion_handle);
+		goto ERROR3;
+	}
+
+	CPP_DBG("in phy addr: 0x%x len: %ld\n", (uint32_t) in_phyaddr, len);
+
+	dest_ion_handle = ion_import_dma_buf(cpp_dev->client,
+		new_frame->dst_fd);
+	if (IS_ERR_OR_NULL(dest_ion_handle)) {
+		pr_err("ION import failed\n");
+		rc = PTR_ERR(dest_ion_handle);
+		goto ERROR4;
+	}
+	rc = ion_map_iommu(cpp_dev->client, dest_ion_handle,
+		cpp_dev->domain_num, 0, SZ_4K, 0,
+		(unsigned long *)&out_phyaddr, &len, 0, 0);
+	if (rc < 0) {
+		rc = PTR_ERR(dest_ion_handle);
+		goto ERROR5;
+	}
+
+	CPP_DBG("out phy addr: 0x%x len: %ld\n", (uint32_t)out_phyaddr, len);
+
+	num_stripes = ((cpp_frame_msg[12] >> 20) & 0x3FF) +
+		((cpp_frame_msg[12] >> 10) & 0x3FF) +
+		(cpp_frame_msg[12] & 0x3FF);
+
+	for (i = 0; i < num_stripes; i++) {
+		cpp_frame_msg[133 + i * 27] += (uint32_t) in_phyaddr;
+		cpp_frame_msg[139 + i * 27] += (uint32_t) out_phyaddr;
+		cpp_frame_msg[140 + i * 27] += (uint32_t) out_phyaddr;
+		cpp_frame_msg[141 + i * 27] += (uint32_t) out_phyaddr;
+		cpp_frame_msg[142 + i * 27] += (uint32_t) out_phyaddr;
+	}
+
+	frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+	if (!frame_qcmd) {
+		pr_err("Insufficient memory. return\n");
+		rc = -ENOMEM;
+		goto ERROR6;
+	}
+
+	atomic_set(&frame_qcmd->on_heap, 1);
+	frame_qcmd->command = new_frame;
+	if (new_frame->frame_type == MSM_CPP_REALTIME_FRAME) {
+		msm_enqueue(&cpp_dev->realtime_q,
+					&frame_qcmd->list_frame);
+	} else if (new_frame->frame_type == MSM_CPP_OFFLINE_FRAME) {
+		msm_enqueue(&cpp_dev->offline_q,
+					&frame_qcmd->list_frame);
+	} else {
+		pr_err("Invalid frame type\n");
+		rc = -EINVAL;
+		goto ERROR7;
+	}
+	msm_cpp_send_frame_to_hardware(cpp_dev);
+	return rc;
+ERROR7:
+	kfree(frame_qcmd);
+ERROR6:
+	ion_unmap_iommu(cpp_dev->client, dest_ion_handle,
+		cpp_dev->domain_num, 0);
+ERROR5:
+	ion_free(cpp_dev->client, dest_ion_handle);
+ERROR4:
+	ion_unmap_iommu(cpp_dev->client, src_ion_handle,
+		cpp_dev->domain_num, 0);
+ERROR3:
+	ion_free(cpp_dev->client, src_ion_handle);
+ERROR2:
+	kfree(cpp_frame_msg);
+ERROR1:
+	kfree(new_frame);
+	return rc;
+
+}
+
+long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
+	struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+	int rc = 0;
+
+	mutex_lock(&cpp_dev->mutex);
+	CPP_DBG("E cmd: %d\n", cmd);
+	switch (cmd) {
+	case VIDIOC_MSM_CPP_CFG:
+		rc = msm_cpp_cfg(cpp_dev, ioctl_ptr);
+		break;
+	case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD: {
+		struct msm_device_queue *queue = &cpp_dev->eventData_q;
+		struct msm_queue_cmd *event_qcmd;
+		struct msm_cpp_frame_info_t *process_frame;
+		event_qcmd = msm_dequeue(queue, list_eventdata);
+		process_frame = event_qcmd->command;
+		CPP_DBG("fid %d\n", process_frame->frame_id);
+		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+				process_frame,
+				sizeof(struct msm_cpp_frame_info_t))) {
+					mutex_unlock(&cpp_dev->mutex);
+					return -EINVAL;
+		}
+		kfree(process_frame->cpp_cmd_msg);
+		kfree(process_frame);
+		kfree(event_qcmd);
+		break;
+	}
+	}
+	mutex_unlock(&cpp_dev->mutex);
+	CPP_DBG("X\n");
+	return 0;
+}
+
+int msm_cpp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub)
+{
+	CPP_DBG("Called\n");
+	return v4l2_event_subscribe(fh, sub, MAX_CPP_V4l2_EVENTS);
+}
+
+int msm_cpp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub)
+{
+	CPP_DBG("Called\n");
+	return v4l2_event_unsubscribe(fh, sub);
+}
+
+static struct v4l2_subdev_core_ops msm_cpp_subdev_core_ops = {
+	.ioctl = msm_cpp_subdev_ioctl,
+	.subscribe_event = msm_cpp_subscribe_event,
+	.unsubscribe_event = msm_cpp_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_ops msm_cpp_subdev_ops = {
+	.core = &msm_cpp_subdev_core_ops,
+};
+
+static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev);
+
+static struct v4l2_file_operations msm_cpp_v4l2_subdev_fops;
+
+static long msm_cpp_subdev_do_ioctl(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+	struct v4l2_fh *vfh = file->private_data;
+
+	switch (cmd) {
+	case VIDIOC_DQEVENT:
+		if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+			return -ENOIOCTLCMD;
+
+		return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
+
+	case VIDIOC_SUBSCRIBE_EVENT:
+		return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
+
+	case VIDIOC_UNSUBSCRIBE_EVENT:
+		return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
+
+	case VIDIOC_MSM_CPP_GET_INST_INFO: {
+		uint32_t i;
+		struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
+		struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+		struct msm_cpp_frame_info_t inst_info;
+		for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
+			if (cpp_dev->cpp_subscribe_list[i].vfh == vfh) {
+				inst_info.inst_id = i;
+				break;
+			}
+		}
+		if (copy_to_user(
+				(void __user *)ioctl_ptr->ioctl_ptr, &inst_info,
+				sizeof(struct msm_cpp_frame_info_t))) {
+			return -EINVAL;
+		}
+	}
+	break;
+	default:
+		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
+	}
+
+	return 0;
+}
+
+static long msm_cpp_subdev_fops_ioctl(struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_cpp_subdev_do_ioctl);
+}
+
+static int cpp_register_domain(void)
+{
+	struct msm_iova_partition cpp_fw_partition = {
+		.start = SZ_128K,
+		.size = SZ_2G - SZ_128K,
+	};
+	struct msm_iova_layout cpp_fw_layout = {
+		.partitions = &cpp_fw_partition,
+		.npartitions = 1,
+		.client_name = "camera_cpp",
+		.domain_flags = 0,
+	};
+
+	return msm_register_domain(&cpp_fw_layout);
+}
+
+static int __devinit cpp_probe(struct platform_device *pdev)
+{
+	struct cpp_device *cpp_dev;
+	int rc = 0;
+
+	cpp_dev = kzalloc(sizeof(struct cpp_device), GFP_KERNEL);
+	if (!cpp_dev) {
+		pr_err("no enough memory\n");
+		return -ENOMEM;
+	}
+
+	cpp_dev->cpp_clk = kzalloc(sizeof(struct clk *) *
+		ARRAY_SIZE(cpp_clk_info), GFP_KERNEL);
+	if (!cpp_dev->cpp_clk) {
+		pr_err("no enough memory\n");
+		rc = -ENOMEM;
+		goto ERROR1;
+	}
+
+	v4l2_subdev_init(&cpp_dev->msm_sd.sd, &msm_cpp_subdev_ops);
+	cpp_dev->msm_sd.sd.internal_ops = &msm_cpp_internal_ops;
+	snprintf(cpp_dev->msm_sd.sd.name, ARRAY_SIZE(cpp_dev->msm_sd.sd.name),
+		 "cpp");
+	cpp_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	cpp_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+	v4l2_set_subdevdata(&cpp_dev->msm_sd.sd, cpp_dev);
+	platform_set_drvdata(pdev, &cpp_dev->msm_sd.sd);
+	mutex_init(&cpp_dev->mutex);
+
+	if (pdev->dev.of_node)
+		of_property_read_u32((&pdev->dev)->of_node,
+					"cell-index", &pdev->id);
+
+	cpp_dev->pdev = pdev;
+
+	cpp_dev->mem = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "cpp");
+	if (!cpp_dev->mem) {
+		pr_err("no mem resource?\n");
+		rc = -ENODEV;
+		goto ERROR2;
+	}
+
+	cpp_dev->vbif_mem = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "cpp_vbif");
+	if (!cpp_dev->vbif_mem) {
+		pr_err("no mem resource?\n");
+		rc = -ENODEV;
+		goto ERROR2;
+	}
+
+	cpp_dev->irq = platform_get_resource_byname(pdev,
+					IORESOURCE_IRQ, "cpp");
+	if (!cpp_dev->irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		rc = -ENODEV;
+		goto ERROR2;
+	}
+
+	cpp_dev->io = request_mem_region(cpp_dev->mem->start,
+		resource_size(cpp_dev->mem), pdev->name);
+	if (!cpp_dev->io) {
+		pr_err("%s: no valid mem region\n", __func__);
+		rc = -EBUSY;
+		goto ERROR2;
+	}
+
+	cpp_dev->domain_num = cpp_register_domain();
+	if (cpp_dev->domain_num < 0) {
+		pr_err("%s: could not register domain\n", __func__);
+		rc = -ENODEV;
+		goto ERROR3;
+	}
+
+	cpp_dev->domain =
+		msm_get_iommu_domain(cpp_dev->domain_num);
+	if (!cpp_dev->domain) {
+		pr_err("%s: cannot find domain\n", __func__);
+		rc = -ENODEV;
+		goto ERROR3;
+	}
+
+	cpp_dev->iommu_ctx = msm_iommu_get_ctx("cpp");
+	if (!cpp_dev->iommu_ctx) {
+		pr_err("%s: cannot get iommu_ctx\n", __func__);
+		rc = -ENODEV;
+		goto ERROR3;
+	}
+
+	media_entity_init(&cpp_dev->msm_sd.sd.entity, 0, NULL, 0);
+	cpp_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+	cpp_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CPP;
+	cpp_dev->msm_sd.sd.entity.name = pdev->name;
+	msm_sd_register(&cpp_dev->msm_sd);
+	msm_cpp_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner;
+	msm_cpp_v4l2_subdev_fops.open = v4l2_subdev_fops.open;
+	msm_cpp_v4l2_subdev_fops.unlocked_ioctl = msm_cpp_subdev_fops_ioctl;
+	msm_cpp_v4l2_subdev_fops.release = v4l2_subdev_fops.release;
+	msm_cpp_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll;
+
+	cpp_dev->msm_sd.sd.devnode->fops = &msm_cpp_v4l2_subdev_fops;
+	cpp_dev->msm_sd.sd.entity.revision = cpp_dev->msm_sd.sd.devnode->num;
+	cpp_dev->state = CPP_STATE_BOOT;
+	cpp_init_hardware(cpp_dev);
+	iommu_attach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
+
+	msm_camera_io_w(0x0, cpp_dev->base +
+					   MSM_CPP_MICRO_IRQGEN_MASK);
+	msm_camera_io_w(0xFFFF, cpp_dev->base +
+					   MSM_CPP_MICRO_IRQGEN_CLR);
+
+	cpp_release_hardware(cpp_dev);
+	cpp_dev->state = CPP_STATE_OFF;
+
+	msm_cpp_enable_debugfs(cpp_dev);
+	msm_queue_init(&cpp_dev->eventData_q, "eventdata");
+	msm_queue_init(&cpp_dev->offline_q, "frame");
+	msm_queue_init(&cpp_dev->realtime_q, "frame");
+	msm_queue_init(&cpp_dev->processing_q, "frame");
+	cpp_dev->cpp_open_cnt = 0;
+
+	return rc;
+
+ERROR3:
+	release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem));
+ERROR2:
+	kfree(cpp_dev->cpp_clk);
+ERROR1:
+	kfree(cpp_dev);
+	return rc;
+}
+
+static const struct of_device_id msm_cpp_dt_match[] = {
+	{.compatible = "qcom,cpp"},
+	{}
+};
+
+static int cpp_device_remove(struct platform_device *dev)
+{
+	struct v4l2_subdev *sd = platform_get_drvdata(dev);
+	struct cpp_device  *cpp_dev;
+	if (!sd) {
+		pr_err("%s: Subdevice is NULL\n", __func__);
+		return 0;
+	}
+
+	cpp_dev = (struct cpp_device *)v4l2_get_subdevdata(sd);
+	if (!cpp_dev) {
+		pr_err("%s: cpp device is NULL\n", __func__);
+		return 0;
+	}
+
+	iommu_detach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
+	msm_sd_unregister(&cpp_dev->msm_sd);
+	release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem));
+	mutex_destroy(&cpp_dev->mutex);
+	kfree(cpp_dev->cpp_clk);
+	kfree(cpp_dev);
+	return 0;
+}
+
+static struct platform_driver cpp_driver = {
+	.probe = cpp_probe,
+	.remove = cpp_device_remove,
+	.driver = {
+		.name = MSM_CPP_DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_cpp_dt_match,
+	},
+};
+
+static int __init msm_cpp_init_module(void)
+{
+	return platform_driver_register(&cpp_driver);
+}
+
+static void __exit msm_cpp_exit_module(void)
+{
+	platform_driver_unregister(&cpp_driver);
+}
+
+static int msm_cpp_debugfs_stream_s(void *data, u64 val)
+{
+	struct cpp_device *cpp_dev = data;
+	CPP_DBG("CPP processing frame E\n");
+	while (1) {
+		mutex_lock(&cpp_dev->mutex);
+		msm_cpp_notify_frame_done(cpp_dev);
+		msm_cpp_send_frame_to_hardware(cpp_dev);
+		mutex_unlock(&cpp_dev->mutex);
+		msleep(20);
+	}
+	CPP_DBG("CPP processing frame X\n");
+	return 0;
+}
+
+static int msm_cpp_debugfs_load_fw(void *data, u64 val)
+{
+	const struct firmware *fw = NULL;
+	struct cpp_device *cpp_dev = data;
+	int rc = 0;
+	CPP_DBG("%s\n", __func__);
+	rc = request_firmware(&fw, "FIRMWARE.bin", &cpp_dev->pdev->dev);
+	if (rc) {
+		pr_err("request_fw failed\n");
+	} else {
+		CPP_DBG("request ok\n");
+		release_firmware(fw);
+	}
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_stream, NULL,
+			msm_cpp_debugfs_stream_s, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_fw, NULL,
+			msm_cpp_debugfs_load_fw, "%llu\n");
+
+static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev)
+{
+	struct dentry *debugfs_base, *debugfs_test;
+	debugfs_base = debugfs_create_dir("msm_camera", NULL);
+	if (!debugfs_base)
+		return -ENOMEM;
+
+	debugfs_test = debugfs_create_file("test", S_IRUGO | S_IWUSR,
+		debugfs_base, (void *)cpp_dev, &cpp_debugfs_stream);
+	if (!debugfs_test) {
+		debugfs_remove(debugfs_base);
+		return -ENOMEM;
+	}
+
+	if (!debugfs_create_file("fw", S_IRUGO | S_IWUSR, debugfs_base,
+			(void *)cpp_dev, &cpp_debugfs_fw)) {
+		debugfs_remove(debugfs_test);
+		debugfs_remove(debugfs_base);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+module_init(msm_cpp_init_module);
+module_exit(msm_cpp_exit_module);
+MODULE_DESCRIPTION("MSM CPP driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
new file mode 100644
index 0000000..8deff72
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -0,0 +1,155 @@
+/* Copyright (c) 2013, 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 __MSM_CPP_H__
+#define __MSM_CPP_H__
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-subdev.h>
+#include "msm_sd.h"
+
+#define MAX_ACTIVE_CPP_INSTANCE 8
+#define MAX_CPP_PROCESSING_FRAME 2
+#define MAX_CPP_V4l2_EVENTS 30
+
+#define MSM_CPP_MICRO_BASE          0x4000
+#define MSM_CPP_MICRO_HW_VERSION    0x0000
+#define MSM_CPP_MICRO_IRQGEN_STAT   0x0004
+#define MSM_CPP_MICRO_IRQGEN_CLR    0x0008
+#define MSM_CPP_MICRO_IRQGEN_MASK   0x000C
+#define MSM_CPP_MICRO_FIFO_TX_DATA  0x0010
+#define MSM_CPP_MICRO_FIFO_TX_STAT  0x0014
+#define MSM_CPP_MICRO_FIFO_RX_DATA  0x0018
+#define MSM_CPP_MICRO_FIFO_RX_STAT  0x001C
+#define MSM_CPP_MICRO_BOOT_START    0x0020
+#define MSM_CPP_MICRO_BOOT_LDORG    0x0024
+#define MSM_CPP_MICRO_CLKEN_CTL     0x0030
+
+#define MSM_CPP_CMD_GET_BOOTLOADER_VER	0x1
+#define MSM_CPP_CMD_FW_LOAD				0x2
+#define MSM_CPP_CMD_EXEC_JUMP			0x3
+#define MSM_CPP_CMD_RESET_HW			0x5
+#define MSM_CPP_CMD_PROCESS_FRAME		0x6
+#define MSM_CPP_CMD_FLUSH_STREAM		0x7
+#define MSM_CPP_CMD_CFG_MEM_PARAM		0x8
+#define MSM_CPP_CMD_ERROR_REQUEST		0x9
+#define MSM_CPP_CMD_GET_STATUS			0xA
+#define MSM_CPP_CMD_GET_FW_VER			0xB
+
+#define MSM_CPP_MSG_ID_CMD          0x3E646D63
+#define MSM_CPP_MSG_ID_OK           0x0A0A4B4F
+#define MSM_CPP_MSG_ID_TRAILER      0xABCDEFAA
+
+#define MSM_CPP_MSG_ID_JUMP_ACK     0x00000001
+#define MSM_CPP_MSG_ID_FRAME_ACK    0x00000002
+#define MSM_CPP_MSG_ID_FRAME_NACK   0x00000003
+#define MSM_CPP_MSG_ID_FLUSH_ACK    0x00000004
+#define MSM_CPP_MSG_ID_FLUSH_NACK   0x00000005
+#define MSM_CPP_MSG_ID_CFG_MEM_ACK  0x00000006
+#define MSM_CPP_MSG_ID_CFG_MEM_INV  0x00000007
+#define MSM_CPP_MSG_ID_ERROR_STATUS 0x00000008
+#define MSM_CPP_MSG_ID_INVALID_CMD  0x00000009
+#define MSM_CPP_MSG_ID_GEN_STATUS   0x0000000A
+#define MSM_CPP_MSG_ID_FLUSHED      0x0000000B
+#define MSM_CPP_MSG_ID_FW_VER       0x0000000C
+
+#define MSM_CPP_JUMP_ADDRESS		0x20
+#define MSM_CPP_START_ADDRESS		0x0
+#define MSM_CPP_END_ADDRESS			0x3F00
+
+#define MSM_CPP_POLL_RETRIES		20
+
+struct cpp_subscribe_info {
+	struct v4l2_fh *vfh;
+	uint32_t active;
+};
+
+enum cpp_state {
+	CPP_STATE_BOOT,
+	CPP_STATE_IDLE,
+	CPP_STATE_ACTIVE,
+	CPP_STATE_OFF,
+};
+
+enum msm_queue {
+	MSM_CAM_Q_CTRL,     /* control command or control command status */
+	MSM_CAM_Q_VFE_EVT,  /* adsp event */
+	MSM_CAM_Q_VFE_MSG,  /* adsp message */
+	MSM_CAM_Q_V4L2_REQ, /* v4l2 request */
+	MSM_CAM_Q_VPE_MSG,  /* vpe message */
+	MSM_CAM_Q_PP_MSG,  /* pp message */
+};
+
+struct msm_queue_cmd {
+	struct list_head list_config;
+	struct list_head list_control;
+	struct list_head list_frame;
+	struct list_head list_pict;
+	struct list_head list_vpe_frame;
+	struct list_head list_eventdata;
+	enum msm_queue type;
+	void *command;
+	atomic_t on_heap;
+	struct timespec ts;
+	uint32_t error_code;
+	uint32_t trans_code;
+};
+
+struct msm_device_queue {
+	struct list_head list;
+	spinlock_t lock;
+	wait_queue_head_t wait;
+	int max;
+	int len;
+	const char *name;
+};
+
+struct cpp_device {
+	struct platform_device *pdev;
+	struct msm_sd_subdev msm_sd;
+	struct v4l2_subdev subdev;
+	struct resource *mem;
+	struct resource *irq;
+	struct resource *io;
+	struct resource	*vbif_mem;
+	struct resource *vbif_io;
+	void __iomem *vbif_base;
+	void __iomem *base;
+	struct clk **cpp_clk;
+	struct regulator *fs_cpp;
+	struct mutex mutex;
+	enum cpp_state state;
+
+	int domain_num;
+	struct iommu_domain *domain;
+	struct device *iommu_ctx;
+	struct ion_client *client;
+	struct kref refcount;
+
+	struct cpp_subscribe_info cpp_subscribe_list[MAX_ACTIVE_CPP_INSTANCE];
+	uint32_t cpp_open_cnt;
+
+	struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */
+
+	/* Offline Frame Queue process when realtime queue is empty */
+	struct msm_device_queue offline_q;
+	/* Realtime Frame Queue process with highest priority */
+	struct msm_device_queue realtime_q;
+	/* Processing Queue
+	 * store frame info for frames sent to microcontroller
+	 */
+	struct msm_device_queue processing_q;
+};
+#endif /* __MSM_CPP_H__ */
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 44e23ed..1cabc3e 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -39,6 +39,24 @@
 	return rc;
 }
 
+int create_pkt_cmd_sys_idle_indicator(
+	struct hfi_cmd_sys_set_property_packet *pkt,
+	u32 enable)
+{
+	struct hfi_enable *hfi;
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
+		sizeof(struct hfi_enable) + sizeof(u32);
+	pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
+	pkt->num_properties = 1;
+	pkt->rg_property_data[0] = HFI_PROPERTY_SYS_IDLE_INDICATOR;
+	hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+	hfi->enable = enable;
+	return 0;
+}
+
 int create_pkt_set_cmd_sys_resource(
 		struct hfi_cmd_sys_set_resource_packet *pkt,
 		struct vidc_resource_hdr *resource_hdr,
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.h b/drivers/media/platform/msm/vidc/hfi_packetization.h
index b2c6e08..8c61a40 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.h
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.h
@@ -22,6 +22,10 @@
 							   u32 arch_type);
 int create_pkt_cmd_sys_pc_prep(struct hfi_cmd_sys_pc_prep_packet *pkt);
 
+int create_pkt_cmd_sys_idle_indicator(
+		struct hfi_cmd_sys_set_property_packet *pkt,
+		u32 enable);
+
 int create_pkt_set_cmd_sys_resource(
 		struct hfi_cmd_sys_set_resource_packet *pkt,
 		struct vidc_resource_hdr *resource_hdr,
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index f6a9949..709eafc 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -823,19 +823,21 @@
 	callback(SESSION_GET_SEQ_HDR_DONE, &data_done);
 }
 
-void hfi_process_msg_packet(
+u32 hfi_process_msg_packet(
 		msm_vidc_callback callback, u32 device_id,
 		struct vidc_hal_msg_pkt_hdr *msg_hdr)
 {
+	u32 rc = 0;
 	if (!callback || !msg_hdr || msg_hdr->size <
 		VIDC_IFACEQ_MIN_PKT_SIZE) {
 		dprintk(VIDC_ERR, "hal_process_msg_packet:bad"
 			"packet/packet size: %d", msg_hdr->size);
-		return;
+		rc = -EINVAL;
+		return rc;
 	}
 
 	dprintk(VIDC_INFO, "Received: 0x%x in ", msg_hdr->packet);
-
+	rc = (u32) msg_hdr->packet;
 	switch (msg_hdr->packet) {
 	case HFI_MSG_EVENT_NOTIFY:
 		hfi_process_event_notify(callback, device_id,
@@ -846,6 +848,8 @@
 			(struct hfi_msg_sys_init_done_packet *)
 					msg_hdr);
 		break;
+	case HFI_MSG_SYS_IDLE:
+		break;
 	case HFI_MSG_SYS_SESSION_INIT_DONE:
 		hfi_process_session_init_done(callback, device_id,
 			(struct hfi_msg_sys_session_init_done_packet *)
@@ -915,4 +919,5 @@
 		dprintk(VIDC_ERR, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
 		break;
 	}
+	return rc;
 }
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 8e2aa30..125c699 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.c
+++ b/drivers/media/platform/msm/vidc/msm_smem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -26,7 +26,7 @@
 		unsigned long align, unsigned long *iova,
 		unsigned long *buffer_size, int flags)
 {
-	int rc;
+	int rc = 0;
 	if (!iova || !buffer_size || !hndl || !clnt) {
 		dprintk(VIDC_ERR, "Invalid params: %p, %p, %p, %p\n",
 				clnt, hndl, iova, buffer_size);
@@ -71,6 +71,7 @@
 	struct ion_handle *hndl;
 	unsigned long iova = 0;
 	unsigned long buffer_size = 0;
+	unsigned long ionflags = 0;
 	int rc = 0;
 	int align = SZ_4K;
 	hndl = ion_import_dma_buf(client->clnt, fd);
@@ -84,7 +85,20 @@
 	mem->domain = domain;
 	mem->partition_num = partition;
 	mem->flags = flags;
-
+	rc = ion_handle_get_flags(client->clnt, hndl, &ionflags);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to get ion flags: %d\n", rc);
+		goto fail_map;
+	}
+	if (ION_IS_CACHED(ionflags)) {
+		mem->kvaddr = ion_map_kernel(client->clnt, hndl);
+		if (!mem->kvaddr) {
+			dprintk(VIDC_ERR,
+					"Failed to map shared mem in kernel\n");
+			rc = -EIO;
+			goto fail_map;
+		}
+	}
 	if (flags & SMEM_SECURE)
 		align = ALIGN(align, SZ_1M);
 
@@ -103,7 +117,9 @@
 		mem->device_addr, mem->size);
 	return rc;
 fail_device_address:
-	ion_unmap_kernel(client->clnt, hndl);
+	if (mem->kvaddr)
+		ion_unmap_kernel(client->clnt, hndl);
+fail_map:
 	ion_free(client->clnt, hndl);
 fail_import_fd:
 	return rc;
@@ -243,31 +259,79 @@
 	return mem;
 }
 
-static int ion_mem_clean_invalidate(struct smem_client *clt,
-	struct msm_smem *mem)
+static int ion_cache_operations(struct smem_client *client,
+	struct msm_smem *mem, enum smem_cache_ops cache_op)
 {
-	/*
-	 * Note: We're always mapping into iommu as uncached
-	 * as a result we don't need to flush/clean anything
-	 */
-	return 0;
+	unsigned long ionflag = 0;
+	int rc = 0;
+	int msm_cache_ops = 0;
+	if (!mem || !client) {
+		dprintk(VIDC_ERR, "Invalid params: %p, %p\n",
+			mem, client);
+		return -EINVAL;
+	}
+	rc = ion_handle_get_flags(client->clnt,	mem->smem_priv,
+		&ionflag);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"ion_handle_get_flags failed: %d\n", rc);
+		goto cache_op_failed;
+	}
+	if (ION_IS_CACHED(ionflag)) {
+		switch (cache_op) {
+		case SMEM_CACHE_CLEAN:
+			msm_cache_ops = ION_IOC_CLEAN_CACHES;
+			break;
+		case SMEM_CACHE_INVALIDATE:
+			msm_cache_ops = ION_IOC_INV_CACHES;
+			break;
+		case SMEM_CACHE_CLEAN_INVALIDATE:
+			msm_cache_ops = ION_IOC_CLEAN_INV_CACHES;
+			break;
+		default:
+			dprintk(VIDC_ERR, "cache operation not supported\n");
+			rc = -EINVAL;
+			goto cache_op_failed;
+		}
+		if (mem->kvaddr) {
+			rc = msm_ion_do_cache_op(client->clnt,
+					(struct ion_handle *)mem->smem_priv,
+					(unsigned long *) mem->kvaddr,
+					(unsigned long)mem->size,
+					msm_cache_ops);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"cache operation failed %d\n", rc);
+				goto cache_op_failed;
+			}
+		} else {
+			dprintk(VIDC_WARN,
+				"cache operation failed as no kernel mapping\n");
+		}
+	}
+cache_op_failed:
+	return rc;
 }
 
-int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem)
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+		enum smem_cache_ops cache_op)
 {
 	struct smem_client *client = clt;
-	int rc;
-	if (!client || !mem) {
-		dprintk(VIDC_ERR, "Invalid  client/handle passed\n");
+	int rc = 0;
+	if (!client) {
+		dprintk(VIDC_ERR, "Invalid params: %p\n",
+			client);
 		return -EINVAL;
 	}
 	switch (client->mem_type) {
 	case SMEM_ION:
-		rc = ion_mem_clean_invalidate(client, mem);
+		rc = ion_cache_operations(client, mem, cache_op);
+		if (rc)
+			dprintk(VIDC_ERR,
+			"Failed cache operations: %d\n", rc);
 		break;
 	default:
 		dprintk(VIDC_ERR, "Mem type not supported\n");
-		rc = -EINVAL;
 		break;
 	}
 	return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_smem.h b/drivers/media/platform/msm/vidc/msm_smem.h
index 6e40bef..d1c8293 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.h
+++ b/drivers/media/platform/msm/vidc/msm_smem.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -37,6 +37,13 @@
 	void *smem_priv;
 };
 
+enum smem_cache_ops {
+	SMEM_CACHE_CLEAN,
+	SMEM_CACHE_INVALIDATE,
+	SMEM_CACHE_CLEAN_INVALIDATE,
+};
+
+
 void *msm_smem_new_client(enum smem_type mtype);
 struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
 		int domain, int partition, int map_kernel);
@@ -44,5 +51,6 @@
 void msm_smem_delete_client(void *clt);
 struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset, int
 		domain, int partition, int flags);
-int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem);
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+		enum smem_cache_ops);
 #endif
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 47eccfa..54047eb 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -54,6 +54,50 @@
 	struct list_head registered_bufs;
 };
 
+struct master_slave {
+	int masters_ocmem[2];
+	int masters_ddr[2];
+	int slaves_ocmem[2];
+	int slaves_ddr[2];
+};
+
+struct bus_pdata_config {
+	int *masters;
+	int *slaves;
+	char *name;
+};
+
+static struct master_slave bus_vectors_masters_slaves = {
+	.masters_ocmem = {MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+				MSM_BUS_MASTER_VIDEO_P1_OCMEM},
+	.masters_ddr = {MSM_BUS_MASTER_VIDEO_P0, MSM_BUS_MASTER_VIDEO_P1},
+	.slaves_ocmem = {MSM_BUS_SLAVE_OCMEM, MSM_BUS_SLAVE_OCMEM},
+	.slaves_ddr = {MSM_BUS_SLAVE_EBI_CH0, MSM_BUS_SLAVE_EBI_CH0},
+};
+
+static struct bus_pdata_config bus_pdata_config_vector[] = {
+{
+	.masters = bus_vectors_masters_slaves.masters_ocmem,
+	.slaves = bus_vectors_masters_slaves.slaves_ocmem,
+	.name = "qcom,enc-ocmem-ab-ib",
+},
+{
+	.masters = bus_vectors_masters_slaves.masters_ocmem,
+	.slaves = bus_vectors_masters_slaves.slaves_ocmem,
+	.name = "qcom,dec-ocmem-ab-ib",
+},
+{
+	.masters = bus_vectors_masters_slaves.masters_ddr,
+	.slaves = bus_vectors_masters_slaves.slaves_ddr,
+	.name = "qcom,enc-ddr-ab-ib",
+},
+{
+	.masters = bus_vectors_masters_slaves.masters_ddr,
+	.slaves = bus_vectors_masters_slaves.slaves_ddr,
+	.name = "qcom,dec-ddr-ab-ib",
+},
+};
+
 static inline struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
 {
 	return container_of(filp->private_data,
@@ -137,10 +181,12 @@
 err_invalid_input:
 	return ret;
 }
-static u32 device_to_uvaddr(struct list_head *list, u32 device_addr)
+
+static struct buffer_info *device_to_uvaddr(
+	struct list_head *list, u32 device_addr)
 {
-	struct buffer_info *temp;
-	u32 uvaddr = 0;
+	struct buffer_info *temp = NULL;
+	int found = 0;
 	int i;
 	if (!list || !device_addr) {
 		dprintk(VIDC_ERR, "Invalid input\n");
@@ -154,16 +200,16 @@
 						== device_addr)  {
 					dprintk(VIDC_INFO,
 					"Found same fd buffer\n");
-					uvaddr = temp->uvaddr[i];
+					found = 1;
 					break;
 				}
 			}
-			if (uvaddr)
+			if (found)
 				break;
 		}
 	}
 err_invalid_input:
-	return uvaddr;
+	return temp;
 }
 
 static int msm_v4l2_open(struct file *filp)
@@ -500,9 +546,10 @@
 		b->m.planes[i].m.userptr = binfo->device_addr[i];
 		dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
 				binfo->device_addr[i]);
-		if (binfo->handle[i]) {
-			rc = msm_smem_clean_invalidate(v4l2_inst->mem_client,
-					binfo->handle[i]);
+		if (binfo->handle[i] &&
+			(b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+			rc = msm_smem_cache_operations(v4l2_inst->mem_client,
+					binfo->handle[i], SMEM_CACHE_CLEAN);
 			if (rc) {
 				dprintk(VIDC_ERR,
 					"Failed to clean caches: %d\n", rc);
@@ -522,6 +569,7 @@
 	int i;
 	struct msm_v4l2_vid_inst *v4l2_inst;
 	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	struct buffer_info *buffer_info;
 	if (b->length > VIDEO_MAX_PLANES) {
 		dprintk(VIDC_ERR, "num planes exceed maximum: %d\n",
 			b->length);
@@ -541,9 +589,10 @@
 				!b->m.planes[i].m.userptr) {
 			continue;
 		}
-		b->m.planes[i].m.userptr = device_to_uvaddr(
+		buffer_info = device_to_uvaddr(
 				&v4l2_inst->registered_bufs,
 				b->m.planes[i].m.userptr);
+		b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
 		if (!b->m.planes[i].m.userptr) {
 			dprintk(VIDC_ERR,
 			"Failed to find user virtual address, 0x%lx, %d, %d\n",
@@ -551,6 +600,16 @@
 			rc = -EINVAL;
 			goto fail_dq_buf;
 		}
+		if (buffer_info->handle[i] &&
+			(b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
+			rc = msm_smem_cache_operations(v4l2_inst->mem_client,
+				buffer_info->handle[i], SMEM_CACHE_INVALIDATE);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to clean caches: %d\n", rc);
+				goto fail_dq_buf;
+			}
+		}
 	}
 fail_dq_buf:
 	return rc;
@@ -743,6 +802,24 @@
 	res->reg_set.reg_tbl = NULL;
 }
 
+static inline void msm_vidc_free_bus_vectors(
+			struct msm_vidc_platform_resources *res)
+{
+	int i, j;
+	if (res->bus_pdata) {
+		for (i = 0; i < ARRAY_SIZE(bus_pdata_config_vector); i++) {
+			for (j = 0; j < res->bus_pdata[i].num_usecases; j++) {
+				kfree(res->bus_pdata[i].usecase[j].vectors);
+				res->bus_pdata[i].usecase[j].vectors = NULL;
+			}
+			kfree(res->bus_pdata[i].usecase);
+			res->bus_pdata[i].usecase = NULL;
+		}
+		kfree(res->bus_pdata);
+		res->bus_pdata = NULL;
+	}
+}
+
 static int msm_vidc_load_freq_table(struct msm_vidc_platform_resources *res)
 {
 	int rc = 0;
@@ -864,6 +941,144 @@
 	return rc;
 }
 
+static void msm_vidc_free_bus_vector(struct msm_bus_scale_pdata *bus_pdata)
+{
+	int i;
+	for (i = 0; i < bus_pdata->num_usecases; i++) {
+		kfree(bus_pdata->usecase[i].vectors);
+		bus_pdata->usecase[i].vectors = NULL;
+	}
+
+	kfree(bus_pdata->usecase);
+	bus_pdata->usecase = NULL;
+}
+
+static int msm_vidc_load_bus_vector(struct platform_device *pdev,
+			struct msm_bus_scale_pdata *bus_pdata, u32 num_ports,
+			struct bus_pdata_config *bus_pdata_config)
+{
+	struct bus_values {
+	    u32 ab;
+	    u32 ib;
+	};
+	struct bus_values *values;
+	int i, j;
+	int rc = 0;
+
+	values = kzalloc(sizeof(*values) * bus_pdata->num_usecases, GFP_KERNEL);
+	if (!values) {
+		dprintk(VIDC_ERR, "%s Failed to alloc bus_values\n", __func__);
+		rc = -ENOMEM;
+		goto err_mem_alloc;
+	}
+
+	if (of_property_read_u32_array(pdev->dev.of_node,
+		    bus_pdata_config->name, (u32 *)values,
+		    bus_pdata->num_usecases * (sizeof(*values)/sizeof(u32)))) {
+		dprintk(VIDC_ERR, "%s Failed to read bus values\n", __func__);
+		rc = -EINVAL;
+		goto err_parse_dt;
+	}
+
+	bus_pdata->usecase = kzalloc(sizeof(*bus_pdata->usecase) *
+		    bus_pdata->num_usecases, GFP_KERNEL);
+	if (!bus_pdata->usecase) {
+		dprintk(VIDC_ERR,
+			"%s Failed to alloc bus_pdata usecase\n", __func__);
+		rc = -ENOMEM;
+		goto err_parse_dt;
+	}
+	bus_pdata->name = bus_pdata_config->name;
+	for (i = 0; i < bus_pdata->num_usecases; i++) {
+		bus_pdata->usecase[i].vectors = kzalloc(
+			sizeof(*bus_pdata->usecase[i].vectors) * num_ports,
+			GFP_KERNEL);
+		if (!bus_pdata->usecase) {
+			dprintk(VIDC_ERR,
+				"%s Failed to alloc bus_pdata usecase\n",
+				__func__);
+			break;
+		}
+		for (j = 0; j < num_ports; j++) {
+			bus_pdata->usecase[i].vectors[j].ab = (u64)values[i].ab
+									* 1000;
+			bus_pdata->usecase[i].vectors[j].ib = (u64)values[i].ib
+									* 1000;
+			bus_pdata->usecase[i].vectors[j].src =
+						bus_pdata_config->masters[j];
+			bus_pdata->usecase[i].vectors[j].dst =
+						bus_pdata_config->slaves[j];
+			dprintk(VIDC_DBG,
+				"ab = %llu, ib = %llu, src = %d, dst = %d\n",
+				bus_pdata->usecase[i].vectors[j].ab,
+				bus_pdata->usecase[i].vectors[j].ib,
+				bus_pdata->usecase[i].vectors[j].src,
+				bus_pdata->usecase[i].vectors[j].dst);
+		}
+		bus_pdata->usecase[i].num_paths = num_ports;
+	}
+	if (i < bus_pdata->num_usecases) {
+		for (--i; i >= 0; i--) {
+			kfree(bus_pdata->usecase[i].vectors);
+			bus_pdata->usecase[i].vectors = NULL;
+		}
+		kfree(bus_pdata->usecase);
+		bus_pdata->usecase = NULL;
+		rc = -EINVAL;
+	}
+err_parse_dt:
+	kfree(values);
+err_mem_alloc:
+	return rc;
+}
+
+static int msm_vidc_load_bus_vectors(struct msm_vidc_platform_resources *res)
+{
+	u32 num_ports = 0;
+	int rc = 0;
+	int i;
+	struct platform_device *pdev = res->pdev;
+	u32 num_bus_pdata = ARRAY_SIZE(bus_pdata_config_vector);
+
+	if (of_property_read_u32_array(pdev->dev.of_node, "qcom,bus-ports",
+			(u32 *)&num_ports, 1) || (num_ports == 0))
+		goto err_mem_alloc;
+
+	res->bus_pdata = kzalloc(sizeof(*res->bus_pdata) * num_bus_pdata,
+				GFP_KERNEL);
+	if (!res->bus_pdata) {
+		dprintk(VIDC_ERR, "Failed to alloc memory\n");
+		rc = -ENOMEM;
+		goto err_mem_alloc;
+	}
+	for (i = 0; i < num_bus_pdata; i++) {
+		res->bus_pdata[i].num_usecases = get_u32_array_num_elements(
+					pdev, bus_pdata_config_vector[i].name);
+		if (res->bus_pdata[i].num_usecases == 0) {
+			dprintk(VIDC_ERR, "no elements in %s\n",
+				bus_pdata_config_vector[i].name);
+			rc = -EINVAL;
+			break;
+		}
+
+		rc = msm_vidc_load_bus_vector(pdev, &res->bus_pdata[i],
+				num_ports, &bus_pdata_config_vector[i]);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to load bus vector: %d\n", i);
+			break;
+		}
+	}
+	if (i < num_bus_pdata) {
+		for (--i; i >= 0; i--)
+			msm_vidc_free_bus_vector(&res->bus_pdata[i]);
+		kfree(res->bus_pdata);
+		res->bus_pdata = NULL;
+	}
+err_mem_alloc:
+	return rc;
+}
+
 static int read_platform_resources_from_dt(
 		struct msm_vidc_platform_resources *res)
 {
@@ -900,8 +1115,16 @@
 		dprintk(VIDC_ERR, "Failed to load reg table: %d\n", rc);
 		goto err_load_reg_table;
 	}
+
+	rc = msm_vidc_load_bus_vectors(res);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to load bus vectors: %d\n", rc);
+		goto err_load_bus_vectors;
+	}
 	return rc;
 
+err_load_bus_vectors:
+	msm_vidc_free_reg_table(res);
 err_load_reg_table:
 	msm_vidc_free_iommu_maps(res);
 err_load_iommu_maps:
@@ -1132,6 +1355,7 @@
 	msm_vidc_free_freq_table(&core->resources);
 	msm_vidc_free_iommu_maps(&core->resources);
 	msm_vidc_free_reg_table(&core->resources);
+	msm_vidc_free_bus_vectors(&core->resources);
 	kfree(core);
 	return rc;
 }
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 9f5f5af..6a83334 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -362,9 +362,7 @@
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
 	struct v4l2_event dqevent;
-	struct v4l2_control control = {0};
 	struct msm_vidc_cb_event *event_notify;
-	int rc = 0;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		dqevent.id = 0;
@@ -372,16 +370,7 @@
 		switch (event_notify->hal_event_type) {
 		case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
 			dqevent.type =
-				V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
-			control.id =
-				V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
-			rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
-			if (rc)
-				dprintk(VIDC_WARN,
-					"Failed to get Smooth streamng flag\n");
-			if (!rc && control.value == true)
-				dqevent.type =
-					V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+				V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
 			break;
 		case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
 			dqevent.type =
@@ -1929,6 +1918,12 @@
 				rc = -ENOMEM;
 				goto err_no_mem;
 			}
+			rc = msm_smem_cache_operations(inst->mem_client,
+					handle, SMEM_CACHE_CLEAN);
+			if (rc) {
+				dprintk(VIDC_WARN,
+				"Failed to clean cache may cause undefined behavior\n");
+			}
 			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
 			if (!binfo) {
 				dprintk(VIDC_ERR, "Out of memory\n");
@@ -2014,6 +2009,12 @@
 				rc = -ENOMEM;
 				goto err_no_mem;
 			}
+			rc = msm_smem_cache_operations(inst->mem_client,
+					handle, SMEM_CACHE_CLEAN);
+			if (rc) {
+				dprintk(VIDC_WARN,
+				"Failed to clean cache may cause undefined behavior\n");
+			}
 			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
 			if (!binfo) {
 				dprintk(VIDC_ERR, "Out of memory\n");
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index b713d8b..65542bc 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -18,6 +18,7 @@
 int msm_vidc_debug = 0x3;
 int msm_fw_debug = 0x18;
 int msm_fw_debug_mode = 0x1;
+int msm_fw_low_power_mode = 0x1;
 
 struct debug_buffer {
 	char ptr[MAX_DBG_BUF_SIZE];
@@ -159,6 +160,11 @@
 		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
 		goto failed_create_dir;
 	}
+	if (!debugfs_create_u32("fw_low_power_mode", S_IRUGO | S_IWUSR,
+			parent, &msm_fw_low_power_mode)) {
+		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+		goto failed_create_dir;
+	}
 failed_create_dir:
 	return dir;
 }
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index 07568ef..fb06af6 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -44,6 +44,7 @@
 extern int msm_vidc_debug;
 extern int msm_fw_debug;
 extern int msm_fw_debug_mode;
+extern int msm_fw_low_power_mode;
 
 #define dprintk(__level, __fmt, arg...)	\
 	do { \
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index ca8af9c..8fc6452 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -42,6 +42,7 @@
 	struct msm_vidc_iommu_info *iommu_maps;
 	uint32_t iommu_maps_size;
 	struct reg_set reg_set;
+	struct msm_bus_scale_pdata *bus_pdata;
 	struct platform_device *pdev;
 };
 
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index bce9909..da44ec1 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -48,408 +48,6 @@
 	{0xFA181000, 0x1000},
 };
 
-static struct msm_bus_vectors enc_ocmem_init_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
-		.dst = MSM_BUS_SLAVE_OCMEM,
-		.ab = 0,
-		.ib = 0,
-	},
-};
-
-static struct msm_bus_vectors enc_ocmem_perf1_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
-		.dst = MSM_BUS_SLAVE_OCMEM,
-		.ab = 138200000,
-		.ib = 1222000000,
-	},
-};
-
-static struct msm_bus_vectors enc_ocmem_perf2_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
-		.dst = MSM_BUS_SLAVE_OCMEM,
-		.ab = 414700000,
-		.ib = 1222000000,
-	},
-};
-
-static struct msm_bus_vectors enc_ocmem_perf3_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
-		.dst = MSM_BUS_SLAVE_OCMEM,
-		.ab = 940000000,
-		.ib = 2444000000U,
-	},
-};
-
-static struct msm_bus_vectors enc_ocmem_perf4_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
-		.dst = MSM_BUS_SLAVE_OCMEM,
-		.ab = 1880000000,
-		.ib = 2444000000U,
-	},
-};
-
-static struct msm_bus_vectors enc_ocmem_perf5_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
-		.dst = MSM_BUS_SLAVE_OCMEM,
-		.ab = 3008000000U,
-		.ib = 3910400000U,
-	},
-};
-
-static struct msm_bus_vectors enc_ocmem_perf6_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
-		.dst = MSM_BUS_SLAVE_OCMEM,
-		.ab = 3760000000U,
-		.ib = 4888000000ULL,
-	},
-};
-
-static struct msm_bus_vectors dec_ocmem_init_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
-		.dst = MSM_BUS_SLAVE_OCMEM,
-		.ab = 0,
-		.ib = 0,
-	},
-};
-
-static struct msm_bus_vectors dec_ocmem_perf1_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
-		.dst = MSM_BUS_SLAVE_OCMEM,
-		.ab = 176900000,
-		.ib = 1556640000,
-	},
-};
-
-static struct msm_bus_vectors dec_ocmem_perf2_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
-		.dst = MSM_BUS_SLAVE_OCMEM,
-		.ab = 456200000,
-		.ib = 1556640000,
-	},
-};
-
-static struct msm_bus_vectors dec_ocmem_perf3_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
-		.dst = MSM_BUS_SLAVE_OCMEM,
-		.ab = 864800000,
-		.ib = 1556640000,
-	},
-};
-
-static struct msm_bus_vectors dec_ocmem_perf4_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
-		.dst = MSM_BUS_SLAVE_OCMEM,
-		.ab = 1729600000,
-		.ib = 3113280000U,
-	},
-};
-
-static struct msm_bus_vectors dec_ocmem_perf5_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
-		.dst = MSM_BUS_SLAVE_OCMEM,
-		.ab = 2767360000U,
-		.ib = 4981248000ULL,
-	},
-};
-
-static struct msm_bus_vectors dec_ocmem_perf6_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
-		.dst = MSM_BUS_SLAVE_OCMEM,
-		.ab = 3459200000U,
-		.ib = 6226560000ULL,
-	},
-};
-
-static struct msm_bus_paths enc_ocmem_perf_vectors[]  = {
-	{
-		ARRAY_SIZE(enc_ocmem_init_vectors),
-		enc_ocmem_init_vectors,
-	},
-	{
-		ARRAY_SIZE(enc_ocmem_perf1_vectors),
-		enc_ocmem_perf1_vectors,
-	},
-	{
-		ARRAY_SIZE(enc_ocmem_perf2_vectors),
-		enc_ocmem_perf2_vectors,
-	},
-	{
-		ARRAY_SIZE(enc_ocmem_perf3_vectors),
-		enc_ocmem_perf3_vectors,
-	},
-	{
-		ARRAY_SIZE(enc_ocmem_perf4_vectors),
-		enc_ocmem_perf4_vectors,
-	},
-	{
-		ARRAY_SIZE(enc_ocmem_perf5_vectors),
-		enc_ocmem_perf5_vectors,
-	},
-	{
-		ARRAY_SIZE(enc_ocmem_perf6_vectors),
-		enc_ocmem_perf6_vectors,
-	},
-};
-
-static struct msm_bus_paths dec_ocmem_perf_vectors[]  = {
-	{
-		ARRAY_SIZE(dec_ocmem_init_vectors),
-		dec_ocmem_init_vectors,
-	},
-	{
-		ARRAY_SIZE(dec_ocmem_perf1_vectors),
-		dec_ocmem_perf1_vectors,
-	},
-	{
-		ARRAY_SIZE(dec_ocmem_perf2_vectors),
-		dec_ocmem_perf2_vectors,
-	},
-	{
-		ARRAY_SIZE(dec_ocmem_perf3_vectors),
-		dec_ocmem_perf3_vectors,
-	},
-	{
-		ARRAY_SIZE(dec_ocmem_perf4_vectors),
-		dec_ocmem_perf4_vectors,
-	},
-	{
-		ARRAY_SIZE(dec_ocmem_perf5_vectors),
-		dec_ocmem_perf5_vectors,
-	},
-	{
-		ARRAY_SIZE(dec_ocmem_perf6_vectors),
-		dec_ocmem_perf6_vectors,
-	},
-};
-
-
-static struct msm_bus_scale_pdata enc_ocmem_bus_data = {
-	.usecase = enc_ocmem_perf_vectors,
-	.num_usecases = ARRAY_SIZE(enc_ocmem_perf_vectors),
-	.name = "msm_vidc_enc_ocmem",
-};
-
-static struct msm_bus_scale_pdata dec_ocmem_bus_data = {
-	.usecase = dec_ocmem_perf_vectors,
-	.num_usecases = ARRAY_SIZE(dec_ocmem_perf_vectors),
-	.name = "msm_vidc_dec_ocmem",
-};
-
-static struct msm_bus_vectors enc_ddr_init_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 0,
-		.ib = 0,
-	},
-};
-
-
-static struct msm_bus_vectors enc_ddr_perf1_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 60000000,
-		.ib = 664950000,
-	},
-};
-
-static struct msm_bus_vectors enc_ddr_perf2_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 181000000,
-		.ib = 664950000,
-	},
-};
-
-static struct msm_bus_vectors enc_ddr_perf3_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 403000000,
-		.ib = 664950000,
-	},
-};
-
-static struct msm_bus_vectors enc_ddr_perf4_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 806000000,
-		.ib = 1329900000,
-	},
-};
-
-static struct msm_bus_vectors enc_ddr_perf5_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 1289600000,
-		.ib = 2127840000U,
-	},
-};
-
-static struct msm_bus_vectors enc_ddr_perf6_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 161200000,
-		.ib = 6400000000ULL,
-	},
-};
-
-static struct msm_bus_vectors dec_ddr_init_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 0,
-		.ib = 0,
-	},
-};
-
-static struct msm_bus_vectors dec_ddr_perf1_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 110000000,
-		.ib = 909000000,
-	},
-};
-
-static struct msm_bus_vectors dec_ddr_perf2_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 268000000,
-		.ib = 909000000,
-	},
-};
-
-static struct msm_bus_vectors dec_ddr_perf3_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 505000000,
-		.ib = 909000000,
-	},
-};
-
-static struct msm_bus_vectors dec_ddr_perf4_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 1010000000,
-		.ib = 1818000000,
-	},
-};
-
-static struct msm_bus_vectors dec_ddr_perf5_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 1616000000,
-		.ib = 2908800000U,
-	},
-};
-
-static struct msm_bus_vectors dec_ddr_perf6_vectors[]  = {
-	{
-		.src = MSM_BUS_MASTER_VIDEO_P0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 2020000000U,
-		.ib = 6400000000ULL,
-	},
-};
-
-static struct msm_bus_paths enc_ddr_perf_vectors[]  = {
-	{
-		ARRAY_SIZE(enc_ddr_init_vectors),
-		enc_ddr_init_vectors,
-	},
-	{
-		ARRAY_SIZE(enc_ddr_perf1_vectors),
-		enc_ddr_perf1_vectors,
-	},
-	{
-		ARRAY_SIZE(enc_ddr_perf2_vectors),
-		enc_ddr_perf2_vectors,
-	},
-	{
-		ARRAY_SIZE(enc_ddr_perf3_vectors),
-		enc_ddr_perf3_vectors,
-	},
-	{
-		ARRAY_SIZE(enc_ddr_perf4_vectors),
-		enc_ddr_perf4_vectors,
-	},
-	{
-		ARRAY_SIZE(enc_ddr_perf5_vectors),
-		enc_ddr_perf5_vectors,
-	},
-	{
-		ARRAY_SIZE(enc_ddr_perf6_vectors),
-		enc_ddr_perf6_vectors,
-	},
-};
-
-static struct msm_bus_paths dec_ddr_perf_vectors[]  = {
-	{
-		ARRAY_SIZE(dec_ddr_init_vectors),
-		dec_ddr_init_vectors,
-	},
-	{
-		ARRAY_SIZE(dec_ddr_perf1_vectors),
-		dec_ddr_perf1_vectors,
-	},
-	{
-		ARRAY_SIZE(dec_ddr_perf2_vectors),
-		dec_ddr_perf2_vectors,
-	},
-	{
-		ARRAY_SIZE(dec_ddr_perf3_vectors),
-		dec_ddr_perf3_vectors,
-	},
-	{
-		ARRAY_SIZE(dec_ddr_perf4_vectors),
-		dec_ddr_perf4_vectors,
-	},
-	{
-		ARRAY_SIZE(dec_ddr_perf5_vectors),
-		dec_ddr_perf5_vectors,
-	},
-	{
-		ARRAY_SIZE(dec_ddr_perf6_vectors),
-		dec_ddr_perf6_vectors,
-	},
-};
-
-static struct msm_bus_scale_pdata enc_ddr_bus_data = {
-	.usecase = enc_ddr_perf_vectors,
-	.num_usecases = ARRAY_SIZE(enc_ddr_perf_vectors),
-	.name = "msm_vidc_enc_ddr",
-};
-
-static struct msm_bus_scale_pdata dec_ddr_bus_data = {
-	.usecase = dec_ddr_perf_vectors,
-	.num_usecases = ARRAY_SIZE(dec_ddr_perf_vectors),
-	.name = "msm_vidc_dec_ddr",
-};
-
 #define TZBSP_MEM_PROTECT_VIDEO_VAR 0x8
 struct tzbsp_memprot {
 	u32 cp_start;
@@ -755,20 +353,19 @@
 		rc = -ENOMEM;
 		goto fail_smem_alloc;
 	}
-	rc = msm_smem_clean_invalidate(clnt, alloc);
-	if (rc) {
-		dprintk(VIDC_ERR, "NOTE: Failed to clean caches\n");
-		goto fail_clean_cache;
-	}
 	dprintk(VIDC_DBG, "venus_hfi_alloc:ptr=%p,size=%d",
 			alloc->kvaddr, size);
+	rc = msm_smem_cache_operations(clnt, alloc,
+		SMEM_CACHE_CLEAN);
+	if (rc) {
+		dprintk(VIDC_WARN, "Failed to clean cache\n");
+		dprintk(VIDC_WARN, "This may result in undefined behavior\n");
+	}
 	vmem->mem_size = alloc->size;
 	vmem->mem_data = alloc;
 	vmem->align_virtual_addr = (u8 *) alloc->kvaddr;
 	vmem->align_device_addr = (u8 *)alloc->device_addr;
 	return rc;
-fail_clean_cache:
-	msm_smem_free(clnt, alloc);
 fail_smem_alloc:
 	return rc;
 }
@@ -814,6 +411,93 @@
 	rmb();
 	return rc;
 }
+static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device,
+	enum vidc_clocks clk_level)
+{
+	int i;
+	struct venus_core_clock *cl;
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+		return;
+	}
+	if (device->clocks_enabled == 0) {
+		dprintk(VIDC_DBG, "VCODEC clocks are already disabled");
+		goto already_disabled;
+	}
+	for (i = 0; i < clk_level; i++) {
+		cl = &device->resources.clock[i];
+		clk_disable_unprepare(cl->clk);
+	}
+already_disabled:
+	device->clocks_enabled = 0;
+}
+static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device,
+	enum vidc_clocks clk_level)
+{
+	int i;
+	struct venus_core_clock *cl;
+	int rc = 0;
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+		return -EINVAL;
+	}
+	if (device->clocks_enabled == 1) {
+		dprintk(VIDC_DBG, "VCODEC clocks are already enabled");
+		goto already_enabled;
+	}
+	for (i = 0; i < clk_level; i++) {
+		cl = &device->resources.clock[i];
+		rc = clk_prepare_enable(cl->clk);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to enable clocks\n");
+			goto fail_clk_enable;
+		} else {
+			dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
+		}
+	}
+already_enabled:
+	device->clocks_enabled = 1;
+	return rc;
+fail_clk_enable:
+	for (; i >= 0; i--) {
+		cl = &device->resources.clock[i];
+		clk_disable_unprepare(cl->clk);
+	}
+	return rc;
+}
+
+static unsigned long venus_hfi_get_clock_rate(struct venus_core_clock *clock,
+	int num_mbs_per_sec)
+{
+	int num_rows = clock->count;
+	struct load_freq_table *table = clock->load_freq_tbl;
+	unsigned long ret = table[num_rows-1].freq;
+	int i;
+	for (i = 0; i < num_rows; i++) {
+		if (num_mbs_per_sec > table[i].load)
+			break;
+		ret = table[i].freq;
+	}
+	dprintk(VIDC_PROF, "Required clock rate = %lu\n", ret);
+	return ret;
+}
+
+static int venus_hfi_scale_clocks(void *dev, int load)
+{
+	int rc = 0;
+	struct venus_hfi_device *device = dev;
+	device->load = load;
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid args: %p\n", device);
+		return -EINVAL;
+	}
+	rc = clk_set_rate(device->resources.clock[VCODEC_CLK].clk,
+		venus_hfi_get_clock_rate(&device->resources.clock[VCODEC_CLK],
+			load));
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
+	return rc;
+}
 
 static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device,
 					void *pkt)
@@ -821,7 +505,6 @@
 	u32 rx_req_is_set = 0;
 	struct vidc_iface_q_info *q_info;
 	int result = -EPERM;
-
 	if (!device || !pkt) {
 		dprintk(VIDC_ERR, "Invalid Params");
 		return -EINVAL;
@@ -833,7 +516,16 @@
 		dprintk(VIDC_ERR, "cannot write to shared Q's");
 		goto err_q_write;
 	}
-
+	result = venus_hfi_clk_gating_off(device, VCODEC_CLK);
+	if (result) {
+		dprintk(VIDC_ERR, "VCODEC clock enable failed\n");
+		goto err_q_write;
+	}
+	result = venus_hfi_scale_clocks(device, device->load);
+	if (result) {
+		dprintk(VIDC_ERR, "VCODEC clock scaling failed\n");
+		goto err_q_write;
+	}
 	if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) {
 		if (rx_req_is_set)
 			venus_hfi_write_register(
@@ -1218,6 +910,18 @@
 		return -ENOTEMPTY;
 	return 0;
 }
+static int venus_hfi_sys_set_idle_message(struct venus_hfi_device *device,
+	int enable)
+{
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	struct hfi_cmd_sys_set_property_packet *pkt =
+		(struct hfi_cmd_sys_set_property_packet *) &packet;
+	create_pkt_cmd_sys_idle_indicator(pkt, enable);
+	if (venus_hfi_iface_cmdq_write(device, pkt))
+		return -ENOTEMPTY;
+	return 0;
+}
+
 
 static int venus_hfi_core_init(void *device)
 {
@@ -1660,6 +1364,8 @@
 		goto err_session_init_fail;
 	if (venus_hfi_sys_set_debug(dev, msm_fw_debug))
 		dprintk(VIDC_ERR, "Setting fw_debug msg ON failed");
+	if (venus_hfi_sys_set_idle_message(dev, msm_fw_low_power_mode))
+		dprintk(VIDC_ERR, "Setting idle response ON failed");
 	return (void *) new_session;
 
 err_session_init_fail:
@@ -2049,10 +1755,50 @@
 	device->callback(SYS_WATCHDOG_TIMEOUT, &cmd_done);
 }
 
+static int venus_hfi_is_cmd_pending(struct venus_hfi_device *dev)
+{
+	struct hfi_queue_header *queue;
+	struct vidc_iface_q_info *q_info;
+	u32 write_ptr, read_ptr;
+	u32 rc = 0;
+	q_info = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
+	if (!q_info)
+		dprintk(VIDC_ERR, "cannot read shared Q's");
+	queue = (struct hfi_queue_header *) q_info->q_hdr;
+	if (!queue) {
+		dprintk(VIDC_ERR, "queue not present");
+		return -ENOENT;
+	}
+	write_ptr = (u32)queue->qhdr_write_idx;
+	read_ptr = (u32)queue->qhdr_read_idx;
+	rc = read_ptr - write_ptr;
+	return rc;
+}
+
+static int venus_hfi_try_clk_gating(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	u32 ctrl_status = 0;
+	if (!device) {
+		dprintk(VIDC_ERR, "invalid device");
+		return -ENODEV;
+	}
+	mutex_lock(&device->write_lock);
+	rc = venus_hfi_is_cmd_pending(device);
+	ctrl_status = venus_hfi_read_register(
+		device->hal_data->register_base_addr,
+		VIDC_CPU_CS_SCIACMDARG0);
+	if (((ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK)
+		!= 0) && !rc)
+		venus_hfi_clk_gating_on(device, VCODEC_CLK);
+	mutex_unlock(&device->write_lock);
+	return rc;
+}
+
 static void venus_hfi_response_handler(struct venus_hfi_device *device)
 {
 	u8 packet[VIDC_IFACEQ_MED_PKT_SIZE];
-
+	u32 rc = 0;
 	dprintk(VIDC_INFO, "#####venus_hfi_response_handler#####\n");
 	if (device) {
 		if ((device->intr_status &
@@ -2063,9 +1809,12 @@
 		}
 
 		while (!venus_hfi_iface_msgq_read(device, packet)) {
-			hfi_process_msg_packet(device->callback,
+			rc = hfi_process_msg_packet(device->callback,
 				device->device_id,
 				(struct vidc_hal_msg_pkt_hdr *) packet);
+			if (rc == HFI_MSG_SYS_IDLE)
+				rc = venus_hfi_try_clk_gating(device);
+
 		}
 		while (!venus_hfi_iface_dbgq_read(device, packet)) {
 			struct hfi_msg_sys_debug_packet *pkt =
@@ -2233,50 +1982,45 @@
 	for (i = 0; i < VCODEC_MAX_CLKS; i++)
 		clk_put(device->resources.clock[i].clk);
 }
-
-static unsigned long venus_hfi_get_clock_rate(struct venus_core_clock *clock,
-	int num_mbs_per_sec)
+static inline void venus_hfi_disable_clks(struct venus_hfi_device *device)
 {
-	int num_rows = clock->count;
-	struct load_freq_table *table = clock->load_freq_tbl;
-	unsigned long ret = table[num_rows-1].freq;
 	int i;
-	for (i = 0; i < num_rows; i++) {
-		if (num_mbs_per_sec > table[i].load)
-			break;
-		ret = table[i].freq;
-	}
-	dprintk(VIDC_PROF, "Required clock rate = %lu\n", ret);
-	return ret;
-}
-
-static int venus_hfi_scale_clocks(void *dev, int load)
-{
-	int rc = 0;
-	struct venus_hfi_device *device = dev;
+	struct venus_core_clock *cl;
 	if (!device) {
-		dprintk(VIDC_ERR, "Invalid args: %p\n", device);
-		return -EINVAL;
+		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+		return;
+	}
+	if (device->clocks_enabled) {
+		cl = &device->resources.clock[VCODEC_CLK];
+		clk_disable_unprepare(cl->clk);
 	}
 
-	rc = clk_set_rate(device->resources.clock[VCODEC_CLK].clk,
-		venus_hfi_get_clock_rate(&device->resources.clock[VCODEC_CLK],
-		load));
-	if (rc)
-		dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
-	return rc;
+	for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
+		cl = &device->resources.clock[i];
+		clk_disable_unprepare(cl->clk);
+	}
+	device->clocks_enabled = 0;
 }
-
 static inline int venus_hfi_enable_clks(struct venus_hfi_device *device)
 {
-	int i;
+	int i = 0;
 	struct venus_core_clock *cl;
 	int rc = 0;
 	if (!device) {
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return -EINVAL;
 	}
-	for (i = 0; i < VCODEC_MAX_CLKS; i++) {
+	if (!device->clocks_enabled) {
+		cl = &device->resources.clock[VCODEC_CLK];
+		rc = clk_prepare_enable(cl->clk);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to enable clocks\n");
+			goto fail_clk_enable;
+		} else {
+			dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
+		}
+	}
+	for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
 		cl = &device->resources.clock[i];
 		rc = clk_prepare_enable(cl->clk);
 		if (rc) {
@@ -2286,6 +2030,7 @@
 			dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
 		}
 	}
+	device->clocks_enabled = 1;
 	return rc;
 fail_clk_enable:
 	for (; i >= 0; i--) {
@@ -2294,21 +2039,6 @@
 	}
 	return rc;
 }
-
-static inline void venus_hfi_disable_clks(struct venus_hfi_device *device)
-{
-	int i;
-	struct venus_core_clock *cl;
-	if (!device) {
-		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
-		return;
-	}
-	for (i = 0; i < VCODEC_MAX_CLKS; i++) {
-		cl = &device->resources.clock[i];
-		clk_disable_unprepare(cl->clk);
-	}
-}
-
 static int venus_hfi_register_iommu_domains(struct venus_hfi_device *device,
 					struct msm_vidc_platform_resources *res)
 {
@@ -2403,31 +2133,31 @@
 {
 	struct venus_bus_info *bus_info;
 	int rc = 0;
-	if (!device)
+	if ((!device) || (!device->res->bus_pdata))
 		return -EINVAL;
 
 	bus_info = &device->resources.bus_info;
 
 	bus_info->ddr_handle[MSM_VIDC_ENCODER] =
-		msm_bus_scale_register_client(&enc_ddr_bus_data);
+		msm_bus_scale_register_client(&device->res->bus_pdata[2]);
 	if (!bus_info->ddr_handle[MSM_VIDC_ENCODER]) {
 		dprintk(VIDC_ERR, "Failed to register bus scale client\n");
 		goto err_init_bus;
 	}
 	bus_info->ddr_handle[MSM_VIDC_DECODER] =
-		msm_bus_scale_register_client(&dec_ddr_bus_data);
+		msm_bus_scale_register_client(&device->res->bus_pdata[3]);
 	if (!bus_info->ddr_handle[MSM_VIDC_DECODER]) {
 		dprintk(VIDC_ERR, "Failed to register bus scale client\n");
 		goto err_init_bus;
 	}
 	bus_info->ocmem_handle[MSM_VIDC_ENCODER] =
-		msm_bus_scale_register_client(&enc_ocmem_bus_data);
+		msm_bus_scale_register_client(&device->res->bus_pdata[0]);
 	if (!bus_info->ocmem_handle[MSM_VIDC_ENCODER]) {
 		dprintk(VIDC_ERR, "Failed to register bus scale client\n");
 		goto err_init_bus;
 	}
 	bus_info->ocmem_handle[MSM_VIDC_DECODER] =
-		msm_bus_scale_register_client(&dec_ocmem_bus_data);
+		msm_bus_scale_register_client(&device->res->bus_pdata[1]);
 	if (!bus_info->ocmem_handle[MSM_VIDC_DECODER]) {
 		dprintk(VIDC_ERR, "Failed to register bus scale client\n");
 		goto err_init_bus;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index 58314dd..2ffb9d4 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -175,6 +175,8 @@
 	struct list_head sess_head;
 	u32 intr_status;
 	u32 device_id;
+	u32 load;
+	u32 clocks_enabled;
 	struct mutex read_lock;
 	struct mutex write_lock;
 	msm_vidc_callback callback;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index f565d3b..75594b3 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -830,7 +830,7 @@
 
 extern struct hal_device_data hal_ctxt;
 
-void hfi_process_msg_packet(msm_vidc_callback callback,
+u32 hfi_process_msg_packet(msm_vidc_callback callback,
 		u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr);
 #endif
 
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_io.h b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
index 2bc8e6a..eeffe35 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_io.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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,7 @@
 #define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_SHFT	0x1
 #define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_BMSK	0x1
 #define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_SHFT	0x0
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK     0x40000000
 
 /* HFI_QTBL_INFO */
 #define VIDC_CPU_CS_SCIACMDARG1		(VIDC_CPU_CS_BASE_OFFS + 0x50)
diff --git a/drivers/misc/smsc_hub.c b/drivers/misc/smsc_hub.c
index 2ffe4ca..bc338a4 100644
--- a/drivers/misc/smsc_hub.c
+++ b/drivers/misc/smsc_hub.c
@@ -491,9 +491,7 @@
 {
 	int ret = 0;
 
-	if (!IS_ERR(smsc_hub->ref_clk)) {
-		clk_disable_unprepare(smsc_hub->ref_clk);
-	} else {
+	if (smsc_hub->xo_handle) {
 		ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_OFF);
 		if (ret) {
 			pr_err("%s: failed to devote for TCXO\n"
@@ -507,9 +505,7 @@
 {
 	int ret = 0;
 
-	if (!IS_ERR(smsc_hub->ref_clk)) {
-		clk_prepare_enable(smsc_hub->ref_clk);
-	} else {
+	if (smsc_hub->xo_handle) {
 		ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
 		if (ret) {
 			pr_err("%s: failed to vote for TCXO\n"
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 82d58ef..13e23e8 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -136,6 +136,7 @@
 	int			amux_2_trim_delta;
 	uint16_t		prev_last_good_ocv_raw;
 	int			rconn_mohm;
+	int			rbatt_capacitive_mohm;
 	struct mutex		last_ocv_uv_mutex;
 	int			last_ocv_uv;
 	int			last_ocv_temp_decidegc;
@@ -847,8 +848,8 @@
 {
 	int ibat_ua, vbat_uv, ocv_est_uv;
 	int rc;
-
-	int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm;
+	int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm
+				+ chip->rbatt_capacitive_mohm;
 
 	rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
 							&ibat_ua,
@@ -917,7 +918,10 @@
 	rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
 							&ibat_ua,
 							&vbat_uv);
-
+	/*
+	 * don't include rbatt and rbatt_capacitve since we expect this to
+	 * be used with a fake battery which does not have internal resistnaces
+	 */
 	ocv_est_uv = vbat_uv + (ibat_ua * the_chip->rconn_mohm) / 1000;
 	pr_debug("forcing ocv to be %d due to bms reset mode\n", ocv_est_uv);
 	the_chip->last_ocv_uv = ocv_est_uv;
@@ -1072,6 +1076,10 @@
 	pr_debug("adding rconn_mohm = %d rbatt = %d\n",
 				the_chip->rconn_mohm, rbatt);
 
+	rbatt += the_chip->rbatt_capacitive_mohm;
+	pr_debug("adding rbatt_capacitive_mohm = %d rbatt = %d\n",
+				the_chip->rbatt_capacitive_mohm, rbatt);
+
 	if (is_between(20, 10, soc_rbatt))
 		rbatt = rbatt
 			+ ((20 - soc_rbatt) * chip->delta_rbatt_mohm) / 10;
@@ -1583,6 +1591,8 @@
 }
 EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current);
 
+#define SIGN(x) ((x) < 0 ? -1 : 1)
+
 static void find_ocv_for_soc(struct pm8921_bms_chip *chip,
 			int batt_temp,
 			int chargecycles,
@@ -1597,7 +1607,6 @@
 	int pc, new_pc;
 	int batt_temp_degc = batt_temp / 10;
 	int ocv;
-	int count = 0;
 
 	rc = (s64)shutdown_soc * (fcc_uah - uuc_uah);
 	rc = div_s64(rc, 100) + cc_uah + uuc_uah;
@@ -1611,17 +1620,55 @@
 	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);
 
-	/* try 10 times to get a close enough pc */
-	while (abs(new_pc - pc) > 1 && count++ < 10) {
+	if (abs(new_pc - pc) > 0) {
+		/* Maximum spins to make in while-loop when searching in
+		 * full resolution.
+		 */
+		const unsigned int max_spin_count =
+			chip->max_voltage_uv / 1000 - chip->v_cutoff + 1;
+		unsigned int count = 0;
 		int delta_mv = 5;
+		int diff = abs(new_pc - pc);
+		char sign = SIGN(new_pc - pc);
+		char old_sign;
+		int old_diff;
+		int old_ocv;
 
-		if (new_pc > pc)
-			delta_mv = -1 * delta_mv;
+		do {
+			count++;
+			old_ocv = ocv;
+			old_diff = diff;
+			old_sign = sign;
 
-		ocv = ocv + delta_mv;
-		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);
+			if (new_pc > pc)
+				ocv -= delta_mv;
+			else
+				ocv += delta_mv;
+
+			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 = abs(new_pc - pc);
+			sign = SIGN(new_pc - pc);
+
+			if (sign != old_sign) {
+				if (delta_mv == 5) {
+					/*
+					 * we crossed our desired PC probably
+					 * becuase we were overcorrecting
+					 */
+					delta_mv = 1;
+				} else {
+					/* we crossed our desired PC even with
+					 * 1mV steps, choose the best of two */
+					if (diff > old_diff)
+						ocv = old_ocv;
+
+					break;
+				}
+			}
+		} while (count <= max_spin_count && diff > 0);
 	}
 
 	*ocv_uv = ocv * 1000;
@@ -2869,6 +2916,8 @@
 		chip->default_rbatt_mohm
 				= palladium_1500_data.default_rbatt_mohm;
 		chip->delta_rbatt_mohm = palladium_1500_data.delta_rbatt_mohm;
+		chip->rbatt_capacitive_mohm
+			= palladium_1500_data.rbatt_capacitive_mohm;
 		return 0;
 desay:
 		chip->fcc = desay_5200_data.fcc;
@@ -2878,6 +2927,8 @@
 		chip->rbatt_sf_lut = desay_5200_data.rbatt_sf_lut;
 		chip->default_rbatt_mohm = desay_5200_data.default_rbatt_mohm;
 		chip->delta_rbatt_mohm = desay_5200_data.delta_rbatt_mohm;
+		chip->rbatt_capacitive_mohm
+			= desay_5200_data.rbatt_capacitive_mohm;
 		return 0;
 }
 
@@ -3008,9 +3059,9 @@
 	int ret = 0;
 	struct pm8921_soc_params raw;
 
-	mutex_lock(&the_chip->bms_output_lock);
+	mutex_lock(&the_chip->last_ocv_uv_mutex);
 	read_soc_params_raw(the_chip, &raw, 300);
-	mutex_unlock(&the_chip->bms_output_lock);
+	mutex_lock(&the_chip->last_ocv_uv_mutex);
 
 	*val = 0;
 
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 6135e71..7f60128 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -2375,7 +2375,7 @@
 
 	of_property_read_u32(node, "spi-max-frequency",
 			&pdata->max_clock_speed);
-	of_property_read_u32(node, "infinite_mode",
+	of_property_read_u32(node, "qcom,infinite-mode",
 			&pdata->infinite_mode);
 
 	pdata->ver_reg_exists = of_property_read_bool(node
@@ -2485,13 +2485,12 @@
 			goto err_probe_exit;
 		}
 
-		rc = of_property_read_u32(pdev->dev.of_node,
-				"cell-index", &pdev->id);
-		if (rc)
+		rc = of_alias_get_id(pdev->dev.of_node, "spi");
+		if (rc < 0)
 			dev_warn(&pdev->dev,
 				"using default bus_num %d\n", pdev->id);
 		else
-			master->bus_num = pdev->id;
+			master->bus_num = pdev->id = rc;
 
 		for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
 			dd->spi_gpios[i] = of_get_gpio_flags(pdev->dev.of_node,
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 0e3daeb..5aca48d 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -81,7 +81,7 @@
 {
 	static int limit_init;
 	struct tsens_device tsens_dev;
-	unsigned long temp = 0;
+	long temp = 0;
 	uint32_t max_freq = limited_max_freq;
 	int cpu = 0;
 	int ret = 0;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 0011a1a..beba33f 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -165,6 +165,7 @@
 	struct clk		*iface_clk;
 	struct clk		*sleep_clk;
 	struct clk		*hsphy_sleep_clk;
+	struct clk		*utmi_clk;
 	struct regulator	*hsusb_3p3;
 	struct regulator	*hsusb_1p8;
 	struct regulator	*hsusb_vddcx;
@@ -1636,9 +1637,12 @@
 	clk_disable_unprepare(mdwc->core_clk);
 	clk_disable_unprepare(mdwc->iface_clk);
 
-	/* USB PHY no more requires TCXO */
-	if (!host_bus_suspend)
+	if (!host_bus_suspend) {
+		clk_disable_unprepare(mdwc->utmi_clk);
+
+		/* USB PHY no more requires TCXO */
 		clk_disable_unprepare(mdwc->xo_clk);
+	}
 
 	if (mdwc->bus_perf_client) {
 		ret = msm_bus_scale_client_update_request(
@@ -1705,8 +1709,12 @@
 
 	dwc3_ssusb_ldo_enable(1);
 	dwc3_ssusb_config_vddcx(1);
-	if (!host_bus_suspend)
+
+	if (!host_bus_suspend) {
 		dwc3_hsusb_config_vddcx(1);
+		clk_prepare_enable(mdwc->utmi_clk);
+	}
+
 	clk_prepare_enable(mdwc->ref_clk);
 	usleep_range(1000, 1200);
 
@@ -2235,15 +2243,22 @@
 	}
 	clk_prepare_enable(msm->hsphy_sleep_clk);
 
+	msm->utmi_clk = devm_clk_get(&pdev->dev, "utmi_clk");
+	if (IS_ERR(msm->utmi_clk)) {
+		dev_err(&pdev->dev, "failed to get utmi_clk\n");
+		ret = PTR_ERR(msm->utmi_clk);
+		goto disable_sleep_a_clk;
+	}
+	clk_prepare_enable(msm->utmi_clk);
+
 	msm->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
 	if (IS_ERR(msm->ref_clk)) {
 		dev_err(&pdev->dev, "failed to get ref_clk\n");
 		ret = PTR_ERR(msm->ref_clk);
-		goto disable_sleep_a_clk;
+		goto disable_utmi_clk;
 	}
 	clk_prepare_enable(msm->ref_clk);
 
-
 	of_get_property(node, "qcom,vdd-voltage-level", &len);
 	if (len == sizeof(tmp)) {
 		of_property_read_u32_array(node, "qcom,vdd-voltage-level",
@@ -2526,6 +2541,8 @@
 	dwc3_ssusb_config_vddcx(0);
 disable_ref_clk:
 	clk_disable_unprepare(msm->ref_clk);
+disable_utmi_clk:
+	clk_disable_unprepare(msm->utmi_clk);
 disable_sleep_a_clk:
 	clk_disable_unprepare(msm->hsphy_sleep_clk);
 disable_sleep_clk:
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 27781b8..935a540 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -66,6 +66,7 @@
 	NCM_NOTIFY_NONE,
 	NCM_NOTIFY_CONNECT,
 	NCM_NOTIFY_SPEED,
+	NCM_NOTIFY_RESPONSE_AVAILABLE,
 };
 
 struct f_mbim {
@@ -571,6 +572,7 @@
 		return;
 	}
 
+	req->length = sizeof *event;
 	event = req->buf;
 	event->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
 			| USB_RECIP_INTERFACE;
@@ -581,7 +583,7 @@
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(dev->not_port.notify,
-			   dev->not_port.notify_req, GFP_ATOMIC);
+			   req, GFP_ATOMIC);
 	if (ret) {
 		atomic_dec(&dev->not_port.notify_count);
 		pr_err("ep enqueue error %d\n", ret);
@@ -610,6 +612,13 @@
 		return 0;
 	}
 
+	if (dev->not_port.notify_state != NCM_NOTIFY_RESPONSE_AVAILABLE) {
+		pr_err("dev:%p state=%d, recover!!\n", dev,
+			dev->not_port.notify_state);
+		mbim_free_ctrl_pkt(cpkt);
+		return 0;
+	}
+
 	spin_lock_irqsave(&dev->lock, flags);
 	list_add_tail(&cpkt->list, &dev->cpkt_resp_q);
 	spin_unlock_irqrestore(&dev->lock, flags);
@@ -750,10 +759,18 @@
 	switch (mbim->not_port.notify_state) {
 
 	case NCM_NOTIFY_NONE:
+		if (atomic_read(&mbim->not_port.notify_count) > 0)
+			pr_err("Pending notifications in NCM_NOTIFY_NONE\n");
+		else
+			pr_debug("No pending notifications\n");
+
+		return;
+
+	case NCM_NOTIFY_RESPONSE_AVAILABLE:
 		pr_debug("Notification %02x sent\n", event->bNotificationType);
 
 		if (atomic_read(&mbim->not_port.notify_count) <= 0) {
-			pr_debug("notify_none: done");
+			pr_debug("notify_response_avaliable: done");
 			return;
 		}
 
@@ -778,7 +795,7 @@
 
 		pr_info("notify connect %s\n",
 			mbim->is_open ? "true" : "false");
-		mbim->not_port.notify_state = NCM_NOTIFY_NONE;
+		mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
 		break;
 
 	case NCM_NOTIFY_SPEED:
@@ -830,7 +847,7 @@
 	 */
 	pr_debug("dev:%p\n", mbim);
 
-	mbim->not_port.notify_state = NCM_NOTIFY_SPEED;
+	mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
 	mbim_do_notify(mbim);
 }
 
@@ -1365,6 +1382,8 @@
 	pr_info("SET DEVICE OFFLINE");
 	atomic_set(&mbim->online, 0);
 
+	mbim->not_port.notify_state = NCM_NOTIFY_NONE;
+
 	mbim_clear_queues(mbim);
 	mbim_reset_function_queue(mbim);
 
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 24f3cb1..a09b1ab 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -842,7 +842,7 @@
 	u32 __iomem	*status_reg = &ehci->regs->port_status[
 				(wIndex & 0xff) - 1];
 	u32 __iomem	*hostpc_reg = NULL;
-	u32		temp, temp1, status, cmd = 0;
+	u32		temp, temp1, status;
 	unsigned long	flags;
 	int		retval = 0;
 	unsigned	selector;
@@ -1221,31 +1221,13 @@
 				ehci->reset_done [wIndex] = jiffies
 						+ msecs_to_jiffies (50);
 			}
-
-			if (ehci->reset_sof_bug && (temp & PORT_RESET)) {
-				cmd = ehci_readl(ehci, &ehci->regs->command);
-				cmd &= ~CMD_RUN;
-				ehci_writel(ehci, cmd, &ehci->regs->command);
-				if (handshake(ehci, &ehci->regs->status,
-						STS_HALT, STS_HALT, 16 * 125))
-					ehci_info(ehci,
-						"controller halt failed\n");
-			}
-			ehci_writel(ehci, temp, status_reg);
-			if (ehci->reset_sof_bug && (temp & PORT_RESET)
-				&& hcd->driver->enable_ulpi_control) {
-				hcd->driver->enable_ulpi_control(hcd,
-						PORT_RESET);
+			if (ehci->reset_sof_bug && (temp & PORT_RESET) &&
+					hcd->driver->reset_sof_bug_handler) {
 				spin_unlock_irqrestore(&ehci->lock, flags);
-				usleep_range(50000, 55000);
-				if (handshake(ehci, status_reg,
-						PORT_RESET, 0, 10 * 1000))
-					ehci_info(ehci,
-						"failed to clear reset\n");
+				hcd->driver->reset_sof_bug_handler(hcd, temp);
 				spin_lock_irqsave(&ehci->lock, flags);
-				hcd->driver->disable_ulpi_control(hcd);
-				cmd |= CMD_RUN;
-				ehci_writel(ehci, cmd, &ehci->regs->command);
+			} else {
+				ehci_writel(ehci, temp, status_reg);
 			}
 			break;
 
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index fc4d1b6..a559ccf 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -101,6 +101,8 @@
 	struct completion	rt_completion;
 	int			resume_status;
 	int			resume_again;
+	int			bus_reset;
+	int			reset_again;
 
 	struct pm_qos_request pm_qos_req_dma;
 };
@@ -430,7 +432,7 @@
 
 }
 
-static int ulpi_read(struct msm_hsic_hcd *mehci, u32 reg)
+static int __maybe_unused ulpi_read(struct msm_hsic_hcd *mehci, u32 reg)
 {
 	struct usb_hcd *hcd = hsic_to_hcd(mehci);
 	int cnt = 0;
@@ -501,37 +503,6 @@
 	return 0;
 }
 
-#define HSIC_DBG1		0X38
-#define ULPI_MANUAL_ENABLE	BIT(4)
-#define ULPI_LINESTATE_DATA	BIT(5)
-#define ULPI_LINESTATE_STROBE	BIT(6)
-static void ehci_msm_enable_ulpi_control(struct usb_hcd *hcd, u32 linestate)
-{
-	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
-	int val;
-
-	switch (linestate) {
-	case PORT_RESET:
-		val = ulpi_read(mehci, HSIC_DBG1);
-		val |= ULPI_MANUAL_ENABLE;
-		val &= ~(ULPI_LINESTATE_DATA | ULPI_LINESTATE_STROBE);
-		ulpi_write(mehci, val, HSIC_DBG1);
-		break;
-	default:
-		pr_info("%s: Unknown linestate:%0x\n", __func__, linestate);
-	}
-}
-
-static void ehci_msm_disable_ulpi_control(struct usb_hcd *hcd)
-{
-	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
-	int val;
-
-	val = ulpi_read(mehci, HSIC_DBG1);
-	val &= ~ULPI_MANUAL_ENABLE;
-	ulpi_write(mehci, val, HSIC_DBG1);
-}
-
 static int msm_hsic_config_gpios(struct msm_hsic_hcd *mehci, int gpio_en)
 {
 	int rc = 0;
@@ -955,6 +926,26 @@
 				__func__, ret);
 }
 
+static int msm_hsic_reset_done(struct usb_hcd *hcd)
+{
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	u32 __iomem *status_reg = &ehci->regs->port_status[0];
+	int ret;
+
+	ehci_writel(ehci, ehci_readl(ehci, status_reg) & ~(PORT_RWC_BITS |
+					PORT_RESET), status_reg);
+
+	ret = handshake(ehci, status_reg, PORT_RESET, 0, 1 * 1000);
+
+	if (ret)
+		pr_err("reset handshake failed in %s\n", __func__);
+	else
+		ehci_writel(ehci, ehci_readl(ehci, &ehci->regs->command) |
+				CMD_RUN, &ehci->regs->command);
+
+	return ret;
+}
+
 #define STS_GPTIMER0_INTERRUPT	BIT(24)
 static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd)
 {
@@ -982,16 +973,28 @@
 	if (status & STS_GPTIMER0_INTERRUPT) {
 		int timeleft;
 
-		dbg_log_event(NULL, "FPR: gpt0_isr", 0);
+		dbg_log_event(NULL, "FPR: gpt0_isr", mehci->bus_reset);
 
 		timeleft = GPT_CNT(ehci_readl(ehci,
 						 &mehci->timer->gptimer1_ctrl));
 		if (timeleft) {
-			ehci_writel(ehci, ehci_readl(ehci,
-				&ehci->regs->command) | CMD_RUN,
-				&ehci->regs->command);
-		} else
-			mehci->resume_again = 1;
+			if (mehci->bus_reset) {
+				ret = msm_hsic_reset_done(hcd);
+				if (ret) {
+					mehci->reset_again = 1;
+					dbg_log_event(NULL, "RESET: fail", 0);
+				}
+			} else {
+				ehci_writel(ehci, ehci_readl(ehci,
+					&ehci->regs->command) | CMD_RUN,
+					&ehci->regs->command);
+			}
+		} else {
+			if (mehci->bus_reset)
+				mehci->reset_again = 1;
+			else
+				mehci->resume_again = 1;
+		}
 
 		dbg_log_event(NULL, "FPR: timeleft", timeleft);
 
@@ -1047,6 +1050,83 @@
 
 #ifdef CONFIG_PM
 
+#define RESET_RETRY_LIMIT 3
+#define RESET_SIGNAL_TIME_SOF_USEC (50 * 1000)
+#define RESET_SIGNAL_TIME_USEC (20 * 1000)
+static void ehci_hsic_reset_sof_bug_handler(struct usb_hcd *hcd, u32 val)
+{
+	struct ehci_hcd	*ehci = hcd_to_ehci(hcd);
+	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+	struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
+	u32 __iomem *status_reg = &ehci->regs->port_status[0];
+	unsigned long flags;
+	int retries = 0, ret, cnt = RESET_SIGNAL_TIME_USEC;
+
+	if (pdata && pdata->swfi_latency)
+		pm_qos_update_request(&mehci->pm_qos_req_dma,
+			pdata->swfi_latency + 1);
+
+	mehci->bus_reset = 1;
+retry:
+	retries++;
+	dbg_log_event(NULL, "RESET: start", retries);
+	pr_debug("reset begin %d\n", retries);
+	mehci->reset_again = 0;
+	spin_lock_irqsave(&ehci->lock, flags);
+	ehci_writel(ehci, val, status_reg);
+	ehci_writel(ehci, GPT_LD(RESET_SIGNAL_TIME_USEC - 1),
+					&mehci->timer->gptimer0_ld);
+	ehci_writel(ehci, GPT_RESET | GPT_RUN,
+			&mehci->timer->gptimer0_ctrl);
+	ehci_writel(ehci, INTR_MASK | STS_GPTIMER0_INTERRUPT,
+			&ehci->regs->intr_enable);
+
+	ehci_writel(ehci, GPT_LD(RESET_SIGNAL_TIME_SOF_USEC - 1),
+			&mehci->timer->gptimer1_ld);
+	ehci_writel(ehci, GPT_RESET | GPT_RUN,
+		&mehci->timer->gptimer1_ctrl);
+
+	spin_unlock_irqrestore(&ehci->lock, flags);
+	wait_for_completion(&mehci->gpt0_completion);
+
+	if (!mehci->reset_again)
+		goto done;
+
+	if (handshake(ehci, status_reg, PORT_RESET, 0, 10 * 1000)) {
+		pr_err("reset handshake fatal error\n");
+		dbg_log_event(NULL, "RESET: fatal", retries);
+		goto fail;
+	}
+
+	if (retries < RESET_RETRY_LIMIT)
+		goto retry;
+
+	/* complete reset in tight loop */
+	pr_info("RESET in tight loop\n");
+	dbg_log_event(NULL, "RESET: tight", 0);
+
+	spin_lock_irqsave(&ehci->lock, flags);
+	ehci_writel(ehci, val, status_reg);
+	while (cnt--)
+		udelay(1);
+	ret = msm_hsic_reset_done(hcd);
+	spin_unlock_irqrestore(&ehci->lock, flags);
+	if (ret) {
+		pr_err("RESET in tight loop failed\n");
+		dbg_log_event(NULL, "RESET: tight failed", 0);
+		goto fail;
+	}
+
+done:
+	dbg_log_event(NULL, "RESET: done", retries);
+	pr_debug("reset completed\n");
+fail:
+	mehci->bus_reset = 0;
+	if (pdata && pdata->swfi_latency)
+		pm_qos_update_request(&mehci->pm_qos_req_dma,
+			PM_QOS_DEFAULT_VALUE);
+}
+
 static int ehci_hsic_bus_suspend(struct usb_hcd *hcd)
 {
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
@@ -1321,10 +1401,8 @@
 	.log_urb		= dbg_log_event,
 	.dump_regs		= dump_hsic_regs,
 
-	.enable_ulpi_control	= ehci_msm_enable_ulpi_control,
-	.disable_ulpi_control	= ehci_msm_disable_ulpi_control,
-
 	.set_autosuspend_delay = ehci_msm_set_autosuspend_delay,
+	.reset_sof_bug_handler	= ehci_hsic_reset_sof_bug_handler,
 };
 
 static int msm_hsic_init_clocks(struct msm_hsic_hcd *mehci, u32 init)
@@ -1933,6 +2011,12 @@
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
 	struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
 
+	/* If the device was removed no need to call pm_runtime_disable */
+	if (pdev->dev.power.power_state.event != PM_EVENT_INVALID)
+		pm_runtime_disable(&pdev->dev);
+
+	pm_runtime_set_suspended(&pdev->dev);
+
 	/* Remove the HCD prior to releasing our resources. */
 	usb_remove_hcd(hcd);
 
@@ -1966,12 +2050,6 @@
 	ehci_hsic_msm_debugfs_cleanup();
 	device_init_wakeup(&pdev->dev, 0);
 
-	/* If the device was removed no need to call pm_runtime_disable */
-	if (pdev->dev.power.power_state.event != PM_EVENT_INVALID)
-		pm_runtime_disable(&pdev->dev);
-
-	pm_runtime_set_suspended(&pdev->dev);
-
 	destroy_workqueue(ehci_wq);
 
 	msm_hsic_config_gpios(mehci, 0);
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index c69676f..b6882b8 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -57,7 +57,6 @@
 };
 
 struct mdss_data_type {
-	u32 rev;
 	u32 mdp_rev;
 	struct clk *mdp_clk[MDSS_MAX_CLK];
 	struct regulator *fs;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 9d4053e..5c89938 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -615,6 +615,12 @@
 static int mdss_fb_blank(int blank_mode, struct fb_info *info)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	if (blank_mode == FB_BLANK_POWERDOWN) {
+		struct fb_event event;
+		event.info = info;
+		event.data = &blank_mode;
+		fb_notifier_call_chain(FB_EVENT_BLANK, &event);
+	}
 	mdss_fb_pan_idle(mfd);
 	if (mfd->op_enable == 0) {
 		if (blank_mode == FB_BLANK_UNBLANK)
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index ce5f707..308ae87 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -27,6 +27,7 @@
 #include <linux/iommu.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <linux/memory_alloc.h>
@@ -55,7 +56,6 @@
 
 static DEFINE_SPINLOCK(mdp_lock);
 static DEFINE_MUTEX(mdp_clk_lock);
-static DEFINE_MUTEX(mdp_suspend_mutex);
 
 #define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val)		\
 	{						\
@@ -111,7 +111,7 @@
 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 void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on);
 static int mdss_mdp_parse_dt(struct platform_device *pdev);
 static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev);
 static int mdss_mdp_parse_dt_mixer(struct platform_device *pdev);
@@ -612,8 +612,7 @@
 		pr_err("unable to get gdsc regulator\n");
 		return -EINVAL;
 	}
-	regulator_enable(mdata->fs);
-	mdata->fs_ena = true;
+	mdata->fs_ena = false;
 
 	if (mdss_mdp_irq_clk_register(mdata, "bus_clk", MDSS_CLK_AXI) ||
 	    mdss_mdp_irq_clk_register(mdata, "iface_clk", MDSS_CLK_AHB) ||
@@ -673,7 +672,7 @@
 	int i;
 
 	if (!mdata->iommu_attached) {
-		pr_warn("mdp iommu already dettached\n");
+		pr_debug("mdp iommu already dettached\n");
 		return 0;
 	}
 
@@ -754,9 +753,12 @@
 
 static int mdss_hw_init(struct mdss_data_type *mdata)
 {
+	int i, j;
+	char *offset;
+
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-	mdata->rev = MDSS_MDP_REG_READ(MDSS_REG_HW_VERSION);
 	mdata->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
+	pr_info_once("MDP Rev=%x\n", mdata->mdp_rev);
 
 	if (mdata->hw_settings) {
 		struct mdss_hw_settings *hws = mdata->hw_settings;
@@ -766,6 +768,16 @@
 			hws++;
 		}
 	}
+
+	for (i = 0; i < mdata->nmixers_intf; i++) {
+		offset = mdata->mixer_intf[i].dspp_base +
+				MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
+		for (j = 0; j < ENHIST_LUT_ENTRIES; j++)
+			writel_relaxed(j, offset);
+
+		/* swap */
+		writel_relaxed(i, offset + 4);
+	}
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	pr_debug("MDP hw init done\n");
 
@@ -798,8 +810,6 @@
 	mdata->smp_mb_cnt = MDSS_MDP_SMP_MMB_BLOCKS;
 	mdata->smp_mb_size = MDSS_MDP_SMP_MMB_SIZE;
 
-	pr_info("mdss_revision=%x\n", mdata->rev);
-	pr_info("mdp_hw_revision=%x\n", mdata->mdp_rev);
 
 	mdata->iclient = msm_ion_client_create(-1, mdata->pdev->name);
 	if (IS_ERR_OR_NULL(mdata->iclient)) {
@@ -809,10 +819,6 @@
 	}
 
 	rc = mdss_iommu_init(mdata);
-	if (!IS_ERR_VALUE(rc))
-		mdss_iommu_attach(mdata);
-
-	rc = mdss_hw_init(mdata);
 
 	return rc;
 }
@@ -910,15 +916,16 @@
 		goto probe_done;
 	}
 
-	rc = mdss_mdp_register_early_suspend(mdata);
+	rc = mdss_mdp_debug_init(mdata);
 	if (rc) {
-		pr_err("unable to register early suspend\n");
+		pr_err("unable to initialize mdp debugging\n");
 		goto probe_done;
 	}
 
-	rc = mdss_mdp_debug_init(mdata);
-	if (rc)
-		pr_err("unable to initialize mdp debugging\n");
+	pm_runtime_set_suspended(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+	if (!pm_runtime_enabled(&pdev->dev))
+		mdss_mdp_footswitch_ctrl(mdata, true);
 
 probe_done:
 	if (IS_ERR_VALUE(rc)) {
@@ -1320,16 +1327,14 @@
 
 static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on)
 {
-	mutex_lock(&mdp_suspend_mutex);
-	if (!mdata->suspend || !mdata->fs) {
-		mutex_unlock(&mdp_suspend_mutex);
+	if (!mdata->fs)
 		return;
-	}
 
 	if (on && !mdata->fs_ena) {
 		pr_debug("Enable MDP FS\n");
 		regulator_enable(mdata->fs);
 		mdss_iommu_attach(mdata);
+		mdss_hw_init(mdata);
 		mdata->fs_ena = true;
 	} else if (!on && mdata->fs_ena) {
 		pr_debug("Disable MDP FS\n");
@@ -1337,7 +1342,6 @@
 		regulator_disable(mdata->fs);
 		mdata->fs_ena = false;
 	}
-	mutex_unlock(&mdp_suspend_mutex);
 }
 
 static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata)
@@ -1350,18 +1354,6 @@
 		return ret;
 	}
 
-	flush_workqueue(mdata->clk_ctrl_wq);
-
-	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(mdata, false);
-
 	pr_debug("suspend done\n");
 
 	return 0;
@@ -1371,11 +1363,6 @@
 {
 	int ret = 0;
 
-	mdss_mdp_footswitch_ctrl(mdata, true);
-	mutex_lock(&mdp_suspend_mutex);
-	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);
@@ -1385,7 +1372,37 @@
 	return ret;
 }
 
-#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
+#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
+static int mdss_mdp_pm_suspend(struct device *dev)
+{
+	struct mdss_data_type *mdata;
+
+	mdata = dev_get_drvdata(dev);
+	if (!mdata)
+		return -ENODEV;
+
+	dev_dbg(dev, "display pm suspend\n");
+
+	return mdss_mdp_suspend_sub(mdata);
+}
+
+static int mdss_mdp_pm_resume(struct device *dev)
+{
+	struct mdss_data_type *mdata;
+
+	mdata = dev_get_drvdata(dev);
+	if (!mdata)
+		return -ENODEV;
+
+	dev_dbg(dev, "display pm resume\n");
+
+	return mdss_mdp_resume_sub(mdata);
+}
+
+#define mdss_mdp_suspend NULL
+#define mdss_mdp_resume NULL
+#else
 static int mdss_mdp_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
@@ -1393,7 +1410,7 @@
 	if (!mdata)
 		return -ENODEV;
 
-	pr_debug("display suspend\n");
+	dev_dbg(&pdev->dev, "display suspend\n");
 
 	return mdss_mdp_suspend_sub(mdata);
 }
@@ -1405,62 +1422,63 @@
 	if (!mdata)
 		return -ENODEV;
 
-	pr_debug("display resume\n");
+	dev_dbg(&pdev->dev, "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)
+#ifdef CONFIG_PM_RUNTIME
+static int mdss_mdp_runtime_resume(struct device *dev)
 {
-	struct mdss_data_type *mdata;
-	mdata = container_of(h, struct mdss_data_type, early_suspend);
+	struct mdss_data_type *mdata = dev_get_drvdata(dev);
+	if (!mdata)
+		return -ENODEV;
 
-	pr_debug("display early suspend\n");
+	dev_dbg(dev, "pm_runtime: resuming...\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_DISABLE_FB;
-	register_early_suspend(&mdata->early_suspend);
+	mdss_mdp_footswitch_ctrl(mdata, true);
 
 	return 0;
 }
 
-static int mdss_mdp_remove_early_suspend(struct mdss_data_type *mdata)
+static int mdss_mdp_runtime_idle(struct device *dev)
 {
-	unregister_early_suspend(&mdata->early_suspend);
+	struct mdss_data_type *mdata = dev_get_drvdata(dev);
+	if (!mdata)
+		return -ENODEV;
+
+	dev_dbg(dev, "pm_runtime: idling...\n");
+
+	flush_workqueue(mdata->clk_ctrl_wq);
 
 	return 0;
 }
-#else
-static int mdss_mdp_register_early_suspend(struct mdss_data_type *mdata)
+
+static int mdss_mdp_runtime_suspend(struct device *dev)
 {
-	return 0;
-}
-static int mdss_mdp_remove_early_suspend(struct mdss_data_type *mdata)
-{
+	struct mdss_data_type *mdata = dev_get_drvdata(dev);
+	if (!mdata)
+		return -ENODEV;
+	dev_dbg(dev, "pm_runtime: suspending...\n");
+
+	if (mdata->clk_ena) {
+		pr_err("MDP suspend failed\n");
+		return -EBUSY;
+	}
+	mdss_mdp_footswitch_ctrl(mdata, false);
+
 	return 0;
 }
 #endif
+#endif
+
+static const struct dev_pm_ops mdss_mdp_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mdss_mdp_pm_suspend, mdss_mdp_pm_resume)
+	SET_RUNTIME_PM_OPS(mdss_mdp_runtime_suspend,
+			mdss_mdp_runtime_resume,
+			mdss_mdp_runtime_idle)
+};
 
 static int mdss_mdp_remove(struct platform_device *pdev)
 {
@@ -1470,7 +1488,6 @@
 	pm_runtime_disable(&pdev->dev);
 	mdss_mdp_pp_term(&pdev->dev);
 	mdss_mdp_bus_scale_unregister(mdata);
-	mdss_mdp_remove_early_suspend(mdata);
 	mdss_debugfs_remove(mdata);
 	return 0;
 }
@@ -1494,6 +1511,7 @@
 		 */
 		.name = "mdp",
 		.of_match_table = mdss_mdp_dt_match,
+		.pm = &mdss_mdp_pm_ops,
 	},
 };
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index ca8c130..0c891f9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -18,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/uaccess.h>
 
 #include <mach/iommu_domains.h>
@@ -93,11 +94,7 @@
 		return -EOVERFLOW;
 	}
 
-	if (req->flags & MDSS_MDP_ROT_ONLY) {
-		/* dst res should match src res in rotation only mode*/
-		req->dst_rect.w = req->src_rect.w;
-		req->dst_rect.h = req->src_rect.h;
-	} else {
+	if (!(req->flags & MDSS_MDP_ROT_ONLY)) {
 		u32 dst_w, dst_h;
 
 		if ((CHECK_BOUNDS(req->dst_rect.x, req->dst_rect.w, xres) ||
@@ -504,9 +501,22 @@
 int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
 {
 	struct msm_fb_data_type *mfd = ctl->mfd;
+	struct mdss_mdp_pipe *pipe;
 	int ret;
 
 	mutex_lock(&mfd->ov_lock);
+	mutex_lock(&mfd->lock);
+	list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
+		if (pipe->params_changed || pipe->back_buf.num_planes) {
+			ret = mdss_mdp_pipe_queue_data(pipe, &pipe->back_buf);
+			if (IS_ERR_VALUE(ret)) {
+				pr_warn("Unable to queue data for pnum=%d\n",
+						pipe->num);
+				mdss_mdp_overlay_free_buf(&pipe->back_buf);
+			}
+		}
+	}
+	mutex_unlock(&mfd->lock);
 
 	if (mfd->kickoff_fnc)
 		ret = mfd->kickoff_fnc(ctl);
@@ -683,7 +693,6 @@
 static int mdss_mdp_overlay_queue(struct msm_fb_data_type *mfd,
 				  struct msmfb_overlay_data *req)
 {
-	struct mdss_mdp_ctl *ctl;
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_mdp_data *src_data;
 	int ret;
@@ -709,12 +718,7 @@
 	ret = mdss_mdp_overlay_get_buf(mfd, src_data, &req->data, 1, flags);
 	if (IS_ERR_VALUE(ret)) {
 		pr_err("src_data pmem error\n");
-	} else {
-		ret = mdss_mdp_pipe_queue_data(pipe, src_data);
-		if (IS_ERR_VALUE(ret))
-			mdss_mdp_overlay_free_buf(src_data);
 	}
-	ctl = pipe->mixer->ctl;
 	mdss_mdp_pipe_unmap(pipe);
 
 	return ret;
@@ -1321,6 +1325,8 @@
 		mfd->ctl = ctl;
 	}
 
+	pm_runtime_get_sync(&mfd->pdev->dev);
+
 	rc = mdss_mdp_ctl_start(mfd->ctl);
 	if (rc == 0) {
 		atomic_inc(&ov_active_panels);
@@ -1332,6 +1338,8 @@
 	} else {
 		mdss_mdp_ctl_destroy(mfd->ctl);
 		mfd->ctl = NULL;
+
+		pm_runtime_put(&mfd->pdev->dev);
 	}
 
 	return rc;
@@ -1364,6 +1372,8 @@
 
 		if (atomic_dec_return(&ov_active_panels) == 0)
 			mdss_mdp_rotator_release_all();
+
+		pm_runtime_put(&mfd->pdev->dev);
 	}
 
 	return rc;
@@ -1404,6 +1414,9 @@
 		return rc;
 	}
 
+	pm_runtime_set_suspended(&mfd->pdev->dev);
+	pm_runtime_enable(&mfd->pdev->dev);
+
 	kobject_uevent(&dev->kobj, KOBJ_ADD);
 	pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index ee48f31..851d608 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -844,9 +844,6 @@
 int mdss_mdp_pp_init(struct device *dev)
 {
 	int ret = 0;
-	int i;
-	u32 offset;
-	uint32_t data[ENHIST_LUT_ENTRIES];
 
 	mutex_lock(&mdss_pp_mutex);
 	if (!mdss_pp_res) {
@@ -856,20 +853,6 @@
 			pr_err("%s mdss_pp_res allocation failed!", __func__);
 			ret = -ENOMEM;
 		}
-
-		for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
-			data[i] = i;
-
-		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-		/* Initialize Histogram LUT for all DSPPs */
-		for (i = 0; i < MDSS_MDP_MAX_DSPP; i++) {
-			offset = MDSS_MDP_REG_DSPP_OFFSET(i) +
-						MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
-			mdss_pp_res->enhist_disp_cfg[i].data = data;
-			pp_update_hist_lut(offset,
-					&mdss_pp_res->enhist_disp_cfg[i]);
-		}
-		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	}
 	mutex_unlock(&mdss_pp_mutex);
 	return ret;
diff --git a/include/linux/mfd/pm8xxx/batterydata-lib.h b/include/linux/mfd/pm8xxx/batterydata-lib.h
index 5ff1cfb..f27ceca 100644
--- a/include/linux/mfd/pm8xxx/batterydata-lib.h
+++ b/include/linux/mfd/pm8xxx/batterydata-lib.h
@@ -89,6 +89,8 @@
  *			readings from bms are not available.
  * @delta_rbatt_mohm:	the resistance to be added towards lower soc to
  *			compensate for battery capacitance.
+ * @rbatt_capacitve_mohm: the resistance to be added to compensate for
+ *				battery capacitance
  */
 
 struct bms_battery_data {
@@ -100,6 +102,7 @@
 	struct sf_lut		*rbatt_sf_lut;
 	int			default_rbatt_mohm;
 	int			delta_rbatt_mohm;
+	int			rbatt_capacitive_mohm;
 };
 
 #if defined(CONFIG_PM8921_BMS) || \
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index a3347c4..1849cee 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -1149,6 +1149,23 @@
  */
 int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_usbid_param *param,
 		uint32_t *low_threshold, uint32_t *high_threshold);
+/**
+ * qpnp_vadc_iadc_sync_request() - Performs Voltage ADC read and
+ *		locks the peripheral. When performing simultaneous
+ *		voltage and current request the VADC peripheral is
+ *		prepared for conversion and the IADC sync conversion
+ *		is done from the IADC peripheral.
+ * @channel:	Input channel to perform the voltage ADC read.
+ */
+int32_t qpnp_vadc_iadc_sync_request(enum qpnp_vadc_channels channel);
+/**
+ * qpnp_vadc_iadc_sync_complete_request() - Reads the ADC result and
+ *		unlocks the peripheral.
+ * @result:	Structure pointer of type adc_chan_result
+ *		in which the ADC read results are stored.
+ */
+int32_t qpnp_vadc_iadc_sync_complete_request(
+	enum qpnp_vadc_channels channel, struct qpnp_vadc_result *result);
 #else
 static inline int32_t qpnp_vadc_read(uint32_t channel,
 				struct qpnp_vadc_result *result)
@@ -1218,6 +1235,13 @@
 static inline int32_t qpnp_adc_tm_scale_voltage_therm_pu2(
 				uint32_t reg, int64_t *result)
 { return -ENXIO; }
+static inline int32_t qpnp_vadc_iadc_sync_request(
+				enum qpnp_vadc_channels channel)
+{ return -ENXIO; }
+static inline int32_t qpnp_vadc_iadc_sync_complete_request(
+				enum qpnp_vadc_channels channel,
+				struct qpnp_vadc_result *result)
+{ return -ENXIO; }
 #endif
 
 /* Public API */
@@ -1226,7 +1250,7 @@
 /**
  * qpnp_iadc_read() - Performs ADC read on the current channel.
  * @channel:	Input channel to perform the ADC read.
- * @result:	Current across rsens in mV.
+ * @result:	Current across rsense in mA.
  */
 int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
 				struct qpnp_iadc_result *result);
@@ -1245,7 +1269,6 @@
  *		type qpnp_iadc_calib.
  */
 int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib *result);
-
 /**
  * qpnp_iadc_is_ready() - Clients can use this API to check if the
  *			  device is ready to use.
@@ -1253,15 +1276,34 @@
  *		has not occured.
  */
 int32_t qpnp_iadc_is_ready(void);
+/**
+ * qpnp_iadc_vadc_sync_read() - Performs synchronous VADC and IADC read.
+ *		The api is to be used only by the BMS to perform
+ *		simultaneous VADC and IADC measurement for battery voltage
+ *		and current.
+ * @i_channel:	Input battery current channel to perform the IADC read.
+ * @i_result:	Current across the rsense in mA.
+ * @v_channel:	Input battery voltage channel to perform VADC read.
+ * @v_result:	Voltage on the vbatt channel with units in mV.
+ */
+int32_t qpnp_iadc_vadc_sync_read(
+	enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
+	enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result);
 #else
 static inline int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
 						struct qpnp_iadc_result *result)
 { return -ENXIO; }
+static inline int32_t qpnp_iadc_get_rsense(int32_t *rsense)
+{ return -ENXIO; }
 static inline int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib
 									*result)
 { return -ENXIO; }
 static inline int32_t qpnp_iadc_is_ready(void)
 { return -ENXIO; }
+static inline int32_t qpnp_iadc_vadc_sync_read(
+	enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
+	enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
+{ return -ENXIO; }
 #endif
 
 /* Public API */
@@ -1323,8 +1365,6 @@
 { return -ENXIO; }
 static inline int32_t qpnp_adc_tm_is_ready(void)
 { return -ENXIO; }
-static inline int32_t qpnp_iadc_get_rsense(int32_t *rsense)
-{ return -ENXIO; }
 #endif
 
 #endif
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 268aa48..4fb20f6 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -349,9 +349,8 @@
 	/* to log submission/completion events*/
 	void	(*log_urb)(struct urb *urb, char *event, unsigned extra);
 	void	(*dump_regs)(struct usb_hcd *);
-	void	(*enable_ulpi_control)(struct usb_hcd *hcd, u32 linestate);
-	void	(*disable_ulpi_control)(struct usb_hcd *hcd);
 	void	(*set_autosuspend_delay)(struct usb_device *);
+	void	(*reset_sof_bug_handler)(struct usb_hcd *hcd, u32 val);
 };
 
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
diff --git a/include/media/Kbuild b/include/media/Kbuild
index 060047f..16786a9 100644
--- a/include/media/Kbuild
+++ b/include/media/Kbuild
@@ -14,3 +14,4 @@
 header-y += msmb_isp.h
 header-y += msmb_ispif.h
 header-y += msmb_generic_buf_mgr.h
+header-y += msmb_pproc.h
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
new file mode 100644
index 0000000..939c4e3
--- /dev/null
+++ b/include/media/msmb_pproc.h
@@ -0,0 +1,114 @@
+#ifndef __MSMB_PPROC_H
+#define __MSMB_PPROC_H
+
+#ifdef MSM_CAMERA_BIONIC
+#include <sys/types.h>
+#endif
+#include <linux/videodev2.h>
+#include <linux/types.h>
+
+/* Should be same as VIDEO_MAX_PLANES in videodev2.h */
+#define MAX_PLANES VIDEO_MAX_PLANES
+
+#define MAX_NUM_CPP_STRIPS 8
+
+enum msm_cpp_frame_type {
+	MSM_CPP_OFFLINE_FRAME,
+	MSM_CPP_REALTIME_FRAME,
+};
+
+struct msm_cpp_frame_strip_info {
+	int scale_v_en;
+	int scale_h_en;
+
+	int upscale_v_en;
+	int upscale_h_en;
+
+	int src_start_x;
+	int src_end_x;
+	int src_start_y;
+	int src_end_y;
+
+	/* Padding is required for upscaler because it does not
+	 * pad internally like other blocks, also needed for rotation
+	 * rotation expects all the blocks in the stripe to be the same size
+	 * Padding is done such that all the extra padded pixels
+	 * are on the right and bottom
+	 */
+	int pad_bottom;
+	int pad_top;
+	int pad_right;
+	int pad_left;
+
+	int v_init_phase;
+	int h_init_phase;
+	int h_phase_step;
+	int v_phase_step;
+
+	int prescale_crop_width_first_pixel;
+	int prescale_crop_width_last_pixel;
+	int prescale_crop_height_first_line;
+	int prescale_crop_height_last_line;
+
+	int postscale_crop_height_first_line;
+	int postscale_crop_height_last_line;
+	int postscale_crop_width_first_pixel;
+	int postscale_crop_width_last_pixel;
+
+	int dst_start_x;
+	int dst_end_x;
+	int dst_start_y;
+	int dst_end_y;
+
+	int bytes_per_pixel;
+	unsigned int source_address;
+	unsigned int destination_address;
+	unsigned int src_stride;
+	unsigned int dst_stride;
+	int rotate_270;
+	int horizontal_flip;
+	int vertical_flip;
+	int scale_output_width;
+	int scale_output_height;
+	int prescale_crop_en;
+	int postscale_crop_en;
+};
+
+struct msm_cpp_frame_info_t {
+	int32_t frame_id;
+	uint32_t inst_id;
+	uint32_t client_id;
+	enum msm_cpp_frame_type frame_type;
+	uint32_t num_strips;
+	struct msm_cpp_frame_strip_info *strip_info;
+	uint32_t msg_len;
+	uint32_t *cpp_cmd_msg;
+	int src_fd;
+	int dst_fd;
+};
+
+struct msm_ver_num_info {
+	uint32_t main;
+	uint32_t minor;
+	uint32_t rev;
+};
+
+#define VIDIOC_MSM_CPP_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_GET_EVENTPAYLOAD \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_GET_INST_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl_t)
+
+#define V4L2_EVENT_CPP_FRAME_DONE  (V4L2_EVENT_PRIVATE_START + 0)
+
+struct msm_camera_v4l2_ioctl_t {
+	uint32_t id;
+	uint32_t len;
+	uint32_t trans_code;
+	void __user *ioctl_ptr;
+};
+
+#endif /* __MSMB_PPROC_H */
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 28be822..1746502 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -2169,45 +2169,44 @@
 {
 	struct snd_soc_codec *codec = w->codec;
 	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
-	u16 micb_int_reg;
+	u16 micb_int_reg = 0, micb_ctl_reg = 0;
 	u8 cfilt_sel_val = 0;
 	char *internal1_text = "Internal1";
 	char *internal2_text = "Internal2";
 	char *internal3_text = "Internal3";
 	enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
 
-	pr_debug("%s %d\n", __func__, event);
-	switch (w->reg) {
-	case TAIKO_A_MICB_1_CTL:
+	pr_debug("%s: w->name %s event %d\n", __func__, w->name, event);
+	if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1"))) {
+		micb_ctl_reg = TAIKO_A_MICB_1_CTL;
 		micb_int_reg = TAIKO_A_MICB_1_INT_RBIAS;
 		cfilt_sel_val = taiko->resmgr.pdata->micbias.bias1_cfilt_sel;
 		e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
 		e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
 		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
-		break;
-	case TAIKO_A_MICB_2_CTL:
+	} else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2"))) {
+		micb_ctl_reg = TAIKO_A_MICB_2_CTL;
 		micb_int_reg = TAIKO_A_MICB_2_INT_RBIAS;
 		cfilt_sel_val = taiko->resmgr.pdata->micbias.bias2_cfilt_sel;
 		e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_2_ON;
 		e_post_on = WCD9XXX_EVENT_POST_MICBIAS_2_ON;
 		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_2_OFF;
-		break;
-	case TAIKO_A_MICB_3_CTL:
+	} else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3"))) {
+		micb_ctl_reg = TAIKO_A_MICB_2_CTL;
 		micb_int_reg = TAIKO_A_MICB_3_INT_RBIAS;
 		cfilt_sel_val = taiko->resmgr.pdata->micbias.bias3_cfilt_sel;
 		e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_3_ON;
 		e_post_on = WCD9XXX_EVENT_POST_MICBIAS_3_ON;
 		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_3_OFF;
-		break;
-	case TAIKO_A_MICB_4_CTL:
+	} else if (strnstr(w->name, "MIC BIAS4", sizeof("MIC BIAS4"))) {
+		micb_ctl_reg = TAIKO_A_MICB_2_CTL;
 		micb_int_reg = taiko->resmgr.reg_addr->micb_4_int_rbias;
 		cfilt_sel_val = taiko->resmgr.pdata->micbias.bias4_cfilt_sel;
 		e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_4_ON;
 		e_post_on = WCD9XXX_EVENT_POST_MICBIAS_4_ON;
 		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_4_OFF;
-		break;
-	default:
-		pr_err("%s: Error, invalid micbias register\n", __func__);
+	} else {
+		pr_err("%s: Error, invalid micbias %s\n", __func__, w->name);
 		return -EINVAL;
 	}
 
@@ -2226,6 +2225,16 @@
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
 
+		if (micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
+			WCD9XXX_BCL_LOCK(&taiko->resmgr);
+			wcd9xxx_resmgr_add_cond_update_bits(&taiko->resmgr,
+						  WCD9XXX_COND_HPH_MIC,
+						  micb_ctl_reg, w->shift,
+						  false);
+			WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
+		} else
+			snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
+					    1 << w->shift);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		usleep_range(20000, 20000);
@@ -2233,6 +2242,16 @@
 		wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_on);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		if (micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
+			WCD9XXX_BCL_LOCK(&taiko->resmgr);
+			wcd9xxx_resmgr_rm_cond_update_bits(&taiko->resmgr,
+						  WCD9XXX_COND_HPH_MIC,
+						  micb_ctl_reg, 7, false);
+			WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
+		} else
+			snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
+					    0);
+
 		/* Let MBHC module know so micbias switch to be off */
 		wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_off);
 
@@ -4220,15 +4239,18 @@
 
 
 	SND_SOC_DAPM_INPUT("AMIC1"),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TAIKO_A_MICB_1_CTL, 7, 0,
-		taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TAIKO_A_MICB_1_CTL, 7, 0,
-		taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TAIKO_A_MICB_1_CTL, 7, 0,
-		taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SND_SOC_NOPM, 7, 0,
+			       taiko_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", SND_SOC_NOPM, 7, 0,
+			       taiko_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", SND_SOC_NOPM, 7, 0,
+			       taiko_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_ADC_E("ADC1", NULL, TAIKO_A_TX_1_2_EN, 7, 0,
 		taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -4311,31 +4333,38 @@
 	SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
 
 	SND_SOC_DAPM_INPUT("AMIC2"),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TAIKO_A_MICB_2_CTL, 7, 0,
-		taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU |	SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TAIKO_A_MICB_2_CTL, 7, 0,
-		taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TAIKO_A_MICB_2_CTL, 7, 0,
-		taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TAIKO_A_MICB_2_CTL, 7, 0,
-		taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TAIKO_A_MICB_3_CTL, 7, 0,
-		taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TAIKO_A_MICB_3_CTL, 7, 0,
-		taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TAIKO_A_MICB_3_CTL, 7, 0,
-		taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TAIKO_A_MICB_4_CTL, 7,
-				0, taiko_codec_enable_micbias,
-				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SND_SOC_NOPM, 7, 0,
+			       taiko_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", SND_SOC_NOPM, 7, 0,
+			       taiko_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU |
+			       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", SND_SOC_NOPM, 7, 0,
+			       taiko_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", SND_SOC_NOPM, 7, 0,
+			       taiko_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", SND_SOC_NOPM, 7, 0,
+			       taiko_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", SND_SOC_NOPM, 7, 0,
+			       taiko_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU |
+			       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", SND_SOC_NOPM, 7, 0,
+			       taiko_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU |
+			       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", SND_SOC_NOPM, 7,
+			       0, taiko_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_ADC_E("ADC2", NULL, TAIKO_A_TX_1_2_EN, 3, 0,
 		taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index c1a1aa1..b3549cc 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -83,6 +83,7 @@
 #define VDDIO_MICBIAS_MV 1800
 
 #define WCD9XXX_HPHL_STATUS_READY_WAIT_US 1000
+#define WCD9XXX_MUX_SWITCH_READY_WAIT_US 100
 #define WCD9XXX_MEAS_DELTA_MAX_MV 50
 #define WCD9XXX_GM_SWAP_THRES_MIN_MV 150
 #define WCD9XXX_GM_SWAP_THRES_MAX_MV 500
@@ -373,8 +374,14 @@
 	}
 }
 
-static void wcd9xxx_jack_report(struct snd_soc_jack *jack, int status, int mask)
+static void wcd9xxx_jack_report(struct wcd9xxx_mbhc *mbhc,
+				struct snd_soc_jack *jack, int status, int mask)
 {
+	if (jack == &mbhc->headset_jack)
+		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+						WCD9XXX_COND_HPH_MIC,
+						status & SND_JACK_MICROPHONE);
+
 	snd_soc_jack_report_no_dapm(jack, status, mask);
 }
 
@@ -387,7 +394,7 @@
 	codec = mbhc->codec;
 	if (mbhc->hph_status & jack_status) {
 		mbhc->hph_status &= ~jack_status;
-		wcd9xxx_jack_report(&mbhc->headset_jack,
+		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
 				    mbhc->hph_status, WCD9XXX_JACK_MASK);
 		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
 				    0x00);
@@ -617,14 +624,14 @@
 		else if (mbhc->buttons_pressed) {
 			pr_debug("%s: release of button press%d\n",
 				 __func__, jack_type);
-			wcd9xxx_jack_report(&mbhc->button_jack, 0,
+			wcd9xxx_jack_report(mbhc, &mbhc->button_jack, 0,
 					    mbhc->buttons_pressed);
 			mbhc->buttons_pressed &=
 				~WCD9XXX_JACK_BUTTON_MASK;
 		}
 		pr_debug("%s: Reporting removal %d(%x)\n", __func__,
 			 jack_type, mbhc->hph_status);
-		wcd9xxx_jack_report(&mbhc->headset_jack, mbhc->hph_status,
+		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack, mbhc->hph_status,
 				    WCD9XXX_JACK_MASK);
 		wcd9xxx_set_and_turnoff_hph_padac(mbhc);
 		hphrocp_off_report(mbhc, SND_JACK_OC_HPHR);
@@ -637,7 +644,7 @@
 			if (mbhc->hph_status && mbhc->hph_status != jack_type) {
 				pr_debug("%s: Reporting removal (%x)\n",
 					 __func__, mbhc->hph_status);
-				wcd9xxx_jack_report(&mbhc->headset_jack,
+				wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
 						    0, WCD9XXX_JACK_MASK);
 				mbhc->hph_status = 0;
 			}
@@ -657,7 +664,7 @@
 		}
 		pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
 			 jack_type, mbhc->hph_status);
-		wcd9xxx_jack_report(&mbhc->headset_jack,
+		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
 				    mbhc->hph_status, WCD9XXX_JACK_MASK);
 		wcd9xxx_clr_and_turnon_hph_padac(mbhc);
 	}
@@ -1605,6 +1612,14 @@
 
 	pr_debug("%s: enter, removal interrupt\n", __func__);
 	WCD9XXX_BCL_LOCK(mbhc->resmgr);
+	/*
+	 * While we don't know whether MIC is there or not, let the resmgr know
+	 * so micbias can be disabled temporarily
+	 */
+	if (mbhc->current_plug == PLUG_TYPE_HEADSET)
+		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+						WCD9XXX_COND_HPH_MIC, false);
+
 	vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
 		 mbhc->mbhc_micbias_switched);
 	if (vddio)
@@ -1623,6 +1638,10 @@
 	 */
 	if (vddio && (mbhc->current_plug == PLUG_TYPE_HEADSET))
 		__wcd9xxx_switch_micbias(mbhc, 1, true, true);
+
+	if (mbhc->current_plug == PLUG_TYPE_HEADSET)
+		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+						WCD9XXX_COND_HPH_MIC, true);
 	WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
 
 	return IRQ_HANDLED;
@@ -1678,7 +1697,7 @@
 	pr_debug("%s: STA: %d, DCE: %d\n", __func__, sta_mv, dce_mv);
 
 	pr_debug("%s: Reporting long button press event\n", __func__);
-	wcd9xxx_jack_report(&mbhc->button_jack, mbhc->buttons_pressed,
+	wcd9xxx_jack_report(mbhc, &mbhc->button_jack, mbhc->buttons_pressed,
 			    mbhc->buttons_pressed);
 
 	pr_debug("%s: leave\n", __func__);
@@ -2356,7 +2375,7 @@
 		if (ret == 0) {
 			pr_debug("%s: Reporting long button release event\n",
 				 __func__);
-			wcd9xxx_jack_report(&mbhc->button_jack, 0,
+			wcd9xxx_jack_report(mbhc, &mbhc->button_jack, 0,
 					    mbhc->buttons_pressed);
 		} else {
 			if (wcd9xxx_is_fake_press(mbhc)) {
@@ -2369,12 +2388,14 @@
 				} else {
 					pr_debug("%s: Reporting btn press\n",
 						 __func__);
-					wcd9xxx_jack_report(&mbhc->button_jack,
+					wcd9xxx_jack_report(mbhc,
+							 &mbhc->button_jack,
 							 mbhc->buttons_pressed,
 							 mbhc->buttons_pressed);
 					pr_debug("%s: Reporting btn release\n",
 						 __func__);
-					wcd9xxx_jack_report(&mbhc->button_jack,
+					wcd9xxx_jack_report(mbhc,
+						      &mbhc->button_jack,
 						      0, mbhc->buttons_pressed);
 				}
 			}
@@ -2413,7 +2434,7 @@
 					  WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 			mbhc->hphlocp_cnt = 0;
 			mbhc->hph_status |= SND_JACK_OC_HPHL;
-			wcd9xxx_jack_report(&mbhc->headset_jack,
+			wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
 					    mbhc->hph_status,
 					    WCD9XXX_JACK_MASK);
 		}
@@ -2442,7 +2463,7 @@
 				    WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 		mbhc->hphrocp_cnt = 0;
 		mbhc->hph_status |= SND_JACK_OC_HPHR;
-		wcd9xxx_jack_report(&mbhc->headset_jack,
+		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
 				    mbhc->hph_status, WCD9XXX_JACK_MASK);
 	}
 
@@ -2515,6 +2536,7 @@
 static void wcd9xxx_mbhc_cal(struct wcd9xxx_mbhc *mbhc)
 {
 	u8 cfilt_mode;
+	u16 reg0, reg1;
 	struct snd_soc_codec *codec = mbhc->codec;
 
 	pr_debug("%s: enter\n", __func__);
@@ -2544,15 +2566,28 @@
 	snd_soc_write(codec, WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0x78);
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
 
-	/* DCE measurement for 0 volts */
+	/* Pull down micbias to ground */
+	reg0 = snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg);
+	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 1, 1);
+	/* Disconnect override from micbias */
+	reg1 = snd_soc_read(codec, WCD9XXX_A_MAD_ANA_CTRL);
+	snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 0);
+	/* Connect the MUX to micbias */
+	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x82);
+	usleep_range(WCD9XXX_MUX_SWITCH_READY_WAIT_US,
+		     WCD9XXX_MUX_SWITCH_READY_WAIT_US +
+		     WCD9XXX_USLEEP_RANGE_MARGIN_US);
+	/* DCE measurement for 0 voltage */
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x04);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
-	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x81);
-	usleep_range(100, 100);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x04);
-	usleep_range(mbhc->mbhc_data.t_dce, mbhc->mbhc_data.t_dce);
-	mbhc->mbhc_data.dce_z = wcd9xxx_read_dce_result(codec);
+	mbhc->mbhc_data.dce_z = __wcd9xxx_codec_sta_dce(mbhc, 1, true, false);
+	/* STA measurement for 0 voltage */
+	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
+	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
+	mbhc->mbhc_data.sta_z = __wcd9xxx_codec_sta_dce(mbhc, 0, true, false);
+	/* Restore registers */
+	snd_soc_write(codec, mbhc->mbhc_bias_regs.ctl_reg, reg0);
+	snd_soc_write(codec, WCD9XXX_A_MAD_ANA_CTRL, reg1);
 
 	/* DCE measurment for MB voltage */
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
@@ -2563,17 +2598,10 @@
 	usleep_range(mbhc->mbhc_data.t_dce, mbhc->mbhc_data.t_dce);
 	mbhc->mbhc_data.dce_mb = wcd9xxx_read_dce_result(codec);
 
-	/* STA measuremnt for 0 volts */
+	/* STA Measurement for MB Voltage */
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x02);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
-	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x81);
-	usleep_range(100, 100);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x02);
-	usleep_range(mbhc->mbhc_data.t_sta, mbhc->mbhc_data.t_sta);
-	mbhc->mbhc_data.sta_z = wcd9xxx_read_sta_result(codec);
-
-	/* STA Measurement for MB Voltage */
 	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x82);
 	usleep_range(100, 100);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x02);
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 17edd4a..2011346 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -94,6 +94,14 @@
 	"WCD9XXX_EVENT_LAST",
 };
 
+struct wcd9xxx_resmgr_cond_entry {
+	unsigned short reg;
+	int shift;
+	bool invert;
+	enum wcd9xxx_resmgr_cond cond;
+	struct list_head list;
+};
+
 static enum wcd9xxx_clock_type wcd9xxx_save_clock(struct wcd9xxx_resmgr
 						  *resmgr);
 static void wcd9xxx_restore_clock(struct wcd9xxx_resmgr *resmgr,
@@ -640,6 +648,93 @@
 	return rc;
 }
 
+void wcd9xxx_resmgr_cond_trigger_cond(struct wcd9xxx_resmgr *resmgr,
+				      enum wcd9xxx_resmgr_cond cond)
+{
+	struct list_head *l;
+	struct wcd9xxx_resmgr_cond_entry *e;
+	bool set;
+
+	pr_debug("%s: enter\n", __func__);
+	WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+	set = !!test_bit(cond, &resmgr->cond_flags);
+	list_for_each(l, &resmgr->update_bit_cond_h) {
+		e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
+		if (e->cond == cond)
+			snd_soc_update_bits(resmgr->codec, e->reg,
+					    1 << e->shift,
+					    (set ? !e->invert : e->invert)
+					    << e->shift);
+	}
+	pr_debug("%s: leave\n", __func__);
+}
+
+void wcd9xxx_resmgr_cond_update_cond(struct wcd9xxx_resmgr *resmgr,
+				     enum wcd9xxx_resmgr_cond cond, bool set)
+{
+	WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+	if ((set && !test_and_set_bit(cond, &resmgr->cond_flags)) ||
+	    (!set && test_and_clear_bit(cond, &resmgr->cond_flags))) {
+		pr_debug("%s: Resource %d condition changed to %s\n", __func__,
+			 cond, set ? "set" : "clear");
+		wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
+	}
+}
+
+int wcd9xxx_resmgr_add_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
+					enum wcd9xxx_resmgr_cond cond,
+					unsigned short reg, int shift,
+					bool invert)
+{
+	struct wcd9xxx_resmgr_cond_entry *entry;
+
+	WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	entry->cond = cond;
+	entry->reg = reg;
+	entry->shift = shift;
+	entry->invert = invert;
+	list_add_tail(&entry->list, &resmgr->update_bit_cond_h);
+
+	wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
+
+	return 0;
+}
+
+/*
+ * wcd9xxx_resmgr_rm_cond_update_bits :
+ * Clear bit and remove from the conditional bit update list
+ */
+int wcd9xxx_resmgr_rm_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
+				       enum wcd9xxx_resmgr_cond cond,
+				       unsigned short reg, int shift,
+				       bool invert)
+{
+	struct list_head *l, *next;
+	struct wcd9xxx_resmgr_cond_entry *e = NULL;
+
+	pr_debug("%s: enter\n", __func__);
+	WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+	list_for_each_safe(l, next, &resmgr->update_bit_cond_h) {
+		e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
+		if (e->reg == reg && e->shift == shift && e->invert == invert) {
+			snd_soc_update_bits(resmgr->codec, e->reg,
+					    1 << e->shift,
+					    e->invert << e->shift);
+			list_del(&e->list);
+			kfree(e);
+			return 0;
+		}
+	}
+	pr_err("%s: Cannot find update bit entry reg 0x%x, shift %d\n",
+	       __func__, e ? e->reg : 0, e ? e->shift : 0);
+
+	return -EINVAL;
+}
+
 int wcd9xxx_resmgr_register_notifier(struct wcd9xxx_resmgr *resmgr,
 				     struct notifier_block *nblock)
 {
@@ -669,6 +764,8 @@
 	resmgr->pdata = pdata;
 	resmgr->reg_addr = reg_addr;
 
+	INIT_LIST_HEAD(&resmgr->update_bit_cond_h);
+
 	BLOCKING_INIT_NOTIFIER_HEAD(&resmgr->notifier);
 
 	mutex_init(&resmgr->codec_resource_lock);
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index 6c30eeb..53c48f6 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -125,6 +125,9 @@
 	/* Notifier needs mbhc pointer with resmgr */
 	struct wcd9xxx_mbhc *mbhc;
 
+	unsigned long cond_flags;
+	struct list_head update_bit_cond_h;
+
 	/*
 	 * Currently, only used for mbhc purpose, to protect
 	 * concurrent execution of mbhc threaded irq handlers and
@@ -189,4 +192,18 @@
 void wcd9xxx_resmgr_notifier_call(struct wcd9xxx_resmgr *resmgr,
 				  const enum wcd9xxx_notify_event e);
 
+enum wcd9xxx_resmgr_cond {
+	WCD9XXX_COND_HPH_MIC = 1,
+};
+int wcd9xxx_resmgr_rm_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
+				       enum wcd9xxx_resmgr_cond cond,
+				       unsigned short reg, int shift,
+				       bool invert);
+int wcd9xxx_resmgr_add_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
+					enum wcd9xxx_resmgr_cond cond,
+					unsigned short reg, int shift,
+					bool invert);
+void wcd9xxx_resmgr_cond_update_cond(struct wcd9xxx_resmgr *resmgr,
+				     enum wcd9xxx_resmgr_cond cond, bool set);
+
 #endif /* __WCD9XXX_COMMON_H__ */
diff --git a/sound/soc/msm/msm-pcm-voip.c b/sound/soc/msm/msm-pcm-voip.c
index 41e4c60..22bc9e1 100644
--- a/sound/soc/msm/msm-pcm-voip.c
+++ b/sound/soc/msm/msm-pcm-voip.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -155,7 +155,8 @@
 };
 
 static int voip_get_media_type(uint32_t mode, uint32_t rate_type,
-				unsigned int samp_rate);
+				unsigned int samp_rate,
+				uint32_t *media_type);
 static int voip_get_rate_type(uint32_t mode,
 				uint32_t rate,
 				uint32_t *rate_type);
@@ -934,12 +935,12 @@
 			goto done;
 		}
 		prtd->rate_type = rate_type;
-		media_type = voip_get_media_type(prtd->mode,
-						prtd->rate_type,
-						prtd->play_samp_rate);
-		if (media_type < 0) {
+		ret = voip_get_media_type(prtd->mode,
+					  prtd->rate_type,
+					  prtd->play_samp_rate,
+					  &media_type);
+		if (ret < 0) {
 			pr_err("fail at getting media_type\n");
-			ret = -EINVAL;
 			goto done;
 		}
 		pr_debug(" media_type=%d, rate_type=%d\n", media_type,
@@ -1210,49 +1211,50 @@
 }
 
 static int voip_get_media_type(uint32_t mode, uint32_t rate_type,
-				unsigned int samp_rate)
+				unsigned int samp_rate,
+				uint32_t *media_type)
 {
-	uint32_t media_type;
+	int ret = 0;
 
 	pr_debug("%s: mode=%d, samp_rate=%d\n", __func__,
 		mode, samp_rate);
 	switch (mode) {
 	case MODE_AMR:
-		media_type = VSS_MEDIA_ID_AMR_NB_MODEM;
+		*media_type = VSS_MEDIA_ID_AMR_NB_MODEM;
 		break;
 	case MODE_AMR_WB:
-		media_type = VSS_MEDIA_ID_AMR_WB_MODEM;
+		*media_type = VSS_MEDIA_ID_AMR_WB_MODEM;
 		break;
 	case MODE_PCM:
 		if (samp_rate == 8000)
-			media_type = VSS_MEDIA_ID_PCM_NB;
+			*media_type = VSS_MEDIA_ID_PCM_NB;
 		else
-			media_type = VSS_MEDIA_ID_PCM_WB;
+			*media_type = VSS_MEDIA_ID_PCM_WB;
 		break;
 	case MODE_IS127: /* EVRC-A */
-		media_type = VSS_MEDIA_ID_EVRC_MODEM;
+		*media_type = VSS_MEDIA_ID_EVRC_MODEM;
 		break;
 	case MODE_4GV_NB: /* EVRC-B */
-		media_type = VSS_MEDIA_ID_4GV_NB_MODEM;
+		*media_type = VSS_MEDIA_ID_4GV_NB_MODEM;
 		break;
 	case MODE_4GV_WB: /* EVRC-WB */
-		media_type = VSS_MEDIA_ID_4GV_WB_MODEM;
+		*media_type = VSS_MEDIA_ID_4GV_WB_MODEM;
 		break;
 	case MODE_G711:
 	case MODE_G711A:
 		if (rate_type == MVS_G711A_MODE_MULAW)
-			media_type = VSS_MEDIA_ID_G711_MULAW;
+			*media_type = VSS_MEDIA_ID_G711_MULAW;
 		else
-			media_type = VSS_MEDIA_ID_G711_ALAW;
+			*media_type = VSS_MEDIA_ID_G711_ALAW;
 		break;
 	default:
 		pr_debug(" input mode is not supported\n");
-		media_type = -EINVAL;
+		ret = -EINVAL;
 	}
 
-	pr_debug("%s: media_type is 0x%x\n", __func__, media_type);
+	pr_debug("%s: media_type is 0x%x\n", __func__, *media_type);
 
-	return media_type;
+	return ret;
 }
 
 
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index b7f8714..7c5e599 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -1041,18 +1041,18 @@
 	btn_low[0] = -50;
 	btn_high[0] = 20;
 	btn_low[1] = 21;
-	btn_high[1] = 63;
-	btn_low[2] = 64;
-	btn_high[2] = 106;
-	btn_low[3] = 107;
-	btn_high[3] = 146;
-	btn_low[4] = 146;
-	btn_high[4] = 186;
-	btn_low[5] = 187;
-	btn_high[5] = 221;
-	btn_low[6] = 222;
-	btn_high[6] = 253;
-	btn_low[7] = 254;
+	btn_high[1] = 61;
+	btn_low[2] = 62;
+	btn_high[2] = 104;
+	btn_low[3] = 105;
+	btn_high[3] = 148;
+	btn_low[4] = 149;
+	btn_high[4] = 189;
+	btn_low[5] = 190;
+	btn_high[5] = 228;
+	btn_low[6] = 229;
+	btn_high[6] = 269;
+	btn_low[7] = 270;
 	btn_high[7] = 500;
 	n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_READY);
 	n_ready[0] = 80;
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index 145f095..1969fe8 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -30,6 +30,15 @@
 
 #define AUDIO_OCMEM_BUF_SIZE (512 * SZ_1K)
 
+#define _BIT_MASK_\
+		((1 << OCMEM_STATE_EXIT) |\
+		(1 << OCMEM_STATE_GROW) |\
+		(1 << OCMEM_STATE_SHRINK))
+
+#define set_bit_pos(x, y)  (atomic_set(&x, (atomic_read(&x) | (1 << y))))
+#define clear_bit_pos(x, y)  (atomic_set(&x, (atomic_read(&x) & (~(1 << y)))))
+#define test_bit_pos(x, y) ((atomic_read(&x)) & (1 << y))
+
 static int enable_ocmem_audio_voice = 1;
 module_param(enable_ocmem_audio_voice, int,
 			S_IRUGO | S_IWUSR | S_IWGRP);
@@ -48,6 +57,8 @@
 	OCMEM_STATE_MAP_FAIL,
 	OCMEM_STATE_UNMAP_FAIL,
 	OCMEM_STATE_EXIT,
+	OCMEM_STATE_SSR,
+	OCMEM_STATE_DISABLE,
 };
 static void audio_ocmem_process_workdata(struct work_struct *work);
 
@@ -74,6 +85,7 @@
 	atomic_t  audio_cond;
 	atomic_t  audio_exit;
 	spinlock_t audio_lock;
+	struct mutex protect_lock;
 	struct workqueue_struct *audio_ocmem_workqueue;
 	struct workqueue_struct *voice_ocmem_workqueue;
 	bool ocmem_en;
@@ -81,7 +93,6 @@
 
 static struct audio_ocmem_prv audio_ocmem_lcl;
 
-
 static int audio_ocmem_client_cb(struct notifier_block *this,
 		 unsigned long event1, void *data)
 {
@@ -97,7 +108,9 @@
 	switch (event1) {
 	case OCMEM_MAP_DONE:
 		pr_debug("%s: map done\n", __func__);
-		atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_COMPL);
+		clear_bit_pos(audio_ocmem_lcl.audio_state,
+				OCMEM_STATE_MAP_TRANSITION);
+		set_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_COMPL);
 		break;
 	case OCMEM_MAP_FAIL:
 		pr_debug("%s: map fail\n", __func__);
@@ -105,7 +118,9 @@
 		break;
 	case OCMEM_UNMAP_DONE:
 		pr_debug("%s: unmap done\n", __func__);
-		atomic_set(&audio_ocmem_lcl.audio_state,
+		clear_bit_pos(audio_ocmem_lcl.audio_state,
+				OCMEM_STATE_UNMAP_TRANSITION);
+		set_bit_pos(audio_ocmem_lcl.audio_state,
 				OCMEM_STATE_UNMAP_COMPL);
 		break;
 	case OCMEM_UNMAP_FAIL:
@@ -115,13 +130,13 @@
 		break;
 	case OCMEM_ALLOC_GROW:
 		rbuf = data;
-		if (rbuf->len == AUDIO_OCMEM_BUF_SIZE) {
+		if ((rbuf->len == AUDIO_OCMEM_BUF_SIZE)) {
 			audio_ocmem_lcl.buf = data;
 			pr_debug("%s: Alloc grow request received buf->addr: 0x%08lx\n",
 						__func__,
 						(audio_ocmem_lcl.buf)->addr);
-			atomic_set(&audio_ocmem_lcl.audio_state,
-							OCMEM_STATE_GROW);
+			set_bit_pos(audio_ocmem_lcl.audio_state,
+					OCMEM_STATE_GROW);
 		} else {
 			pr_debug("%s: Alloc grow request with size: %ld",
 							__func__,
@@ -132,19 +147,33 @@
 		break;
 	case OCMEM_ALLOC_SHRINK:
 		pr_debug("%s: Alloc shrink request received\n", __func__);
-		atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_SHRINK);
+		set_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_SHRINK);
 		break;
 	default:
 		pr_err("%s: Invalid event[%ld]\n", __func__, event1);
 		break;
 	}
 	spin_unlock_irqrestore(&audio_ocmem_lcl.audio_lock, flags);
-	if (!vwait && (atomic_read(&audio_ocmem_lcl.audio_cond))) {
 		atomic_set(&audio_ocmem_lcl.audio_cond, 0);
 		wake_up(&audio_ocmem_lcl.audio_wait);
-	}
 	return rc;
 }
+int get_state_to_process(atomic_t *state)
+{
+
+	if (test_bit_pos((*state), OCMEM_STATE_SHRINK)) {
+		pr_debug("%s: returning shrink state\n", __func__);
+		return OCMEM_STATE_SHRINK;
+	} else if (test_bit_pos((*state), OCMEM_STATE_GROW)) {
+		pr_debug("%s: returning grow state\n", __func__);
+		return OCMEM_STATE_GROW;
+	} else if (test_bit_pos((*state), OCMEM_STATE_EXIT)) {
+		pr_debug("%s: returning exit state\n", __func__);
+		return OCMEM_STATE_EXIT;
+	} else
+		return -EINVAL;
+
+}
 
 /**
  * audio_ocmem_enable() - Exercise OCMEM for audio
@@ -159,36 +188,12 @@
 {
 	int ret;
 	int i, j;
+	int state_bit;
 	struct ocmem_buf *buf = NULL;
 	struct avcs_cmd_rsp_get_low_power_segments_info_t *lp_segptr;
 
 	pr_debug("%s\n", __func__);
-	/* Non-blocking ocmem allocate (asynchronous) */
-	buf = ocmem_allocate_nb(cid, AUDIO_OCMEM_BUF_SIZE);
-	if (IS_ERR_OR_NULL(buf)) {
-		pr_err("%s: failed: %d\n", __func__, cid);
-		return -ENOMEM;
-	}
-	atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_ALLOC);
-
-	audio_ocmem_lcl.buf = buf;
-	atomic_set(&audio_ocmem_lcl.audio_exit, 0);
-	atomic_set(&audio_ocmem_lcl.audio_cond, 1);
-	pr_debug("%s: buf->len: %ld\n", __func__, buf->len);
-	if (!buf->len) {
-		pr_debug("%s: buf.len is 0, waiting for ocmem region\n",
-								__func__);
-		wait_event_interruptible(audio_ocmem_lcl.audio_wait,
-			(atomic_read(&audio_ocmem_lcl.audio_cond) == 0)	||
-			(atomic_read(&audio_ocmem_lcl.audio_exit) == 1));
-		if (atomic_read(&audio_ocmem_lcl.audio_exit)) {
-			pr_err("%s: audio playback ended while waiting for ocmem\n",
-					__func__);
-			ret = -EINVAL;
-			goto fail_cmd;
-		}
-	}
-	pr_debug("%s: buf->len: %ld\n", __func__, (audio_ocmem_lcl.buf)->len);
+	atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_DEFAULT);
 	if (audio_ocmem_lcl.lp_memseg_ptr == NULL) {
 		/* Retrieve low power segments */
 		ret = core_get_low_power_segments(
@@ -213,6 +218,42 @@
 			(uint32_t)audio_ocmem_lcl.mlist.chunks[j].ddr_paddr,
 			(uint32_t)audio_ocmem_lcl.mlist.chunks[j].size);
 	}
+	/* Non-blocking ocmem allocate (asynchronous) */
+	buf = ocmem_allocate_nb(cid, AUDIO_OCMEM_BUF_SIZE);
+	if (IS_ERR_OR_NULL(buf)) {
+		pr_err("%s: failed: %d\n", __func__, cid);
+		return -ENOMEM;
+	}
+
+	set_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_ALLOC);
+
+	audio_ocmem_lcl.buf = buf;
+	atomic_set(&audio_ocmem_lcl.audio_exit, 0);
+	atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+	pr_debug("%s: buf->len: %ld\n", __func__, buf->len);
+	if (!buf->len) {
+		pr_debug("%s: buf.len is 0, waiting for ocmem region\n",
+								__func__);
+		mutex_unlock(&audio_ocmem_lcl.protect_lock);
+		wait_event_interruptible(audio_ocmem_lcl.audio_wait,
+			(atomic_read(&audio_ocmem_lcl.audio_cond) == 0)	||
+			(atomic_read(&audio_ocmem_lcl.audio_exit) == 1));
+		if (atomic_read(&audio_ocmem_lcl.audio_exit)) {
+			ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
+			if (ret) {
+				pr_err("%s: ocmem_free failed, state[%d]\n",
+				__func__,
+				atomic_read(&audio_ocmem_lcl.audio_state));
+			}
+			pr_info("%s: audio playback ended while waiting for ocmem\n",
+					__func__);
+			ret = 0;
+			goto fail_cmd;
+		}
+		clear_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_GROW);
+		mutex_trylock(&audio_ocmem_lcl.protect_lock);
+	}
+	pr_debug("%s: buf->len: %ld\n", __func__, (audio_ocmem_lcl.buf)->len);
 
 	/* vote for ocmem bus bandwidth */
 	ret = msm_bus_scale_client_update_request(
@@ -221,7 +262,7 @@
 	if (ret)
 		pr_err("%s: failed to vote for bus bandwidth\n", __func__);
 
-	atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_TRANSITION);
+	set_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_TRANSITION);
 
 	pr_debug("%s: buf->addr: 0x%08lx, len: %ld, audio_state[0x%x]\n",
 				__func__,
@@ -236,16 +277,25 @@
 		atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_FAIL);
 	}
 
+	wait_event_interruptible(audio_ocmem_lcl.audio_wait,
+			test_bit_pos(audio_ocmem_lcl.audio_state,
+				OCMEM_STATE_MAP_COMPL) != 0);
+	atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+
+	mutex_unlock(&audio_ocmem_lcl.protect_lock);
 	pr_debug("%s: audio_cond[%d] audio_state[0x%x]\n", __func__,
 				atomic_read(&audio_ocmem_lcl.audio_cond),
 				atomic_read(&audio_ocmem_lcl.audio_state));
-	while ((atomic_read(&audio_ocmem_lcl.audio_state) !=
-						OCMEM_STATE_EXIT)) {
+
+	while ((test_bit_pos(audio_ocmem_lcl.audio_state,
+					OCMEM_STATE_DISABLE)) == 0) {
 
 		wait_event_interruptible(audio_ocmem_lcl.audio_wait,
-				atomic_read(&audio_ocmem_lcl.audio_cond) == 0);
+				(atomic_read(&audio_ocmem_lcl.audio_state) &
+						_BIT_MASK_) != 0);
 
-		switch (atomic_read(&audio_ocmem_lcl.audio_state)) {
+		state_bit = get_state_to_process(&audio_ocmem_lcl.audio_state);
+		switch (state_bit) {
 		case OCMEM_STATE_MAP_COMPL:
 			pr_debug("%s: audio_cond[0x%x], audio_state[0x%x]\n",
 			__func__, atomic_read(&audio_ocmem_lcl.audio_cond),
@@ -258,6 +308,10 @@
 			pr_debug("%s: ocmem shrink request process\n",
 							__func__);
 			atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+			clear_bit_pos(audio_ocmem_lcl.audio_state,
+					OCMEM_STATE_MAP_COMPL);
+			set_bit_pos(audio_ocmem_lcl.audio_state,
+					OCMEM_STATE_UNMAP_TRANSITION);
 			ret = ocmem_unmap(cid, audio_ocmem_lcl.buf,
 					&audio_ocmem_lcl.mlist);
 			if (ret) {
@@ -267,12 +321,9 @@
 				goto fail_cmd;
 			}
 
-			atomic_set(&audio_ocmem_lcl.audio_state,
-					OCMEM_STATE_UNMAP_TRANSITION);
 			wait_event_interruptible(audio_ocmem_lcl.audio_wait,
-				atomic_read(&audio_ocmem_lcl.audio_cond) == 0);
-			atomic_set(&audio_ocmem_lcl.audio_state,
-					OCMEM_STATE_UNMAP_COMPL);
+				test_bit_pos(audio_ocmem_lcl.audio_state,
+					OCMEM_STATE_UNMAP_COMPL) != 0);
 			ret = ocmem_shrink(cid, audio_ocmem_lcl.buf, 0);
 			if (ret) {
 				pr_err("%s: ocmem_shrink failed, state[%d]\n",
@@ -281,11 +332,18 @@
 				goto fail_cmd;
 			}
 			atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+			clear_bit_pos(audio_ocmem_lcl.audio_state,
+					OCMEM_STATE_SHRINK);
+			pr_debug("%s:shrink process complete\n", __func__);
 			break;
 		case OCMEM_STATE_GROW:
 			pr_debug("%s: ocmem grow request process\n",
 							__func__);
 			atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+			clear_bit_pos(audio_ocmem_lcl.audio_state,
+					OCMEM_STATE_UNMAP_COMPL);
+			set_bit_pos(audio_ocmem_lcl.audio_state,
+					OCMEM_STATE_MAP_TRANSITION);
 			ret = ocmem_map(cid, audio_ocmem_lcl.buf,
 						&audio_ocmem_lcl.mlist);
 			if (ret) {
@@ -294,14 +352,102 @@
 				atomic_read(&audio_ocmem_lcl.audio_state));
 				goto fail_cmd;
 			}
-			atomic_set(&audio_ocmem_lcl.audio_state,
-				OCMEM_STATE_MAP_TRANSITION);
 			wait_event_interruptible(audio_ocmem_lcl.audio_wait,
-				atomic_read(&audio_ocmem_lcl.audio_cond) == 0);
-			atomic_set(&audio_ocmem_lcl.audio_state,
-				OCMEM_STATE_MAP_COMPL);
+				test_bit_pos(audio_ocmem_lcl.audio_state,
+					OCMEM_STATE_MAP_COMPL) != 0);
+
+			clear_bit_pos(audio_ocmem_lcl.audio_state,
+					OCMEM_STATE_GROW);
 			atomic_set(&audio_ocmem_lcl.audio_cond, 1);
 			break;
+		case OCMEM_STATE_EXIT:
+			if (test_bit_pos(audio_ocmem_lcl.audio_state,
+						OCMEM_STATE_MAP_COMPL)) {
+				clear_bit_pos(audio_ocmem_lcl.audio_state,
+					OCMEM_STATE_MAP_COMPL);
+				set_bit_pos(audio_ocmem_lcl.audio_state,
+					OCMEM_STATE_UNMAP_TRANSITION);
+				ret = ocmem_unmap(cid, audio_ocmem_lcl.buf,
+						&audio_ocmem_lcl.mlist);
+				if (ret) {
+					pr_err("%s: ocmem_unmap failed, state[0x%x]\n",
+					__func__,
+				atomic_read(&audio_ocmem_lcl.audio_state));
+					goto fail_cmd;
+				}
+				wait_event_interruptible(
+				audio_ocmem_lcl.audio_wait,
+				test_bit_pos(audio_ocmem_lcl.audio_state,
+					OCMEM_STATE_UNMAP_COMPL) != 0);
+			}
+
+			if (test_bit_pos(audio_ocmem_lcl.audio_state,
+						OCMEM_STATE_SHRINK)) {
+				pr_debug("%s: SHRINK while exiting\n",
+								__func__);
+				ret = ocmem_shrink(cid, audio_ocmem_lcl.buf,
+									0);
+				if (ret) {
+					pr_err("%s: ocmem_shrink failed, state[0x%x]\n",
+						__func__,
+				atomic_read(&audio_ocmem_lcl.audio_state));
+					goto fail_cmd;
+				}
+				clear_bit_pos(audio_ocmem_lcl.audio_state,
+						OCMEM_STATE_SHRINK);
+
+			}
+
+			pr_debug("%s: calling ocmem free\n", __func__);
+			ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
+			if (ret == -EAGAIN) {
+				pr_debug("%s: received EAGAIN\n", __func__);
+				if (test_bit_pos(audio_ocmem_lcl.audio_state,
+							OCMEM_STATE_SHRINK)) {
+					ret = ocmem_shrink(cid,
+							audio_ocmem_lcl.buf,
+							0);
+					if (ret) {
+						pr_err("%s: ocmem_shrink failed, state[0x%x]\n",
+							__func__,
+				atomic_read(&audio_ocmem_lcl.audio_state));
+							goto fail_cmd;
+					}
+					pr_debug("calling free after EAGAIN");
+					ret = ocmem_free(OCMEM_LP_AUDIO,
+							audio_ocmem_lcl.buf);
+					if (ret) {
+						pr_err("%s: ocmem_free failed\n",
+								__func__);
+						goto fail_cmd;
+					}
+				} else {
+					pr_debug("%s: shrink callback already processed\n",
+								__func__);
+					goto fail_cmd;
+				}
+			} else if (ret) {
+				pr_err("%s: ocmem_free failed, state[0x%x], ret:%d\n",
+					__func__,
+				atomic_read(&audio_ocmem_lcl.audio_state),
+				ret);
+				goto fail_cmd;
+			}
+			pr_debug("%s: ocmem_free success\n", __func__);
+			msm_bus_scale_client_update_request(
+				audio_ocmem_lcl.audio_ocmem_bus_client,
+				0);
+			set_bit_pos(audio_ocmem_lcl.audio_state,
+						OCMEM_STATE_DISABLE);
+			break;
+
+
+		case -EINVAL:
+			pr_info("%s: audio_cond[%d] audio_state[0x%x]\n",
+				__func__,
+				atomic_read(&audio_ocmem_lcl.audio_cond),
+				atomic_read(&audio_ocmem_lcl.audio_state));
+			break;
 		}
 	}
 	ret = 0;
@@ -320,64 +466,17 @@
  */
 int audio_ocmem_disable(int cid)
 {
-	int ret;
-	int cur_state;
-
-	pr_debug("%s: disable\n", __func__);
-	cur_state = atomic_read(&audio_ocmem_lcl.audio_state);
-	if (atomic_cmpxchg(&audio_ocmem_lcl.audio_cond, 1, 0)) {
-		atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_EXIT);
-		wake_up(&audio_ocmem_lcl.audio_wait);
-	}
 
 	pr_debug("%s: audio_cond[0x%x], audio_state[0x%x]\n", __func__,
 			 atomic_read(&audio_ocmem_lcl.audio_cond),
 			 atomic_read(&audio_ocmem_lcl.audio_state));
-	switch (cur_state) {
-	case OCMEM_STATE_MAP_COMPL:
-		atomic_set(&audio_ocmem_lcl.audio_cond, 1);
-		ret = ocmem_unmap(cid, audio_ocmem_lcl.buf,
-					&audio_ocmem_lcl.mlist);
-		if (ret) {
-			pr_err("%s: ocmem_unmap failed, state[%d]\n",
-				__func__,
-				atomic_read(&audio_ocmem_lcl.audio_state));
-			goto fail_cmd;
-		}
+	set_bit_pos(audio_ocmem_lcl.audio_state,
+				OCMEM_STATE_EXIT);
+	wake_up(&audio_ocmem_lcl.audio_wait);
 
-		atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_EXIT);
-
-		wait_event_interruptible(audio_ocmem_lcl.audio_wait,
-				atomic_read(&audio_ocmem_lcl.audio_cond) == 0);
-	case OCMEM_STATE_UNMAP_COMPL:
-	case OCMEM_STATE_MAP_FAIL:
-	case OCMEM_STATE_MAP_TRANSITION:
-	case OCMEM_STATE_ALLOC:
-		ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
-		if (ret) {
-			pr_err("%s: ocmem_free failed, state[%d]\n",
-				__func__,
-				atomic_read(&audio_ocmem_lcl.audio_state));
-			goto fail_cmd;
-		}
-		pr_debug("%s: state=%d", __func__,
-			atomic_read(&audio_ocmem_lcl.audio_state));
-		atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_EXIT);
-		pr_debug("%s: ocmem_free success\n", __func__);
-		break;
-
-	default:
-		pr_debug("%s:error: state=%d", __func__,
-			atomic_read(&audio_ocmem_lcl.audio_state));
-		break;
-
-	}
-	msm_bus_scale_client_update_request(
-				audio_ocmem_lcl.audio_ocmem_bus_client,
-				0);
+	mutex_unlock(&audio_ocmem_lcl.protect_lock);
+	pr_debug("%s: exit\n", __func__);
 	return 0;
-fail_cmd:
-	return ret;
 }
 
 static void voice_ocmem_process_workdata(struct work_struct *work)
@@ -497,6 +596,10 @@
 			container_of(work, struct audio_ocmem_workdata, work);
 
 	en = audio_ocm_work->en;
+	mutex_lock(&audio_ocmem_lcl.protect_lock);
+	/* if previous work waiting for ocmem - signal it to exit */
+	atomic_set(&audio_ocmem_lcl.audio_exit, 1);
+	pr_debug("%s: acquired mutex for %d\n", __func__, en);
 	switch (audio_ocm_work->id) {
 	case AUDIO:
 		cid = OCMEM_LP_AUDIO;
@@ -548,9 +651,6 @@
 		workdata->id = id;
 		workdata->en = enable;
 
-		/* if previous work waiting for ocmem - signal it to exit */
-		atomic_set(&audio_ocmem_lcl.audio_exit, 1);
-
 		INIT_WORK(&workdata->work, audio_ocmem_process_workdata);
 		queue_work(audio_ocmem_lcl.audio_ocmem_workqueue,
 							&workdata->work);
@@ -611,6 +711,7 @@
 	atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_DEFAULT);
 	atomic_set(&audio_ocmem_lcl.audio_exit, 0);
 	spin_lock_init(&audio_ocmem_lcl.audio_lock);
+	mutex_init(&audio_ocmem_lcl.protect_lock);
 	audio_ocmem_lcl.ocmem_en = true;
 
 	/* populate platform data */
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index 49f1d70..b5ce28f 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -140,7 +140,8 @@
 };
 
 static int voip_get_media_type(uint32_t mode,
-				unsigned int samp_rate);
+				unsigned int samp_rate,
+				unsigned int *media_type);
 static int voip_get_rate_type(uint32_t mode,
 				uint32_t rate,
 				uint32_t *rate_type);
@@ -782,11 +783,11 @@
 			goto done;
 		}
 		prtd->rate_type = rate_type;
-		media_type = voip_get_media_type(prtd->mode,
-						prtd->play_samp_rate);
-		if (media_type < 0) {
+		ret = voip_get_media_type(prtd->mode,
+						prtd->play_samp_rate,
+						&media_type);
+		if (ret < 0) {
 			pr_err("fail at getting media_type\n");
-			ret = -EINVAL;
 			goto done;
 		}
 		pr_debug(" media_type=%d, rate_type=%d\n", media_type,
@@ -1058,42 +1059,43 @@
 }
 
 static int voip_get_media_type(uint32_t mode,
-				unsigned int samp_rate)
+				unsigned int samp_rate,
+				unsigned int *media_type)
 {
-	uint32_t media_type;
+	int ret = 0;
 
 	pr_debug("%s: mode=%d, samp_rate=%d\n", __func__,
 		mode, samp_rate);
 	switch (mode) {
 	case MODE_AMR:
-		media_type = VSS_MEDIA_ID_AMR_NB_MODEM;
+		*media_type = VSS_MEDIA_ID_AMR_NB_MODEM;
 		break;
 	case MODE_AMR_WB:
-		media_type = VSS_MEDIA_ID_AMR_WB_MODEM;
+		*media_type = VSS_MEDIA_ID_AMR_WB_MODEM;
 		break;
 	case MODE_PCM:
 		if (samp_rate == 8000)
-			media_type = VSS_MEDIA_ID_PCM_NB;
+			*media_type = VSS_MEDIA_ID_PCM_NB;
 		else
-			media_type = VSS_MEDIA_ID_PCM_WB;
+			*media_type = VSS_MEDIA_ID_PCM_WB;
 		break;
 	case MODE_IS127: /* EVRC-A */
-		media_type = VSS_MEDIA_ID_EVRC_MODEM;
+		*media_type = VSS_MEDIA_ID_EVRC_MODEM;
 		break;
 	case MODE_4GV_NB: /* EVRC-B */
-		media_type = VSS_MEDIA_ID_4GV_NB_MODEM;
+		*media_type = VSS_MEDIA_ID_4GV_NB_MODEM;
 		break;
 	case MODE_4GV_WB: /* EVRC-WB */
-		media_type = VSS_MEDIA_ID_4GV_WB_MODEM;
+		*media_type = VSS_MEDIA_ID_4GV_WB_MODEM;
 		break;
 	default:
 		pr_debug(" input mode is not supported\n");
-		media_type = -EINVAL;
+		ret = -EINVAL;
 	}
 
-	pr_debug("%s: media_type is 0x%x\n", __func__, media_type);
+	pr_debug("%s: media_type is 0x%x\n", __func__, *media_type);
 
-	return media_type;
+	return ret;
 }