Merge "arm/dt: pm8941: Add devices for pmic vibrators"
diff --git a/Documentation/devicetree/bindings/arm/msm/bcl.txt b/Documentation/devicetree/bindings/arm/msm/bcl.txt
new file mode 100644
index 0000000..e11a817
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/bcl.txt
@@ -0,0 +1,15 @@
+* Battery Current Limit
+
+This Battery Current Limit device, provides an interface to detect and notify
+interested applications when the SOC is drawing current in excess of the limits
+specified.
+
+The device tree parameters for bcl are:
+
+Required parameters:
+- compatible: Must be "qcom,bcl"
+
+Example:
+	qcom,bcl {
+		compatible = "qcom,bcl";
+	};
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/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 2ea9ba9..1e47c02 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -62,6 +62,7 @@
 Optional Properties:
 - qcom,initial-powerlevel: This value indicates which qcom,gpu-pwrlevel should be used at start time
 			   and when coming back out of resume
+- qcom,step-pwrlevel:	   How many qcom,gpu-pwrlevel should be decremented at once
 - qcom,idle-timeout:	   This property represents the time in microseconds for idle timeout.
 - qcom,nap-allowed:	   Boolean. <0> or <1> to disable/enable nap.
 - qcom,chipid:		   If it exists this property is used to replace
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/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 03b01ee..a868b75 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -34,6 +34,8 @@
 					system thermal mitigation level.
 
 Parent node optional properties:
+- qcom,chg-maxinput-usb-ma:		Maximum input current USB.
+- qcom,chg-maxinput-dc-ma:		Maximum input current DC.
 - qcom,chg-charging-disabled:		Set this property to disable charging
 					by default. This can then be overriden
 					writing the the module parameter
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 232ddec..fed8cb4 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -6,6 +6,21 @@
 
  - compatible : "qcom,msm-pcm-dsp"
 
+ - qcom,msm-pcm-dsp-id : device node id
+
+* msm-pcm-low-latency
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-dsp"
+
+ - qcom,msm-pcm-dsp-id : device node id
+
+   Optional properties
+
+      - qcom,msm-pcm-low-latency : Flag indicating whether
+        the device node is of type low latency.
+
 * msm-pcm-routing
 
 Required properties:
@@ -212,7 +227,14 @@
 Example:
 
         qcom,msm-pcm {
-                compatible = "qcom,msm-pcm-dsp";
+		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <0>;
+	};
+
+	qcom,msm-pcm-low-latency {
+		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <1>;
+		qcom,msm-pcm-low-latency;
         };
 
         qcom,msm-pcm-routing {
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/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
index 0682cd1..67a986b 100644
--- a/Documentation/devicetree/bindings/thermal/tsens.txt
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -29,6 +29,11 @@
 	       sensor used to compute the offset. Slope is represented
 	       as ADC code/DegC and the value is multipled by a factor
 	       of 1000.
+- qcom,calib-mode : Calibration masks to use to abstract the offset data from efuse.
+		    Select from the following strings.
+		    "fuse_map1" : Used for 8974/9x25 fuse calibration map.
+		    "fuse_map2" : Used for 8x26 fuse calibration map.
+		    "fuse_map3" : Used for 8x10 fuse calibration map.
 
 Optional properties:
 - qcom,calibration-less-mode : If present the pre-characterized data for offsets
@@ -45,6 +50,7 @@
 	interrupts = <0 184 0>;
 	qcom,calibration-less-mode;
 	qcom,sensors = <11>;
-	qcom,slope = <1134 1122 1142 1123 1176 1176 1176 1186 1176
-			1176>;
+	qcom,slope = <3200 3200 3200 3200 3200 3200 3200 3200 3200
+			3200>;
+	qcom,calib-mode = "fuse_map1";
 };
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
index 6ebab2b..1c3cf29 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -41,18 +41,18 @@
 		qcom,mdss-pan-dsi-mdp-tr = <0x0>;
 		qcom,mdss-pan-dsi-dma-tr = <0x04>;
 		qcom,mdss-pan-frame-rate = <60>;
-		qcom,panel-phy-regulatorSettings = [03 01 01 00  /* Regualotor settings */
+		qcom,panel-phy-regulatorSettings = [07 09 03 00  /* Regualotor settings */
 						    20 00 01];
-		qcom,panel-phy-timingSettings = [69 29 1f 00 55 55
-						    19 2a 2a 03 04 00];
-		qcom,panel-phy-strengthCtrl = [77 06];
+		qcom,panel-phy-timingSettings = [b0 23 1b 00 94 93
+						    1e 25 15 03 04 00];
+		qcom,panel-phy-strengthCtrl = [ff 06];
 		qcom,panel-phy-bistCtrl = [00 00 b1 ff           /* BIST Ctrl settings */
 					   00 00];
-		qcom,panel-phy-laneConfig = [00 c2 45 00 00 00 00 01 75 /* lane0 config */
-					     00 c2 45 00 00 00 00 01 75 /* lane1 config */
-					     00 c2 45 00 00 00 00 01 75 /* lane2 config */
-					     00 c2 45 00 00 00 00 01 75 /* lane3 config */
-					     00 02 45 00 00 00 00 01 97]; /* Clk ln config */
+		qcom,panel-phy-laneConfig = [00 00 00 00 00 00 00 01 97 /* lane0 config */
+					     00 00 00 00 05 00 00 01 97 /* lane1 config */
+					     00 00 00 00 0a 00 00 01 97 /* lane2 config */
+					     00 00 00 00 0f 00 00 01 97 /* lane3 config */
+					     00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
 
 		qcom,panel-on-cmds = [23 01 00 00 0a 02 b0 00
 					23 01 00 00 0a 02 b2 00
diff --git a/arch/arm/boot/dts/msm-iommu-v0.dtsi b/arch/arm/boot/dts/msm-iommu-v0.dtsi
index c6eb1b9..59b2a90 100644
--- a/arch/arm/boot/dts/msm-iommu-v0.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v0.dtsi
@@ -130,14 +130,14 @@
 		qcom,iommu-ctx@fd860000 {
 			reg = <0xfd860000 0x1000>;
 			interrupts = <0 247 0>;
-			qcom,iommu-ctx-mids = <>;
+			qcom,iommu-ctx-mids = <0 1 3>;
 			label = "mdpe_0";
 		};
 
 		qcom,iommu-ctx@fd861000 {
 			reg = <0xfd861000 0x1000>;
 			interrupts = <0 247 0>;
-			qcom,iommu-ctx-mids = <>;
+			qcom,iommu-ctx-mids = <2>;
 			label = "mdpe_1";
 		};
 	};
@@ -155,14 +155,14 @@
 		qcom,iommu-ctx@fd870000 {
 			reg = <0xfd870000 0x1000>;
 			interrupts = <0 247 0>;
-			qcom,iommu-ctx-mids = <>;
+			qcom,iommu-ctx-mids = <0>;
 			label = "mdps_0";
 		};
 
 		qcom,iommu-ctx@fd871000 {
 			reg = <0xfd871000 0x1000>;
 			interrupts = <0 247 0>;
-			qcom,iommu-ctx-mids = <>;
+			qcom,iommu-ctx-mids = <1>;
 			label = "mdps_1";
 		};
 	};
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 94db3ea..ce4513b 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -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
@@ -15,4 +15,400 @@
 	#size-cells = <0>;
 	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>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		regulator@1400 {
+			regulator-name = "8226_s1";
+			spmi-dev-container;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qpnp-regulator";
+			reg = <0x1400 0x300>;
+			status = "disabled";
+
+			qcom,ctl@1400 {
+				reg = <0x1400 0x100>;
+			};
+			qcom,ps@1500 {
+				reg = <0x1500 0x100>;
+			};
+			qcom,freq@1600 {
+				reg = <0x1600 0x100>;
+			};
+		};
+
+		regulator@1700 {
+			regulator-name = "8226_s2";
+			spmi-dev-container;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qpnp-regulator";
+			reg = <0x1700 0x300>;
+			status = "disabled";
+
+			qcom,ctl@1700 {
+				reg = <0x1700 0x100>;
+			};
+			qcom,ps@1800 {
+				reg = <0x1800 0x100>;
+			};
+			qcom,freq@1900 {
+				reg = <0x1900 0x100>;
+			};
+		};
+
+		regulator@1a00 {
+			regulator-name = "8226_s3";
+			spmi-dev-container;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qpnp-regulator";
+			reg = <0x1a00 0x300>;
+			status = "disabled";
+
+			qcom,ctl@1a00 {
+				reg = <0x1a00 0x100>;
+			};
+			qcom,ps@1b00 {
+				reg = <0x1b00 0x100>;
+			};
+			qcom,freq@1c00 {
+				reg = <0x1c00 0x100>;
+			};
+		};
+
+		regulator@1d00 {
+			regulator-name = "8226_s4";
+			spmi-dev-container;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qpnp-regulator";
+			reg = <0x1d00 0x300>;
+			status = "disabled";
+
+			qcom,ctl@1d00 {
+				reg = <0x1d00 0x100>;
+			};
+			qcom,ps@1e00 {
+				reg = <0x1e00 0x100>;
+			};
+			qcom,freq@1f00 {
+				reg = <0x1f00 0x100>;
+			};
+		};
+
+		regulator@2000 {
+			regulator-name = "8226_s5";
+			spmi-dev-container;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qpnp-regulator";
+			reg = <0x2000 0x300>;
+			status = "disabled";
+
+			qcom,ctl@2000 {
+				reg = <0x2000 0x100>;
+			};
+			qcom,ps@2100 {
+				reg = <0x2100 0x100>;
+			};
+			qcom,freq@2200 {
+				reg = <0x2200 0x100>;
+			};
+		};
+
+		regulator@4000 {
+			regulator-name = "8226_l1";
+			reg = <0x4000 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4100 {
+			regulator-name = "8226_l2";
+			reg = <0x4100 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4200 {
+			regulator-name = "8226_l3";
+			reg = <0x4200 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4300 {
+			regulator-name = "8226_l4";
+			reg = <0x4300 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4400 {
+			regulator-name = "8226_l5";
+			reg = <0x4400 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4500 {
+			regulator-name = "8226_l6";
+			reg = <0x4500 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4600 {
+			regulator-name = "8226_l7";
+			reg = <0x4600 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4700 {
+			regulator-name = "8226_l8";
+			reg = <0x4700 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4800 {
+			regulator-name = "8226_l9";
+			reg = <0x4800 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4900 {
+			regulator-name = "8226_l10";
+			reg = <0x4900 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4b00 {
+			regulator-name = "8226_l12";
+			reg = <0x4b00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4d00 {
+			regulator-name = "8226_l14";
+			reg = <0x4d00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4e00 {
+			regulator-name = "8226_l15";
+			reg = <0x4e00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4f00 {
+			regulator-name = "8226_l16";
+			reg = <0x4f00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@5000 {
+			regulator-name = "8226_l17";
+			reg = <0x5000 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@5100 {
+			regulator-name = "8226_l18";
+			reg = <0x5100 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@5200 {
+			regulator-name = "8226_l19";
+			reg = <0x5200 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@5300 {
+			regulator-name = "8226_l20";
+			reg = <0x5300 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@5400 {
+			regulator-name = "8226_l21";
+			reg = <0x5400 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@5500 {
+			regulator-name = "8226_l22";
+			reg = <0x5500 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@5600 {
+			regulator-name = "8226_l23";
+			reg = <0x5600 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@5700 {
+			regulator-name = "8226_l24";
+			reg = <0x5700 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@5900 {
+			regulator-name = "8226_l26";
+			reg = <0x5900 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@5a00 {
+			regulator-name = "8226_l27";
+			reg = <0x5a00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@5b00 {
+			regulator-name = "8226_l28";
+			reg = <0x5b00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@8000 {
+			regulator-name = "8226_lvs1";
+			reg = <0x8000 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+	};
 };
diff --git a/arch/arm/boot/dts/msm8226-bus.dtsi b/arch/arm/boot/dts/msm8226-bus.dtsi
new file mode 100644
index 0000000..28d0840
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-bus.dtsi
@@ -0,0 +1,1126 @@
+/* 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.
+ */
+
+/ {
+	msm-mmss-noc@fc478000 {
+		compatible = "msm-bus-fabric";
+		reg = <0xfc478000 0x00004000>;
+		cell-id = <2048>;
+		label = "msm_mmss_noc";
+		qcom,fabclk-dual = "bus_clk";
+		qcom,fabclk-active = "bus_a_clk";
+		qcom,ntieredslaves = <0>;
+		qcom,qos-freq = <4800>;
+		qcom,hw-sel = "NoC";
+		qcom,rpm-en;
+
+		mas-gfx3d {
+			cell-id = <26>;
+			label = "mas-gfx3d";
+			qcom,masterp = <2>;
+			qcom,tier = <2>;
+			qcom,hw-sel = "NoC";
+			qcom,perm-mode = "Bypass";
+			qcom,mode = "Bypass";
+			qcom,ws = <10000>;
+			qcom,qport = <2>;
+			qcom,mas-hw-id = <6>;
+		};
+
+		mas-jpeg {
+			cell-id = <62>;
+			label = "mas-jpeg";
+			qcom,masterp = <4>;
+			qcom,tier = <2>;
+			qcom,hw-sel = "NoC";
+			qcom,perm-mode = "Bypass";
+			qcom,mode = "Bypass";
+			qcom,qport = <0>;
+			qcom,ws = <10000>;
+			qcom,mas-hw-id = <7>;
+		};
+
+		mas-mdp-port0 {
+			cell-id = <22>;
+			label = "mas-mdp-port0";
+			qcom,masterp = <5>;
+			qcom,tier = <2>;
+			qcom,hw-sel = "NoC";
+			qcom,perm-mode = "Bypass";
+			qcom,mode = "Bypass";
+			qcom,qport = <1>;
+			qcom,ws = <10000>;
+			qcom,mas-hw-id = <8>;
+		};
+
+		mas-video-p0 {
+			cell-id = <63>;
+			label = "mas-video-p0";
+			qcom,masterp = <6>;
+			qcom,tier = <2>;
+			qcom,hw-sel = "NoC";
+			qcom,perm-mode = "Bypass";
+			qcom,mode = "Bypass";
+			qcom,ws = <10000>;
+			qcom,qport = <4>;
+			qcom,mas-hw-id = <9>;
+		};
+
+		mas-vfe {
+			cell-id = <29>;
+			label = "mas-vfe";
+			qcom,masterp = <16>;
+			qcom,tier = <2>;
+			qcom,hw-sel = "NoC";
+			qcom,perm-mode = "Bypass";
+			qcom,mode = "Bypass";
+			qcom,ws = <10000>;
+			qcom,qport = <6>;
+			qcom,mas-hw-id = <11>;
+		};
+
+		fab-cnoc {
+			cell-id = <5120>;
+			label = "fab-cnoc";
+			qcom,gateway;
+			qcom,masterp = <0 1>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "RPM";
+			qcom,mas-hw-id = <4>;
+		};
+
+		fab-bimc {
+			cell-id = <0>;
+			label = "fab-bimc";
+			qcom,gateway;
+			qcom,slavep = <16>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "NoC";
+			qcom,slv-hw-id = <16>;
+		};
+
+		slv-camera-cfg {
+			cell-id = <589>;
+			label = "slv-camera-cfg";
+			qcom,slavep = <0>;
+			qcom,tier = <2>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "NoC";
+			qcom,slv-hw-id = <3>;
+		};
+
+		slv-display-cfg {
+			cell-id = <590>;
+			label = "slv-display-cfg";
+			qcom,slavep = <1>;
+			qcom,tier = <2>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "NoC";
+			qcom,slv-hw-id = <4>;
+		};
+
+		slv-ocmem-cfg {
+			cell-id = <591>;
+			label = "slv-ocmem-cfg";
+			qcom,slavep = <2>;
+			qcom,tier = <2>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "NoC";
+			qcom,slv-hw-id = <5>;
+		};
+
+		slv-cpr-cfg {
+			cell-id = <592>;
+			label = "slv-cpr-cfg";
+			qcom,slavep = <3>;
+			qcom,tier = <2>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "NoC";
+			qcom,slv-hw-id = <6>;
+		};
+
+		slv-cpr-xpu-cfg {
+			cell-id = <593>;
+			label = "slv-cpr-xpu-cfg";
+			qcom,slavep = <4>;
+			qcom,tier = <2>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "NoC";
+			qcom,slv-hw-id = <7>;
+		};
+
+		slv-misc-cfg {
+			cell-id = <594>;
+			label = "slv-misc-cfg";
+			qcom,slavep = <6>;
+			qcom,tier = <2>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "NoC";
+			qcom,slv-hw-id = <8>;
+		};
+
+		slv-misc-xpu-cfg {
+			cell-id = <595>;
+			label = "slv-misc-xpu-cfg";
+			qcom,slavep = <7>;
+			qcom,tier = <2>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "NoC";
+			qcom,slv-hw-id = <9>;
+		};
+
+		slv-venus-cfg {
+			cell-id = <596>;
+			label = "slv-venus-cfg";
+			qcom,slavep = <8>;
+			qcom,tier = <2>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "NoC";
+			qcom,slv-hw-id = <10>;
+		};
+
+		slv-gfx3d-cfg {
+			cell-id = <598>;
+			label = "slv-gfx3d-cfg";
+			qcom,slavep = <9>;
+			qcom,tier = <2>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "NoC";
+			qcom,slv-hw-id = <11>;
+		};
+
+		slv-mmss-clk-cfg {
+			cell-id = <599>;
+			label = "slv-mmss-clk-cfg";
+			qcom,slavep = <11>;
+			qcom,tier = <2>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "NoC";
+			qcom,slv-hw-id = <12>;
+		};
+
+		slv-mmss-clk-xpu-cfg {
+			cell-id = <600>;
+			label = "slv-mmss-clk-xpu-cfg";
+			qcom,slavep = <12>;
+			qcom,tier = <2>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "NoC";
+			qcom,slv-hw-id = <13>;
+		};
+
+		slv-mnoc-mpu-cfg {
+			cell-id = <601>;
+			label = "slv-mnoc-mpu-cfg";
+			qcom,slavep = <13>;
+			qcom,tier = <2>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "NoC";
+			qcom,slv-hw-id = <14>;
+		};
+
+		slv-onoc-mpu-cfg {
+			cell-id = <602>;
+			label = "slv-onoc-mpu-cfg";
+			qcom,slavep = <14>;
+			qcom,tier = <2>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "NoC";
+			qcom,slv-hw-id = <15>;
+		};
+
+		slv-service-mnoc {
+			cell-id = <603>;
+			label = "slv-service-mnoc";
+			qcom,slavep = <18>;
+			qcom,tier = <2>;
+			qcom,buswidth = <16>;
+			qcom,hw-sel = "NoC";
+			qcom,slv-hw-id = <17>;
+		};
+
+	};
+
+	msm-sys-noc@fc460000 {
+		compatible = "msm-bus-fabric";
+		reg = <0xfc460000 0x00004000>;
+		cell-id = <1024>;
+		label = "msm_sys_noc";
+		qcom,fabclk-dual = "bus_clk";
+		qcom,fabclk-active = "bus_a_clk";
+		qcom,ntieredslaves = <0>;
+		qcom,qos-freq = <4800>;
+		qcom,hw-sel = "NoC";
+		qcom,rpm-en;
+
+		mas-lpass-ahb {
+			cell-id = <52>;
+			label = "mas-lpass-ahb";
+			qcom,masterp = <0>;
+			qcom,tier = <2>;
+			qcom,qport = <0>;
+			qcom,mas-hw-id = <18>;
+			qcom,mode = "Fixed";
+			qcom,prio-rd = <2>;
+			qcom,prio-wr = <2>;
+		};
+
+		mas-qdss-bam {
+			cell-id = <53>;
+			label = "mas-qdss-bam";
+			qcom,masterp = <1>;
+			qcom,tier = <2>;
+			qcom,mode = "Fixed";
+			qcom,qport = <1>;
+			qcom,mas-hw-id = <19>;
+		};
+
+		mas-snoc-cfg {
+			cell-id = <54>;
+			label = "mas-snoc-cfg";
+			qcom,masterp = <2>;
+			qcom,tier = <2>;
+			qcom,mas-hw-id = <20>;
+		};
+
+		fab-bimc {
+			cell-id = <0>;
+			label= "fab-bimc";
+			qcom,gateway;
+			qcom,slavep = <7>;
+			qcom,masterp = <3>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <21>;
+			qcom,slv-hw-id = <24>;
+		};
+
+		fab-cnoc {
+			cell-id = <5120>;
+			label = "fab-cnoc";
+			qcom,gateway;
+			qcom,slavep = <8>;
+			qcom,masterp = <4>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <22>;
+			qcom,slv-hw-id = <25>;
+		};
+
+		fab-pnoc {
+			cell-id = <4096>;
+			label = "fab-pnoc";
+			qcom,gateway;
+			qcom,slavep = <10>;
+			qcom,masterp = <10>;
+			qcom,buswidth = <8>;
+			qcom,qport = <8>;
+			qcom,mas-hw-id = <29>;
+			qcom,slv-hw-id = <28>;
+			qcom,mode = "Fixed";
+			qcom,prio-rd = <2>;
+			qcom,prio-wr = <2>;
+		};
+
+		fab-ovnoc {
+			cell-id = <6144>;
+			label = "fab-ovnoc";
+			qcom,gateway;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <53>;
+			qcom,slv-hw-id = <77>;
+		};
+
+		mas-crypto-core0 {
+			cell-id = <55>;
+			label = "mas-crypto-core0";
+			qcom,masterp = <5>;
+			qcom,tier = <2>;
+			qcom,mode = "Fixed";
+/*			qcom,qport = <2>;*/
+			qcom,mas-hw-id = <23>;
+			qcom,hw-sel = "NoC";
+			qcom,prio-rd = <1>;
+			qcom,prio-wr = <1>;
+		};
+
+		mas-lpass-proc {
+			cell-id = <11>;
+			label = "mas-lpass-proc";
+			qcom,masterp = <6>;
+			qcom,tier = <2>;
+			qcom,qport = <4>;
+			qcom,mas-hw-id = <25>;
+			qcom,mode = "Fixed";
+			qcom,prio-rd = <2>;
+			qcom,prio-wr = <2>;
+		};
+
+		mas-mss {
+			cell-id = <38>;
+			label = "mas-mss";
+			qcom,masterp = <7>;
+			qcom,tier = <2>;
+			qcom,mas-hw-id = <26>;
+		};
+
+		mas-mss-nav {
+			cell-id = <57>;
+			label = "mas-mss-nav";
+			qcom,masterp = <8>;
+			qcom,tier = <2>;
+			qcom,mas-hw-id = <27>;
+		};
+
+		mas-ocmem-dma {
+			cell-id = <58>;
+			label = "mas-ocmem-dma";
+			qcom,masterp = <9>;
+			qcom,tier = <2>;
+			qcom,mode = "Fixed";
+			qcom,qport = <7>;
+			qcom,mas-hw-id = <28>;
+		};
+
+		mas-wcss {
+			cell-id = <59>;
+			label = "mas-wcss";
+			qcom,masterp = <11>;
+			qcom,tier = <2>;
+			qcom,mas-hw-id = <30>;
+		};
+
+		mas-qdss-etr {
+			cell-id = <60>;
+			label = "mas-qdss-etr";
+			qcom,masterp = <12>;
+			qcom,tier = <2>;
+			qcom,qport = <10>;
+			qcom,mode = "Fixed";
+			qcom,mas-hw-id = <31>;
+		};
+
+		slv-ampss {
+			cell-id = <520>;
+			label = "slv-ampss";
+			qcom,slavep = <1>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <20>;
+		};
+
+		slv-lpass {
+			cell-id = <522>;
+			label = "slv-lpass";
+			qcom,slavep = <2>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <21>;
+		};
+
+		slv-wcss {
+			cell-id = <584>;
+			label = "slv-wcss";
+			qcom,slavep = <6>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <23>;
+		};
+
+		slv-ocimem {
+			cell-id = <585>;
+			label = "slv-ocimem";
+			qcom,slavep = <9>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <26>;
+		};
+
+		slv-service-snoc {
+			cell-id = <587>;
+			label = "slv-service-snoc";
+			qcom,slavep = <11>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <29>;
+		};
+
+		slv-qdss-stm {
+			cell-id = <588>;
+			label = "slv-qdss-stm";
+			qcom,slavep = <12>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <30>;
+		};
+
+	};
+
+	msm-periph-noc@fc468000 {
+		compatible = "msm-bus-fabric";
+		reg = <0xfc468000 0x00004000>;
+		cell-id = <4096>;
+		label = "msm_periph_noc";
+		qcom,fabclk-dual = "bus_clk";
+		qcom,fabclk-active = "bus_a_clk";
+		qcom,ntieredslaves = <0>;
+		qcom,hw-sel = "NoC";
+		qcom,rpm-en;
+
+		mas-pnoc-cfg {
+			cell-id = <88>;
+			label = "mas-pnoc-cfg";
+			qcom,masterp = <7>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <43>;
+		};
+
+		mas-sdcc-1 {
+			cell-id = <78>;
+			label = "mas-sdcc-1";
+			qcom,masterp = <0>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <33>;
+		};
+
+		mas-sdcc-3 {
+			cell-id = <79>;
+			label = "mas-sdcc-3";
+			qcom,masterp = <1>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <34>;
+		};
+
+		mas-sdcc-2 {
+			cell-id = <81>;
+			label = "mas-sdcc-2";
+			qcom,masterp = <2>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <35>;
+		};
+
+		mas-bam-dma {
+			cell-id = <83>;
+			label = "mas-bam-dma";
+			qcom,masterp = <3>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <38>;
+		};
+
+		mas-usb-hsic {
+			cell-id = <85>;
+			label = "mas-usb-hsic";
+			qcom,masterp = <4>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <40>;
+		};
+
+		mas-blsp-1 {
+			cell-id = <86>;
+			label = "mas-blsp-1";
+			qcom,masterp = <5>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <41>;
+		};
+
+		mas-usb-hs {
+			cell-id = <87>;
+			label = "mas-usb-hs";
+			qcom,masterp = <6>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <42>;
+		};
+
+		fab-snoc {
+			cell-id = <1024>;
+			label = "fab-snoc";
+			qcom,gateway;
+			qcom,slavep = <12>;
+			qcom,masterp = <8>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <45>;
+			qcom,mas-hw-id = <44>;
+		};
+
+		slv-sdcc-1 {
+			cell-id = <606>;
+			label = "slv-sdcc-1";
+			qcom,slavep = <0>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <31>;
+		};
+
+		slv-sdcc-3 {
+			cell-id = <607>;
+			label = "slv-sdcc-3";
+			qcom,slavep = <1>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <32>;
+		};
+
+		slv-sdcc-2 {
+			cell-id = <608>;
+			label = "slv-sdcc-2";
+			qcom,slavep = <2>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <33>;
+		};
+
+		slv-bam-dma {
+			cell-id = <610>;
+			label = "slv-bam-dma";
+			qcom,slavep = <3>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <36>;
+		};
+
+		slv-usb-hsic {
+			cell-id = <612>;
+			label = "slv-usb-hsic";
+			qcom,slavep = <4>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <38>;
+		};
+
+		slv-blsp-1 {
+			cell-id = <613>;
+			label = "slv-blsp-1";
+			qcom,slavep = <5>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <39>;
+		};
+
+		slv-usb-hs {
+			cell-id = <614>;
+			label = "slv-usb-hs";
+			qcom,slavep = <6>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <40>;
+		};
+
+		slv-pdm	{
+			cell-id = <615>;
+			label = "slv-pdm";
+			qcom,slavep = <7>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <41>;
+		};
+
+		slv-periph-apu-cfg {
+			cell-id = <616>;
+			label = "slv-periph-apu-cfg";
+			qcom,slavep = <8>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <42>;
+		};
+
+		slv-pnoc-mpu-cfg {
+			cell-id = <617>;
+			label = "slv-pnoc-mpu-cfg";
+			qcom,slavep = <9>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <43>;
+		};
+
+		slv-prng {
+			cell-id = <618>;
+			label = "slv-prng";
+			qcom,slavep = <10>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <44>;
+		};
+
+		slv-service-pnoc {
+			cell-id = <619>;
+			label = "slv-service-pnoc";
+			qcom,slavep = <12>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <46>;
+		};
+
+	};
+
+	msm-config-noc@fc480000 {
+		compatible = "msm-bus-fabric";
+		reg = <0xfc480000 0x00004000>;
+		cell-id = <5120>;
+		label = "msm_config_noc";
+		qcom,fabclk-dual = "bus_clk";
+		qcom,fabclk-active = "bus_a_clk";
+		qcom,ntieredslaves = <0>;
+		qcom,hw-sel = "NoC";
+		qcom,rpm-en;
+
+		mas-rpm-inst {
+			cell-id = <72>;
+			label = "mas-rpm-inst";
+			qcom,masterp = <0>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <45>;
+		};
+
+		mas-rpm-data {
+			cell-id = <73>;
+			label = "mas-rpm-data";
+			qcom,masterp = <1>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <46>;
+		};
+
+		mas-rpm-sys {
+			cell-id = <74>;
+			label = "mas-rpm-sys";
+			qcom,masterp = <2>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <47>;
+		};
+
+		mas-dehr {
+			cell-id = <75>;
+			label = "mas-dehr";
+			qcom,masterp = <3>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <48>;
+		};
+
+		mas-qdss-dsp {
+			cell-id = <76>;
+			label = "mas-qdss-dap";
+			qcom,masterp = <4>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <49>;
+		};
+
+		mas-spdm {
+			cell-id = <36>;
+			label = "mas-spdm";
+			qcom,masterp = <5>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <50>;
+		};
+
+		mas-tic	{
+			cell-id = <77>;
+			label = "mas-tic";
+			qcom,masterp = <6>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <51>;
+		};
+
+		slv-clk-ctl {
+			cell-id = <620>;
+			label = "slv-clk-ctl";
+			qcom,slavep = <1>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <47>;
+		};
+
+		slv-cnoc-mss {
+			cell-id = <621>;
+			label = "slv-cnoc-mss";
+			qcom,slavep = <2>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <48>;
+		};
+
+		slv-security {
+			cell-id = <622>;
+			label = "slv-security";
+			qcom,slavep = <3>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <49>;
+		};
+
+		slv-tcsr {
+			cell-id = <623>;
+			label = "slv-tcsr";
+			qcom,slavep = <4>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <50>;
+		};
+
+		slv-tlmm {
+			cell-id = <624>;
+			label = "slv-tlmm";
+			qcom,slavep = <5>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <51>;
+		};
+
+		slv-crypto-0-cfg {
+			cell-id = <625>;
+			label = "slv-crypto-0-cfg";
+			qcom,slavep = <6>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <52>;
+		};
+
+		slv-imem-cfg {
+			cell-id = <627>;
+			label = "slv-imem-cfg";
+			qcom,slavep = <7>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <54>;
+		};
+
+		slv-message-ram	{
+			cell-id = <628>;
+			label = "slv-message-ram";
+			qcom,slavep = <8>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <55>;
+		};
+
+		slv-bimc-cfg {
+			cell-id = <629>;
+			label = "slv-bimc-cfg";
+			qcom,slavep = <9>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <56>;
+		};
+
+		slv-boot-rom {
+			cell-id = <630>;
+			label = "slv-boot-rom";
+			qcom,slavep = <10>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <57>;
+		};
+
+		slv-pmic-arb {
+			cell-id = <632>;
+			label = "slv-pmic-arb";
+			qcom,slavep = <12>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <59>;
+		};
+
+		slv-spdm-wrapper {
+			cell-id = <633>;
+			label = "slv-spdm-wrapper";
+			qcom,slavep = <13>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <60>;
+		};
+
+		slv-dehr-cfg {
+			cell-id = <634>;
+			label = "slv-dehr-cfg";
+			qcom,slavep = <14>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <61>;
+		};
+
+		slv-mpm	{
+			cell-id = <536>;
+			label = "slv-mpm";
+			qcom,slavep = <15>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <62>;
+		};
+
+		slv-qdss-cfg {
+			cell-id = <635>;
+			label = "slv-qdss-cfg";
+			qcom,slavep = <16>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <63>;
+		};
+
+		slv-rbcpr-cfg {
+			cell-id = <636>;
+			label = "slv-rbcpr-cfg";
+			qcom,slavep = <17>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <64>;
+		};
+
+		slv-rbcpr-qdss-apu-cfg {
+			cell-id = <637>;
+			label = "slv-rbcpr-qdss-apu-cfg";
+			qcom,slavep = <18>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <65>;
+		};
+
+		fab-snoc {
+			cell-id = <1024>;
+			label = "fab-snoc";
+			qcom,gateway;
+			qcom,slavep = <26>;
+			qcom,masterp = <7>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <52>;
+			qcom,slv-hw-id = <75>;
+		};
+
+		slv-cnoc-mnoc-mmss-cfg {
+			cell-id = <631>;
+			label = "slv-cnoc-mnoc-mmss-cfg";
+			qcom,slavep = <11>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <58>;
+		};
+
+		slv-cnoc-mnoc-cfg {
+			cell-id = <640>;
+			label = "slv-cnoc-mnoc-cfg";
+			qcom,slavep = <19>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <66>;
+		};
+
+		slv-pnoc-cfg {
+			cell-id = <641>;
+			label = "slv-pnoc-cfg";
+			qcom,slavep = <21>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <69>;
+		};
+
+		slv-snoc-mpu-cfg {
+			cell-id = <638>;
+			label = "slv-snoc-mpu-cfg";
+			qcom,slavep = <20>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <67>;
+		};
+
+		slv-snoc-cfg {
+			cell-id = <642>;
+			label = "slv-snoc-cfg";
+			qcom,slavep = <22>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <70>;
+		};
+
+		slv-phy-apu-cfg {
+			cell-id = <644>;
+			label = "slv-phy-apu-cfg";
+			qcom,slavep = <23>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <72>;
+		};
+
+		slv-ebi1-phy-cfg {
+			cell-id = <645>;
+			label = "slv-ebi1-phy-cfg";
+			qcom,slavep = <24>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <73>;
+		};
+
+		slv-rpm {
+			cell-id = <534>;
+			label = "slv-rpm";
+			qcom,slavep = <25>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <74>;
+		};
+
+		slv-service-cnoc {
+			cell-id = <646>;
+			label = "slv-service-cnoc";
+			qcom,slavep = <27>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <76>;
+		};
+
+	};
+
+	msm-bimc@0xfc380000 {
+		compatible = "msm-bus-fabric";
+		reg = <0xfc380000 0x0006A000>;
+		cell-id = <0>;
+		label = "msm_bimc";
+		qcom,fabclk-dual = "mem_clk";
+		qcom,fabclk-active = "mem_a_clk";
+		qcom,ntieredslaves = <0>;
+		qcom,qos-freq = <4800>;
+		qcom,hw-sel = "BIMC";
+		qcom,rpm-en;
+
+		mas-ampss-m0 {
+			cell-id = <1>;
+			label = "mas-ampss-m0";
+			qcom,masterp = <0>;
+			qcom,tier = <2>;
+			qcom,hw-sel = "BIMC";
+			qcom,mode = "Fixed";
+			qcom,qport = <0>;
+			qcom,ws = <10000>;
+			qcom,mas-hw-id = <0>;
+			qcom,prio-rd = <1>;
+			qcom,prio-wr = <1>;
+		};
+
+		mas-mss-proc {
+			cell-id = <65>;
+			label = "mas-mss-proc";
+			qcom,masterp = <1>;
+			qcom,tier = <2>;
+			qcom,hw-sel = "RPM";
+			qcom,mas-hw-id = <1>;
+		};
+
+		fab-mmss-noc {
+			cell-id = <2048>;
+			label = "fab_mmss_noc";
+			qcom,gateway;
+			qcom,masterp = <2>;
+			qcom,qport = <2>;
+			qcom,buswidth = <8>;
+			qcom,ws = <10000>;
+			qcom,mas-hw-id = <2>;
+			qcom,hw-sel = "BIMC";
+			qcom,mode = "Bypass";
+		};
+
+		fab-snoc {
+			cell-id = <1024>;
+			label = "fab-snoc";
+			qcom,gateway;
+			qcom,slavep = <2>;
+			qcom,masterp = <4>;
+			qcom,qport = <4>;
+			qcom,buswidth = <8>;
+			qcom,ws = <10000>;
+			qcom,mas-hw-id = <3>;
+			qcom,slv-hw-id = <2>;
+		};
+
+		slv-ebi-ch0 {
+			cell-id = <512>;
+			label = "slv-ebi-ch0";
+			qcom,slavep = <0>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <0>;
+			qcom,mode = "Bypass";
+		};
+
+		slv-ampss-l2 {
+			cell-id = <514>;
+			label = "slv-ampss-l2";
+			qcom,slavep = <1>;
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,slv-hw-id = <1>;
+		};
+	};
+
+	msm-ocmem-vnoc@6144 {
+		compatible = "msm-bus-fabric";
+		reg = <0x6144 0x2>;
+		cell-id = <6144>;
+		label = "msm-ocmem-vnoc";
+		qcom,ntieredslaves = <0>;
+		qcom,hw-sel = "NoC";
+		qcom,rpm-en;
+		qcom,virt;
+
+		mas-v-ocmem-gfx3d {
+			cell-id = <89>;
+			label = "mas-v-ocmem-gfx3d";
+			qcom,tier = <2>;
+			qcom,buswidth = <8>;
+			qcom,mas-hw-id = <55>;
+		};
+
+		slv-ocmem {
+			cell-id = <604>;
+			label = "slv-ocmem";
+			qcom,slavep = <0 1>;
+			qcom,tier = <2>;
+			qcom,buswidth = <16>;
+			qcom,slv-hw-id = <18>;
+			qcom,slaveclk-dual = "ocmem_clk";
+			qcom,slaveclk-active = "ocmem_a_clk";
+		};
+
+		fab-snoc {
+			cell-id = <1024>;
+			label = "fab-snoc";
+			qcom,gateway;
+			qcom,buswidth = <32>;
+			qcom,ws = <10000>;
+			qcom,mas-hw-id = <57>;
+			qcom,slv-hw-id = <80>;
+		};
+
+		fab-onoc {
+			cell-id = <3072>;
+			label = "fab-onoc";
+			qcom,gateway;
+			qcom,buswidth = <16>;
+			qcom,ws = <10000>;
+			qcom,mas-hw-id = <56>;
+			qcom,slv-hw-id = <79>;
+		};
+
+	};
+};
+
+
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 cb33a40..3ae69fd 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -17,6 +17,7 @@
 /include/ "msm8226-pm.dtsi"
 /include/ "msm8226-smp2p.dtsi"
 /include/ "msm8226-gpu.dtsi"
+/include/ "msm8226-bus.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226";
@@ -80,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>;
@@ -122,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>;
 
@@ -465,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 {
@@ -509,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";
 	};
@@ -528,6 +529,17 @@
 		compatible = "qcom,msm-mem-hole";
 		qcom,memblock-remove = <0x8100000 0x7e00000>; /* Address and Size of Hole */
 	};
+
+	tsens: tsens@fc4a8000 {
+		compatible = "qcom,msm-tsens";
+		reg = <0xfc4a8000 0x2000>,
+		      <0xfc4b8000 0x1000>;
+		reg-names = "tsens_physical", "tsens_eeprom_physical";
+		interrupts = <0 184 0>;
+		qcom,sensors = <7>;
+		qcom,slope = <3200 3200 3200 3200 3200 3200 3200>;
+		qcom,calib-mode = "fuse_map2";
+	};
 };
 
 &gdsc_venus {
@@ -554,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-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 2751d76..ceba72f 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -22,7 +22,8 @@
 
 		qcom,chipid = <0x03030000>;
 
-		qcom,initial-pwrlevel = <1>;
+		qcom,initial-pwrlevel = <2>;
+		qcom,step-pwrlevel = <2>;
 
 		qcom,idle-timeout = <8>; //<HZ/12>
 		qcom,nap-allowed = <1>;
@@ -31,13 +32,15 @@
 
 		/* Bus Scale Settings */
 		qcom,msm-bus,name = "grp3d";
-		qcom,msm-bus,num-cases = <4>;
+		qcom,msm-bus,num-cases = <6>;
 		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <2>;
 		qcom,msm-bus,vectors-KBps =
 				<26 512 0 0>, <89 604 0 0>,
-				<26 512 0 1600000>, <89 604 0 3000000>,
+				<26 512 0 2200000>, <89 604 0 3000000>,
+				<26 512 0 4000000>, <89 604 0 3000000>,
 				<26 512 0 4000000>, <89 604 0 4500000>,
+				<26 512 0 6400000>, <89 604 0 4500000>,
 				<26 512 0 6400000>, <89 604 0 7600000>;
 
 		/* GDSC oxili regulators */
@@ -58,26 +61,40 @@
 			qcom,gpu-pwrlevel@0 {
 				reg = <0>;
 				qcom,gpu-freq = <450000000>;
-				qcom,bus-freq = <3>;
+				qcom,bus-freq = <5>;
 				qcom,io-fraction = <0>;
 			};
 
 			qcom,gpu-pwrlevel@1 {
 				reg = <1>;
 				qcom,gpu-freq = <300000000>;
-				qcom,bus-freq = <2>;
+				qcom,bus-freq = <4>;
 				qcom,io-fraction = <33>;
 			};
 
 			qcom,gpu-pwrlevel@2 {
 				reg = <2>;
+				qcom,gpu-freq = <300000000>;
+				qcom,bus-freq = <3>;
+				qcom,io-fraction = <33>;
+			};
+
+			qcom,gpu-pwrlevel@3 {
+				reg = <3>;
+				qcom,gpu-freq = <200000000>;
+				qcom,bus-freq = <2>;
+				qcom,io-fraction = <100>;
+			};
+
+			qcom,gpu-pwrlevel@4 {
+				reg = <4>;
 				qcom,gpu-freq = <200000000>;
 				qcom,bus-freq = <1>;
 				qcom,io-fraction = <100>;
 			};
 
-			qcom,gpu-pwrlevel@3 {
-				reg = <3>;
+			qcom,gpu-pwrlevel@5 {
+				reg = <5>;
 				qcom,gpu-freq = <27000000>;
 				qcom,bus-freq = <0>;
 				qcom,io-fraction = <0>;
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-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
similarity index 99%
rename from arch/arm/boot/dts/msm8974-pm.dtsi
rename to arch/arm/boot/dts/msm8974-v1-pm.dtsi
index f9b9e33..2de5fad 100644
--- a/arch/arm/boot/dts/msm8974-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-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index eb69c51..7930547 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -18,6 +18,7 @@
 
 /include/ "msm8974.dtsi"
 /include/ "msm8974-v1-iommu.dtsi"
+/include/ "msm8974-v1-pm.dtsi"
 
 / {
 	android_usb@fc42b0c8 {
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
index 584869d..c974884 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
@@ -71,6 +71,7 @@
 	};
 
 	venus_sec_bitstream: qcom,iommu-ctx@fdc8d000 {
+		qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84>;
 		label = "venus_sec_bitstream";
 	};
 
diff --git a/arch/arm/boot/dts/msm8974-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
similarity index 83%
copy from arch/arm/boot/dts/msm8974-pm.dtsi
copy to arch/arm/boot/dts/msm8974-v2-pm.dtsi
index f9b9e33..0ed55ff 100644
--- a/arch/arm/boot/dts/msm8974-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* 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
@@ -28,12 +28,11 @@
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
-				0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
+				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
+				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
 	};
 
 	qcom,spm@f9099000 {
@@ -51,12 +50,11 @@
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
-				0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
+				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
+				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
 	};
 
 	qcom,spm@f90a9000 {
@@ -74,12 +72,11 @@
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
-				0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
+				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
+				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
 	};
 
 	qcom,spm@f90b9000 {
@@ -97,12 +94,11 @@
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
-				0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
+				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
+				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
 	};
 
 	qcom,spm@f9012000 {
@@ -126,9 +122,10 @@
 		qcom,phase-port = <0x1>;
 		qcom,pfm-port = <0x2>;
 		qcom,saw2-spm-cmd-ret = [1f 00 20 03 22 00 0f];
-		qcom,saw2-spm-cmd-gdhs = [00 20 32 42 07 44 22 50 02 32 50 0f];
-		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
-				50 02 32 50 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 20 32 60 70 80 42 07 78 80 44 22 50
+				3b 60 02 32 50 0f];
+		qcom,saw2-spm-cmd-pc = [00 10 32 60 70 80 b0 11 42 07 01 b0 78
+				80 12 44 50 3b 60 02 32 50 0f];
 	};
 
 	qcom,lpm-resources {
@@ -179,13 +176,11 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,use-qtimer;
-
 		qcom,lpm-level@0 {
 			reg = <0x0>;
 			qcom,mode = <0>;        /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
 			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,l2 = <2>;          /* Retention */
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -202,7 +197,7 @@
 			reg = <0x1>;
 			qcom,mode = <4>;        /* MSM_PM_SLEEP_MODE_RETENTION*/
 			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,l2 = <2>;          /* Retention */
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -215,12 +210,11 @@
 			qcom,time-overhead = <105>;
 		};
 
-
 		qcom,lpm-level@2 {
 			reg = <0x2>;
 			qcom,mode = <2>;        /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
 			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,l2 = <2>;          /* Retention */
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -254,7 +248,7 @@
 			reg = <0x4>;
 			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
 			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,l2 = <1>;          /* GDHS */
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO  */
@@ -284,24 +278,9 @@
 
 		qcom,lpm-level@6 {
 			reg = <0x6>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
-			qcom,latency-us = <10300>;
-			qcom,ss-power = <63>;
-			qcom,energy-overhead = <2128000>;
-			qcom,time-overhead = <18200>;
-		};
-
-		qcom,lpm-level@7 {
-			reg = <0x7>;
 			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
 			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,l2 = <1>;          /* GDHS */
 			qcom,vdd-mem-upper-bound = <950000>; /* NORMAL */
 			qcom,vdd-mem-lower-bound = <950000>;  /* SVS SOC */
 			qcom,vdd-dig-upper-bound = <4>;  /* NORMAL */
@@ -312,8 +291,8 @@
 			qcom,time-overhead = <27000>;
 		};
 
-		qcom,lpm-level@8 {
-			reg = <0x8>;
+		qcom,lpm-level@7 {
+			reg = <0x7>;
 			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
 			qcom,xo = <0>;          /* OFF */
 			qcom,l2 = <0>;          /* OFF */
@@ -419,15 +398,12 @@
 			<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;
+		qcom,saw-turns-off-pll;
 	};
 
 	qcom,rpm-log@fc19dc00 {
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 09f559d..a245d8a 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -18,6 +18,7 @@
 
 /include/ "msm8974.dtsi"
 /include/ "msm8974-v2-iommu.dtsi"
+/include/ "msm8974-v2-pm.dtsi"
 
 / {
 	android_usb@fe8050c8 {
@@ -42,9 +43,13 @@
 		/* Off */
 		<26 512 0 0>, <89 604 0 0>,
 		/* SVS */
-		<26 512 0 2504000>, <89 604 0 2400000>,
+		<26 512 0 2400000>, <89 604 0 3000000>,
+		/* Nominal / SVS */
+		<26 512 0 4656000>, <89 604 0 3000000>,
 		/* Nominal */
-		<26 512 0 5016000>, <89 604 0 5334880>,
+		<26 512 0 4656000>, <89 604 0 5334880>,
+		/* Turbo / Nominal */
+		<26 512 0 7464000>, <89 604 0 5334880>,
 		/* Turbo */
 		<26 512 0 7464000>, <89 604 0 6400000>;
 };
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index b63b50f..8138f20 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -11,7 +11,6 @@
  */
 
 /include/ "skeleton.dtsi"
-/include/ "msm8974-pm.dtsi"
 /include/ "msm8974-camera.dtsi"
 /include/ "msm8974-coresight.dtsi"
 /include/ "msm-gdsc.dtsi"
@@ -26,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;
@@ -61,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>;
@@ -377,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>;
@@ -568,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>;
@@ -663,6 +670,13 @@
 
 	qcom,msm-pcm {
 		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <0>;
+	};
+
+	qcom,msm-pcm-low-latency {
+		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <1>;
+		qcom,msm-pcm-low-latency;
 	};
 
 	qcom,msm-pcm-routing {
@@ -884,12 +898,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 {
@@ -947,15 +955,9 @@
 		};
 
 		partition@80000 {
-			reg = <0x80000 0xA0000>;
+			reg = <0x100000 0x80000>;
 			qcom,ocmem-part-name = "lp_audio";
-			qcom,ocmem-part-min = <0xA0000>;
-		};
-
-		partition@E0000 {
-			reg = <0x120000 0x20000>;
-			qcom,ocmem-part-name = "other_os";
-			qcom,ocmem-part-min = <0x20000>;
+			qcom,ocmem-part-min = <0x80000>;
 		};
 
 		partition@100000 {
@@ -964,11 +966,6 @@
 			qcom,ocmem-part-min = <0x55000>;
 		};
 
-		partition@140000 {
-			reg = <0x140000 0x40000>;
-			qcom,ocmem-part-name = "sensors";
-			qcom,ocmem-part-min = <0x40000>;
-		};
 	};
 
 	rpm_bus: qcom,rpm-smd {
@@ -1044,6 +1041,7 @@
 		qcom,sensors = <11>;
 		qcom,slope = <3200 3200 3200 3200 3200 3200 3200 3200 3200
 				3200 3200>;
+		qcom,calib-mode = "fuse_map1";
 	};
 
 	qcom,msm-rtb {
@@ -1261,6 +1259,10 @@
 			qcom,irq-no-suspend;
 		};
 	};
+
+	qcom,bcl {
+		compatible = "qcom,bcl";
+	};
 };
 
 &gdsc_venus {
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 2bdd9fd..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>;
@@ -379,6 +382,7 @@
 		interrupts = <0 184 0>;
 		qcom,sensors = <5>;
 		qcom,slope = <3200 3200 3200 3200 3200>;
+		qcom,calib-mode = "fuse_map1";
 	};
 
 	qcom,msm-rng@f9bff000 {
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index ac92e9d..2bf4630 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -139,9 +139,11 @@
 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
+CONFIG_REGULATOR_QPNP=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_FB=y
@@ -215,3 +217,5 @@
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
 CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8974=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index bd7c1a0..70e72e8 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -69,7 +69,6 @@
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
-CONFIG_MSM_OCMEM_NONSECURE=y
 CONFIG_MSM_RTB=y
 CONFIG_MSM_RTB_SEPARATE_CPUS=y
 CONFIG_MSM_CACHE_ERP=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 2f2e0b3..cd2593a 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -35,6 +35,7 @@
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_EFI_PARTITION=y
 CONFIG_IOSCHED_TEST=y
+CONFIG_DEFAULT_ROW=y
 CONFIG_ARCH_MSM=y
 CONFIG_ARCH_MSM8974=y
 CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
@@ -69,7 +70,6 @@
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
-CONFIG_MSM_OCMEM_NONSECURE=y
 CONFIG_MSM_RTB=y
 CONFIG_MSM_RTB_SEPARATE_CPUS=y
 CONFIG_MSM_CACHE_ERP=y
@@ -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
@@ -475,4 +476,3 @@
 CONFIG_CRYPTO_DEV_QCE=m
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
-CONFIG_DEFAULT_ROW=y
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 85b1bb3..8fb93d0 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -790,7 +790,7 @@
 			 */
 			if (cpu_pmu &&
 				cpu_pmu->plat_device->dev.platform_data) {
-				irq = platform_get_irq(cpu_pmu->plat_device, 1);
+				irq = platform_get_irq(cpu_pmu->plat_device, 0);
 				smp_call_function_single((int)hcpu,
 						disable_irq_callback, &irq, 1);
 			}
@@ -803,7 +803,7 @@
 			 */
 			if (cpu_pmu &&
 				cpu_pmu->plat_device->dev.platform_data) {
-				irq = platform_get_irq(cpu_pmu->plat_device, 1);
+				irq = platform_get_irq(cpu_pmu->plat_device, 0);
 				smp_call_function_single((int)hcpu,
 						enable_irq_callback, &irq, 1);
 			}
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/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 6ba11b2..d8f5425 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -252,7 +252,15 @@
 	{ 0, { 0 } }
 };
 
-static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+static struct pvs_table pvs_v1[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+	[0][0] = { acpu_freq_tbl_pvs0, sizeof(acpu_freq_tbl_pvs0) },
+	[0][1] = { acpu_freq_tbl_pvs1, sizeof(acpu_freq_tbl_pvs1) },
+	[0][2] = { acpu_freq_tbl_pvs2, sizeof(acpu_freq_tbl_pvs2) },
+	[0][3] = { acpu_freq_tbl_pvs3, sizeof(acpu_freq_tbl_pvs3) },
+	[0][4] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
+};
+
+static struct pvs_table pvs_v2[NUM_SPEED_BINS][NUM_PVS] __initdata = {
 	[0][0] = { acpu_freq_tbl_pvs0, sizeof(acpu_freq_tbl_pvs0) },
 	[0][1] = { acpu_freq_tbl_pvs1, sizeof(acpu_freq_tbl_pvs1) },
 	[0][2] = { acpu_freq_tbl_pvs2, sizeof(acpu_freq_tbl_pvs2) },
@@ -269,7 +277,7 @@
 	.scalable = scalable,
 	.scalable_size = sizeof(scalable),
 	.hfpll_data = &hfpll_data,
-	.pvs_tables = pvs_tables,
+	.pvs_tables = pvs_v2,
 	.l2_freq_tbl = l2_freq_tbl,
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
@@ -278,7 +286,7 @@
 	.stby_khz = 300000,
 };
 
-static void __init apply_l2_workaround(void)
+static void __init apply_v1_l2_workaround(void)
 {
 	static struct l2_level resticted_l2_tbl[] __initdata = {
 		[0] = { {  300000, PLL_0, 0,   0 }, LVL_LOW,  1050000, 0 },
@@ -290,7 +298,7 @@
 
 	for (s = 0; s < NUM_SPEED_BINS; s++)
 		for (p = 0; p < NUM_PVS; p++)
-			for (l = pvs_tables[s][p].table; l && l->speed.khz; l++)
+			for (l = pvs_v1[s][p].table; l && l->speed.khz; l++)
 				l->l2_level = l->l2_level > 5 ? 1 : 0;
 
 	acpuclk_8974_params.l2_freq_tbl = resticted_l2_tbl;
@@ -305,9 +313,11 @@
 	 * and 1497.6MHz (non-inclusive), or when vdd_mx is less than 1.05V.
 	 * Restrict L2 operation to safe performance points on these devices.
 	 */
-	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 2 &&
-	    SOCINFO_VERSION_MINOR(socinfo_get_version()) < 2)
-		apply_l2_workaround();
+	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1) {
+		acpuclk_8974_params.pvs_tables = pvs_v1;
+		if (SOCINFO_VERSION_MINOR(socinfo_get_version()) < 2)
+			apply_v1_l2_workaround();
+	}
 
 	return acpuclk_krait_init(&pdev->dev, &acpuclk_8974_params);
 }
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 f115d79..beb064b 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2644,7 +2644,6 @@
 	&apq8064_device_hsusb_host,
 	&android_usb_device,
 	&msm_device_wcnss_wlan,
-	&msm_device_iris_fm,
 	&apq8064_fmem_device,
 #ifdef CONFIG_ANDROID_PMEM
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -2695,8 +2694,6 @@
 	&msm_bus_8064_cpss_fpb,
 	&msm_pil_dsps,
 	&msm_8960_q6_lpass,
-	&msm_pil_vidc,
-	&msm_gss,
 	&apq8064_rtb_device,
 	&apq8064_dcvs_device,
 	&apq8064_msm_gov_device,
@@ -2726,10 +2723,6 @@
 	&apq8064_device_uart_gsbi1,
 	&apq8064_device_uart_gsbi4,
 	&msm_device_sps_apq8064,
-#ifdef CONFIG_MSM_ROTATOR
-	&msm_rotator_device,
-#endif
-	&msm8064_pc_cntr,
 };
 
 static struct platform_device *common_i2s_devices[] __initdata = {
@@ -2894,7 +2887,6 @@
 #ifdef CONFIG_MSM_ROTATOR
 	&msm_rotator_device,
 #endif
-	&msm8064_pc_cntr,
 };
 
 static struct platform_device
@@ -3867,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));
@@ -3976,12 +3970,10 @@
 
 	apq8064_common_init();
 	ethernet_init();
-	msm_rotator_set_split_iommu_domain();
 	fsm8064_ep_pcie_init();
 	platform_add_devices(ep_devices, ARRAY_SIZE(ep_devices));
 	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
 	apq8064_init_gpu();
-	platform_add_devices(apq8064_footswitch, apq8064_num_footswitch);
 	platform_device_register(&cdp_kp_pdev);
 #ifdef CONFIG_MSM_CAMERA
 	apq8064_init_cam();
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index ea943f9..2b331d0 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -27,6 +27,7 @@
 #ifdef CONFIG_ANDROID_PMEM
 #include <linux/android_pmem.h>
 #endif
+#include <linux/regulator/qpnp-regulator.h>
 #include <asm/mach/map.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach/arch.h>
@@ -104,6 +105,7 @@
 	msm_rpm_driver_init();
 	msm_lpmrs_module_init();
 	msm_spm_device_init();
+	qpnp_regulator_init();
 	if (machine_is_msm8226_rumi())
 		msm_clock_init(&msm8226_rumi_clock_init_data);
 	else
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index d974452..d045040 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -63,11 +63,9 @@
 		 * hardware revisions - maybe once that is done, this can be
 		 * reverted.
 		 */
-		.always_on = 1,
 		.lpm_sup = 1,
 		.hpm_uA = 800000, /* 800mA */
 		.lpm_uA = 9000,
-		.reset_at_init = true,
 	},
 };
 
@@ -311,13 +309,11 @@
 	 * This change to the boards will be true for newer versions of the SoC
 	 * as well.
 	 */
-	if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 1 &&
-			SOCINFO_VERSION_MINOR(socinfo_get_version()) >= 2) ||
-			machine_is_msm8930_cdp()) {
-		msm8960_sdc3_data.vreg_data->vdd_data->always_on = false;
-		msm8960_sdc3_data.vreg_data->vdd_data->reset_at_init = false;
+	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1 &&
+			SOCINFO_VERSION_MINOR(socinfo_get_version()) < 2) {
+		msm8960_sdc3_data.vreg_data->vdd_data->always_on = true;
+		msm8960_sdc3_data.vreg_data->vdd_data->reset_at_init = true;
 	}
-
 	/* SDC3: External card slot */
 	if (!machine_is_msm8930_cdp()) {
 		msm8960_sdc3_data.wpswitch_gpio = 0;
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-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index aca6494..54fe11e 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -205,19 +205,17 @@
 	REG_W(0x03, mdss_dsi_base + 0x0228); /* postDiv3 */
 
 	REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
-	REG_W(0x06, mdss_dsi_base + 0x027c); /* Cal CFG4 */
-	REG_W(0x05, mdss_dsi_base + 0x0264); /* Cal CFG4 */
+	REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
+	REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDET CFG2 */
 
 	REG_W(0x0a, mdss_dsi_base + 0x023c); /* SDM CFG1 */
 	REG_W(0xab, mdss_dsi_base + 0x0240); /* SDM CFG2 */
 	REG_W(0x0a, mdss_dsi_base + 0x0244); /* SDM CFG3 */
 	REG_W(0x00, mdss_dsi_base + 0x0248); /* SDM CFG4 */
 
-	udelay(10);
-
 	REG_W(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
 	REG_W(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
-	REG_W(0x01, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
+	REG_W(0x71, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
 	REG_W(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
 	REG_W(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
 
@@ -242,6 +240,22 @@
 	return 0;
 }
 
+static void mdss_dsi_uniphy_pll_lock_detect_setting(void)
+{
+	REG_W(0x04, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
+	udelay(100);
+	REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
+	udelay(500);
+}
+
+static void mdss_dsi_uniphy_pll_sw_reset(void)
+{
+	REG_W(0x01, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
+	udelay(1);
+	REG_W(0x00, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
+	udelay(1);
+}
+
 static int __mdss_dsi_pll_enable(struct clk *c)
 {
 	u32 status;
@@ -264,17 +278,23 @@
 
 	clk_enable(mdss_dsi_ahb_clk);
 
+	mdss_dsi_uniphy_pll_sw_reset();
 	/* PLL power up */
-	for (i = 0; i < 3; i++) {
-		REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
-		REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
-		udelay(20);
-		REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
-		udelay(20);
-		REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
+	/* Add HW recommended delay between
+	   register writes for the update to propagate */
+	REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
+	udelay(1000);
+	REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
+	udelay(1000);
+	REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
+	udelay(1000);
+	REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
+	udelay(1000);
 
+	for (i = 0; i < 3; i++) {
+		mdss_dsi_uniphy_pll_lock_detect_setting();
 		/* poll for PLL ready status */
-		max_reads = 20;
+		max_reads = 5;
 		timeout_us = 100;
 		if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
 				   status,
@@ -286,6 +306,24 @@
 			       __func__);
 		} else
 			break;
+
+		mdss_dsi_uniphy_pll_sw_reset();
+		udelay(1000);
+		/* Add HW recommended delay between
+		   register writes for the update to propagate */
+		REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
+		udelay(1000);
+		REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
+		udelay(1000);
+		REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
+		udelay(1000);
+		REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
+		udelay(1000);
+		REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
+		udelay(1000);
+		REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
+		udelay(2000);
+
 	}
 
 	if ((status & 0x01) != 1) {
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/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index c37b518..26a055d 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -201,6 +201,9 @@
 	struct ipa_ep_cfg_route route;
 };
 
+typedef void (*ipa_notify_cb)(void *priv, enum ipa_dp_evt_type evt,
+		       unsigned long data);
+
 /**
  * struct ipa_connect_params - low-level client connect input parameters. Either
  * client allocates the data and desc FIFO and specifies that in data+desc OR
@@ -228,8 +231,7 @@
 	u32 client_bam_hdl;
 	u32 client_ep_idx;
 	void *priv;
-	void (*notify)(void *priv, enum ipa_dp_evt_type evt,
-			unsigned long data);
+	ipa_notify_cb notify;
 	u32 desc_fifo_sz;
 	u32 data_fifo_sz;
 	bool pipe_mem_preferred;
@@ -290,22 +292,7 @@
 	enum ipa_client_type client;
 	u32 desc_fifo_sz;
 	void *priv;
-	void (*notify)(void *priv,
-			enum ipa_dp_evt_type evt,
-			unsigned long data);
-};
-
-/**
- * struct ipa_msg_meta_wrapper - message meta-data wrapper
- * @meta:	the meta-data itself
- * @link:	opaque to client
- * @meta_wrapper_free:	function to free the metadata wrapper when IPA driver
- *			is done with it
- */
-struct ipa_msg_meta_wrapper {
-	struct ipa_msg_meta meta;
-	struct list_head link;
-	void (*meta_wrapper_free)(struct ipa_msg_meta_wrapper *buff);
+	ipa_notify_cb notify;
 };
 
 /**
@@ -319,32 +306,53 @@
 };
 
 /**
- * struct ipa_msg_wrapper - message wrapper
- * @msg:	the message buffer itself, MUST exist after call returns, will
- *		be freed by IPA driver when it is done with it
- * @link:	opaque to client
- * @msg_free:	function to free the message when IPA driver is done with it
- * @msg_wrapper_free:	function to free the message wrapper when IPA driver is
- *			done with it
+ * typedef ipa_msg_free_fn - callback function
+ * @param buff - [in] the message payload to free
+ * @param len - [in] size of message payload
+ * @param type - [in] the message type
+ *
+ * Message callback registered by kernel client with IPA driver to
+ * free message payload after IPA driver processing is complete
+ *
+ * No return value
  */
-struct ipa_msg_wrapper {
-	void *msg;
-	struct list_head link;
-	void (*msg_free)(void *msg);
-	void (*msg_wrapper_free)(struct ipa_msg_wrapper *buff);
+typedef void (*ipa_msg_free_fn)(void *buff, u32 len, u32 type);
+
+/**
+ * typedef ipa_msg_pull_fn - callback function
+ * @param buff - [in] where to copy message payload
+ * @param len - [in] size of buffer to copy payload into
+ * @param type - [in] the message type
+ *
+ * Message callback registered by kernel client with IPA driver for
+ * IPA driver to pull messages from the kernel client upon demand from
+ * user-space
+ *
+ * Returns how many bytes were copied into the buffer.
+ */
+typedef int (*ipa_msg_pull_fn)(void *buff, u32 len, u32 type);
+
+/**
+ * enum ipa_bridge_dir - direction of the bridge from air interface perspective
+ *
+ * IPA bridge direction
+ */
+enum ipa_bridge_dir {
+	IPA_BRIDGE_DIR_DL,
+	IPA_BRIDGE_DIR_UL,
+	IPA_BRIDGE_DIR_MAX
 };
 
 /**
- * typedef ipa_pull_fn - callback function
- * @buf - [in] the buffer to populate the message into
- * @sz - [in] the size of the buffer
+ * enum ipa_bridge_type - type of SW bridge
  *
- * callback function registered by kernel client with IPA driver for IPA driver
- * to be able to pull messages from the kernel client asynchronously.
- *
- * Returns how many bytes were copied into the buffer, negative on failure.
+ * IPA bridge type
  */
-typedef int (*ipa_pull_fn)(void *buf, uint16_t sz);
+enum ipa_bridge_type {
+	IPA_BRIDGE_TYPE_TETHERED,
+	IPA_BRIDGE_TYPE_EMBEDDED,
+	IPA_BRIDGE_TYPE_MAX
+};
 
 #ifdef CONFIG_IPA
 
@@ -425,6 +433,21 @@
 int ipa_nat_del_cmd(struct ipa_ioc_v4_nat_del *del);
 
 /*
+ * Messaging
+ */
+int ipa_send_msg(struct ipa_msg_meta *meta, void *buff,
+		  ipa_msg_free_fn callback);
+int ipa_register_pull_msg(struct ipa_msg_meta *meta, ipa_msg_pull_fn callback);
+int ipa_deregister_pull_msg(struct ipa_msg_meta *meta);
+
+/*
+ * Interface
+ */
+int ipa_register_intf(const char *name, const struct ipa_tx_intf *tx,
+		       const struct ipa_rx_intf *rx);
+int ipa_deregister_intf(const char *name);
+
+/*
  * Aggregation
  */
 int ipa_set_aggr_mode(enum ipa_aggr_mode mode);
@@ -445,6 +468,15 @@
 			 int wwan_logical_channel_id);
 
 /*
+ * SW bridge (between IPA and A2)
+ */
+int ipa_bridge_setup(enum ipa_bridge_dir dir, enum ipa_bridge_type type,
+		     struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl);
+int ipa_bridge_teardown(enum ipa_bridge_dir dir, enum ipa_bridge_type type,
+			u32 clnt_hdl);
+
+
+/*
  * Data path
  */
 int ipa_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
@@ -473,7 +505,6 @@
 	return -EPERM;
 }
 
-
 /*
  * Configuration
  */
@@ -483,42 +514,36 @@
 	return -EPERM;
 }
 
-
 static inline int ipa_cfg_ep_nat(u32 clnt_hdl,
 		const struct ipa_ep_cfg_nat *ipa_ep_cfg)
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_cfg_ep_hdr(u32 clnt_hdl,
 		const struct ipa_ep_cfg_hdr *ipa_ep_cfg)
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_cfg_ep_mode(u32 clnt_hdl,
 		const struct ipa_ep_cfg_mode *ipa_ep_cfg)
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_cfg_ep_aggr(u32 clnt_hdl,
 		const struct ipa_ep_cfg_aggr *ipa_ep_cfg)
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_cfg_ep_route(u32 clnt_hdl,
 		const struct ipa_ep_cfg_route *ipa_ep_cfg)
 {
 	return -EPERM;
 }
 
-
 /*
  * Header removal / addition
  */
@@ -527,43 +552,36 @@
 	return -EPERM;
 }
 
-
 static inline int ipa_del_hdr(struct ipa_ioc_del_hdr *hdls)
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_commit_hdr(void)
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_reset_hdr(void)
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_get_hdr(struct ipa_ioc_get_hdr *lookup)
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_put_hdr(u32 hdr_hdl)
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_copy_hdr(struct ipa_ioc_copy_hdr *copy)
 {
 	return -EPERM;
 }
 
-
 /*
  * Routing
  */
@@ -572,37 +590,31 @@
 	return -EPERM;
 }
 
-
 static inline int ipa_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls)
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_commit_rt(enum ipa_ip_type ip)
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_reset_rt(enum ipa_ip_type ip)
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup)
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_put_rt_tbl(u32 rt_tbl_hdl)
 {
 	return -EPERM;
 }
 
-
 /*
  * Filtering
  */
@@ -611,25 +623,21 @@
 	return -EPERM;
 }
 
-
 static inline int ipa_del_flt_rule(struct ipa_ioc_del_flt_rule *hdls)
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_commit_flt(enum ipa_ip_type ip)
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_reset_flt(enum ipa_ip_type ip)
 {
 	return -EPERM;
 }
 
-
 /*
  * NAT
  */
@@ -656,6 +664,40 @@
 	return -EPERM;
 }
 
+/*
+ * Messaging
+ */
+static inline int ipa_send_msg(struct ipa_msg_meta *meta, void *buff,
+		ipa_msg_free_fn callback)
+{
+	return -EPERM;
+}
+
+static inline int ipa_register_pull_msg(struct ipa_msg_meta *meta,
+		ipa_msg_pull_fn callback)
+{
+	return -EPERM;
+}
+
+static inline int ipa_deregister_pull_msg(struct ipa_msg_meta *meta)
+{
+	return -EPERM;
+}
+
+/*
+ * Interface
+ */
+static inline int ipa_register_intf(const char *name,
+				     const struct ipa_tx_intf *tx,
+				     const struct ipa_rx_intf *rx)
+{
+	return -EPERM;
+}
+
+static inline int ipa_deregister_intf(const char *name)
+{
+	return -EPERM;
+}
 
 /*
  * Aggregation
@@ -665,19 +707,16 @@
 	return -EPERM;
 }
 
-
 static inline int ipa_set_qcncm_ndp_sig(char sig[3])
 {
 	return -EPERM;
 }
 
-
 static inline int ipa_set_single_ndp_per_mbim(bool enable)
 {
 	return -EPERM;
 }
 
-
 /*
  * rmnet bridge
  */
@@ -686,13 +725,11 @@
 	return -EPERM;
 }
 
-
 static inline int rmnet_bridge_disconnect(void)
 {
 	return -EPERM;
 }
 
-
 static inline int rmnet_bridge_connect(u32 producer_hdl,
 			 u32 consumer_hdl,
 			 int wwan_logical_channel_id)
@@ -700,6 +737,23 @@
 	return -EPERM;
 }
 
+/*
+ * SW bridge (between IPA and A2)
+ */
+static inline int ipa_bridge_setup(enum ipa_bridge_dir dir,
+				    enum ipa_bridge_type type,
+				    struct ipa_sys_connect_params *sys_in,
+				    u32 *clnt_hdl)
+{
+	return -EPERM;
+}
+
+static inline int ipa_bridge_teardown(enum ipa_bridge_dir dir,
+				       enum ipa_bridge_type type,
+				      u32 clnt_hdl)
+{
+	return -EPERM;
+}
 
 /*
  * Data path
@@ -710,7 +764,6 @@
 	return -EPERM;
 }
 
-
 /*
  * System pipes
  */
@@ -720,13 +773,11 @@
 	return -EPERM;
 }
 
-
 static inline int ipa_teardown_sys_pipe(u32 clnt_hdl)
 {
 	return -EPERM;
 }
 
-
 #endif /* CONFIG_IPA*/
 
 #endif /* _IPA_H_ */
diff --git a/arch/arm/mach-msm/include/mach/kgsl.h b/arch/arm/mach-msm/include/mach/kgsl.h
index 2447e81..b68aff8 100644
--- a/arch/arm/mach-msm/include/mach/kgsl.h
+++ b/arch/arm/mach-msm/include/mach/kgsl.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
@@ -21,7 +21,7 @@
 #define KGSL_CLK_MEM_IFACE 0x00000010
 #define KGSL_CLK_AXI	0x00000020
 
-#define KGSL_MAX_PWRLEVELS 5
+#define KGSL_MAX_PWRLEVELS 10
 
 #define KGSL_CONVERT_TO_MBPS(val) \
 	(val*1000*1000U)
@@ -73,6 +73,7 @@
 	unsigned int nap_allowed;
 	unsigned int clk_map;
 	unsigned int idle_needed;
+	unsigned int step_mul;
 	struct msm_bus_scale_pdata *bus_scale_table;
 	struct kgsl_device_iommu_data *iommu_data;
 	int iommu_count;
diff --git a/arch/arm/mach-msm/include/mach/msm_bus_board.h b/arch/arm/mach-msm/include/mach/msm_bus_board.h
index 390160d..8fd3cfc 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus_board.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus_board.h
@@ -102,6 +102,10 @@
 int msm_bus_board_rpm_get_il_ids(uint16_t *id);
 int msm_bus_board_get_iid(int id);
 
+#ifdef CONFIG_ARCH_MSM8226
+#define NFAB 6
+#endif
+
 /*
  * These macros specify the convention followed for allocating
  * ids to fabrics, masters and slaves for 8x60.
@@ -111,7 +115,6 @@
  */
 #define FABRIC_ID_KEY 1024
 #define SLAVE_ID_KEY ((FABRIC_ID_KEY) >> 1)
-#define NUM_FAB 5
 #define MAX_FAB_KEY 7168  /* OR(All fabric ids) */
 
 #define GET_FABID(id) ((id) & MAX_FAB_KEY)
@@ -300,7 +303,7 @@
 	MSM_BUS_MASTER_IPA,
 	MSM_BUS_MASTER_QPIC,
 
-	MSM_BUS_MASTER_LAST = MSM_BUS_MASTER_QPIC,
+	MSM_BUS_MASTER_LAST,
 
 	MSM_BUS_SYSTEM_FPB_MASTER_SYSTEM =
 		MSM_BUS_SYSTEM_MASTER_SYSTEM_FPB,
@@ -457,7 +460,7 @@
 	MSM_BUS_SLAVE_IPS_CFG,
 	MSM_BUS_SLAVE_QPIC,
 
-	MSM_BUS_SLAVE_LAST = MSM_BUS_SLAVE_QPIC,
+	MSM_BUS_SLAVE_LAST,
 
 	MSM_BUS_SYSTEM_FPB_SLAVE_SYSTEM =
 		MSM_BUS_SYSTEM_SLAVE_SYSTEM_FPB,
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 a4adfb8..abb5653 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.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
@@ -29,6 +29,16 @@
 #define TO_OCMEM 0x0
 #define TO_DDR 0x1
 
+#define OCMEM_SVC_ID 15
+#define OCMEM_LOCK_CMD_ID 0x1
+#define OCMEM_UNLOCK_CMD_ID 0x2
+#define OCMEM_ENABLE_DUMP_CMD_ID 0x3
+#define OCMEM_DISABLE_DUMP_CMD_ID 0x4
+
+#define OCMEM_SECURE_SVC_ID 12
+#define OCMEM_SECURE_CFG_ID 0x2
+#define OCMEM_SECURE_DEV_ID 0x5
+
 struct ocmem_zone;
 
 struct ocmem_zone_ops {
@@ -158,6 +168,8 @@
 	/* Request Power State */
 	unsigned power_state;
 	struct ocmem_eviction_data *edata;
+	/* Request that triggered eviction */
+	struct ocmem_req *e_handle;
 };
 
 struct ocmem_handle {
@@ -187,6 +199,10 @@
 int ocmem_notifier_init(void);
 int check_notifier(int);
 const char *get_name(int);
+int get_tz_id(int);
+int ocmem_enable_sec_program(int);
+int ocmem_enable_dump(enum ocmem_client, unsigned long, unsigned long);
+int ocmem_disable_dump(enum ocmem_client, unsigned long, unsigned long);
 int check_id(int);
 int dispatch_notification(int, enum ocmem_notif_type, struct ocmem_buf *);
 
@@ -197,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/include/mach/usb_gadget_xport.h b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
index 9cd4f3f..a183f0e 100644
--- a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
+++ b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
@@ -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
@@ -19,6 +19,7 @@
 	USB_GADGET_XPORT_TTY,
 	USB_GADGET_XPORT_SDIO,
 	USB_GADGET_XPORT_SMD,
+	USB_GADGET_XPORT_QTI,
 	USB_GADGET_XPORT_BAM,
 	USB_GADGET_XPORT_BAM2BAM,
 	USB_GADGET_XPORT_BAM2BAM_IPA,
@@ -38,6 +39,8 @@
 		return "SDIO";
 	case USB_GADGET_XPORT_SMD:
 		return "SMD";
+	case USB_GADGET_XPORT_QTI:
+		return "QTI";
 	case USB_GADGET_XPORT_BAM:
 		return "BAM";
 	case USB_GADGET_XPORT_BAM2BAM:
@@ -63,6 +66,8 @@
 		return USB_GADGET_XPORT_SDIO;
 	if (!strncasecmp("SMD", name, XPORT_STR_LEN))
 		return USB_GADGET_XPORT_SMD;
+	if (!strncasecmp("QTI", name, XPORT_STR_LEN))
+		return USB_GADGET_XPORT_QTI;
 	if (!strncasecmp("BAM", name, XPORT_STR_LEN))
 		return USB_GADGET_XPORT_BAM;
 	if (!strncasecmp("BAM2BAM", name, XPORT_STR_LEN))
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 01be641..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;
@@ -894,8 +903,6 @@
 
 	/* setup the bandgap that configures the reference to the LDO */
 	writel_relaxed(0x00000190, kvreg->mdd_base + MDD_CONFIG_CTL);
-	/* Enable MDD */
-	writel_relaxed(0x00000002, kvreg->mdd_base + MDD_MODE);
 	mb();
 }
 
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_bus/Makefile b/arch/arm/mach-msm/msm_bus/Makefile
index e785c00..2ee07f3 100644
--- a/arch/arm/mach-msm/msm_bus/Makefile
+++ b/arch/arm/mach-msm/msm_bus/Makefile
@@ -14,4 +14,5 @@
 obj-$(CONFIG_ARCH_MSM8930) += msm_bus_board_8930.o
 obj-$(CONFIG_ARCH_MSM8974) += msm_bus_board_8974.o
 obj-$(CONFIG_ARCH_MSM9625) += msm_bus_board_9625.o
+obj-$(CONFIG_ARCH_MSM8226) += msm_bus_id.o
 obj-$(CONFIG_DEBUG_FS) += msm_bus_dbg.o
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 0d28e9d..2c7ceab 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -837,7 +837,7 @@
 	.probe = msm_bus_fabric_probe,
 	.remove = msm_bus_fabric_remove,
 	.driver = {
-		.name = "msm-bus-fabric",
+		.name = "msm_bus_fabric",
 		.owner = THIS_MODULE,
 		.of_match_table = fabric_match,
 	},
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_id.c b/arch/arm/mach-msm/msm_bus/msm_bus_id.c
new file mode 100644
index 0000000..693c51e
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_id.c
@@ -0,0 +1,83 @@
+/* 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/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/rpm.h>
+#include "msm_bus_core.h"
+#include "msm_bus_noc.h"
+#include "msm_bus_bimc.h"
+
+static uint32_t master_iids[MSM_BUS_MASTER_LAST];
+static uint32_t slave_iids[MSM_BUS_SLAVE_LAST - SLAVE_ID_KEY];
+
+static void msm_bus_assign_iids(struct msm_bus_fabric_registration
+	*fabreg, int fabid)
+{
+	int i;
+	for (i = 0; i < fabreg->len; i++) {
+		if (!fabreg->info[i].gateway) {
+			fabreg->info[i].priv_id = fabid + fabreg->info[i].id;
+			if (fabreg->info[i].id < SLAVE_ID_KEY) {
+				WARN(fabreg->info[i].id >= MSM_BUS_MASTER_LAST,
+					"id %d exceeds array size!\n",
+					fabreg->info[i].id);
+				master_iids[fabreg->info[i].id] =
+					fabreg->info[i].priv_id;
+			} else {
+				WARN((fabreg->info[i].id - SLAVE_ID_KEY) >=
+					(MSM_BUS_SLAVE_LAST - SLAVE_ID_KEY),
+					"id %d exceeds array size!\n",
+					fabreg->info[i].id);
+				slave_iids[fabreg->info[i].id - (SLAVE_ID_KEY)]
+					= fabreg->info[i].priv_id;
+			}
+		} else {
+			fabreg->info[i].priv_id = fabreg->info[i].id;
+		}
+	}
+}
+
+static int msm_bus_get_iid(int id)
+{
+	if ((id < SLAVE_ID_KEY && id >= MSM_BUS_MASTER_LAST) ||
+		id >= MSM_BUS_SLAVE_LAST) {
+		MSM_BUS_ERR("Cannot get iid. Invalid id %d passed\n", id);
+		return -EINVAL;
+	}
+
+	return CHECK_ID(((id < SLAVE_ID_KEY) ? master_iids[id] :
+		slave_iids[id - SLAVE_ID_KEY]), id);
+}
+
+
+static struct msm_bus_board_algorithm msm_bus_id_algo = {
+	.board_nfab = NFAB,
+	.get_iid = msm_bus_get_iid,
+	.assign_iids = msm_bus_assign_iids,
+};
+
+int msm_bus_board_rpm_get_il_ids(uint16_t *id)
+{
+	return -ENXIO;
+}
+
+void msm_bus_board_init(struct msm_bus_fabric_registration *pdata)
+{
+	pdata->board_algo = &msm_bus_id_algo;
+}
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.c b/arch/arm/mach-msm/ocmem.c
index 1729742..4685f02 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -693,7 +693,7 @@
 }
 
 /* Enable the ocmem graphics mpU as a workaround */
-/* This will be programmed by TZ after TZ support is integrated */
+#ifdef CONFIG_MSM_OCMEM_NONSECURE
 static int ocmem_init_gfx_mpu(struct platform_device *pdev)
 {
 	int rc;
@@ -714,6 +714,12 @@
 	ocmem_disable_core_clock();
 	return 0;
 }
+#else
+static int ocmem_init_gfx_mpu(struct platform_device *pdev)
+{
+	return 0;
+}
+#endif /* CONFIG_MSM_OCMEM_NONSECURE */
 
 static int __devinit ocmem_debugfs_init(struct platform_device *pdev)
 {
@@ -783,6 +789,11 @@
 
 	platform_set_drvdata(pdev, ocmem_pdata);
 
+	/* Parameter to be updated based on TZ */
+	/* Allow the OCMEM CSR to be programmed */
+	if (ocmem_enable_sec_program(OCMEM_SECURE_DEV_ID))
+		return -EBUSY;
+
 	if (ocmem_debugfs_init(pdev))
 		return -EBUSY;
 
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
index ef3cbae..16dd8b8 100644
--- a/arch/arm/mach-msm/ocmem_api.c
+++ b/arch/arm/mach-msm/ocmem_api.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
@@ -52,9 +52,10 @@
 	ret = process_free(id, handle);
 	mutex_unlock(&handle->handle_mutex);
 
-	if (ret)
-		return -EINVAL;
-
+	if (ret) {
+		pr_err("ocmem: Free failed for client %s\n", get_name(id));
+		return ret;
+	}
 	free_handle(handle);
 	return 0;
 }
@@ -400,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_core.c b/arch/arm/mach-msm/ocmem_core.c
index a011576..4ea1de9 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -17,6 +17,7 @@
 
 #include <mach/ocmem_priv.h>
 #include <mach/rpm-smd.h>
+#include <mach/scm.h>
 
 static unsigned num_regions;
 static unsigned num_macros;
@@ -514,6 +515,23 @@
 	ocmem_clear(offset, len);
 	return 0;
 }
+
+int ocmem_enable_sec_program(int sec_id)
+{
+	return 0;
+}
+
+int ocmem_enable_dump(enum ocmem_client id, unsigned long offset,
+			unsigned long len)
+{
+	return 0;
+}
+
+int ocmem_disable_dump(enum ocmem_client id, unsigned long offset,
+			unsigned long len)
+{
+	return 0;
+}
 #else
 static int ocmem_gfx_mpu_set(unsigned long offset, unsigned long len)
 {
@@ -532,19 +550,117 @@
 static int do_lock(enum ocmem_client id, unsigned long offset,
 			unsigned long len, enum region_mode mode)
 {
-	return 0;
+	int rc;
+	struct ocmem_tz_lock {
+		u32 id;
+		u32 offset;
+		u32 size;
+	} request;
+
+	request.id = get_tz_id(id);
+	request.offset = offset;
+	request.size = len;
+
+	rc = scm_call(OCMEM_SVC_ID, OCMEM_LOCK_CMD_ID, &request,
+				sizeof(request), NULL, 0);
+	if (rc)
+		pr_err("ocmem: Failed to lock region %s[%lx -- %lx] ret = %d\n",
+				get_name(id), offset, offset + len - 1, rc);
+	return rc;
 }
 
 static int do_unlock(enum ocmem_client id, unsigned long offset,
 			unsigned long len)
 {
-	return 0;
+	int rc;
+	struct ocmem_tz_unlock {
+		u32 id;
+		u32 offset;
+		u32 size;
+	} request;
+
+	request.id = get_tz_id(id);
+	request.offset = offset;
+	request.size = len;
+
+	rc = scm_call(OCMEM_SVC_ID, OCMEM_UNLOCK_CMD_ID, &request,
+				sizeof(request), NULL, 0);
+	if (rc)
+		pr_err("ocmem: Failed to unlock region %s[%lx -- %lx] ret = %d\n",
+				get_name(id), offset, offset + len - 1, rc);
+	return rc;
+}
+
+int ocmem_enable_dump(enum ocmem_client id, unsigned long offset,
+			unsigned long len)
+{
+	int rc;
+	struct ocmem_tz_en_dump {
+		u32 id;
+		u32 offset;
+		u32 size;
+	} request;
+
+	request.id = get_tz_id(id);
+	request.offset = offset;
+	request.size = len;
+
+	rc = scm_call(OCMEM_SVC_ID, OCMEM_ENABLE_DUMP_CMD_ID, &request,
+				sizeof(request), NULL, 0);
+	if (rc)
+		pr_err("ocmem: Failed to enable dump %s[%lx -- %lx] ret = %d\n",
+				get_name(id), offset, offset + len - 1, rc);
+	return rc;
+}
+
+int ocmem_disable_dump(enum ocmem_client id, unsigned long offset,
+			unsigned long len)
+{
+	int rc;
+	struct ocmem_tz_dis_dump {
+		u32 id;
+		u32 offset;
+		u32 size;
+	} request;
+
+	request.id = get_tz_id(id);
+	request.offset = offset;
+	request.size = len;
+
+	rc = scm_call(OCMEM_SVC_ID, OCMEM_DISABLE_DUMP_CMD_ID, &request,
+				sizeof(request), NULL, 0);
+	if (rc)
+		pr_err("ocmem: Failed to disable dump %s[%lx -- %lx] ret = %d\n",
+				get_name(id), offset, offset + len - 1, rc);
+	return rc;
+}
+
+int ocmem_enable_sec_program(int sec_id)
+{
+	int rc, scm_ret = 0;
+	struct msm_scm_sec_cfg {
+		unsigned int id;
+		unsigned int spare;
+	} cfg;
+
+	cfg.id = sec_id;
+
+	rc = scm_call(OCMEM_SECURE_SVC_ID, OCMEM_SECURE_CFG_ID, &cfg,
+			sizeof(cfg), &scm_ret, sizeof(scm_ret));
+
+	if (rc || scm_ret) {
+		pr_err("ocmem: Failed to enable secure programming\n");
+		return rc ? rc : -EINVAL;
+	}
+
+	return rc;
 }
 #endif /* CONFIG_MSM_OCMEM_NONSECURE */
 
 int ocmem_lock(enum ocmem_client id, unsigned long offset, unsigned long len,
 					enum region_mode mode)
 {
+	int rc = 0;
 
 	if (len < OCMEM_MIN_ALLOC) {
 		pr_err("ocmem: Invalid len %lx for lock\n", len);
@@ -561,27 +677,38 @@
 
 	commit_region_modes();
 
-	do_lock(id, offset, len, mode);
+	rc = do_lock(id, offset, len, mode);
+	if (rc)
+		goto lock_fail;
 
 	mutex_unlock(&region_ctrl_lock);
 	return 0;
-
+lock_fail:
+	switch_region_mode(offset, len, MODE_DEFAULT);
 switch_region_fail:
+	ocmem_gfx_mpu_remove();
 	mutex_unlock(&region_ctrl_lock);
 	return -EINVAL;
 }
 
 int ocmem_unlock(enum ocmem_client id, unsigned long offset, unsigned long len)
 {
+	int rc = 0;
+
 	if (id == OCMEM_GRAPHICS)
 		ocmem_gfx_mpu_remove();
 
 	mutex_lock(&region_ctrl_lock);
-	do_unlock(id, offset, len);
+	rc = do_unlock(id, offset, len);
+	if (rc)
+		goto unlock_fail;
 	switch_region_mode(offset, len , MODE_DEFAULT);
 	commit_region_modes();
 	mutex_unlock(&region_ctrl_lock);
 	return 0;
+unlock_fail:
+	mutex_unlock(&region_ctrl_lock);
+	return -EINVAL;
 }
 
 #if defined(CONFIG_MSM_OCMEM_POWER_DISABLE)
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index c0603d6..4ff7212 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.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
@@ -206,6 +206,11 @@
 		return rc;
 	}
 
+	/* Clear DM Mask */
+	ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
+	/* Clear DM Interrupts */
+	ocmem_write(DM_INTR_RESET, dm_base + DM_INTR_CLR);
+
 	for (i = 0, j = slot; i < num_chunks; i++, j++) {
 
 		struct ocmem_chunk *chunk = &clist->chunks[i];
@@ -296,10 +301,6 @@
 
 	init_completion(&dm_clear_event);
 	init_completion(&dm_transfer_event);
-	/* Clear DM Mask */
-	ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
-	/* enable dm interrupts */
-	ocmem_write(DM_INTR_RESET, dm_base + DM_INTR_CLR);
 	ocmem_disable_core_clock();
 	return 0;
 }
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 08f93e2..868fd1a 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.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
@@ -25,16 +25,19 @@
 #include <mach/ocmem_priv.h>
 
 enum request_states {
-	R_FREE = 0x0,	/* request is not allocated */
-	R_PENDING,	/* request has a pending operation */
-	R_ALLOCATED,	/* request has been allocated */
-	R_MUST_GROW,	/* request must grow as a part of pending operation */
-	R_MUST_SHRINK,	/* request must shrink as a part of pending operation */
-	R_MUST_MAP,	/* request must be mapped before being used */
-	R_MUST_UNMAP,	/* request must be unmapped when not being used */
-	R_MAPPED,	/* request is mapped and actively used by client */
-	R_UNMAPPED,	/* request is not mapped, so it's not in active use */
-	R_EVICTED,	/* request is evicted and must be restored */
+	R_FREE = 0x0,   /* request is not allocated */
+	R_PENDING,      /* request has a pending operation */
+	R_ALLOCATED,    /* request has been allocated */
+	R_ENQUEUED,     /* request has been enqueued for future retry */
+	R_MUST_GROW,    /* request must grow as a part of pending operation */
+	R_MUST_SHRINK,  /* request must shrink */
+	R_WF_SHRINK,    /* shrink must be ack'ed by a client */
+	R_SHRUNK,       /* request was shrunk */
+	R_MUST_MAP,     /* request must be mapped before being used */
+	R_MUST_UNMAP,   /* request must be unmapped when not being used */
+	R_MAPPED,       /* request is mapped and actively used by client */
+	R_UNMAPPED,     /* request is not mapped, so it's not in active use */
+	R_EVICTED,      /* request is evicted and must be restored */
 };
 
 #define SET_STATE(x, val) (set_bit((val), &(x)->state))
@@ -109,6 +112,16 @@
 	OCMEM_SYSNOC = 3,
 };
 
+enum ocmem_tz_client {
+	TZ_UNUSED = 0x0,
+	TZ_GRAPHICS,
+	TZ_VIDEO,
+	TZ_LP_AUDIO,
+	TZ_SENSORS,
+	TZ_OTHER_OS,
+	TZ_DEBUG,
+};
+
 /**
  * Primary OCMEM Arbitration Table
  **/
@@ -117,20 +130,30 @@
 	int priority;
 	int mode;
 	int hw_interconnect;
+	int tz_id;
 } ocmem_client_table[OCMEM_CLIENT_MAX] = {
-	{OCMEM_GRAPHICS, PRIO_GFX, OCMEM_PERFORMANCE, OCMEM_PORT},
-	{OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
-	{OCMEM_CAMERA, NO_PRIO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
-	{OCMEM_HP_AUDIO, PRIO_HP_AUDIO, OCMEM_PASSIVE, OCMEM_BLOCKED},
-	{OCMEM_VOICE, PRIO_VOICE, OCMEM_PASSIVE, OCMEM_BLOCKED},
-	{OCMEM_LP_AUDIO, PRIO_LP_AUDIO, OCMEM_LOW_POWER, OCMEM_SYSNOC},
-	{OCMEM_SENSORS, PRIO_SENSORS, OCMEM_LOW_POWER, OCMEM_SYSNOC},
-	{OCMEM_OTHER_OS, PRIO_OTHER_OS, OCMEM_LOW_POWER, OCMEM_SYSNOC},
+	{OCMEM_GRAPHICS, PRIO_GFX, OCMEM_PERFORMANCE, OCMEM_PORT,
+								TZ_GRAPHICS},
+	{OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC,
+								TZ_VIDEO},
+	{OCMEM_CAMERA, NO_PRIO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC,
+								TZ_UNUSED},
+	{OCMEM_HP_AUDIO, PRIO_HP_AUDIO, OCMEM_PASSIVE, OCMEM_BLOCKED,
+								TZ_UNUSED},
+	{OCMEM_VOICE, PRIO_VOICE, OCMEM_PASSIVE, OCMEM_BLOCKED,
+								TZ_UNUSED},
+	{OCMEM_LP_AUDIO, PRIO_LP_AUDIO, OCMEM_LOW_POWER, OCMEM_SYSNOC,
+								TZ_LP_AUDIO},
+	{OCMEM_SENSORS, PRIO_SENSORS, OCMEM_LOW_POWER, OCMEM_SYSNOC,
+								TZ_SENSORS},
+	{OCMEM_OTHER_OS, PRIO_OTHER_OS, OCMEM_LOW_POWER, OCMEM_SYSNOC,
+								TZ_OTHER_OS},
 };
 
 static struct rb_root sched_tree;
 static struct mutex sched_mutex;
 static struct mutex allocation_mutex;
+static struct mutex free_mutex;
 
 /* A region represents a continuous interval in OCMEM address space */
 struct ocmem_region {
@@ -225,6 +248,14 @@
 							WIDE_MODE : THIN_MODE;
 }
 
+inline int get_tz_id(int id)
+{
+	if (!check_id(id))
+		return TZ_UNUSED;
+	else
+		return ocmem_client_table[id].tz_id;
+}
+
 /* Returns the address that can be used by a device core to access OCMEM */
 static unsigned long device_address(int id, unsigned long addr)
 {
@@ -489,12 +520,21 @@
 	return TEST_STATE(req, R_MAPPED);
 }
 
+static inline int is_pending_shrink(struct ocmem_req *req)
+{
+	return TEST_STATE(req, R_MUST_SHRINK) ||
+		TEST_STATE(req, R_WF_SHRINK);
+}
+
 /* Must be called with sched_mutex held */
 static int __sched_unmap(struct ocmem_req *req)
 {
 	struct ocmem_req *matched_req = NULL;
 	struct ocmem_region *matched_region = NULL;
 
+	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);
 
@@ -1024,8 +1064,8 @@
 
 	retry = false;
 
-	pr_debug("ocmem: do_allocate: %s request size %lx\n",
-						get_name(owner), sz);
+	pr_debug("ocmem: do_allocate: %s request %p size %lx\n",
+						get_name(owner), req, sz);
 
 retry_next_step:
 
@@ -1146,14 +1186,34 @@
 	return OP_FAIL;
 }
 
+/* Remove the request from eviction lists */
+static void cancel_restore(struct ocmem_req *e_handle,
+				struct ocmem_req *req)
+{
+	struct ocmem_eviction_data *edata = e_handle->edata;
+
+	if (!edata || !req)
+		return;
+
+	if (list_empty(&edata->req_list))
+		return;
+
+	list_del_init(&req->eviction_list);
+	req->e_handle = NULL;
+
+	return;
+}
+
 static int sched_enqueue(struct ocmem_req *priv)
 {
 	struct ocmem_req *next = NULL;
 	mutex_lock(&sched_queue_mutex);
+	SET_STATE(priv, R_ENQUEUED);
 	list_add_tail(&priv->sched_list, &sched_queue[priv->owner]);
 	pr_debug("enqueued req %p\n", priv);
 	list_for_each_entry(next, &sched_queue[priv->owner], sched_list) {
-		pr_debug("pending requests for client %p\n", next);
+		pr_debug("pending request %p for client %s\n", next,
+				get_name(next->owner));
 	}
 	mutex_unlock(&sched_queue_mutex);
 	return 0;
@@ -1178,13 +1238,13 @@
 	list_for_each_entry_safe(req, next, &sched_queue[id], sched_list)
 	{
 		if (req == victim_req) {
-			pr_debug("ocmem: Cancelling pending request %p\n",
-							req);
-			list_del(&req->sched_list);
-			goto dequeue_done;
+			pr_debug("ocmem: Cancelling pending request %p for %s\n",
+						req, get_name(req->owner));
+			list_del_init(&victim_req->sched_list);
+			CLEAR_STATE(victim_req, R_ENQUEUED);
+			break;
 		}
 	}
-
 dequeue_done:
 	mutex_unlock(&sched_queue_mutex);
 	return;
@@ -1206,7 +1266,8 @@
 				pr_debug("ocmem: Fetched pending request %p\n",
 									req);
 				list_del(&req->sched_list);
-			break;
+				CLEAR_STATE(req, R_ENQUEUED);
+				break;
 			}
 		}
 	}
@@ -1400,31 +1461,67 @@
 	unsigned long offset = 0;
 	int rc = 0;
 
+	mutex_lock(&free_mutex);
+
 	if (is_blocked(id)) {
 		pr_err("Client %d cannot request free\n", id);
-		return -EINVAL;
+		goto free_invalid;
 	}
 
 	req = handle_to_req(handle);
 	buffer = handle_to_buffer(handle);
 
-	if (!req)
-		return -EINVAL;
+	if (!req) {
+		pr_err("ocmem: No valid request to free\n");
+		goto free_invalid;
+	}
 
 	if (req->req_start != core_address(id, buffer->addr)) {
 		pr_err("Invalid buffer handle passed for free\n");
-		return -EINVAL;
+		goto free_invalid;
 	}
 
-	mutex_lock(&sched_mutex);
-	sched_dequeue(req);
-	mutex_unlock(&sched_mutex);
+	if (req->edata != NULL) {
+		pr_err("ocmem: Request %p(%2lx) yet to process eviction %p\n",
+					req, req->state, req->edata);
+		goto free_invalid;
+	}
 
-	if (TEST_STATE(req, R_MAPPED)) {
-		/* unmap the interval and clear the memory */
-		rc = process_unmap(req, req->req_start, req->req_end);
-		if (rc < 0)
-			return -EINVAL;
+	if (is_pending_shrink(req)) {
+		pr_err("ocmem: Request %p(%2lx) yet to process eviction\n",
+					req, req->state);
+		goto pending_shrink;
+	}
+
+	/* Remove the request from any restore lists */
+	if (req->e_handle)
+		cancel_restore(req->e_handle, req);
+
+	/* Remove the request from any pending opreations */
+	if (TEST_STATE(req, R_ENQUEUED)) {
+		mutex_lock(&sched_mutex);
+		sched_dequeue(req);
+		mutex_unlock(&sched_mutex);
+	}
+
+	if (!TEST_STATE(req, R_FREE)) {
+
+		if (TEST_STATE(req, R_MAPPED)) {
+			/* unmap the interval and clear the memory */
+			rc = process_unmap(req, req->req_start, req->req_end);
+
+			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 */
@@ -1436,7 +1533,7 @@
 
 		if (rc < 0) {
 			pr_err("Failed to switch OFF memory macros\n");
-			return -EINVAL;
+			goto free_fail;
 		}
 
 	}
@@ -1454,7 +1551,15 @@
 	handle->req = NULL;
 
 	ocmem_schedule_pending();
+	mutex_unlock(&free_mutex);
 	return 0;
+free_fail:
+free_invalid:
+	mutex_unlock(&free_mutex);
+	return -EINVAL;
+pending_shrink:
+	mutex_unlock(&free_mutex);
+	return -EAGAIN;
 }
 
 static void ocmem_rdm_worker(struct work_struct *work)
@@ -1504,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)
 {
@@ -1552,7 +1693,6 @@
 		goto transfer_in_error;
 	}
 
-
 	inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_OCMEM);
 	rc = queue_transfer(req, handle, list, TO_OCMEM);
 
@@ -1585,16 +1725,23 @@
 	if (!req)
 		return -EINVAL;
 
+	mutex_lock(&free_mutex);
+
 	if (req->req_start != core_address(id, buffer->addr)) {
 		pr_err("Invalid buffer handle passed for shrink\n");
-		return -EINVAL;
+		goto shrink_fail;
 	}
 
-	edata = req->edata;
+	if (!req->e_handle) {
+		pr_err("Unable to find evicting request\n");
+		goto shrink_fail;
+	}
+
+	edata = req->e_handle->edata;
 
 	if (!edata) {
 		pr_err("Unable to find eviction data\n");
-		return -EINVAL;
+		goto shrink_fail;
 	}
 
 	pr_debug("Found edata %p in request %p\n", edata, req);
@@ -1603,29 +1750,37 @@
 
 	if (size == 0) {
 		pr_debug("req %p being shrunk to zero\n", req);
-		if (is_mapped(req))
+		if (is_mapped(req)) {
 			rc = process_unmap(req, req->req_start, req->req_end);
 			if (rc < 0)
-				return -EINVAL;
+				goto shrink_fail;
+		}
 		rc = do_free(req);
 		if (rc < 0)
-			return -EINVAL;
+			goto shrink_fail;
+		SET_STATE(req, R_FREE);
 	} else {
 		rc = do_shrink(req, size);
 		if (rc < 0)
-			return -EINVAL;
+			goto shrink_fail;
 	}
 
-	req->edata = NULL;
 	CLEAR_STATE(req, R_ALLOCATED);
-	SET_STATE(req, R_FREE);
+	CLEAR_STATE(req, R_WF_SHRINK);
+	SET_STATE(req, R_SHRUNK);
 
 	if (atomic_dec_and_test(&edata->pending)) {
 		pr_debug("ocmem: All conflicting allocations were shrunk\n");
 		complete(&edata->completion);
 	}
 
+	mutex_unlock(&free_mutex);
 	return 0;
+shrink_fail:
+	pr_err("ocmem: Failed to shrink request %p of %s\n",
+			req, get_name(req->owner));
+	mutex_unlock(&free_mutex);
+	return -EINVAL;
 }
 
 int process_xfer(int id, struct ocmem_handle *handle,
@@ -1730,11 +1885,12 @@
 				if (needs_eviction) {
 					pr_debug("adding %p in region %p to eviction list\n",
 							e_req, tmp_region);
+					SET_STATE(e_req, R_MUST_SHRINK);
 					list_add_tail(
 						&e_req->eviction_list,
 						&edata->req_list);
 					atomic_inc(&edata->pending);
-					e_req->edata = edata;
+					e_req->e_handle = req;
 				}
 			}
 		} else {
@@ -1744,9 +1900,7 @@
 
 	pr_debug("%d requests will be evicted\n", atomic_read(&edata->pending));
 
-	if (!atomic_read(&edata->pending))
-		return -EINVAL;
-	return 0;
+	return atomic_read(&edata->pending);
 }
 
 static void trigger_eviction(struct ocmem_eviction_data *edata)
@@ -1768,8 +1922,10 @@
 			pr_debug("ocmem: Evicting request %p\n", req);
 			buffer.addr = req->req_start;
 			buffer.len = 0x0;
+			CLEAR_STATE(req, R_MUST_SHRINK);
 			dispatch_notification(req->owner, OCMEM_ALLOC_SHRINK,
 								&buffer);
+			SET_STATE(req, R_WF_SHRINK);
 		}
 	}
 	return;
@@ -1791,7 +1947,7 @@
 
 	rc = __evict_common(edata, NULL);
 
-	if (rc < 0)
+	if (rc == 0)
 		goto skip_eviction;
 
 	trigger_eviction(edata);
@@ -1825,9 +1981,10 @@
 
 	edata->passive = false;
 
+	mutex_lock(&free_mutex);
 	rc = __evict_common(edata, req);
 
-	if (rc < 0)
+	if (rc == 0)
 		goto skip_eviction;
 
 	trigger_eviction(edata);
@@ -1835,6 +1992,8 @@
 	pr_debug("ocmem: attaching eviction %p to request %p", edata, req);
 	req->edata = edata;
 
+	mutex_unlock(&free_mutex);
+
 	wait_for_completion(&edata->completion);
 
 	pr_debug("ocmem: eviction completed successfully\n");
@@ -1843,28 +2002,30 @@
 skip_eviction:
 	pr_err("ocmem: Unable to run eviction\n");
 	free_eviction(edata);
-	return -EINVAL;
+	req->edata = NULL;
+	mutex_unlock(&free_mutex);
+	return 0;
 }
 
 static int __restore_common(struct ocmem_eviction_data *edata)
 {
 
 	struct ocmem_req *req = NULL;
-	struct ocmem_req *next = NULL;
 
 	if (!edata)
 		return -EINVAL;
 
-	list_for_each_entry_safe(req, next, &edata->req_list, eviction_list)
-	{
-		if (req) {
-			pr_debug("ocmem: restoring evicted request %p\n",
-								req);
-			list_del(&req->eviction_list);
-			req->op = SCHED_ALLOCATE;
-			sched_enqueue(req);
-			inc_ocmem_stat(zone_of(req), NR_RESTORES);
-		}
+	while (!list_empty(&edata->req_list)) {
+		req = list_first_entry(&edata->req_list, struct ocmem_req,
+						eviction_list);
+		list_del_init(&req->eviction_list);
+		pr_debug("ocmem: restoring evicted request %p\n",
+							req);
+		req->edata = NULL;
+		req->e_handle = NULL;
+		req->op = SCHED_ALLOCATE;
+		inc_ocmem_stat(zone_of(req), NR_RESTORES);
+		sched_enqueue(req);
 	}
 
 	pr_debug("Scheduled all evicted regions\n");
@@ -1883,12 +2044,15 @@
 	if (!req->edata)
 		return 0;
 
+	mutex_lock(&free_mutex);
 	rc = __restore_common(req->edata);
+	mutex_unlock(&free_mutex);
 
 	if (rc < 0)
 		return -EINVAL;
 
 	free_eviction(req->edata);
+	req->edata = NULL;
 	return 0;
 }
 
@@ -1900,7 +2064,9 @@
 	if (!edata)
 		return -EINVAL;
 
+	mutex_lock(&free_mutex);
 	rc = __restore_common(edata);
+	mutex_unlock(&free_mutex);
 
 	if (rc < 0) {
 		pr_err("Failed to restore evicted requests\n");
@@ -1986,6 +2152,7 @@
 
 	void __iomem *req_vaddr;
 	unsigned long offset = 0x0;
+	int rc = 0;
 
 	down_write(&req->rw_sem);
 
@@ -1996,12 +2163,23 @@
 	if (!req_vaddr)
 		goto err_do_dump;
 
+	rc = ocmem_enable_dump(req->owner, offset, req->req_sz);
+
+	if (rc < 0)
+		goto err_do_dump;
+
 	pr_debug("Dumping client %s buffer ocmem p: %lx (v: %p) to ddr %lx\n",
 				get_name(req->owner), req->req_start,
 				req_vaddr, addr);
 
 	memcpy((void *)addr, req_vaddr, req->req_sz);
 
+	rc = ocmem_disable_dump(req->owner, offset, req->req_sz);
+
+	if (rc < 0)
+		pr_err("Failed to secure request %p of %s after dump\n",
+				req, get_name(req->owner));
+
 	up_write(&req->rw_sem);
 	return 0;
 err_do_dump:
@@ -2252,6 +2430,7 @@
 	sched_tree = RB_ROOT;
 	pdata = platform_get_drvdata(pdev);
 	mutex_init(&allocation_mutex);
+	mutex_init(&free_mutex);
 	mutex_init(&sched_mutex);
 	mutex_init(&sched_queue_mutex);
 	ocmem_vaddr = pdata->vbase;
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 8c942ad..bbd0852 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -25,6 +25,7 @@
 	"0  msm: perf: add debug patch logging framework\n"
 	"1  Perf: Restore counter after powercollapse for generic ARM PMU's\n"
 	"2  Perf: Toggle PMU IRQ when CPU's are hotplugged\n"
+	"3  Perf: Correct irq for CPU hotplug detection\n"
 ;
 
 static ssize_t desc_read(struct file *fp, char __user *buf,
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/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index 7f8d3b9..0263faf 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -167,7 +167,7 @@
 
 	/* Assert Q6 resets */
 	val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
-	val = (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENA);
+	val |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENA);
 	writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
 
 	/* Kill power at block headswitch */
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/qdsp5/audio_mvs.c b/arch/arm/mach-msm/qdsp5/audio_mvs.c
index 7d2766d..d1aba82 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mvs.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mvs.c
@@ -1734,6 +1734,7 @@
 {
 	MM_DBG("\n");
 
+	wake_lock_destroy(&audio_mvs_info.suspend_lock);
 	misc_deregister(&audio_mvs_misc);
 }
 
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 172c7eb..e6b9549 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -897,6 +897,11 @@
 	struct audio_client *ac;
 	struct audio_aio_write_param param;
 
+	if (!audio || !buf_node) {
+		pr_err("%s NULL pointer audio=[0x%p], buf_node=[0x%p]\n",
+			__func__, audio, buf_node);
+		return;
+	}
 	pr_debug("%s[%p]: Send write buff %p phy %lx len %d meta_enable = %d\n",
 		__func__, audio, buf_node, buf_node->paddr,
 		buf_node->buf.data_len,
@@ -922,8 +927,7 @@
 	if (!audio->buf_cfg.meta_info_enable)
 		param.flags = 0xFF00;
 
-	if ((buf_node != NULL) &&
-		(buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOF_SET))
+	if (buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOF_SET)
 		param.flags |= AUDIO_DEC_EOF_SET;
 
 	param.uid = param.paddr;
@@ -1317,6 +1321,8 @@
 		}
 		/* Flush DSP */
 		rc = audio_aio_flush(audio);
+		/* Flush input / Output buffer in software*/
+		audio_aio_ioport_reset(audio);
 		if (rc < 0) {
 			pr_err("%s[%p]:AUDIO_FLUSH interrupted\n",
 				__func__, audio);
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/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 19e48759..56623c9 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -134,6 +134,16 @@
 	uint32_t pmic_die_revision;
 };
 
+struct socinfo_v8 {
+	struct socinfo_v7 v7;
+
+	/* only valid when format==8*/
+	uint32_t pmic_model_1;
+	uint32_t pmic_die_revision_1;
+	uint32_t pmic_model_2;
+	uint32_t pmic_die_revision_2;
+};
+
 static union {
 	struct socinfo_v1 v1;
 	struct socinfo_v2 v2;
@@ -142,6 +152,7 @@
 	struct socinfo_v5 v5;
 	struct socinfo_v6 v6;
 	struct socinfo_v7 v7;
+	struct socinfo_v8 v8;
 } *socinfo;
 
 static enum msm_cpu cpu_of_id[] = {
@@ -865,6 +876,7 @@
 	device_create_file(msm_soc_device, &msm_soc_attr_vendor);
 
 	switch (legacy_format) {
+	case 8:
 	case 7:
 		device_create_file(msm_soc_device,
 					&msm_soc_attr_pmic_model);
@@ -1054,6 +1066,7 @@
 			socinfo->v5.accessory_chip,
 			socinfo->v6.hw_platform_subtype);
 		break;
+	case 8:
 	case 7:
 		pr_info("%s: v%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u\n",
 			__func__,
@@ -1076,7 +1089,11 @@
 
 int __init socinfo_init(void)
 {
-	socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v7));
+	socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v8));
+
+	if (!socinfo)
+		socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+				sizeof(struct socinfo_v7));
 
 	if (!socinfo)
 		socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
diff --git a/drivers/base/sync.c b/drivers/base/sync.c
index 809d02b..a97a503 100644
--- a/drivers/base/sync.c
+++ b/drivers/base/sync.c
@@ -324,7 +324,6 @@
 
 		new_pt->fence = dst;
 		list_add(&new_pt->pt_list, &dst->pt_list_head);
-		sync_pt_activate(new_pt);
 	}
 
 	return 0;
@@ -356,7 +355,6 @@
 					new_pt->fence = dst;
 					list_replace(&dst_pt->pt_list,
 						     &new_pt->pt_list);
-					sync_pt_activate(new_pt);
 					sync_pt_free(dst_pt);
 				}
 				collapsed = true;
@@ -372,7 +370,6 @@
 
 			new_pt->fence = dst;
 			list_add(&new_pt->pt_list, &dst->pt_list_head);
-			sync_pt_activate(new_pt);
 		}
 	}
 
@@ -453,6 +450,7 @@
 				    struct sync_fence *a, struct sync_fence *b)
 {
 	struct sync_fence *fence;
+	struct list_head *pos;
 	int err;
 
 	fence = sync_fence_alloc(name);
@@ -467,6 +465,12 @@
 	if (err < 0)
 		goto err;
 
+	list_for_each(pos, &fence->pt_list_head) {
+		struct sync_pt *pt =
+			container_of(pos, struct sync_pt, pt_list);
+		sync_pt_activate(pt);
+	}
+
 	/*
 	 * signal the fence in case one of it's pts were activated before
 	 * they were activated
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 822da91..73fe5d6 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -11,8 +11,106 @@
  * GNU General Public License for more details.
  *
  */
+#include "adsprpc_shared.h"
+
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/pagemap.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/hash.h>
+#include <linux/msm_ion.h>
+#include <mach/msm_smd.h>
+#include <mach/ion.h>
 #include <linux/scatterlist.h>
-#include "adsprpc.h"
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+
+#ifndef ION_ADSPRPC_HEAP_ID
+#define ION_ADSPRPC_HEAP_ID ION_AUDIO_HEAP_ID
+#endif /*ION_ADSPRPC_HEAP_ID*/
+
+#define RPC_TIMEOUT	(5 * HZ)
+#define RPC_HASH_BITS	5
+#define RPC_HASH_SZ	(1 << RPC_HASH_BITS)
+#define BALIGN		32
+
+#define LOCK_MMAP(kernel)\
+		do {\
+			if (!kernel)\
+				down_read(&current->mm->mmap_sem);\
+		} while (0)
+
+#define UNLOCK_MMAP(kernel)\
+		do {\
+			if (!kernel)\
+				up_read(&current->mm->mmap_sem);\
+		} while (0)
+
+
+static inline uint32_t buf_page_start(void *buf)
+{
+	uint32_t start = (uint32_t) buf & PAGE_MASK;
+	return start;
+}
+
+static inline uint32_t buf_page_offset(void *buf)
+{
+	uint32_t offset = (uint32_t) buf & (PAGE_SIZE - 1);
+	return offset;
+}
+
+static inline int buf_num_pages(void *buf, int len)
+{
+	uint32_t start = buf_page_start(buf) >> PAGE_SHIFT;
+	uint32_t end = (((uint32_t) buf + len - 1) & PAGE_MASK) >> PAGE_SHIFT;
+	int nPages = end - start + 1;
+	return nPages;
+}
+
+static inline uint32_t buf_page_size(uint32_t size)
+{
+	uint32_t sz = (size + (PAGE_SIZE - 1)) & PAGE_MASK;
+	return sz > PAGE_SIZE ? sz : PAGE_SIZE;
+}
+
+static inline int buf_get_pages(void *addr, int sz, int nr_pages, int access,
+				  struct smq_phy_page *pages, int nr_elems)
+{
+	struct vm_area_struct *vma;
+	uint32_t start = buf_page_start(addr);
+	uint32_t len = nr_pages << PAGE_SHIFT;
+	unsigned long pfn;
+	int n = -1, err = 0;
+
+	VERIFY(err, 0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
+			      (void __user *)start, len));
+	if (err)
+		goto bail;
+	VERIFY(err, 0 != (vma = find_vma(current->mm, start)));
+	if (err)
+		goto bail;
+	VERIFY(err, ((uint32_t)addr + sz) <= vma->vm_end);
+	if (err)
+		goto bail;
+	n = 0;
+	VERIFY(err, 0 == follow_pfn(vma, start, &pfn));
+	if (err)
+		goto bail;
+	VERIFY(err, nr_elems > 0);
+	if (err)
+		goto bail;
+	pages->addr = __pfn_to_phys(pfn);
+	pages->size = len;
+	n++;
+ bail:
+	return n;
+}
 
 struct smq_invoke_ctx {
 	struct completion work;
@@ -32,6 +130,8 @@
 	struct completion work;
 	struct ion_client *iclient;
 	struct cdev cdev;
+	struct class *class;
+	struct device *dev;
 	dev_t dev_no;
 	spinlock_t wrlock;
 	spinlock_t hlock;
@@ -249,7 +349,6 @@
 	args = (void *)((char *)pbuf->virt + used);
 	rlen = pbuf->size - used;
 	for (i = 0; i < inbufs + outbufs; ++i) {
-		int num;
 
 		rpra[i].buf.len = pra[i].buf.len;
 		if (!rpra[i].buf.len)
@@ -276,18 +375,12 @@
 			args = pbuf->virt;
 			rlen = pbuf->size;
 		}
-		num = buf_num_pages(args, pra[i].buf.len);
-		if (pbuf == ibuf) {
-			list[i].num = num;
-			list[i].pgidx = 0;
-		} else {
-			list[i].num = 1;
-			pages[list[i].pgidx].addr =
-				buf_page_start((void *)(pbuf->phys +
-							 (pbuf->size - rlen)));
-			pages[list[i].pgidx].size =
-				buf_page_size(pra[i].buf.len);
-		}
+		list[i].num = 1;
+		pages[list[i].pgidx].addr =
+			buf_page_start((void *)(pbuf->phys +
+						 (pbuf->size - rlen)));
+		pages[list[i].pgidx].size =
+			buf_page_size(pra[i].buf.len);
 		if (i < inbufs) {
 			if (!kernel) {
 				VERIFY(err, 0 == copy_from_user(args,
@@ -485,9 +578,9 @@
 static void free_dev(struct fastrpc_device *dev)
 {
 	if (dev) {
-		module_put(THIS_MODULE);
 		free_mem(&dev->buf);
 		kfree(dev);
+		module_put(THIS_MODULE);
 	}
 }
 
@@ -609,8 +702,10 @@
 		wait_for_completion(&ctx->work);
 	}
 	context_free(ctx);
+
 	for (i = 0, b = abufs; i < nbufs; ++i, ++b)
 		free_mem(b);
+
 	kfree(abufs);
 	if (dev) {
 		add_dev(me, dev);
@@ -768,11 +863,24 @@
 	VERIFY(err, 0 == cdev_add(&me->cdev, MKDEV(MAJOR(me->dev_no), 0), 1));
 	if (err)
 		goto bail;
-	pr_info("'mknod /dev/%s c %d 0'\n", DEVICE_NAME, MAJOR(me->dev_no));
+	me->class = class_create(THIS_MODULE, "chardrv");
+	VERIFY(err, !IS_ERR(me->class));
+	if (err)
+		goto bail;
+	me->dev = device_create(me->class, NULL, MKDEV(MAJOR(me->dev_no), 0),
+				NULL, DEVICE_NAME);
+	VERIFY(err, !IS_ERR(me->dev));
+	if (err)
+		goto bail;
+	pr_info("'created /dev/%s c %d 0'\n", DEVICE_NAME, MAJOR(me->dev_no));
  bail:
 	if (err) {
 		if (me->dev_no)
 			unregister_chrdev_region(me->dev_no, 1);
+		if (me->class)
+			class_destroy(me->class);
+		if (me->cdev.owner)
+			cdev_del(&me->cdev);
 		fastrpc_deinit();
 	}
 	return err;
@@ -783,6 +891,8 @@
 	struct fastrpc_apps *me = &gfa;
 
 	fastrpc_deinit();
+	device_destroy(me->class, MKDEV(MAJOR(me->dev_no), 0));
+	class_destroy(me->class);
 	cdev_del(&me->cdev);
 	unregister_chrdev_region(me->dev_no, 1);
 }
diff --git a/drivers/char/adsprpc.h b/drivers/char/adsprpc.h
deleted file mode 100644
index 3f1b4a7..0000000
--- a/drivers/char/adsprpc.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-#ifndef ADSPRPC_H
-#define ADSPRPC_H
-
-#include <linux/slab.h>
-#include <linux/completion.h>
-#include <linux/pagemap.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <linux/cdev.h>
-#include <linux/list.h>
-#include <linux/hash.h>
-#include <linux/msm_ion.h>
-#include <mach/msm_smd.h>
-#include <mach/ion.h>
-#include "adsprpc_shared.h"
-
-#ifndef ION_ADSPRPC_HEAP_ID
-#define ION_ADSPRPC_HEAP_ID ION_AUDIO_HEAP_ID
-#endif
-
-#define RPC_TIMEOUT	(5 * HZ)
-#define RPC_HASH_BITS	5
-#define RPC_HASH_SZ	(1 << RPC_HASH_BITS)
-#define BALIGN		32
-
-#define LOCK_MMAP(kernel)\
-		do {\
-			if (!kernel)\
-				down_read(&current->mm->mmap_sem);\
-		} while (0)
-
-#define UNLOCK_MMAP(kernel)\
-		do {\
-			if (!kernel)\
-				up_read(&current->mm->mmap_sem);\
-		} while (0)
-
-
-static inline uint32_t buf_page_start(void *buf)
-{
-	uint32_t start = (uint32_t) buf & PAGE_MASK;
-	return start;
-}
-
-static inline uint32_t buf_page_offset(void *buf)
-{
-	uint32_t offset = (uint32_t) buf & (PAGE_SIZE - 1);
-	return offset;
-}
-
-static inline int buf_num_pages(void *buf, int len)
-{
-	uint32_t start = buf_page_start(buf) >> PAGE_SHIFT;
-	uint32_t end = (((uint32_t) buf + len - 1) & PAGE_MASK) >> PAGE_SHIFT;
-	int nPages = end - start + 1;
-	return nPages;
-}
-
-static inline uint32_t buf_page_size(uint32_t size)
-{
-	uint32_t sz = (size + (PAGE_SIZE - 1)) & PAGE_MASK;
-	return sz > PAGE_SIZE ? sz : PAGE_SIZE;
-}
-
-static inline int buf_get_pages(void *addr, int sz, int nr_pages, int access,
-				  struct smq_phy_page *pages, int nr_elems)
-{
-	struct vm_area_struct *vma;
-	uint32_t start = buf_page_start(addr);
-	uint32_t len = nr_pages << PAGE_SHIFT;
-	unsigned long pfn;
-	int n = -1, err = 0;
-
-	VERIFY(err, 0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
-			      (void __user *)start, len));
-	if (err)
-		goto bail;
-	VERIFY(err, 0 != (vma = find_vma(current->mm, start)));
-	if (err)
-		goto bail;
-	VERIFY(err, ((uint32_t)addr + sz) <= vma->vm_end);
-	if (err)
-		goto bail;
-	n = 0;
-	VERIFY(err, 0 == follow_pfn(vma, start, &pfn));
-	if (err)
-		goto bail;
-	VERIFY(err, nr_elems > 0);
-	if (err)
-		goto bail;
-	pages->addr = __pfn_to_phys(pfn);
-	pages->size = len;
-	n++;
- bail:
-	return n;
-}
-
-#endif
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index dc6ab6f..8932d3c 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -14,6 +14,8 @@
 #ifndef ADSPRPC_SHARED_H
 #define ADSPRPC_SHARED_H
 
+#include <linux/types.h>
+
 #define FASTRPC_IOCTL_INVOKE _IOWR('R', 1, struct fastrpc_ioctl_invoke)
 #define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp"
 #define DEVICE_NAME      "adsprpc-smd"
diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile
index 51349f6..60a6b81 100644
--- a/drivers/gpu/ion/Makefile
+++ b/drivers/gpu/ion/Makefile
@@ -1,4 +1,4 @@
 obj-$(CONFIG_ION) +=	ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o ion_iommu_heap.o ion_cp_heap.o
-obj-$(CONFIG_CMA) += ion_cma_heap.o
+obj-$(CONFIG_CMA) += ion_cma_heap.o ion_cma_secure_heap.o
 obj-$(CONFIG_ION_TEGRA) += tegra/
 obj-$(CONFIG_ION_MSM) += msm/
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
new file mode 100644
index 0000000..2c0e5ae
--- /dev/null
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -0,0 +1,409 @@
+/*
+ * drivers/gpu/ion/ion_secure_cma_heap.c
+ *
+ * Copyright (C) Linaro 2012
+ * Author: <benjamin.gaignard@linaro.org> for ST-Ericsson.
+ * Copyright (c) 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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/ion.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_ion.h>
+#include <mach/iommu_domains.h>
+
+#include <asm/cacheflush.h>
+
+/* for ion_heap_ops structure */
+#include "ion_priv.h"
+#include "msm/ion_cp_common.h"
+
+#define ION_CMA_ALLOCATE_FAILED NULL
+
+struct ion_secure_cma_buffer_info {
+	/*
+	 * This needs to come first for compatibility with the secure buffer API
+	 */
+	struct ion_cp_buffer secure;
+	void *cpu_addr;
+	dma_addr_t handle;
+	struct sg_table *table;
+	bool is_cached;
+};
+
+static int cma_heap_has_outer_cache;
+/*
+ * Create scatter-list for the already allocated DMA buffer.
+ * This function could be replace by dma_common_get_sgtable
+ * as soon as it will avalaible.
+ */
+int ion_secure_cma_get_sgtable(struct device *dev, struct sg_table *sgt,
+			void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	struct page *page = virt_to_page(cpu_addr);
+	int ret;
+
+	ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
+	if (unlikely(ret))
+		return ret;
+
+	sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
+	sg_dma_address(sgt->sgl) = handle;
+	return 0;
+}
+
+/* ION CMA heap operations functions */
+static struct ion_secure_cma_buffer_info *__ion_secure_cma_allocate(
+			    struct ion_heap *heap, struct ion_buffer *buffer,
+			    unsigned long len, unsigned long align,
+			    unsigned long flags)
+{
+	struct device *dev = heap->priv;
+	struct ion_secure_cma_buffer_info *info;
+
+	dev_dbg(dev, "Request buffer allocation len %ld\n", len);
+
+	info = kzalloc(sizeof(struct ion_secure_cma_buffer_info), GFP_KERNEL);
+	if (!info) {
+		dev_err(dev, "Can't allocate buffer info\n");
+		return ION_CMA_ALLOCATE_FAILED;
+	}
+
+	if (!ION_IS_CACHED(flags))
+		info->cpu_addr = dma_alloc_writecombine(dev, len,
+					&(info->handle), 0);
+	else
+		info->cpu_addr = dma_alloc_nonconsistent(dev, len,
+					&(info->handle), 0);
+
+	if (!info->cpu_addr) {
+		dev_err(dev, "Fail to allocate buffer\n");
+		goto err;
+	}
+
+	info->table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!info->table) {
+		dev_err(dev, "Fail to allocate sg table\n");
+		goto err;
+	}
+
+	info->is_cached = ION_IS_CACHED(flags);
+
+	ion_secure_cma_get_sgtable(dev,
+			info->table, info->cpu_addr, info->handle, len);
+
+	info->secure.buffer = info->handle;
+
+	/* keep this for memory release */
+	buffer->priv_virt = info;
+	dev_dbg(dev, "Allocate buffer %p\n", buffer);
+	return info;
+
+err:
+	kfree(info);
+	return ION_CMA_ALLOCATE_FAILED;
+}
+
+static int ion_secure_cma_allocate(struct ion_heap *heap,
+			    struct ion_buffer *buffer,
+			    unsigned long len, unsigned long align,
+			    unsigned long flags)
+{
+	unsigned long secure_allocation = flags & ION_SECURE;
+	struct ion_secure_cma_buffer_info *buf = NULL;
+
+	if (!secure_allocation) {
+		pr_err("%s: non-secure allocation disallowed from heap %s %lx\n",
+			__func__, heap->name, flags);
+		return -ENOMEM;
+	}
+
+	buf = __ion_secure_cma_allocate(heap, buffer, len, align, flags);
+
+	if (buf) {
+		buf->secure.want_delayed_unsecure = 0;
+		atomic_set(&buf->secure.secure_cnt, 0);
+		mutex_init(&buf->secure.lock);
+		buf->secure.is_secure = 1;
+		return 0;
+	} else {
+		return -ENOMEM;
+	}
+}
+
+
+static void ion_secure_cma_free(struct ion_buffer *buffer)
+{
+	struct device *dev = buffer->heap->priv;
+	struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
+
+	dev_dbg(dev, "Release buffer %p\n", buffer);
+	/* release memory */
+	dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle);
+	/* release sg table */
+	kfree(info->table);
+	kfree(info);
+}
+
+static int ion_secure_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer,
+			ion_phys_addr_t *addr, size_t *len)
+{
+	struct device *dev = heap->priv;
+	struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
+
+	dev_dbg(dev, "Return buffer %p physical address 0x%x\n", buffer,
+		info->handle);
+
+	*addr = info->handle;
+	*len = buffer->size;
+
+	return 0;
+}
+
+struct sg_table *ion_secure_cma_heap_map_dma(struct ion_heap *heap,
+					 struct ion_buffer *buffer)
+{
+	struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
+
+	return info->table;
+}
+
+void ion_secure_cma_heap_unmap_dma(struct ion_heap *heap,
+			       struct ion_buffer *buffer)
+{
+	return;
+}
+
+static int ion_secure_cma_mmap(struct ion_heap *mapper,
+			struct ion_buffer *buffer,
+			struct vm_area_struct *vma)
+{
+	return -EINVAL;
+}
+
+static void *ion_secure_cma_map_kernel(struct ion_heap *heap,
+				struct ion_buffer *buffer)
+{
+	struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
+
+	atomic_inc(&info->secure.map_cnt);
+	return info->cpu_addr;
+}
+
+static void ion_secure_cma_unmap_kernel(struct ion_heap *heap,
+				 struct ion_buffer *buffer)
+{
+	struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
+
+	atomic_dec(&info->secure.map_cnt);
+	return;
+}
+
+int ion_secure_cma_map_iommu(struct ion_buffer *buffer,
+				struct ion_iommu_map *data,
+				unsigned int domain_num,
+				unsigned int partition_num,
+				unsigned long align,
+				unsigned long iova_length,
+				unsigned long flags)
+{
+	int ret = 0;
+	struct iommu_domain *domain;
+	unsigned long extra;
+	unsigned long extra_iova_addr;
+	struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
+	struct sg_table *table = info->table;
+	int prot = IOMMU_WRITE | IOMMU_READ;
+
+	data->mapped_size = iova_length;
+
+	if (!msm_use_iommu()) {
+		data->iova_addr = info->handle;
+		return 0;
+	}
+
+	extra = iova_length - buffer->size;
+
+	ret = msm_allocate_iova_address(domain_num, partition_num,
+						data->mapped_size, align,
+						&data->iova_addr);
+
+	if (ret)
+		goto out;
+
+	domain = msm_get_iommu_domain(domain_num);
+
+	if (!domain) {
+		ret = -EINVAL;
+		goto out1;
+	}
+
+	ret = iommu_map_range(domain, data->iova_addr, table->sgl,
+				buffer->size, prot);
+
+	if (ret) {
+		pr_err("%s: could not map %lx in domain %p\n",
+			__func__, data->iova_addr, domain);
+		goto out1;
+	}
+
+	extra_iova_addr = data->iova_addr + buffer->size;
+	if (extra) {
+		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;
+	}
+	return ret;
+
+out2:
+	iommu_unmap_range(domain, data->iova_addr, buffer->size);
+out1:
+	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+				data->mapped_size);
+out:
+	return ret;
+}
+
+
+void ion_secure_cma_unmap_iommu(struct ion_iommu_map *data)
+{
+	unsigned int domain_num;
+	unsigned int partition_num;
+	struct iommu_domain *domain;
+
+	if (!msm_use_iommu())
+		return;
+
+	domain_num = iommu_map_domain(data);
+	partition_num = iommu_map_partition(data);
+
+	domain = msm_get_iommu_domain(domain_num);
+
+	if (!domain) {
+		WARN(1, "Could not get domain %d. Corruption?\n", domain_num);
+		return;
+	}
+
+	iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
+	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+				data->mapped_size);
+
+	return;
+}
+
+int ion_secure_cma_cache_ops(struct ion_heap *heap,
+			struct ion_buffer *buffer, void *vaddr,
+			unsigned int offset, unsigned int length,
+			unsigned int cmd)
+{
+	void (*outer_cache_op)(phys_addr_t, phys_addr_t);
+
+	switch (cmd) {
+	case ION_IOC_CLEAN_CACHES:
+		dmac_clean_range(vaddr, vaddr + length);
+		outer_cache_op = outer_clean_range;
+		break;
+	case ION_IOC_INV_CACHES:
+		dmac_inv_range(vaddr, vaddr + length);
+		outer_cache_op = outer_inv_range;
+		break;
+	case ION_IOC_CLEAN_INV_CACHES:
+		dmac_flush_range(vaddr, vaddr + length);
+		outer_cache_op = outer_flush_range;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (cma_heap_has_outer_cache) {
+		struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
+
+		outer_cache_op(info->handle, info->handle + length);
+	}
+
+	return 0;
+}
+
+static int ion_secure_cma_print_debug(struct ion_heap *heap, struct seq_file *s,
+			const struct rb_root *mem_map)
+{
+	if (mem_map) {
+		struct rb_node *n;
+
+		seq_printf(s, "\nMemory Map\n");
+		seq_printf(s, "%16.s %14.s %14.s %14.s\n",
+			   "client", "start address", "end address",
+			   "size (hex)");
+
+		for (n = rb_first(mem_map); n; n = rb_next(n)) {
+			struct mem_map_data *data =
+					rb_entry(n, struct mem_map_data, node);
+			const char *client_name = "(null)";
+
+
+			if (data->client_name)
+				client_name = data->client_name;
+
+			seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
+				   client_name, data->addr,
+				   data->addr_end,
+				   data->size, data->size);
+		}
+	}
+	return 0;
+}
+
+static struct ion_heap_ops ion_secure_cma_ops = {
+	.allocate = ion_secure_cma_allocate,
+	.free = ion_secure_cma_free,
+	.map_dma = ion_secure_cma_heap_map_dma,
+	.unmap_dma = ion_secure_cma_heap_unmap_dma,
+	.phys = ion_secure_cma_phys,
+	.map_user = ion_secure_cma_mmap,
+	.map_kernel = ion_secure_cma_map_kernel,
+	.unmap_kernel = ion_secure_cma_unmap_kernel,
+	.map_iommu = ion_secure_cma_map_iommu,
+	.unmap_iommu = ion_secure_cma_unmap_iommu,
+	.cache_op = ion_secure_cma_cache_ops,
+	.print_debug = ion_secure_cma_print_debug,
+	.secure_buffer = ion_cp_secure_buffer,
+	.unsecure_buffer = ion_cp_unsecure_buffer,
+};
+
+struct ion_heap *ion_secure_cma_heap_create(struct ion_platform_heap *data)
+{
+	struct ion_heap *heap;
+
+	heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL);
+
+	if (!heap)
+		return ERR_PTR(-ENOMEM);
+
+	heap->ops = &ion_secure_cma_ops;
+	/* set device as private heaps data, later it will be
+	 * used to make the link with reserved CMA memory */
+	heap->priv = data->priv;
+	heap->type = ION_HEAP_TYPE_SECURE_DMA;
+	cma_heap_has_outer_cache = data->has_outer_cache;
+	return heap;
+}
+
+void ion_secure_cma_heap_destroy(struct ion_heap *heap)
+{
+	kfree(heap);
+}
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index 98c1a8c..ff2b8dd 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -2,7 +2,7 @@
  * drivers/gpu/ion/ion_heap.c
  *
  * Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-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
@@ -44,6 +44,10 @@
 	case ION_HEAP_TYPE_DMA:
 		heap = ion_cma_heap_create(heap_data);
 		break;
+
+	case ION_HEAP_TYPE_SECURE_DMA:
+		heap = ion_secure_cma_heap_create(heap_data);
+		break;
 #endif
 	default:
 		pr_err("%s: Invalid heap type %d\n", __func__,
@@ -89,6 +93,9 @@
 	case ION_HEAP_TYPE_DMA:
 		ion_cma_heap_destroy(heap);
 		break;
+	case ION_HEAP_TYPE_SECURE_DMA:
+		ion_secure_cma_heap_destroy(heap);
+		break;
 #endif
 	default:
 		pr_err("%s: Invalid heap type %d\n", __func__,
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 2473dd2..77ecfa5 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -2,7 +2,7 @@
  * drivers/gpu/ion/ion_priv.h
  *
  * Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-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
@@ -262,6 +262,9 @@
 #ifdef CONFIG_CMA
 struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *);
 void ion_cma_heap_destroy(struct ion_heap *);
+
+struct ion_heap *ion_secure_cma_heap_create(struct ion_platform_heap *);
+void ion_secure_cma_heap_destroy(struct ion_heap *);
 #endif
 
 struct ion_heap *msm_get_contiguous_heap(void);
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index fb365ba..b660968 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.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
@@ -662,12 +662,14 @@
 
 int ion_heap_allow_secure_allocation(enum ion_heap_type type)
 {
-	return type == ((enum ion_heap_type) ION_HEAP_TYPE_CP);
+	return type == ((enum ion_heap_type) ION_HEAP_TYPE_CP) ||
+		type == ((enum ion_heap_type) ION_HEAP_TYPE_SECURE_DMA);
 }
 
 int ion_heap_allow_handle_secure(enum ion_heap_type type)
 {
-	return type == ((enum ion_heap_type) ION_HEAP_TYPE_CP);
+	return type == ((enum ion_heap_type) ION_HEAP_TYPE_CP) ||
+		type == ((enum ion_heap_type) ION_HEAP_TYPE_SECURE_DMA);
 }
 
 int ion_heap_allow_heap_secure(enum ion_heap_type type)
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 0127735..e245cfc 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -539,11 +539,11 @@
 /* RBBM_CLOCK_CTL default value */
 #define A305_RBBM_CLOCK_CTL_DEFAULT   0xAAAAAAAA
 #define A320_RBBM_CLOCK_CTL_DEFAULT   0xBFFFFFFF
-#define A330_RBBM_CLOCK_CTL_DEFAULT   0xAAAAAAAE
+#define A330_RBBM_CLOCK_CTL_DEFAULT   0xBFFCFFFF
 #define A330v2_RBBM_CLOCK_CTL_DEFAULT 0xBFFCFFFF
 #define A305B_RBBM_CLOCK_CTL_DEFAULT  0xAAAAAAAA
 
-#define A330_RBBM_GPR0_CTL_DEFAULT  0x0AE2B8AE
+#define A330_RBBM_GPR0_CTL_DEFAULT    0x00000000
 #define A330v2_RBBM_GPR0_CTL_DEFAULT  0x00000000
 
 /* COUNTABLE FOR SP PERFCOUNTER */
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index c495890..08f19f7 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -160,10 +160,10 @@
 	/* size of gmem for gpu*/
 	unsigned int gmem_size;
 	/* version of pm4 microcode that supports sync_lock
-	   between CPU and GPU for SMMU-v1 programming */
+	   between CPU and GPU for IOMMU-v0 programming */
 	unsigned int sync_lock_pm4_ver;
 	/* version of pfp microcode that supports sync_lock
-	   between CPU and GPU for SMMU-v1 programming */
+	   between CPU and GPU for IOMMU-v0 programming */
 	unsigned int sync_lock_pfp_ver;
 } adreno_gpulist[] = {
 	{ ADRENO_REV_A200, 0, 2, ANY_ID, ANY_ID,
@@ -759,6 +759,10 @@
 		&pdata->init_level))
 		pdata->init_level = 1;
 
+	if (adreno_of_read_property(parent, "qcom,step-pwrlevel",
+		&pdata->step_mul))
+		pdata->step_mul = 1;
+
 	if (pdata->init_level < 0 || pdata->init_level > pdata->num_levels) {
 		KGSL_CORE_ERR("Initial power level out of range\n");
 		pdata->init_level = 1;
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index d4cccbd..c43ac51 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -435,6 +435,8 @@
 	/* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
 	if (adreno_is_a305(adreno_dev) || adreno_is_a320(adreno_dev))
 		adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000E0602);
+	else if (adreno_is_a330(adreno_dev) || adreno_is_a305b(adreno_dev))
+		adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x003E2008);
 
 	rb->rptr = 0;
 	rb->wptr = 0;
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index 764b044..ba88a42 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -465,8 +465,11 @@
 	}
 
 	ret = kgsl_gem_init_obj(dev, file_priv, obj, &handle);
-	if (ret)
+	if (ret) {
+		drm_gem_object_release(obj);
+		DRM_ERROR("Unable to initialize GEM object ret = %d\n", ret);
 		return ret;
+	}
 
 	create->handle = handle;
 	return 0;
@@ -539,6 +542,106 @@
 }
 
 int
+kgsl_gem_create_from_ion_ioctl(struct drm_device *dev, void *data,
+		      struct drm_file *file_priv)
+{
+	struct drm_kgsl_gem_create_from_ion *args = data;
+	struct drm_gem_object *obj;
+	struct ion_handle *ion_handle;
+	struct drm_kgsl_gem_object *priv;
+	struct sg_table *sg_table;
+	struct scatterlist *s;
+	int ret, handle;
+	unsigned long size;
+
+	ion_handle = ion_import_dma_buf(kgsl_drm_ion_client, args->ion_fd);
+	if (IS_ERR_OR_NULL(ion_handle)) {
+		DRM_ERROR("Unable to import dmabuf.  Error number = %d\n",
+			(int)PTR_ERR(ion_handle));
+		return -EINVAL;
+	}
+
+	ion_handle_get_size(kgsl_drm_ion_client, ion_handle, &size);
+
+	if (size == 0) {
+		ion_free(kgsl_drm_ion_client, ion_handle);
+		DRM_ERROR(
+		"cannot create GEM object from zero size ION buffer\n");
+		return -EINVAL;
+	}
+
+	obj = drm_gem_object_alloc(dev, size);
+
+	if (obj == NULL) {
+		ion_free(kgsl_drm_ion_client, ion_handle);
+		DRM_ERROR("Unable to allocate the GEM object\n");
+		return -ENOMEM;
+	}
+
+	ret = kgsl_gem_init_obj(dev, file_priv, obj, &handle);
+	if (ret) {
+		ion_free(kgsl_drm_ion_client, ion_handle);
+		drm_gem_object_release(obj);
+		DRM_ERROR("Unable to initialize GEM object ret = %d\n", ret);
+		return ret;
+	}
+
+	priv = obj->driver_private;
+	priv->ion_handle = ion_handle;
+
+	priv->type = DRM_KGSL_GEM_TYPE_KMEM;
+	list_add(&priv->list, &kgsl_mem_list);
+
+	priv->pagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
+
+	priv->memdesc.pagetable = priv->pagetable;
+
+	sg_table = ion_sg_table(kgsl_drm_ion_client,
+		priv->ion_handle);
+	if (IS_ERR_OR_NULL(priv->ion_handle)) {
+		DRM_ERROR("Unable to get ION sg table\n");
+		ion_free(kgsl_drm_ion_client,
+			priv->ion_handle);
+		priv->ion_handle = NULL;
+		kgsl_mmu_putpagetable(priv->pagetable);
+		drm_gem_object_release(obj);
+		kfree(priv);
+		return -ENOMEM;
+	}
+
+	priv->memdesc.sg = sg_table->sgl;
+
+	/* Calculate the size of the memdesc from the sglist */
+
+	priv->memdesc.sglen = 0;
+
+	for (s = priv->memdesc.sg; s != NULL; s = sg_next(s)) {
+		priv->memdesc.size += s->length;
+		priv->memdesc.sglen++;
+	}
+
+	ret = kgsl_mmu_map(priv->pagetable, &priv->memdesc,
+		GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+	if (ret) {
+		DRM_ERROR("kgsl_mmu_map failed.  ret = %d\n", ret);
+		ion_free(kgsl_drm_ion_client,
+			priv->ion_handle);
+		priv->ion_handle = NULL;
+		kgsl_mmu_putpagetable(priv->pagetable);
+		drm_gem_object_release(obj);
+		kfree(priv);
+		return -ENOMEM;
+	}
+
+	priv->bufs[0].offset = 0;
+	priv->bufs[0].gpuaddr = priv->memdesc.gpuaddr;
+	priv->flags |= DRM_KGSL_GEM_FLAG_MAPPED;
+
+	args->handle = handle;
+	return 0;
+}
+
+int
 kgsl_gem_get_ion_fd_ioctl(struct drm_device *dev, void *data,
 			struct drm_file *file_priv)
 {
@@ -563,6 +666,12 @@
 		if (priv->ion_handle) {
 			args->ion_fd = ion_share_dma_buf(
 				kgsl_drm_ion_client, priv->ion_handle);
+			if (args->ion_fd < 0) {
+				DRM_ERROR(
+				"Could not share ion buffer. Error = %d\n",
+					args->ion_fd);
+				ret = -EINVAL;
+			}
 		} else {
 			DRM_ERROR("GEM object has no ion memory allocated.\n");
 			ret = -EINVAL;
@@ -1266,6 +1375,8 @@
 	DRM_IOCTL_DEF_DRV(KGSL_GEM_MMAP, kgsl_gem_mmap_ioctl, 0),
 	DRM_IOCTL_DEF_DRV(KGSL_GEM_GET_BUFINFO, kgsl_gem_get_bufinfo_ioctl, 0),
 	DRM_IOCTL_DEF_DRV(KGSL_GEM_GET_ION_FD, kgsl_gem_get_ion_fd_ioctl, 0),
+	DRM_IOCTL_DEF_DRV(KGSL_GEM_CREATE_FROM_ION,
+		kgsl_gem_create_from_ion_ioctl, 0),
 	DRM_IOCTL_DEF_DRV(KGSL_GEM_SET_BUFCOUNT,
 		      kgsl_gem_set_bufcount_ioctl, 0),
 	DRM_IOCTL_DEF_DRV(KGSL_GEM_SET_ACTIVE, kgsl_gem_set_active_ioctl, 0),
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index df190ff..df8e1d0 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -34,7 +34,7 @@
 #include "z180.h"
 
 
-static struct kgsl_iommu_register_list kgsl_iommuv1_reg[KGSL_IOMMU_REG_MAX] = {
+static struct kgsl_iommu_register_list kgsl_iommuv0_reg[KGSL_IOMMU_REG_MAX] = {
 	{ 0, 0, 0 },				/* GLOBAL_BASE */
 	{ 0x10, 0x0003FFFF, 14 },		/* TTBR0 */
 	{ 0x14, 0x0003FFFF, 14 },		/* TTBR1 */
@@ -45,7 +45,7 @@
 	{ 0x818, 0, 0 },			/* V2PUR */
 };
 
-static struct kgsl_iommu_register_list kgsl_iommuv2_reg[KGSL_IOMMU_REG_MAX] = {
+static struct kgsl_iommu_register_list kgsl_iommuv1_reg[KGSL_IOMMU_REG_MAX] = {
 	{ 0, 0, 0 },				/* GLOBAL_BASE */
 	{ 0x20, 0x00FFFFFF, 14 },		/* TTBR0 */
 	{ 0x28, 0x00FFFFFF, 14 },		/* TTBR1 */
@@ -1191,15 +1191,15 @@
 	if (status)
 		goto done;
 
-	iommu->iommu_reg_list = kgsl_iommuv1_reg;
-	iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
+	iommu->iommu_reg_list = kgsl_iommuv0_reg;
+	iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V0;
 
 	if (msm_soc_version_supports_iommu_v0()) {
+		iommu->iommu_reg_list = kgsl_iommuv0_reg;
+		iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V0;
+	} else {
 		iommu->iommu_reg_list = kgsl_iommuv1_reg;
 		iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
-	} else {
-		iommu->iommu_reg_list = kgsl_iommuv2_reg;
-		iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V2;
 	}
 
 	/* A nop is required in an indirect buffer when switching
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index 25f0d45..bf40113 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -15,8 +15,8 @@
 
 #include <mach/iommu.h>
 
-#define KGSL_IOMMU_CTX_OFFSET_V1	0
-#define KGSL_IOMMU_CTX_OFFSET_V2	0x8000
+#define KGSL_IOMMU_CTX_OFFSET_V0	0
+#define KGSL_IOMMU_CTX_OFFSET_V1	0x8000
 #define KGSL_IOMMU_CTX_SHIFT		12
 
 /* TLBLKCR feilds */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 2945b7b..8078316 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -357,13 +357,13 @@
 	return snprintf(buf, PAGE_SIZE, "%d\n", pwr->num_pwrlevels - 1);
 }
 
-/* Given a GPU clock value, return the nearest powerlevel */
+/* Given a GPU clock value, return the lowest matching powerlevel */
 
 static int _get_nearest_pwrlevel(struct kgsl_pwrctrl *pwr, unsigned int clock)
 {
 	int i;
 
-	for (i = 0; i < pwr->num_pwrlevels - 1; i++) {
+	for (i = pwr->num_pwrlevels - 1; i >= 0; i--) {
 		if (abs(pwr->pwrlevels[i].gpu_freq - clock) < 5000000)
 			return i;
 	}
@@ -1000,8 +1000,11 @@
 		}
 	}
 
+	/* Set the power level step multiplier with 1 as the default */
+	pwr->step_mul = pdata->step_mul ? pdata->step_mul : 1;
+
 	/* Set the CPU latency to 501usec to allow low latency PC modes */
-	pwr->pm_qos_latency = 3;
+	pwr->pm_qos_latency = 501;
 
 	pm_runtime_enable(device->parentdev);
 	register_early_suspend(&device->display_off);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 72ad4d1..ced52e1 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -62,6 +62,7 @@
  * @clk_stats - structure of clock statistics
  * @pm_qos_req_dma - the power management quality of service structure
  * @pm_qos_latency - allowed CPU latency in microseconds
+ * @step_mul - multiplier for moving between power levels
  */
 
 struct kgsl_pwrctrl {
@@ -89,6 +90,7 @@
 	struct kgsl_clk_stats clk_stats;
 	struct pm_qos_request pm_qos_req_dma;
 	unsigned int pm_qos_latency;
+	unsigned int step_mul;
 };
 
 void kgsl_pwrctrl_irq(struct kgsl_device *device, int state);
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index aa6861e..9b2ac70 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.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
@@ -38,6 +38,10 @@
  * per frame for 60fps content.
  */
 #define FLOOR			5000
+/* CEILING is 50msec, larger than any standard
+ * frame length, but less than the idle timer.
+ */
+#define CEILING			50000
 #define SWITCH_OFF		200
 #define SWITCH_OFF_RESET_TH	40
 #define SKIP_COUNTER		500
@@ -163,11 +167,24 @@
 		priv->no_switch_cnt = 0;
 	}
 
-	idle = priv->bin.total_time - priv->bin.busy_time;
+	/* If there is an extended block of busy processing,
+	 * increase frequency.  Otherwise run the normal algorithm.
+	 */
+	if (priv->bin.busy_time > CEILING) {
+		val = -1;
+	} else {
+		idle = priv->bin.total_time - priv->bin.busy_time;
+		idle = (idle > 0) ? idle : 0;
+		val = __secure_tz_entry(TZ_UPDATE_ID, idle, device->id);
+	}
 	priv->bin.total_time = 0;
 	priv->bin.busy_time = 0;
-	idle = (idle > 0) ? idle : 0;
-	val = __secure_tz_entry(TZ_UPDATE_ID, idle, device->id);
+
+	/* If the decision is to move to a lower level, make sure the GPU
+	 * frequency drops.
+	 */
+	if (val > 0)
+		val *= pwr->step_mul;
 	if (val)
 		kgsl_pwrctrl_pwrlevel_change(device,
 					     pwr->active_pwrlevel + val);
diff --git a/drivers/gud/mobicore_driver/api.c b/drivers/gud/mobicore_driver/api.c
index 2506bc2..871f6cc 100644
--- a/drivers/gud/mobicore_driver/api.c
+++ b/drivers/gud/mobicore_driver/api.c
@@ -2,6 +2,7 @@
  * MobiCore Driver Kernel Module.
  *
  * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/drivers/gud/mobicore_driver/debug.h b/drivers/gud/mobicore_driver/debug.h
index f166605..0195877 100644
--- a/drivers/gud/mobicore_driver/debug.h
+++ b/drivers/gud/mobicore_driver/debug.h
@@ -14,8 +14,7 @@
 extern struct device *mcd;
 
 #define MCDRV_DBG_ERROR(dev, txt, ...) \
-	dev_err(dev, "[%d] %s() ### ERROR: " txt, \
-		task_pid_vnr(current), \
+	dev_err(dev, "MobiCore %s() ### ERROR: " txt, \
 		__func__, \
 		##__VA_ARGS__)
 
@@ -32,15 +31,12 @@
 #endif
 
 #define MCDRV_DBG(dev, txt, ...) \
-	dev_info(dev, "[%d on CPU%d] %s(): " txt, \
-		 task_pid_vnr(current), \
-		 raw_smp_processor_id(), \
+	dev_info(dev, "MobiCore %s(): " txt, \
 		 __func__, \
 		 ##__VA_ARGS__)
 
 #define MCDRV_DBG_WARN(dev, txt, ...) \
-	dev_warn(dev, "[%d] %s() WARNING: " txt, \
-		 task_pid_vnr(current), \
+	dev_warn(dev, "MobiCore %s() WARNING: " txt, \
 		 __func__, \
 		 ##__VA_ARGS__)
 
diff --git a/drivers/gud/mobicore_driver/fastcall.h b/drivers/gud/mobicore_driver/fastcall.h
index 9f360c1..d5f9abc 100644
--- a/drivers/gud/mobicore_driver/fastcall.h
+++ b/drivers/gud/mobicore_driver/fastcall.h
@@ -15,6 +15,15 @@
 
 #include "debug.h"
 
+/* Use the arch_extension sec pseudo op before switching to secure world */
+#if defined(__GNUC__) && \
+	defined(__GNUC_MINOR__) && \
+	defined(__GNUC_PATCHLEVEL__) && \
+	((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)) \
+	>= 40502
+#define MC_ARCH_EXTENSION_SEC
+#endif
+
 /*
  * MobiCore SMCs
  */
@@ -93,16 +102,18 @@
  */
 static inline long _smc(void *data)
 {
+	int ret = 0;
 	union fc_generic fc_generic;
-	memcpy(&fc_generic, data, sizeof(union fc_generic));
+
 	if (data == NULL)
 		return -EPERM;
+
 #ifdef MC_SMC_FASTCALL
 	{
-		int ret = 0;
-		ret = smc_fastcall(data, sizeof(union fc_generic));
+		ret = smc_fastcall(data, sizeof(fc_generic));
 	}
 #else
+	memcpy(&fc_generic, data, sizeof(union fc_generic));
 	{
 		/* SVC expect values in r0-r3 */
 		register u32 reg0 __asm__("r0") = fc_generic.as_in.cmd;
@@ -128,7 +139,7 @@
 		memcpy(data, &fc_generic, sizeof(union fc_generic));
 	}
 #endif
-	return 0;
+	return ret;
 }
 
 /*
diff --git a/drivers/gud/mobicore_driver/logging.c b/drivers/gud/mobicore_driver/logging.c
index 089b91c..4160292 100644
--- a/drivers/gud/mobicore_driver/logging.c
+++ b/drivers/gud/mobicore_driver/logging.c
@@ -5,6 +5,7 @@
  * buffer and the Linux log
  *
  * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -51,17 +52,27 @@
 	uint32_t log_data;		/* Value, if any */
 };
 
+static bool prev_eol;			/* Previous char was a EOL */
+static uint16_t prev_source;		/* Previous Log source */
 static uint32_t log_pos;		/* MobiCore log previous position */
 static struct mc_trace_buf *log_buf;	/* MobiCore log buffer structure */
 struct task_struct *log_thread;		/* Log Thread task structure */
 static char *log_line;			/* Log Line buffer */
 static uint32_t log_line_len;		/* Log Line buffer current length */
+static int thread_err;
 
-static void log_eol(void)
+static void log_eol(uint16_t source)
 {
 	if (!strnlen(log_line, LOG_LINE_SIZE))
 		return;
-	dev_info(mcd, "%s\n", log_line);
+	prev_eol = true;
+	/* MobiCore Userspace */
+	if (prev_source)
+		dev_info(mcd, "%03x|%s\n", prev_source, log_line);
+	/* MobiCore kernel */
+	else
+		dev_info(mcd, "%s\n", log_line);
+
 	log_line_len = 0;
 	log_line[0] = 0;
 }
@@ -70,53 +81,29 @@
  * Collect chars in log_line buffer and output the buffer when it is full.
  * No locking needed because only "mobicore_log" thread updates this buffer.
  */
-static void log_char(char ch)
+static void log_char(char ch, uint16_t source)
 {
 	if (ch == '\n' || ch == '\r') {
-		log_eol();
+		log_eol(source);
 		return;
 	}
 
-	if (log_line_len >= LOG_LINE_SIZE - 1) {
-		dev_info(mcd, "%s\n", log_line);
-		log_line_len = 0;
-		log_line[0] = 0;
-	}
+	if (log_line_len >= LOG_LINE_SIZE - 1 || source != prev_source)
+		log_eol(source);
+
 
 	log_line[log_line_len] = ch;
 	log_line[log_line_len + 1] = 0;
 	log_line_len++;
-}
-
-/*
- * Put a string to the log line.
- */
-static void log_str(const char *s)
-{
-	int i;
-
-	for (i = 0; i < strnlen(s, LOG_LINE_SIZE); i++)
-		log_char(s[i]);
-}
-
-static uint32_t process_v1log(void)
-{
-	char *last_char = log_buf->buff + log_buf->write_pos;
-	char *buff = log_buf->buff + log_pos;
-	while (buff != last_char) {
-		log_char(*(buff++));
-		/* Wrap around */
-		if (buff - (char *)log_buf >= log_size)
-			buff = log_buf->buff;
-	}
-	return buff - log_buf->buff;
+	prev_eol = false;
+	prev_source = source;
 }
 
 static const uint8_t HEX2ASCII[16] = {
 	'0', '1', '2', '3', '4', '5', '6', '7',
 	'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
 
-static void dbg_raw_nro(uint32_t format, uint32_t value)
+static void dbg_raw_nro(uint32_t format, uint32_t value, uint16_t source)
 {
 	int digits = 1;
 	uint32_t base = (format & LOG_INTEGER_DECIMAL) ? 10 : 16;
@@ -139,17 +126,17 @@
 	if (width > digits) {
 		char ch = (base == 10) ? ' ' : '0';
 		while (width > digits) {
-			log_char(ch);
+			log_char(ch, source);
 			width--;
 		}
 	}
 
 	if (negative)
-		log_char('-');
+		log_char('-', source);
 
 	while (digits-- > 0) {
 		uint32_t d = value / digit_base;
-		log_char(HEX2ASCII[d]);
+		log_char(HEX2ASCII[d], source);
 		value = value - d * digit_base;
 		digit_base /= base;
 	}
@@ -157,36 +144,32 @@
 
 static void log_msg(struct logmsg_struct *msg)
 {
-	unsigned char msgtxt[5];
-	int mpos = 0;
-
 	switch (msg->ctrl & LOG_TYPE_MASK) {
 	case LOG_TYPE_CHAR: {
 		uint32_t ch;
 		ch = msg->log_data;
 		while (ch != 0) {
-			msgtxt[mpos++] = ch&0xFF;
+			log_char(ch & 0xFF, msg->source);
 			ch >>= 8;
 		}
-		msgtxt[mpos] = 0;
-		log_str(msgtxt);
 		break;
 	}
 	case LOG_TYPE_INTEGER: {
-		dbg_raw_nro(msg->ctrl, msg->log_data);
+		dbg_raw_nro(msg->ctrl, msg->log_data, msg->source);
 		break;
 	}
 	default:
 		break;
 	}
 	if (msg->ctrl & LOG_EOL)
-		log_eol();
+		log_eol(msg->source);
 }
 
-static uint32_t process_v2log(void)
+static uint32_t process_log(void)
 {
 	char *last_msg = log_buf->buff + log_buf->write_pos;
 	char *buff = log_buf->buff + log_pos;
+
 	while (buff != last_msg) {
 		log_msg((struct logmsg_struct *)buff);
 		buff += sizeof(struct logmsg_struct);
@@ -201,19 +184,19 @@
 /* log_worker() - Worker thread processing the log_buf buffer. */
 static int log_worker(void *p)
 {
-	if (log_buf == NULL)
-		return -EFAULT;
+	int ret = 0;
+	if (log_buf == NULL) {
+		ret = -EFAULT;
+		goto err_kthread;
+	}
 
 	while (!kthread_should_stop()) {
 		if (log_buf->write_pos == log_pos)
 			schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);
 
 		switch (log_buf->version) {
-		case 1:
-			log_pos = process_v1log();
-			break;
 		case 2:
-			log_pos = process_v2log();
+			log_pos = process_log();
 			break;
 		default:
 			MCDRV_DBG_ERROR(mcd, "Unknown Mobicore log data");
@@ -222,11 +205,23 @@
 			 * Stop the thread as we have no idea what
 			 * happens next
 			 */
-			return -EFAULT;
+			ret = -EFAULT;
+			goto err_kthread;
 		}
 	}
+err_kthread:
 	MCDRV_DBG(mcd, "Logging thread stopped!");
-	return 0;
+	thread_err = ret;
+	/* Wait until the next kthread_stop() is called, if it was already
+	 * called we just slip through, if there is an error signal it and
+	 * wait to get the signal */
+	set_current_state(TASK_INTERRUPTIBLE);
+	while (!kthread_should_stop()) {
+		schedule();
+		set_current_state(TASK_INTERRUPTIBLE);
+	}
+	set_current_state(TASK_RUNNING);
+	return ret;
 }
 
 /*
@@ -239,6 +234,14 @@
 	if (log_thread == NULL || IS_ERR(log_thread))
 		return;
 
+	/* The thread itself is in some error condition so just get
+	 * rid of it */
+	if (thread_err != 0) {
+		kthread_stop(log_thread);
+		log_thread = NULL;
+		return;
+	}
+
 	wake_up_process(log_thread);
 }
 
@@ -258,6 +261,9 @@
 	log_thread = NULL;
 	log_line = NULL;
 	log_line_len = 0;
+	prev_eol = false;
+	prev_source = 0;
+	thread_err = 0;
 
 	/* Sanity check for the log size */
 	if (log_size < PAGE_SIZE)
@@ -271,11 +277,11 @@
 		return -ENOMEM;
 	}
 
-	log_thread = kthread_create(log_worker, NULL, "mobicore_log");
+	log_thread = kthread_create(log_worker, NULL, "mc_log");
 	if (IS_ERR(log_thread)) {
 		MCDRV_DBG_ERROR(mcd, "MobiCore log thread creation failed!");
 		ret = -EFAULT;
-		goto mobicore_log_setup_log_line;
+		goto err_free_line;
 	}
 
 	sched_setscheduler(log_thread, SCHED_IDLE, &param);
@@ -288,7 +294,7 @@
 	if (!log_buf) {
 		MCDRV_DBG_ERROR(mcd, "Failed to get page for logger!");
 		ret = -ENOMEM;
-		goto mobicore_log_setup_kthread;
+		goto err_stop_kthread;
 	}
 	phys_log_buf = virt_to_phys(log_buf);
 
@@ -308,16 +314,17 @@
 		free_pages((unsigned long)log_buf, get_order(log_size));
 		log_buf = NULL;
 		ret = -EIO;
-		goto mobicore_log_setup_kthread;
+		goto err_stop_kthread;
 	}
+	set_task_state(log_thread, TASK_INTERRUPTIBLE);
 
 	MCDRV_DBG(mcd, "fc_log Logger version %u\n", log_buf->version);
 	return 0;
 
-mobicore_log_setup_kthread:
+err_stop_kthread:
 	kthread_stop(log_thread);
 	log_thread = NULL;
-mobicore_log_setup_log_line:
+err_free_line:
 	kfree(log_line);
 	log_line = NULL;
 	return ret;
diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/mobicore_driver/main.c
index 1a745b3..3fc9e17 100644
--- a/drivers/gud/mobicore_driver/main.c
+++ b/drivers/gud/mobicore_driver/main.c
@@ -11,6 +11,7 @@
  * fd = open(/dev/mobicore-user)
  *
  * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -81,7 +82,7 @@
 }
 
 /* Frees the memory associated with a buffer */
-static int free_buffer(struct mc_buffer *buffer)
+static int free_buffer(struct mc_buffer *buffer, bool unlock)
 {
 	if (buffer->handle == 0)
 		return -EINVAL;
@@ -89,16 +90,15 @@
 	if (buffer->addr == 0)
 		return -EINVAL;
 
-	if (!atomic_dec_and_test(&buffer->usage)) {
+	MCDRV_DBG_VERBOSE(mcd,
+			  "handle=%u phys_addr=0x%p, virt_addr=0x%p len=%u\n",
+		  buffer->handle, buffer->phys, buffer->addr, buffer->len);
 
-		MCDRV_DBG_VERBOSE(mcd, "Could not free buffer h=%u",
-				  buffer->handle);
+	if (!atomic_dec_and_test(&buffer->usage)) {
+		MCDRV_DBG_VERBOSE(mcd, "Could not free %u", buffer->handle);
 		return 0;
 	}
 
-	MCDRV_DBG(mcd, "handle=%u phys_addr=0x%p, virt_addr=0x%p\n",
-		  buffer->handle, buffer->phys, buffer->addr);
-
 	list_del(&buffer->list);
 
 	free_continguous_pages(buffer->addr, buffer->order);
@@ -106,6 +106,37 @@
 	return 0;
 }
 
+static uint32_t mc_find_cont_wsm_addr(struct mc_instance *instance, void *uaddr,
+	uint32_t *addr, uint32_t len)
+{
+	int ret = 0;
+	struct mc_buffer *buffer;
+
+	if (WARN(!instance, "No instance data available"))
+		return -EFAULT;
+
+	mutex_lock(&instance->lock);
+
+	mutex_lock(&ctx.bufs_lock);
+
+	/* search for the given handle in the buffers list */
+	list_for_each_entry(buffer, &ctx.cont_bufs, list) {
+		if (buffer->uaddr == uaddr && buffer->len == len) {
+			*addr = (uint32_t)buffer->addr;
+			goto found;
+		}
+	}
+
+	/* Coundn't find the buffer */
+	ret = -EINVAL;
+
+found:
+	mutex_unlock(&ctx.bufs_lock);
+	mutex_unlock(&instance->lock);
+
+	return ret;
+}
+
 static uint32_t mc_find_cont_wsm(struct mc_instance *instance, uint32_t handle,
 	uint32_t *phys, uint32_t *len)
 {
@@ -152,10 +183,16 @@
  * Returns 0 if no error
  *
  */
-static int __free_buffer(struct mc_instance *instance, uint32_t handle)
+static int __free_buffer(struct mc_instance *instance, uint32_t handle,
+		bool unlock)
 {
 	int ret = 0;
 	struct mc_buffer *buffer;
+	void *uaddr = NULL;
+	size_t len = 0;
+#ifndef MC_VM_UNMAP
+	struct mm_struct *mm = current->mm;
+#endif
 
 	if (WARN(!instance, "No instance data available"))
 		return -EFAULT;
@@ -163,6 +200,46 @@
 	mutex_lock(&ctx.bufs_lock);
 	/* search for the given handle in the buffers list */
 	list_for_each_entry(buffer, &ctx.cont_bufs, list) {
+		if (buffer->handle == handle) {
+			uaddr = buffer->uaddr;
+			len = buffer->len;
+			goto found_buffer;
+		}
+	}
+	goto err;
+found_buffer:
+	if (!is_daemon(instance) || buffer->instance != instance)
+		goto err;
+	mutex_unlock(&ctx.bufs_lock);
+	/* Only unmap if the request is comming from the user space and
+	 * it hasn't already been unmapped */
+	if (unlock == false && uaddr != NULL)
+#ifndef MC_VM_UNMAP
+		/* do_munmap must be done with mm->mmap_sem taken */
+		down_write(&mm->mmap_sem);
+		ret = do_munmap(mm, (long unsigned int)uaddr, len);
+		if (ret < 0) {
+			/* Something is not right if we end up here, better not
+			 * clean the buffer so we just leak memory instead of
+			 * creating security issues */
+			MCDRV_DBG_ERROR(mcd, "Memory can't be unmapped\n");
+		}
+		up_write(&mm->mmap_sem);
+		if (ret < 0)
+			return -EINVAL;
+#else
+		if (vm_munmap((long unsigned int)uaddr, len) < 0) {
+			/* Something is not right if we end up here, better not
+			 * clean the buffer so we just leak memory instead of
+			 * creating security issues */
+			MCDRV_DBG_ERROR(mcd, "Memory can't be unmapped\n");
+			return -EINVAL;
+		}
+#endif
+
+	mutex_lock(&ctx.bufs_lock);
+	/* search for the given handle in the buffers list */
+	list_for_each_entry(buffer, &ctx.cont_bufs, list) {
 		if (buffer->handle == handle)
 			goto del_buffer;
 	}
@@ -170,7 +247,7 @@
 	goto err;
 
 del_buffer:
-	ret = free_buffer(buffer);
+	ret = free_buffer(buffer, unlock);
 err:
 	mutex_unlock(&ctx.bufs_lock);
 	return ret;
@@ -185,7 +262,7 @@
 
 	mutex_lock(&instance->lock);
 
-	ret = __free_buffer(instance, handle);
+	ret = __free_buffer(instance, handle, false);
 	mutex_unlock(&instance->lock);
 	return ret;
 }
@@ -253,8 +330,8 @@
 	INIT_LIST_HEAD(&cbuffer->list);
 	list_add(&cbuffer->list, &ctx.cont_bufs);
 
-	MCDRV_DBG(mcd,
-		  "allocated phys=0x%p - 0x%p, size=%ld, kvirt=0x%p, h=%d\n",
+	MCDRV_DBG_VERBOSE(mcd,
+			  "allocated phys=0x%p - 0x%p, size=%ld, kvirt=0x%p, h=%d\n",
 		  phys, (void *)((unsigned int)phys+allocated_size),
 		  allocated_size, addr, cbuffer->handle);
 	*buffer = cbuffer;
@@ -332,6 +409,7 @@
 	int ret = 0;
 	struct mc_l2_table *table = NULL;
 	struct task_struct *task = current;
+	uint32_t kbuff = 0x0;
 
 	if (WARN(!instance, "No instance data available"))
 		return -EFAULT;
@@ -341,7 +419,12 @@
 		return -EINVAL;
 	}
 
-	table = mc_alloc_l2_table(instance, task, (void *)buffer, len);
+	MCDRV_DBG_VERBOSE(mcd, "buffer: %p, len=%08x\n", (void *)buffer, len);
+
+	if (!mc_find_cont_wsm_addr(instance, (void *)buffer, &kbuff, len))
+		table = mc_alloc_l2_table(instance, NULL, (void *)kbuff, len);
+	else
+		table = mc_alloc_l2_table(instance, task, (void *)buffer, len);
 
 	if (IS_ERR(table)) {
 		MCDRV_DBG_ERROR(mcd, "new_used_l2_table() failed\n");
@@ -421,7 +504,7 @@
 	/* Not a l2 table, then it must be a buffer */
 	if (ret == -EINVAL) {
 		/* Call the non locking variant! */
-		ret = __free_buffer(instance, handle);
+		ret = __free_buffer(instance, handle, true);
 	}
 	mutex_unlock(&instance->lock);
 
@@ -471,8 +554,8 @@
 	struct mc_buffer *buffer = 0;
 	int ret = 0;
 
-	MCDRV_DBG(mcd, "enter (vma start=0x%p, size=%ld, mci=%p)\n",
-		  (void *)vmarea->vm_start, len, ctx.mci_base.phys);
+	MCDRV_DBG_VERBOSE(mcd, "enter (vma start=0x%p, size=%ld, mci=%p)\n",
+			  (void *)vmarea->vm_start, len, ctx.mci_base.phys);
 
 	if (WARN(!instance, "No instance data available"))
 		return -EFAULT;
@@ -496,7 +579,8 @@
 		return -EINVAL;
 
 found:
-		vmarea->vm_flags |= VM_RESERVED;
+		buffer->uaddr = (void *)vmarea->vm_start;
+		vmarea->vm_flags |= VM_IO;
 		/*
 		 * Convert kernel address to user address. Kernel address begins
 		 * at PAGE_OFFSET, user address range is below PAGE_OFFSET.
@@ -507,6 +591,10 @@
 		pfn = (unsigned int)paddr >> PAGE_SHIFT;
 		ret = (int)remap_pfn_range(vmarea, vmarea->vm_start, pfn,
 			buffer->len, vmarea->vm_page_prot);
+		/* If the remap failed then don't mark this buffer as marked
+		 * since the unmaping will also fail */
+		if (ret)
+			buffer->uaddr = NULL;
 		mutex_unlock(&ctx.bufs_lock);
 	} else {
 		if (!is_daemon(instance))
@@ -516,7 +604,7 @@
 		if (!paddr)
 			return -EFAULT;
 
-		vmarea->vm_flags |= VM_RESERVED;
+		vmarea->vm_flags |= VM_IO;
 		/*
 		 * Convert kernel address to user address. Kernel address begins
 		 * at PAGE_OFFSET, user address range is below PAGE_OFFSET.
@@ -614,8 +702,8 @@
 		map.reused = 0;
 		if (copy_to_user(uarg, &map, sizeof(map)))
 			ret = -EFAULT;
-
-		ret = 0;
+		else
+			ret = 0;
 		break;
 	}
 	default:
@@ -754,6 +842,13 @@
 		break;
 	}
 
+	case MC_IO_LOG_SETUP: {
+#ifdef MC_MEM_TRACES
+		ret = mobicore_log_setup();
+#endif
+		break;
+	}
+
 	/* The rest is handled commonly by user IOCTL */
 	default:
 		ret = mc_fd_user_ioctl(file, cmd, arg);
@@ -887,7 +982,7 @@
 	list_for_each_entry_safe(buffer, tmp, &ctx.cont_bufs, list) {
 		if (buffer->instance == instance) {
 			buffer->instance = NULL;
-			free_buffer(buffer);
+			free_buffer(buffer, false);
 		}
 	}
 	mutex_unlock(&ctx.bufs_lock);
@@ -1097,10 +1192,6 @@
 		goto free_admin;
 	}
 
-#ifdef MC_MEM_TRACES
-	mobicore_log_setup();
-#endif
-
 	/* initialize event counter for signaling of an IRQ to zero */
 	atomic_set(&ctx.isr_counter, 0);
 
@@ -1159,6 +1250,7 @@
 module_init(mobicore_init);
 module_exit(mobicore_exit);
 MODULE_AUTHOR("Giesecke & Devrient GmbH");
+MODULE_AUTHOR("Trustonic Limited");
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("MobiCore driver");
 
diff --git a/drivers/gud/mobicore_driver/main.h b/drivers/gud/mobicore_driver/main.h
index e23c516..2c316bc 100644
--- a/drivers/gud/mobicore_driver/main.h
+++ b/drivers/gud/mobicore_driver/main.h
@@ -27,7 +27,7 @@
 
 /* Instance data for MobiCore Daemon and TLCs. */
 struct mc_instance {
-	/* Instance lock */
+	/* lock for the instance */
 	struct mutex lock;
 	/* unique handle */
 	unsigned int handle;
@@ -48,6 +48,8 @@
 	atomic_t		usage;
 	/* virtual Kernel start address */
 	void			*addr;
+	/* virtual Userspace start address */
+	void			*uaddr;
 	/* physical start address */
 	void			*phys;
 	/* order of number of pages */
diff --git a/drivers/gud/mobicore_driver/mem.c b/drivers/gud/mobicore_driver/mem.c
index da711ce..1fe351b 100644
--- a/drivers/gud/mobicore_driver/mem.c
+++ b/drivers/gud/mobicore_driver/mem.c
@@ -11,6 +11,7 @@
  * which has to be created by the fd = open(/dev/mobicore) command.
  *
  * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -355,14 +356,6 @@
 	MCDRV_DBG_VERBOSE(mcd, "WSM addr=0x%p, len=0x%08x\n", wsm_buffer,
 			  wsm_len);
 
-	/*
-	 * Check if called from kernel space and if
-	 * wsm_buffer is actually vmalloced or not
-	 */
-	if (task == NULL && !is_vmalloc_addr(wsm_buffer)) {
-		MCDRV_DBG_ERROR(mcd, "WSM addr is not a vmalloc address");
-		return -EINVAL;
-	}
 
 	/* calculate page usage */
 	virt_addr_page = (void *)(((unsigned long)(wsm_buffer)) & PAGE_MASK);
@@ -405,6 +398,20 @@
 			return ret;
 		}
 	}
+	/* Request comes from kernel space(cont buffer) */
+	else if (task == NULL && !is_vmalloc_addr(wsm_buffer)) {
+		void *uaddr = wsm_buffer;
+		for (i = 0; i < nr_of_pages; i++) {
+			page = virt_to_page(uaddr);
+			if (!page) {
+				MCDRV_DBG_ERROR(mcd, "failed to map address");
+				return -EINVAL;
+			}
+			get_page(page);
+			l2table_as_array_of_pointers_to_page[i] = page;
+			uaddr += PAGE_SIZE;
+		}
+	}
 	/* Request comes from kernel space(vmalloc buffer) */
 	else {
 		void *uaddr = wsm_buffer;
diff --git a/drivers/gud/mobicore_driver/ops.c b/drivers/gud/mobicore_driver/ops.c
index 509b4e9..b44a842 100644
--- a/drivers/gud/mobicore_driver/ops.c
+++ b/drivers/gud/mobicore_driver/ops.c
@@ -11,6 +11,7 @@
  * which has to be created by the fd = open(/dev/mobicore) command.
  *
  * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -20,6 +21,8 @@
 #include <linux/kthread.h>
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/cpu.h>
 
 #include "main.h"
 #include "fastcall.h"
@@ -27,6 +30,29 @@
 #include "mem.h"
 #include "debug.h"
 
+struct fastcall_work_struct {
+	struct work_struct work;
+	void *data;
+};
+
+static void fastcall_work_func(struct work_struct *work)
+{
+	struct fastcall_work_struct *fc_work =
+		container_of(work, struct fastcall_work_struct, work);
+	_smc(fc_work->data);
+}
+
+void mc_fastcall(void *data)
+{
+	struct fastcall_work_struct work = {
+		.data = data,
+	};
+	INIT_WORK(&work.work, fastcall_work_func);
+	schedule_work_on(0, &work.work);
+
+	flush_work(&work.work);
+}
+
 int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info)
 {
 	int ret = 0;
diff --git a/drivers/gud/mobicore_driver/ops.h b/drivers/gud/mobicore_driver/ops.h
index 673399f..efe5f05 100644
--- a/drivers/gud/mobicore_driver/ops.h
+++ b/drivers/gud/mobicore_driver/ops.h
@@ -22,9 +22,6 @@
 int mc_init(uint32_t base, uint32_t  nq_offset, uint32_t  nq_length,
 	    uint32_t mcp_offset, uint32_t  mcp_length);
 
-static inline void mc_fastcall(void *data)
-{
-	work_on_cpu(0, _smc, data);
-}
+void mc_fastcall(void *data);
 
 #endif /* _MC_OPS_H_ */
diff --git a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
index 9efa026..7febcb6 100644
--- a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
+++ b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
@@ -3,6 +3,7 @@
  * its internal structures and defines.
  *
  * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -35,6 +36,11 @@
 }
 
 /* Enable mobicore mem traces */
-#define MC_MEM_TRACES
+/* #define MC_MEM_TRACES */
+
+/* Enable the use of vm_unamp instead of the deprecated do_munmap
+ * and other 3.7 features
+ */
+#define MC_VM_UNMAP
 
 #endif /* _MC_PLATFORM_H_ */
diff --git a/drivers/gud/mobicore_driver/public/mc_kernel_api.h b/drivers/gud/mobicore_driver/public/mc_kernel_api.h
index 7a038c4..cca0636 100644
--- a/drivers/gud/mobicore_driver/public/mc_kernel_api.h
+++ b/drivers/gud/mobicore_driver/public/mc_kernel_api.h
@@ -2,6 +2,7 @@
  * Interface to be used by module MobiCoreKernelAPI.
  *
  * <-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/drivers/gud/mobicore_driver/public/mc_linux.h b/drivers/gud/mobicore_driver/public/mc_linux.h
index 99b7769..bb95c26 100644
--- a/drivers/gud/mobicore_driver/public/mc_linux.h
+++ b/drivers/gud/mobicore_driver/public/mc_linux.h
@@ -11,6 +11,7 @@
  * "insmod mcDrvModule.ko".
  *
  * <-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -206,4 +207,9 @@
  * Only available to the daemon */
 #define MC_IO_RESOLVE_CONT_WSM	_IOWR(MC_IOC_MAGIC, 16, struct mc_ioctl_execute)
 
+/*
+ * Setup the mem traces when called.
+ * Only available to the daemon */
+#define MC_IO_LOG_SETUP		_IO(MC_IOC_MAGIC, 17)
+
 #endif /* _MC_LINUX_H_ */
diff --git a/drivers/gud/mobicore_driver/public/version.h b/drivers/gud/mobicore_driver/public/version.h
index b08dd95..591ca3d 100644
--- a/drivers/gud/mobicore_driver/public/version.h
+++ b/drivers/gud/mobicore_driver/public/version.h
@@ -1,5 +1,6 @@
 /*
  * <-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
diff --git a/drivers/gud/mobicore_kernelapi/include/mcinq.h b/drivers/gud/mobicore_kernelapi/include/mcinq.h
index b874925..34216a7 100644
--- a/drivers/gud/mobicore_kernelapi/include/mcinq.h
+++ b/drivers/gud/mobicore_kernelapi/include/mcinq.h
@@ -112,6 +112,6 @@
 	struct notification_queue_header hdr;
 	/* Notification elements. */
 	struct notification notification[MIN_NQ_ELEM];
-} ;
+};
 
 #endif /* _MCINQ_H_ */
diff --git a/drivers/gud/mobicore_kernelapi/main.c b/drivers/gud/mobicore_kernelapi/main.c
index 50359b1..73de93a 100644
--- a/drivers/gud/mobicore_kernelapi/main.c
+++ b/drivers/gud/mobicore_kernelapi/main.c
@@ -139,13 +139,27 @@
 
 static int __init mcapi_init(void)
 {
+	/* struct netlink_kernel_cfg netlink_cfg; */
+
 	dev_set_name(mc_kapi, "mcapi");
 
 	dev_info(mc_kapi, "Mobicore API module initialized!\n");
 
+	/*
+	 * netlink_cfg.groups = 0;
+	 * netlink_cfg.flags = 0;
+	 * netlink_cfg.input = mcapi_callback;
+	 * netlink_cfg.cb_mutex = NULL;
+	 * netlink_cfg.bind = NULL;
+	 */
 	mod_ctx = kzalloc(sizeof(struct mc_kernelapi_ctx), GFP_KERNEL);
 
 	/* start kernel thread */
+
+	/*
+	 * mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK,
+	 *					    &netlink_cfg);
+	 */
 	mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK, 0,
 					    mcapi_callback, NULL, THIS_MODULE);
 
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..da43a08 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"};
 
@@ -191,14 +192,18 @@
 qup_i2c_interrupt(int irq, void *devid)
 {
 	struct qup_i2c_dev *dev = devid;
-	uint32_t status = readl_relaxed(dev->base + QUP_I2C_STATUS);
-	uint32_t status1 = readl_relaxed(dev->base + QUP_ERROR_FLAGS);
-	uint32_t op_flgs = readl_relaxed(dev->base + QUP_OPERATIONAL);
+	uint32_t status = 0;
+	uint32_t status1 = 0;
+	uint32_t op_flgs = 0;
 	int err = 0;
 
 	if (pm_runtime_suspended(dev->dev))
 		return IRQ_NONE;
 
+	status = readl_relaxed(dev->base + QUP_I2C_STATUS);
+	status1 = readl_relaxed(dev->base + QUP_ERROR_FLAGS);
+	op_flgs = readl_relaxed(dev->base + QUP_OPERATIONAL);
+
 	if (!dev->msg || !dev->complete) {
 		/* Clear Error interrupt if it's a level triggered interrupt*/
 		if (dev->num_irqs == 1) {
@@ -1235,18 +1240,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/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index c78eec3..b43c13e 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -999,4 +999,13 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called synaptics_dsx_fw_update.
 
+config SECURE_TOUCH
+	bool "Secure Touch"
+	depends on TOUCHSCREEN_ATMEL_MXT
+	help
+	  Say Y here to enable Secure Touch support in the Atmel MXT
+	  driver.
+
+	  If unsure, say N.
+
 endif
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 1d56a0a..0c20815 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -38,6 +38,14 @@
 #define MXT_SUSPEND_LEVEL 1
 #endif
 
+#if defined(CONFIG_SECURE_TOUCH)
+#include <linux/completion.h>
+#include <linux/pm_runtime.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <linux/atomic.h>
+#endif
+
 /* Family ID */
 #define MXT224_ID	0x80
 #define MXT224E_ID	0x81
@@ -383,6 +391,11 @@
 	bool update_cfg;
 	const char *fw_name;
 	bool no_force_update;
+#if defined(CONFIG_SECURE_TOUCH)
+	atomic_t st_enabled;
+	atomic_t st_pending_irqs;
+	struct completion st_completion;
+#endif
 };
 
 static struct dentry *debug_base;
@@ -979,6 +992,23 @@
 		mxt_release_all(data);
 }
 
+#if defined(CONFIG_SECURE_TOUCH)
+static irqreturn_t mxt_filter_interrupt(struct mxt_data *data)
+{
+	if (atomic_read(&data->st_enabled)) {
+		atomic_cmpxchg(&data->st_pending_irqs, 0, 1);
+		complete(&data->st_completion);
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+}
+#else
+static irqreturn_t mxt_filter_interrupt(struct mxt_data *data)
+{
+	return IRQ_NONE;
+}
+#endif
+
 static irqreturn_t mxt_interrupt(int irq, void *dev_id)
 {
 	struct mxt_data *data = dev_id;
@@ -992,6 +1022,9 @@
 		return IRQ_HANDLED;
 	}
 
+	if (IRQ_HANDLED == mxt_filter_interrupt(data))
+		goto end;
+
 	do {
 		if (mxt_read_message(data, &message)) {
 			dev_err(dev, "Failed to read message\n");
@@ -1910,6 +1943,100 @@
 	return count;
 }
 
+#if defined(CONFIG_SECURE_TOUCH)
+
+static ssize_t mxt_secure_touch_enable_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct mxt_data *data = dev_get_drvdata(dev);
+	return scnprintf(buf, PAGE_SIZE, "%d", atomic_read(&data->st_enabled));
+}
+/*
+ * Accept only "0" and "1" valid values.
+ * "0" will reset the st_enabled flag, then wake up the reading process.
+ * The bus driver is notified via pm_runtime that it is not required to stay
+ * awake anymore.
+ * It will also make sure the queue of events is emptied in the controller,
+ * in case a touch happened in between the secure touch being disabled and
+ * the local ISR being ungated.
+ * "1" will set the st_enabled flag and clear the st_pending_irqs flag.
+ * The bus driver is requested via pm_runtime to stay awake.
+ */
+static ssize_t mxt_secure_touch_enable_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct mxt_data *data = dev_get_drvdata(dev);
+	unsigned long value;
+	int err = 0;
+
+	if (count > 2)
+		return -EINVAL;
+
+	err = kstrtoul(buf, 10, &value);
+	if (err != 0)
+		return err;
+
+	err = count;
+
+	switch (value) {
+	case 0:
+		if (atomic_read(&data->st_enabled) == 0)
+			break;
+
+		pm_runtime_put(&data->client->adapter->dev);
+		atomic_set(&data->st_enabled, 0);
+		complete(&data->st_completion);
+		mxt_interrupt(data->client->irq, data);
+		break;
+	case 1:
+		if (atomic_read(&data->st_enabled)) {
+			err = -EBUSY;
+			break;
+		}
+
+		if (pm_runtime_get(data->client->adapter->dev.parent) < 0) {
+			dev_err(&data->client->dev, "pm_runtime_get failed\n");
+			err = -EIO;
+			break;
+		}
+		atomic_set(&data->st_pending_irqs, 0);
+		atomic_set(&data->st_enabled, 1);
+		break;
+	default:
+		dev_err(&data->client->dev, "unsupported value: %lu\n", value);
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static ssize_t mxt_secure_touch_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct mxt_data *data = dev_get_drvdata(dev);
+	int err;
+
+	if (atomic_read(&data->st_enabled) == 0)
+		return -EBADF;
+
+	err = wait_for_completion_interruptible(&data->st_completion);
+
+	if (err)
+		return err;
+
+	if (atomic_cmpxchg(&data->st_pending_irqs, 1, 0) != 1)
+		return -EBADF;
+
+	return scnprintf(buf, PAGE_SIZE, "%u", 1);
+}
+
+static DEVICE_ATTR(secure_touch_enable, 0666, mxt_secure_touch_enable_show,
+	mxt_secure_touch_enable_store);
+static DEVICE_ATTR(secure_touch, 0444, mxt_secure_touch_show, NULL);
+#endif
+
 static DEVICE_ATTR(object, 0444, mxt_object_show, NULL);
 static DEVICE_ATTR(update_fw, 0664, NULL, mxt_update_fw_store);
 static DEVICE_ATTR(force_cfg_update, 0664, NULL, mxt_force_cfg_update_store);
@@ -1918,6 +2045,10 @@
 	&dev_attr_object.attr,
 	&dev_attr_update_fw.attr,
 	&dev_attr_force_cfg_update.attr,
+#if defined(CONFIG_SECURE_TOUCH)
+	&dev_attr_secure_touch_enable.attr,
+	&dev_attr_secure_touch.attr,
+#endif
 	NULL
 };
 
@@ -2655,6 +2786,17 @@
 
 #endif
 
+#if defined(CONFIG_SECURE_TOUCH)
+static void __devinit secure_touch_init(struct mxt_data *data)
+{
+	init_completion(&data->st_completion);
+}
+#else
+static void __devinit secure_touch_init(struct mxt_data *data)
+{
+}
+#endif
+
 static int __devinit mxt_probe(struct i2c_client *client,
 		const struct i2c_device_id *id)
 {
@@ -2840,6 +2982,8 @@
 
 	mxt_debugfs_init(data);
 
+	secure_touch_init(data);
+
 	return 0;
 
 err_unregister_device:
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index c447231..abb5bbc 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -1529,7 +1529,7 @@
 static ssize_t fwu_sysfs_config_id_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
-	unsigned char config_id[8];
+	unsigned char config_id[4];
 	/* device config id */
 	fwu->fn_ptr->read(fwu->rmi4_data,
 				fwu->f34_fd.ctrl_base_addr,
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/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index b8c507e..8ce8dbf 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -320,7 +320,8 @@
 		if (BUF_SRC(bufq->stream_id))
 			list_add_tail(&buf_info->list, &bufq->head);
 		else
-			buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf);
+			buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf,
+				bufq->session_id, bufq->stream_id);
 		buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED;
 		rc = 0;
 		break;
@@ -366,7 +367,8 @@
 		} else {
 			buf_info->vb2_buf->v4l2_buf.timestamp = *tv;
 			buf_info->vb2_buf->v4l2_buf.sequence  = frame_id;
-			buf_mgr->vb2_ops->buf_done(buf_info->vb2_buf);
+			buf_mgr->vb2_ops->buf_done(buf_info->vb2_buf,
+				bufq->session_id, bufq->stream_id);
 		}
 	}
 
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index d412435..d714ffb 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -54,27 +54,34 @@
 	DISABLE_CAMIF_IMMEDIATELY
 };
 
+struct msm_isp_timestamp {
+	/*Monotonic clock for v4l2 buffer*/
+	struct timeval buf_time;
+	/*Wall clock for userspace event*/
+	struct timeval event_time;
+};
+
 struct msm_vfe_irq_ops {
 	void (*read_irq_status) (struct vfe_device *vfe_dev,
 		uint32_t *irq_status0, uint32_t *irq_status1);
 	void (*process_reg_update) (struct vfe_device *vfe_dev,
 		uint32_t irq_status0, uint32_t irq_status1,
-		struct timeval *tv);
+		struct msm_isp_timestamp *ts);
 	void (*process_reset_irq) (struct vfe_device *vfe_dev,
 		uint32_t irq_status0, uint32_t irq_status1);
 	void (*process_halt_irq) (struct vfe_device *vfe_dev,
 		uint32_t irq_status0, uint32_t irq_status1);
 	void (*process_camif_irq) (struct vfe_device *vfe_dev,
 		uint32_t irq_status0, uint32_t irq_status1,
-		struct timeval *tv);
+		struct msm_isp_timestamp *ts);
 	void (*process_axi_irq) (struct vfe_device *vfe_dev,
 		uint32_t irq_status0, uint32_t irq_status1,
-		struct timeval *tv);
+		struct msm_isp_timestamp *ts);
 	void (*process_error_irq) (struct vfe_device *vfe_dev,
 		uint32_t irq_status0, uint32_t irq_status1);
 	void (*process_stats_irq) (struct vfe_device *vfe_dev,
 		uint32_t irq_status0, uint32_t irq_status1,
-		struct timeval *tv);
+		struct msm_isp_timestamp *ts);
 };
 
 struct msm_vfe_axi_ops {
@@ -109,10 +116,6 @@
 	void (*clear_wm_xbar_reg) (struct vfe_device *vfe_dev,
 		struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
 
-	void (*cfg_rdi_reg) (struct vfe_device *vfe_dev,
-		struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
-		uint8_t plane_idx);
-
 	void (*cfg_ub) (struct vfe_device *vfe_dev);
 
 	void (*update_ping_pong_addr) (struct vfe_device *vfe_dev,
@@ -125,7 +128,7 @@
 };
 
 struct msm_vfe_core_ops {
-	void (*reg_update) (struct vfe_device *vfe_dev, uint32_t update_mask);
+	void (*reg_update) (struct vfe_device *vfe_dev);
 	long (*reset_hw) (struct vfe_device *vfe_dev);
 	int (*init_hw) (struct vfe_device *vfe_dev);
 	void (*init_hw_reg) (struct vfe_device *vfe_dev);
@@ -134,6 +137,9 @@
 		struct msm_vfe_pix_cfg *pix_cfg);
 	void (*update_camif_state) (struct vfe_device *vfe_dev,
 		enum msm_isp_camif_update_state update_state);
+	void (*cfg_rdi_reg) (struct vfe_device *vfe_dev,
+		struct msm_vfe_rdi_cfg *rdi_cfg,
+		enum msm_vfe_input_src input_src);
 	int (*get_platform_data) (struct vfe_device *vfe_dev);
 	void (*get_error_mask) (uint32_t *error_mask0, uint32_t *error_mask1);
 	void (*process_error_status) (struct vfe_device *vfe_dev);
@@ -224,8 +230,6 @@
 	enum msm_vfe_axi_stream_src stream_src;
 	uint8_t num_planes;
 	uint8_t wm[MAX_PLANES_PER_STREAM];
-	uint8_t rdi[MAX_PLANES_PER_STREAM];
-	uint8_t rdi_master[MAX_PLANES_PER_STREAM];
 	uint8_t comp_mask_index;
 	struct msm_isp_buffer *buf[2];
 	uint32_t session_id;
@@ -235,13 +239,18 @@
 	uint8_t buf_divert;
 	enum msm_vfe_axi_stream_type stream_type;
 
+	uint32_t frame_based;
 	uint32_t framedrop_period;
 	uint32_t framedrop_pattern;
+	uint32_t num_burst_capture;/*number of frame to capture*/
 	uint32_t init_frame_drop;
 	uint32_t burst_frame_count;/*number of sof before burst stop*/
-	uint32_t num_burst_capture;/*number of frame to capture*/
-	uint8_t auto_trigger_stop;
 	uint8_t framedrop_update;
+
+	/*Run time update variables*/
+	uint32_t runtime_init_frame_drop;
+	uint32_t runtime_burst_frame_count;/*number of sof before burst stop*/
+	uint8_t runtime_framedrop_update;
 };
 
 struct msm_vfe_axi_composite_info {
@@ -270,9 +279,6 @@
 	uint32_t wm_image_size[MAX_NUM_WM];
 	enum msm_wm_ub_cfg_type wm_ub_cfg_policy;
 	uint8_t num_used_wm;
-	uint8_t free_rdi[MAX_NUM_RDI];
-	uint8_t free_rdi_master[MAX_NUM_RDI][MAX_NUM_RDI_MASTER];
-	uint8_t num_used_rdi;
 	uint8_t num_active_stream;
 	struct msm_vfe_axi_composite_info
 		composite_info[MAX_NUM_COMPOSITE_MASK];
@@ -325,7 +331,7 @@
 	struct list_head list;
 	uint32_t vfeInterruptStatus0;
 	uint32_t vfeInterruptStatus1;
-	struct timeval tv;
+	struct msm_isp_timestamp ts;
 	uint8_t cmd_used;
 };
 
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index 750963c..8f00e80 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -24,10 +24,7 @@
 #define VFE32_BURST_LEN 4
 #define VFE32_EQUAL_SLICE_UB 117
 #define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx)
-#define VFE32_RDI_BASE(idx) (0x734 + 0x4 * idx)
-#define VFE32_RDI_MN_BASE(m) (0x734 + 0x4 * m/3)
-#define VFE32_RDI_MN_SEL_SHIFT(m) (4*(m%3) + 4)
-#define VFE32_RDI_MN_FB_SHIFT(m) ((m%3) + 16)
+#define VFE32_RDI_BASE(idx) (idx ? 0x734 + 0x4 * (idx - 1) : 0x06FC)
 #define VFE32_XBAR_BASE(idx) (0x40 + 0x4 * (idx / 4))
 #define VFE32_XBAR_SHIFT(idx) ((idx % 4) * 8)
 #define VFE32_PING_PONG_BASE(wm, ping_pong) \
@@ -170,7 +167,8 @@
 }
 
 static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev,
-	uint32_t irq_status0, uint32_t irq_status1, struct timeval *tv)
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
 {
 	if (!(irq_status0 & 0x1F))
 		return;
@@ -178,12 +176,13 @@
 	if (irq_status0 & BIT(0)) {
 		ISP_DBG("%s: PIX0 frame id: %lu\n", __func__,
 			vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
-		msm_isp_sof_notify(vfe_dev, VFE_PIX_0, tv);
+		msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
 	}
 }
 
 static void msm_vfe32_process_stats_irq(struct vfe_device *vfe_dev,
-	uint32_t irq_status0, uint32_t irq_status1, struct timeval *tv)
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
 {
 	/* todo: add stats specific code */
 	return;
@@ -321,7 +320,8 @@
 }
 
 static void msm_vfe32_process_reg_update(struct vfe_device *vfe_dev,
-	uint32_t irq_status0, uint32_t irq_status1, struct timeval *tv)
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
 {
 	if (!(irq_status0 & 0x20) && !(irq_status1 & 0x1C000000))
 		return;
@@ -336,9 +336,9 @@
 }
 
 static void msm_vfe32_reg_update(
-	struct vfe_device *vfe_dev, uint32_t update_mask)
+	struct vfe_device *vfe_dev)
 {
-	msm_camera_io_w_mb(update_mask, vfe_dev->vfe_base + 0x260);
+	msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x260);
 }
 
 static long msm_vfe32_reset_hardware(struct vfe_device *vfe_dev)
@@ -358,12 +358,14 @@
 static void msm_vfe32_axi_enable_wm(struct vfe_device *vfe_dev,
 	uint8_t wm_idx, uint8_t enable)
 {
+	uint32_t val = msm_camera_io_r(
+	   vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx));
 	if (enable)
-		msm_camera_io_w_mb(0x1,
-			vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx));
+		val |= 0x1;
 	else
-		msm_camera_io_w_mb(0x0,
-			vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx));
+		val &= ~0x1;
+	msm_camera_io_w_mb(val,
+		vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx));
 }
 
 static void msm_vfe32_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
@@ -423,13 +425,13 @@
 {
 	uint32_t framedrop_pattern = 0, framedrop_period = 0;
 
-	if (stream_info->init_frame_drop == 0) {
+	if (stream_info->runtime_init_frame_drop == 0) {
 		framedrop_pattern = stream_info->framedrop_pattern;
 		framedrop_period = stream_info->framedrop_period;
 	}
 
 	if (stream_info->stream_type == BURST_STREAM &&
-		stream_info->burst_frame_count == 0) {
+		stream_info->runtime_burst_frame_count == 0) {
 		framedrop_pattern = 0;
 		framedrop_period = 0;
 	}
@@ -519,6 +521,27 @@
 	}
 }
 
+static void msm_vfe32_cfg_rdi_reg(struct vfe_device *vfe_dev,
+	struct msm_vfe_rdi_cfg *rdi_cfg, enum msm_vfe_input_src input_src)
+{
+	uint8_t rdi = input_src - VFE_RAW_0;
+	uint32_t rdi_reg_cfg;
+	rdi_reg_cfg = msm_camera_io_r(
+		vfe_dev->vfe_base + VFE32_RDI_BASE(0));
+	rdi_reg_cfg &= ~(BIT(16 + rdi));
+	rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi);
+	msm_camera_io_w(rdi_reg_cfg,
+		vfe_dev->vfe_base + VFE32_RDI_BASE(0));
+
+	rdi_reg_cfg = msm_camera_io_r(
+		vfe_dev->vfe_base + VFE32_RDI_BASE(rdi));
+	rdi_reg_cfg &= 0x70003;
+	rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4;
+	msm_camera_io_w(
+		rdi_reg_cfg, vfe_dev->vfe_base + VFE32_RDI_BASE(rdi));
+
+}
+
 static void msm_vfe32_axi_cfg_wm_reg(
 	struct vfe_device *vfe_dev,
 	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
@@ -531,22 +554,37 @@
 			(stream_cfg_cmd->axi_stream_handle & 0xFF)];
 	uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]);
 
-	/*WR_IMAGE_SIZE*/
-	val =
-		((msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
-		stream_cfg_cmd->plane_cfg[
-			plane_idx].output_width)+1)/2 - 1) << 16 |
-		(stream_cfg_cmd->plane_cfg[plane_idx].output_height - 1);
-	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10);
+	if (!stream_info->frame_based) {
+		/*WR_IMAGE_SIZE*/
+		val =
+			((msm_isp_cal_word_per_line(
+			stream_cfg_cmd->output_format,
+			stream_cfg_cmd->plane_cfg[plane_idx].
+			output_width)+1)/2 - 1) << 16 |
+			(stream_cfg_cmd->plane_cfg[plane_idx].
+			output_height - 1);
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10);
 
-	/*WR_BUFFER_CFG*/
-	val =
-		msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
-		  stream_cfg_cmd->plane_cfg[plane_idx].output_stride) << 16 |
-		(stream_cfg_cmd->plane_cfg[
-			plane_idx].output_scan_lines - 1) << 4 |
-		VFE32_BURST_LEN >> 2;
-	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+		/*WR_BUFFER_CFG*/
+		val =
+			msm_isp_cal_word_per_line(
+			stream_cfg_cmd->output_format,
+			stream_cfg_cmd->plane_cfg[plane_idx].
+			output_stride) << 16 |
+			(stream_cfg_cmd->plane_cfg[plane_idx].
+			output_height - 1) << 4 | VFE32_BURST_LEN >> 2;
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+	} else {
+		msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
+		val =
+			msm_isp_cal_word_per_line(
+			stream_cfg_cmd->output_format,
+			stream_cfg_cmd->plane_cfg[plane_idx].
+			output_width) << 16 |
+			(stream_cfg_cmd->plane_cfg[plane_idx].
+			output_height - 1) << 4 | VFE32_BURST_LEN >> 2;
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+	}
 	return;
 }
 
@@ -563,36 +601,6 @@
 	return;
 }
 
-static void msm_vfe32_axi_cfg_rdi_reg(
-	struct vfe_device *vfe_dev,
-	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
-	uint8_t plane_idx)
-{
-	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
-	struct msm_vfe_axi_stream *stream_info =
-	 &axi_data->stream_info[(stream_cfg_cmd->axi_stream_handle & 0xFF)];
-	struct msm_vfe_axi_plane_cfg *plane_cfg =
-		&stream_cfg_cmd->plane_cfg[plane_idx];
-	uint8_t rdi = stream_info->rdi[plane_idx];
-	uint8_t rdi_master = stream_info->rdi_master[plane_idx];
-	uint32_t rdi_reg_cfg;
-
-	rdi_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_RDI_BASE(rdi));
-	rdi_reg_cfg = (rdi_reg_cfg & 0xFFFFFFF) | rdi_master << 28;
-	msm_camera_io_w(rdi_reg_cfg, vfe_dev->vfe_base + VFE32_RDI_BASE(rdi));
-
-	rdi_reg_cfg = msm_camera_io_r(
-		vfe_dev->vfe_base + VFE32_RDI_MN_BASE(rdi_master));
-	rdi_reg_cfg &= ~((0xF << VFE32_RDI_MN_SEL_SHIFT(rdi_master)) |
-		BIT(VFE32_RDI_MN_FB_SHIFT(rdi_master)));
-	rdi_reg_cfg |= (plane_cfg->rdi_cid <<
-		VFE32_RDI_MN_SEL_SHIFT(rdi_master) |
-		(stream_cfg_cmd->frame_base <<
-			VFE32_RDI_MN_FB_SHIFT(rdi_master)));
-	msm_camera_io_w(rdi_reg_cfg, vfe_dev->vfe_base +
-		VFE32_RDI_MN_BASE(rdi_master));
-}
-
 static void msm_vfe32_axi_cfg_wm_xbar_reg(
 	struct vfe_device *vfe_dev,
 	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
@@ -633,13 +641,14 @@
 	case IDEAL_RAW:
 		xbar_cfg = 0x80;
 		break;
-	case RDI:
-		if (stream_info->rdi[plane_idx] == 0)
-			xbar_cfg = 0xA0;
-		else if (stream_info->rdi[plane_idx] == 1)
-			xbar_cfg = 0xC0;
-		else if (stream_info->rdi[plane_idx] == 2)
-			xbar_cfg = 0xE0;
+	case RDI_INTF_0:
+		xbar_cfg = 0xA0;
+		break;
+	case RDI_INTF_1:
+		xbar_cfg = 0xC0;
+		break;
+	case RDI_INTF_2:
+		xbar_cfg = 0xE0;
 		break;
 	default:
 		pr_err("%s: Invalid stream src\n", __func__);
@@ -881,7 +890,6 @@
 			.clear_wm_reg = msm_vfe32_axi_clear_wm_reg,
 			.cfg_wm_xbar_reg = msm_vfe32_axi_cfg_wm_xbar_reg,
 			.clear_wm_xbar_reg = msm_vfe32_axi_clear_wm_xbar_reg,
-			.cfg_rdi_reg = msm_vfe32_axi_cfg_rdi_reg,
 			.cfg_ub = msm_vfe32_cfg_axi_ub,
 			.update_ping_pong_addr =
 				msm_vfe32_update_ping_pong_addr,
@@ -894,6 +902,7 @@
 			.reg_update = msm_vfe32_reg_update,
 			.cfg_camif = msm_vfe32_cfg_camif,
 			.update_camif_state = msm_vfe32_update_camif_state,
+			.cfg_rdi_reg = msm_vfe32_cfg_rdi_reg,
 			.reset_hw = msm_vfe32_reset_hardware,
 			.init_hw = msm_vfe32_init_hardware,
 			.init_hw_reg = msm_vfe32_init_hardware_reg,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index ed4aa7f..1d931df 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -30,13 +30,11 @@
 #endif
 
 #define VFE40_BURST_LEN 3
+#define VFE40_STATS_BURST_LEN 2
 #define VFE40_UB_SIZE 1536
-#define VFE40_EQUAL_SLICE_UB 304
+#define VFE40_EQUAL_SLICE_UB 286
 #define VFE40_WM_BASE(idx) (0x6C + 0x24 * idx)
 #define VFE40_RDI_BASE(idx) (0x2E8 + 0x4 * idx)
-#define VFE40_RDI_MN_BASE(m) (0x2E8 + 0x4 * m/3)
-#define VFE40_RDI_MN_SEL_SHIFT(m) (4*(m%3) + 4)
-#define VFE40_RDI_MN_FB_SHIFT(m) ((m%3) + 16)
 #define VFE40_XBAR_BASE(idx) (0x58 + 0x4 * (idx / 2))
 #define VFE40_XBAR_SHIFT(idx) ((idx%2) ? 16 : 0)
 #define VFE40_PING_PONG_BASE(wm, ping_pong) \
@@ -284,7 +282,8 @@
 }
 
 static void msm_vfe40_process_camif_irq(struct vfe_device *vfe_dev,
-	uint32_t irq_status0, uint32_t irq_status1, struct timeval *tv)
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
 {
 	if (!(irq_status0 & 0xF))
 		return;
@@ -294,7 +293,7 @@
 		if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
 			&& vfe_dev->axi_data.src_info[VFE_PIX_0].
 			pix_stream_count == 0) {
-			msm_isp_sof_notify(vfe_dev, VFE_PIX_0, tv);
+			msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
 			msm_isp_update_framedrop_reg(vfe_dev);
 		}
 	}
@@ -445,35 +444,33 @@
 }
 
 static void msm_vfe40_process_reg_update(struct vfe_device *vfe_dev,
-	uint32_t irq_status0, uint32_t irq_status1, struct timeval *tv)
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
 {
-	uint32_t update_mask = 0xF;
 	if (!(irq_status0 & 0xF0))
 		return;
 
 	if (irq_status0 & BIT(4))
-		msm_isp_sof_notify(vfe_dev, VFE_PIX_0, tv);
+		msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
 	if (irq_status0 & BIT(5))
-		msm_isp_sof_notify(vfe_dev, VFE_RAW_0, tv);
+		msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts);
 	if (irq_status0 & BIT(6))
-		msm_isp_sof_notify(vfe_dev, VFE_RAW_1, tv);
+		msm_isp_sof_notify(vfe_dev, VFE_RAW_1, ts);
 	if (irq_status0 & BIT(7))
-		msm_isp_sof_notify(vfe_dev, VFE_RAW_2, tv);
+		msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts);
 
 	if (vfe_dev->axi_data.stream_update)
 		msm_isp_axi_stream_update(vfe_dev);
 	msm_isp_update_framedrop_reg(vfe_dev);
 	msm_isp_update_error_frame_count(vfe_dev);
 
-	vfe_dev->hw_info->vfe_ops.core_ops.
-		reg_update(vfe_dev, update_mask);
+	vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
 	return;
 }
 
-static void msm_vfe40_reg_update(
-	struct vfe_device *vfe_dev, uint32_t update_mask)
+static void msm_vfe40_reg_update(struct vfe_device *vfe_dev)
 {
-	msm_camera_io_w_mb(update_mask, vfe_dev->vfe_base + 0x378);
+	msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x378);
 }
 
 static long msm_vfe40_reset_hardware(struct vfe_device *vfe_dev)
@@ -493,12 +490,14 @@
 static void msm_vfe40_axi_enable_wm(struct vfe_device *vfe_dev,
 	uint8_t wm_idx, uint8_t enable)
 {
+	uint32_t val;
+	val = msm_camera_io_r(vfe_dev->vfe_base + VFE40_WM_BASE(wm_idx));
 	if (enable)
-		msm_camera_io_w_mb(0x1,
-			vfe_dev->vfe_base + VFE40_WM_BASE(wm_idx));
+		val |= 0x1;
 	else
-		msm_camera_io_w_mb(0x0,
-			vfe_dev->vfe_base + VFE40_WM_BASE(wm_idx));
+		val &= ~0x1;
+	msm_camera_io_w_mb(val,
+		vfe_dev->vfe_base + VFE40_WM_BASE(wm_idx));
 }
 
 static void msm_vfe40_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
@@ -559,13 +558,13 @@
 	uint32_t i, temp;
 	uint32_t framedrop_pattern = 0, framedrop_period = 0;
 
-	if (stream_info->init_frame_drop == 0) {
+	if (stream_info->runtime_init_frame_drop == 0) {
 		framedrop_pattern = stream_info->framedrop_pattern;
 		framedrop_period = stream_info->framedrop_period;
 	}
 
 	if (stream_info->stream_type == BURST_STREAM &&
-			stream_info->burst_frame_count == 0) {
+			stream_info->runtime_burst_frame_count == 0) {
 		framedrop_pattern = 0;
 		framedrop_period = 0;
 	}
@@ -622,7 +621,9 @@
 		break;
 	case PIX_ENCODER:
 	case PIX_VIEWFINDER:
-	case RDI:
+	case RDI_INTF_0:
+	case RDI_INTF_1:
+	case RDI_INTF_2:
 	default:
 		pr_err("%s: Invalid stream source\n", __func__);
 		return;
@@ -707,6 +708,27 @@
 	}
 }
 
+static void msm_vfe40_cfg_rdi_reg(
+	struct vfe_device *vfe_dev, struct msm_vfe_rdi_cfg *rdi_cfg,
+	enum msm_vfe_input_src input_src)
+{
+	uint8_t rdi = input_src - VFE_RAW_0;
+	uint32_t rdi_reg_cfg;
+	rdi_reg_cfg = msm_camera_io_r(
+		vfe_dev->vfe_base + VFE40_RDI_BASE(0));
+	rdi_reg_cfg &= ~(BIT(16 + rdi));
+	rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi);
+	msm_camera_io_w(rdi_reg_cfg,
+		vfe_dev->vfe_base + VFE40_RDI_BASE(0));
+
+	rdi_reg_cfg = msm_camera_io_r(
+		vfe_dev->vfe_base + VFE40_RDI_BASE(rdi));
+	rdi_reg_cfg &= 0x70003;
+	rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4;
+	msm_camera_io_w(
+		rdi_reg_cfg, vfe_dev->vfe_base + VFE40_RDI_BASE(rdi));
+}
+
 static void msm_vfe40_axi_cfg_wm_reg(
 	struct vfe_device *vfe_dev,
 	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
@@ -719,24 +741,37 @@
 			(stream_cfg_cmd->axi_stream_handle & 0xFF)];
 	uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]);
 
-	/*WR_IMAGE_SIZE*/
-	val =
-		((msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
-		stream_cfg_cmd->plane_cfg[plane_idx].
-			output_width)+1)/2 - 1) << 16 |
-			(stream_cfg_cmd->plane_cfg[plane_idx].
-			output_height - 1);
-	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+	if (!stream_info->frame_based) {
+		/*WR_IMAGE_SIZE*/
+		val =
+			((msm_isp_cal_word_per_line(
+				stream_cfg_cmd->output_format,
+				stream_cfg_cmd->plane_cfg[plane_idx].
+				output_width)+1)/2 - 1) << 16 |
+				(stream_cfg_cmd->plane_cfg[plane_idx].
+				output_height - 1);
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
 
-	/*WR_BUFFER_CFG*/
-	val =
-		msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
-		stream_cfg_cmd->plane_cfg[
-			plane_idx].output_stride) << 16 |
-		(stream_cfg_cmd->plane_cfg[
-			plane_idx].output_height - 1) << 4 |
-		VFE40_BURST_LEN;
-	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
+		/*WR_BUFFER_CFG*/
+		val =
+			msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
+			stream_cfg_cmd->plane_cfg[
+				plane_idx].output_stride) << 16 |
+			(stream_cfg_cmd->plane_cfg[
+				plane_idx].output_height - 1) << 4 |
+			VFE40_BURST_LEN;
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
+	} else {
+		msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
+		val =
+			msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
+			stream_cfg_cmd->plane_cfg[
+				plane_idx].output_width) << 16 |
+			(stream_cfg_cmd->plane_cfg[
+				plane_idx].output_height - 1) << 4 |
+			VFE40_BURST_LEN;
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
+	}
 
 	/*WR_IRQ_SUBSAMPLE_PATTERN*/
 	msm_camera_io_w(0xFFFFFFFF,
@@ -762,40 +797,6 @@
 	return;
 }
 
-static void msm_vfe40_axi_cfg_rdi_reg(
-	struct vfe_device *vfe_dev,
-	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
-	uint8_t plane_idx)
-{
-	struct msm_vfe_axi_shared_data *axi_data =
-		&vfe_dev->axi_data;
-	struct msm_vfe_axi_stream *stream_info =
-		&axi_data->stream_info[
-			(stream_cfg_cmd->axi_stream_handle & 0xFF)];
-	struct msm_vfe_axi_plane_cfg *plane_cfg =
-		&stream_cfg_cmd->plane_cfg[plane_idx];
-	uint8_t rdi = stream_info->rdi[plane_idx];
-	uint8_t rdi_master = stream_info->rdi_master[plane_idx];
-	uint32_t rdi_reg_cfg;
-
-	rdi_reg_cfg = msm_camera_io_r(
-		vfe_dev->vfe_base + VFE40_RDI_BASE(rdi));
-	rdi_reg_cfg = (rdi_reg_cfg & 0xFFFFFFF) | rdi_master << 28;
-	msm_camera_io_w(
-		rdi_reg_cfg, vfe_dev->vfe_base + VFE40_RDI_BASE(rdi));
-
-	rdi_reg_cfg = msm_camera_io_r(
-		vfe_dev->vfe_base + VFE40_RDI_MN_BASE(rdi_master));
-	rdi_reg_cfg &= ~((0xF << VFE40_RDI_MN_SEL_SHIFT(rdi_master)) |
-		(0x1 << VFE40_RDI_MN_FB_SHIFT(rdi_master)));
-	rdi_reg_cfg |=
-		(plane_cfg->rdi_cid << VFE40_RDI_MN_SEL_SHIFT(rdi_master) |
-		(stream_cfg_cmd->frame_base <<
-		VFE40_RDI_MN_FB_SHIFT(rdi_master)));
-	msm_camera_io_w(rdi_reg_cfg,
-		vfe_dev->vfe_base + VFE40_RDI_MN_BASE(rdi_master));
-}
-
 static void msm_vfe40_axi_cfg_wm_xbar_reg(
 	struct vfe_device *vfe_dev,
 	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
@@ -837,13 +838,14 @@
 	case IDEAL_RAW:
 		xbar_cfg = 0x400;
 		break;
-	case RDI:
-		if (stream_info->rdi[plane_idx] == 0)
-			xbar_cfg = 0x500;
-		else if (stream_info->rdi[plane_idx] == 1)
-			xbar_cfg = 0x600;
-		else if (stream_info->rdi[plane_idx] == 2)
-			xbar_cfg = 0x700;
+	case RDI_INTF_0:
+		xbar_cfg = 0x500;
+		break;
+	case RDI_INTF_1:
+		xbar_cfg = 0x600;
+		break;
+	case RDI_INTF_2:
+		xbar_cfg = 0x700;
 		break;
 	default:
 		pr_err("%s: Invalid stream src\n", __func__);
@@ -1063,8 +1065,8 @@
 	uint32_t ub_offset = VFE40_UB_SIZE;
 	uint32_t ub_size[VFE40_NUM_STATS_TYPE] = {
 		64, /*MSM_ISP_STATS_BE*/
-		64, /*MSM_ISP_STATS_BG*/
-		64, /*MSM_ISP_STATS_BF*/
+		128, /*MSM_ISP_STATS_BG*/
+		128, /*MSM_ISP_STATS_BF*/
 		16, /*MSM_ISP_STATS_AWB*/
 		8,  /*MSM_ISP_STATS_RS*/
 		16, /*MSM_ISP_STATS_CS*/
@@ -1074,7 +1076,7 @@
 
 	for (i = 0; i < VFE40_NUM_STATS_TYPE; i++) {
 		ub_offset -= ub_size[i];
-		msm_camera_io_w(VFE40_BURST_LEN << 30 |
+		msm_camera_io_w(VFE40_STATS_BURST_LEN << 30 |
 			ub_offset << 16 | (ub_size[i] - 1),
 			vfe_dev->vfe_base + VFE40_STATS_BASE(i) + 0xC);
 	}
@@ -1264,7 +1266,6 @@
 			.clear_wm_reg = msm_vfe40_axi_clear_wm_reg,
 			.cfg_wm_xbar_reg = msm_vfe40_axi_cfg_wm_xbar_reg,
 			.clear_wm_xbar_reg = msm_vfe40_axi_clear_wm_xbar_reg,
-			.cfg_rdi_reg = msm_vfe40_axi_cfg_rdi_reg,
 			.cfg_ub = msm_vfe40_cfg_axi_ub,
 			.update_ping_pong_addr =
 				msm_vfe40_update_ping_pong_addr,
@@ -1277,6 +1278,7 @@
 			.reg_update = msm_vfe40_reg_update,
 			.cfg_camif = msm_vfe40_cfg_camif,
 			.update_camif_state = msm_vfe40_update_camif_state,
+			.cfg_rdi_reg = msm_vfe40_cfg_rdi_reg,
 			.reset_hw = msm_vfe40_reset_hardware,
 			.init_hw = msm_vfe40_init_hardware,
 			.init_hw_reg = msm_vfe40_init_hardware_reg,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index ac3ce0a..eaec1e1 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -14,6 +14,10 @@
 #include "msm_isp_util.h"
 #include "msm_isp_axi_util.h"
 
+#define SRC_TO_INTF(src) \
+	((src < RDI_INTF_0) ? VFE_PIX_0 : \
+	(VFE_RAW_0 + src - RDI_INTF_0))
+
 int msm_isp_axi_create_stream(
 	struct msm_vfe_axi_shared_data *axi_data,
 	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
@@ -78,6 +82,18 @@
 	case V4L2_PIX_FMT_SGBRG12:
 	case V4L2_PIX_FMT_SGRBG12:
 	case V4L2_PIX_FMT_SRGGB12:
+	case V4L2_PIX_FMT_QBGGR8:
+	case V4L2_PIX_FMT_QGBRG8:
+	case V4L2_PIX_FMT_QGRBG8:
+	case V4L2_PIX_FMT_QRGGB8:
+	case V4L2_PIX_FMT_QBGGR10:
+	case V4L2_PIX_FMT_QGBRG10:
+	case V4L2_PIX_FMT_QGRBG10:
+	case V4L2_PIX_FMT_QRGGB10:
+	case V4L2_PIX_FMT_QBGGR12:
+	case V4L2_PIX_FMT_QGBRG12:
+	case V4L2_PIX_FMT_QGRBG12:
+	case V4L2_PIX_FMT_QRGGB12:
 		stream_info->num_planes = 1;
 		break;
 	case V4L2_PIX_FMT_NV12:
@@ -103,14 +119,6 @@
 		return rc;
 	}
 
-	if (stream_cfg_cmd->stream_src == RDI) {
-		if (axi_data->hw_info->num_rdi -
-			axi_data->num_used_rdi < stream_info->num_planes) {
-			pr_err("%s: No free RDI\n", __func__);
-			return rc;
-		}
-	}
-
 	if (stream_cfg_cmd->init_frame_drop >= MAX_INIT_FRAME_DROP) {
 		pr_err("%s: Invalid skip pattern\n", __func__);
 		return rc;
@@ -122,6 +130,7 @@
 	}
 
 	stream_info->stream_src = stream_cfg_cmd->stream_src;
+	stream_info->frame_based = stream_cfg_cmd->frame_base;
 	return 0;
 }
 
@@ -135,6 +144,10 @@
 	case V4L2_PIX_FMT_SGBRG8:
 	case V4L2_PIX_FMT_SGRBG8:
 	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_QBGGR8:
+	case V4L2_PIX_FMT_QGBRG8:
+	case V4L2_PIX_FMT_QGRBG8:
+	case V4L2_PIX_FMT_QRGGB8:
 		size = plane_cfg[plane_idx].output_height *
 		plane_cfg[plane_idx].output_width;
 		break;
@@ -142,6 +155,10 @@
 	case V4L2_PIX_FMT_SGBRG10:
 	case V4L2_PIX_FMT_SGRBG10:
 	case V4L2_PIX_FMT_SRGGB10:
+	case V4L2_PIX_FMT_QBGGR10:
+	case V4L2_PIX_FMT_QGBRG10:
+	case V4L2_PIX_FMT_QGRBG10:
+	case V4L2_PIX_FMT_QRGGB10:
 		/* TODO: fix me */
 		size = plane_cfg[plane_idx].output_height *
 		plane_cfg[plane_idx].output_width;
@@ -150,6 +167,10 @@
 	case V4L2_PIX_FMT_SGBRG12:
 	case V4L2_PIX_FMT_SGRBG12:
 	case V4L2_PIX_FMT_SRGGB12:
+	case V4L2_PIX_FMT_QBGGR12:
+	case V4L2_PIX_FMT_QGBRG12:
+	case V4L2_PIX_FMT_QGRBG12:
+	case V4L2_PIX_FMT_QRGGB12:
 		/* TODO: fix me */
 		size = plane_cfg[plane_idx].output_height *
 		plane_cfg[plane_idx].output_width;
@@ -205,38 +226,6 @@
 	}
 }
 
-void msm_isp_axi_reserve_rdi(struct msm_vfe_axi_shared_data *axi_data,
-	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
-{
-	int i, j;
-	struct msm_vfe_axi_stream *stream_info =
-	&axi_data->stream_info[(stream_cfg_cmd->axi_stream_handle & 0xFF)];
-
-	for (i = 0; i < stream_info->num_planes; i++) {
-		uint8_t csid = stream_cfg_cmd->plane_cfg[i].csid_src;
-
-		for (j = 0; j < axi_data->hw_info->num_rdi; j++) {
-			if (!axi_data->free_rdi[j]) {
-				axi_data->free_rdi[j] = 1;
-				axi_data->num_used_rdi++;
-				break;
-			}
-		}
-		stream_info->rdi[i] = j;
-
-		for (j = 0; j < axi_data->hw_info->num_rdi; j++) {
-			if (!axi_data->free_rdi_master[csid][j]) {
-				axi_data->free_rdi_master[csid][j] = 1;
-				axi_data->num_used_rdi++;
-				break;
-			}
-		}
-		stream_info->rdi_master[i] =
-			csid * axi_data->hw_info->num_rdi_master + j;
-	}
-	return;
-}
-
 void msm_isp_axi_reserve_comp_mask(
 	struct msm_vfe_axi_shared_data *axi_data,
 	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
@@ -277,8 +266,7 @@
 	struct vfe_device *vfe_dev,
 	struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
 {
-	int rc = 0, i, j;
-	uint8_t src_state;
+	int rc = 0, i;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
 	struct msm_vfe_axi_stream *stream_info;
 	enum msm_vfe_axi_state valid_state =
@@ -292,24 +280,6 @@
 			rc = -EINVAL;
 			break;
 		}
-		/*
-		 * For RDI stream, if multiple RDIs are used
-		 * check if all the RDI srcs are in the same state, on/off
-		 */
-		if (stream_info->stream_src == RDI) {
-			src_state = axi_data->src_info[
-				stream_info->rdi[0]+1].active;
-			for (j = 0; j < stream_info->num_planes; j++) {
-				if (src_state !=
-						axi_data->src_info[
-						stream_info->rdi[j]+1].active) {
-					pr_err("%s: RDI stream has inconsistent state\n",
-						__func__);
-					rc = -EINVAL;
-					break;
-				}
-			}
-		}
 
 		if (stream_cfg_cmd->cmd == START_STREAM) {
 			stream_info->bufq_handle =
@@ -334,74 +304,46 @@
 	struct msm_vfe_axi_stream *stream_info;
 	for (i = 0; i < MAX_NUM_STREAM; i++) {
 		stream_info = &axi_data->stream_info[i];
-		if (stream_info->framedrop_update) {
-			if (stream_info->init_frame_drop == 0) {
-				stream_info->framedrop_update = 0;
+		if (stream_info->state != ACTIVE)
+			continue;
+
+		if (stream_info->runtime_framedrop_update) {
+			stream_info->runtime_init_frame_drop--;
+			if (stream_info->runtime_init_frame_drop == 0) {
+				stream_info->runtime_framedrop_update = 0;
 				vfe_dev->hw_info->vfe_ops.axi_ops.
 				cfg_framedrop(vfe_dev, stream_info);
 			}
 		}
 		if (stream_info->stream_type == BURST_STREAM) {
-			if (stream_info->burst_frame_count == 0 &&
-					stream_info->state == ACTIVE) {
+			stream_info->runtime_burst_frame_count--;
+			if (stream_info->runtime_burst_frame_count == 0) {
 				vfe_dev->hw_info->vfe_ops.axi_ops.
 				cfg_framedrop(vfe_dev, stream_info);
-				if (stream_info->stream_src == RDI) {
-					uint32_t wm_reload_mask = 0,
-					reg_update_mask = 0;
-					stream_info->state = STOP_PENDING;
-					msm_isp_axi_stream_enable_cfg(
-						vfe_dev, stream_info,
-						&wm_reload_mask,
-						&reg_update_mask);
-				}
+				vfe_dev->hw_info->vfe_ops.core_ops.
+				 reg_update(vfe_dev);
 			}
 		}
 	}
 }
 
-void msm_isp_update_framedrop_count(
-	struct vfe_device *vfe_dev)
+static void msm_isp_reset_framedrop(struct vfe_device *vfe_dev,
+			struct msm_vfe_axi_stream *stream_info)
 {
-	int i;
-	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
-	struct msm_vfe_axi_stream *stream_info;
-	for (i = 0; i < MAX_NUM_STREAM; i++) {
-		stream_info = &axi_data->stream_info[i];
-		if (stream_info->framedrop_update) {
-			stream_info->init_frame_drop--;
-			if (stream_info->init_frame_drop == 1) {
-				vfe_dev->hw_info->vfe_ops.core_ops.
-					reg_update(vfe_dev, 0xF);
-			}
-		}
-		if (stream_info->stream_type == BURST_STREAM) {
-			stream_info->burst_frame_count--;
-			if (stream_info->burst_frame_count == 1) {
-				vfe_dev->hw_info->vfe_ops.core_ops.
-					reg_update(vfe_dev, 0xF);
-			} else if (stream_info->burst_frame_count == 0) {
-				if (stream_info->stream_src != RDI) {
-					vfe_dev->hw_info->vfe_ops.core_ops.
-						update_camif_state(vfe_dev,
-						DISABLE_CAMIF);
-					pr_err("%s: pending burst_cnt = %d, disable camif\n",
-						__func__,
-						stream_info->burst_frame_count);
-				}
-			}
-		}
-	}
+	stream_info->runtime_init_frame_drop = stream_info->init_frame_drop;
+	stream_info->runtime_burst_frame_count =
+		stream_info->burst_frame_count;
+	stream_info->runtime_framedrop_update = stream_info->framedrop_update;
+	vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop(vfe_dev, stream_info);
 }
 
 void msm_isp_sof_notify(struct vfe_device *vfe_dev,
-	enum msm_vfe_input_src frame_src, struct timeval *tv) {
+	enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts) {
 	struct msm_isp_event_data sof_event;
 	switch (frame_src) {
 	case VFE_PIX_0:
 		ISP_DBG("%s: PIX0 frame id: %lu\n", __func__,
 			vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
-		msm_isp_update_framedrop_count(vfe_dev);
 		vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id++;
 		if (vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id == 0)
 			vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id = 1;
@@ -409,6 +351,12 @@
 	case VFE_RAW_0:
 	case VFE_RAW_1:
 	case VFE_RAW_2:
+		ISP_DBG("%s: RDI%d frame id: %lu\n",
+			__func__, frame_src - VFE_RAW_0,
+			vfe_dev->axi_data.src_info[frame_src].frame_id);
+		vfe_dev->axi_data.src_info[frame_src].frame_id++;
+		if (vfe_dev->axi_data.src_info[frame_src].frame_id == 0)
+			vfe_dev->axi_data.src_info[frame_src].frame_id = 1;
 		break;
 	default:
 		pr_err("%s: invalid frame src %d received\n",
@@ -417,7 +365,7 @@
 	}
 
 	sof_event.frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
-	sof_event.timestamp = *tv;
+	sof_event.timestamp = ts->event_time;
 	msm_isp_send_event(vfe_dev, ISP_EVENT_SOF, &sof_event);
 }
 
@@ -501,13 +449,10 @@
 		return rc;
 	}
 
-	msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_cfg_cmd);
-	if (stream_cfg_cmd->stream_src == RDI)
-		msm_isp_axi_reserve_rdi(&vfe_dev->axi_data, stream_cfg_cmd);
-
 	stream_info =
 		&vfe_dev->axi_data.
 			stream_info[(stream_cfg_cmd->axi_stream_handle & 0xFF)];
+	msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_cfg_cmd);
 
 	if (stream_cfg_cmd->stream_src == CAMIF_RAW ||
 		stream_cfg_cmd->stream_src == IDEAL_RAW)
@@ -515,7 +460,6 @@
 				cfg_io_format(vfe_dev, stream_cfg_cmd);
 
 	msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);
-	vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop(vfe_dev, stream_info);
 
 	if (stream_info->num_planes > 1) {
 		msm_isp_axi_reserve_comp_mask(
@@ -531,12 +475,8 @@
 		vfe_dev->hw_info->vfe_ops.axi_ops.
 			cfg_wm_reg(vfe_dev, stream_cfg_cmd, i);
 
-	vfe_dev->hw_info->vfe_ops.axi_ops.
-		cfg_wm_xbar_reg(vfe_dev, stream_cfg_cmd, i);
-
-	if (stream_cfg_cmd->stream_src == RDI)
 		vfe_dev->hw_info->vfe_ops.axi_ops.
-			cfg_rdi_reg(vfe_dev, stream_cfg_cmd, i);
+			cfg_wm_xbar_reg(vfe_dev, stream_cfg_cmd, i);
 	}
 	return rc;
 }
@@ -590,7 +530,7 @@
 void msm_isp_axi_stream_enable_cfg(
 	struct vfe_device *vfe_dev,
 	struct msm_vfe_axi_stream *stream_info,
-	uint32_t *wm_reload_mask, uint32_t *reg_update_mask)
+	uint32_t *wm_reload_mask)
 {
 	int i;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
@@ -605,10 +545,9 @@
 			vfe_dev->hw_info->vfe_ops.axi_ops.
 				enable_wm(vfe_dev, stream_info->wm[i], 0);
 
-	*wm_reload_mask |= (1 << stream_info->wm[i]);
-	if (stream_info->stream_src == RDI)
-		*reg_update_mask |= (1 << stream_info->rdi[i]);
+		*wm_reload_mask |= (1 << stream_info->wm[i]);
 	}
+
 	if (stream_info->state == START_PENDING) {
 		axi_data->num_active_stream++;
 		stream_info->state = ACTIVE;
@@ -622,14 +561,14 @@
 {
 	int i;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
-	uint32_t wm_reload_mask = 0x0, reg_update_mask = 0x1;
+	uint32_t wm_reload_mask = 0x0;
 	for (i = 0; i < MAX_NUM_STREAM; i++) {
 		if (axi_data->stream_info[i].state == START_PENDING ||
 				axi_data->stream_info[i].state ==
 					STOP_PENDING) {
 			msm_isp_axi_stream_enable_cfg(
 				vfe_dev, &axi_data->stream_info[i],
-				&wm_reload_mask, &reg_update_mask);
+				&wm_reload_mask);
 			if (axi_data->stream_info[i].state == STOP_PENDING)
 				axi_data->stream_info[i].state = STOPPING;
 		}
@@ -637,10 +576,8 @@
 	/*Reload AXI*/
 	vfe_dev->hw_info->vfe_ops.axi_ops.
 		reload_wm(vfe_dev, wm_reload_mask);
-	/*Reg update per src*/
-	vfe_dev->hw_info->vfe_ops.core_ops.
-		reg_update(vfe_dev, reg_update_mask);
 	if (vfe_dev->axi_data.stream_update) {
+		vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
 		ISP_DBG("%s: send update complete\n", __func__);
 		vfe_dev->axi_data.stream_update = 0;
 		complete(&vfe_dev->stream_config_complete);
@@ -714,17 +651,20 @@
 
 static void msm_isp_process_done_buf(struct vfe_device *vfe_dev,
 	struct msm_vfe_axi_stream *stream_info, struct msm_isp_buffer *buf,
-	struct timeval *tv)
+	struct msm_isp_timestamp *ts)
 {
 	struct msm_isp_event_data buf_event;
+	uint32_t stream_idx = stream_info->stream_handle & 0xFF;
 	uint32_t frame_id = vfe_dev->axi_data.
-		src_info[stream_info->stream_src].frame_id;
-	if (buf && tv) {
+		src_info[SRC_TO_INTF(stream_info->stream_src)].frame_id;
+
+	if (buf && ts) {
 		if (stream_info->buf_divert) {
 			vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr,
-				buf->bufq_handle, buf->buf_idx, tv, frame_id);
+				buf->bufq_handle, buf->buf_idx,
+				&ts->buf_time, frame_id);
 			buf_event.frame_id = frame_id;
-			buf_event.timestamp = *tv;
+			buf_event.timestamp = ts->buf_time;
 			buf_event.u.buf_done.session_id =
 				stream_info->session_id;
 			buf_event.u.buf_done.stream_id =
@@ -732,11 +672,12 @@
 			buf_event.u.buf_done.handle =
 				stream_info->bufq_handle;
 			buf_event.u.buf_done.buf_idx = buf->buf_idx;
-			msm_isp_send_event(
-				vfe_dev, ISP_EVENT_BUF_DIVERT, &buf_event);
+			msm_isp_send_event(vfe_dev, ISP_EVENT_BUF_DIVERT +
+					stream_idx, &buf_event);
 		} else {
 			vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr,
-				buf->bufq_handle, buf->buf_idx, tv, frame_id);
+				buf->bufq_handle, buf->buf_idx,
+				&ts->buf_time, frame_id);
 		}
 	}
 }
@@ -758,7 +699,7 @@
 		stream_info =
 			&axi_data->stream_info[
 			(stream_cfg_cmd->stream_handle[i] & 0xFF)];
-		if (stream_info->stream_src  != RDI)
+		if (stream_info->stream_src  < RDI_INTF_0)
 			pix_stream_cnt++;
 		if (stream_info->stream_src == PIX_ENCODER ||
 				stream_info->stream_src == PIX_VIEWFINDER) {
@@ -830,7 +771,7 @@
 {
 	int rc = 0, i;
 	struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd = arg;
-	uint32_t wm_reload_mask = 0x0, reg_update_mask = 0x1;
+	uint32_t wm_reload_mask = 0x0;
 	struct msm_vfe_axi_stream *stream_info;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
 	uint8_t src_state;
@@ -866,17 +807,19 @@
 			&axi_data->stream_info[
 				(stream_cfg_cmd->stream_handle[i] & 0xFF)];
 
-		if (stream_info->stream_src == RDI)
-			src_state =
-				axi_data->src_info[
-					stream_info->rdi[0]+1].active;
-		else
+		if (stream_info->stream_src < RDI_INTF_0)
 			src_state = axi_data->src_info[0].active;
+		else
+			src_state = axi_data->src_info[
+			(stream_info->stream_src - RDI_INTF_0)].active;
 
 		stream_info->state = (stream_cfg_cmd->cmd == START_STREAM) ?
 			START_PENDING : STOP_PENDING;
 
 		if (stream_cfg_cmd->cmd == START_STREAM) {
+			/*Configure framedrop*/
+			msm_isp_reset_framedrop(vfe_dev, stream_info);
+
 			/*Set address for both PING & PONG register */
 			rc = msm_isp_cfg_ping_pong_address(vfe_dev,
 				stream_info, VFE_PONG_FLAG);
@@ -900,14 +843,13 @@
 		if (src_state && camif_update != DISABLE_CAMIF) {
 			/*On the fly stream start/stop */
 			wait_for_complete = 1;
-			reg_update_mask = 0xF; /*TD: Maybe set this per src*/
 		} else {
-			if (vfe_dev->dump_reg)
+			if (vfe_dev->dump_reg &&
+				stream_cfg_cmd->cmd == START_STREAM)
 				msm_camera_io_dump_2(vfe_dev->vfe_base, 0x900);
 			/*Configure AXI start bits to start immediately*/
 			msm_isp_axi_stream_enable_cfg(
-				vfe_dev, stream_info,
-				&wm_reload_mask, &reg_update_mask);
+				vfe_dev, stream_info, &wm_reload_mask);
 		}
 	}
 	if (!wait_for_complete) {
@@ -915,9 +857,9 @@
 		if (stream_cfg_cmd->cmd == START_STREAM)
 			vfe_dev->hw_info->vfe_ops.axi_ops.
 			reload_wm(vfe_dev, wm_reload_mask);
-		/*Reg update per src*/
+
 		vfe_dev->hw_info->vfe_ops.core_ops.
-			reg_update(vfe_dev, reg_update_mask);
+			reg_update(vfe_dev);
 
 		if (camif_update == ENABLE_CAMIF)
 			vfe_dev->hw_info->vfe_ops.core_ops.
@@ -932,9 +874,7 @@
 		if (stream_cfg_cmd->cmd == START_STREAM)
 			vfe_dev->hw_info->vfe_ops.axi_ops.
 			reload_wm(vfe_dev, wm_reload_mask);
-		/*Reg update per src*/
-		vfe_dev->hw_info->vfe_ops.core_ops.
-			reg_update(vfe_dev, reg_update_mask);
+		vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
 		rc = wait_for_completion_interruptible_timeout(
 			&vfe_dev->stream_config_complete,
 			msecs_to_jiffies(500));
@@ -980,7 +920,7 @@
 
 void msm_isp_process_axi_irq(struct vfe_device *vfe_dev,
 	uint32_t irq_status0, uint32_t irq_status1,
-	struct timeval *tv)
+	struct msm_isp_timestamp *ts)
 {
 	int i, rc = 0;
 	struct msm_isp_buffer *done_buf = NULL;
@@ -1026,7 +966,7 @@
 				}
 				if (done_buf && !rc)
 					msm_isp_process_done_buf(vfe_dev,
-					stream_info, done_buf, tv);
+					stream_info, done_buf, ts);
 			}
 		}
 		wm_mask &= ~(comp_info->stream_composite_mask);
@@ -1041,6 +981,9 @@
 			}
 			stream_idx = axi_data->free_wm[i] & 0xFF;
 			stream_info = &axi_data->stream_info[stream_idx];
+			ISP_DBG("%s: stream%d frame id: 0x%x\n",
+				__func__,
+				stream_idx, stream_info->frame_id);
 			stream_info->frame_id++;
 			msm_isp_get_done_buf(vfe_dev, stream_info,
 						pingpong_status, &done_buf);
@@ -1051,7 +994,7 @@
 			}
 			if (done_buf && !rc)
 				msm_isp_process_done_buf(vfe_dev,
-				stream_info, done_buf, tv);
+				stream_info, done_buf, ts);
 		}
 	}
 	return;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
index 9765ae2..ba845bc 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
@@ -48,15 +48,14 @@
 
 void msm_isp_axi_stream_enable_cfg(struct vfe_device *vfe_dev,
 	struct msm_vfe_axi_stream *stream_info,
-	uint32_t *wm_reload_mask, uint32_t *reg_update_mask);
+	uint32_t *wm_reload_mask);
 
 void msm_isp_axi_stream_update(struct vfe_device *vfe_dev);
 
 void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev);
-void msm_isp_update_framedrop_count(struct vfe_device *vfe_dev);
 void msm_isp_sof_notify(struct vfe_device *vfe_dev,
-	enum msm_vfe_input_src frame_src, struct timeval *tv);
+	enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts);
 void msm_isp_process_axi_irq(struct vfe_device *vfe_dev,
 	uint32_t irq_status0, uint32_t irq_status1,
-	struct timeval *tv);
+	struct msm_isp_timestamp *ts);
 #endif /* __MSM_ISP_AXI_UTIL_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index bf348d0..a29fe9c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -58,7 +58,7 @@
 
 void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
 	uint32_t irq_status0, uint32_t irq_status1,
-	struct timeval *tv)
+	struct msm_isp_timestamp *ts)
 {
 	int i;
 	struct msm_isp_event_data buf_event;
@@ -98,13 +98,17 @@
 				done_buf->buf_idx;
 			vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr,
 				done_buf->bufq_handle, done_buf->buf_idx,
-				tv, 0);
+				&ts->buf_time, vfe_dev->axi_data.
+				src_info[VFE_PIX_0].frame_id);
 		}
 	}
 
 	if (stats_event->stats_mask) {
-		buf_event.timestamp = *tv;
-		msm_isp_send_event(vfe_dev, ISP_EVENT_STATS_NOTIFY, &buf_event);
+		buf_event.timestamp = ts->event_time;
+		buf_event.frame_id =
+			vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+		msm_isp_send_event(vfe_dev, ISP_EVENT_STATS_NOTIFY +
+				stream_info->stats_type, &buf_event);
 	}
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h
index 2f51b7b..13e1fd6 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h
@@ -17,7 +17,7 @@
 
 void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
 	uint32_t irq_status0, uint32_t irq_status1,
-	struct timeval *tv);
+	struct msm_isp_timestamp *ts);
 int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg);
 int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg);
 int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index e181b53..bbdfaa6 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -20,13 +20,13 @@
 
 #define MAX_ISP_V4l2_EVENTS 100
 
-void msm_isp_gettimeofday(struct timeval *tv)
+static inline void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp)
 {
 	struct timespec ts;
-
 	ktime_get_ts(&ts);
-	tv->tv_sec = ts.tv_sec;
-	tv->tv_usec = ts.tv_nsec/1000;
+	time_stamp->buf_time.tv_sec = ts.tv_sec;
+	time_stamp->buf_time.tv_usec = ts.tv_nsec/1000;
+	do_gettimeofday(&(time_stamp->event_time));
 }
 
 int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
@@ -81,6 +81,18 @@
 	return rc;
 }
 
+int msm_isp_cfg_rdi(struct vfe_device *vfe_dev,
+	struct msm_vfe_rdi_cfg *rdi_cfg, enum msm_vfe_input_src input_src)
+{
+	int rc = 0;
+	/*TD Validate config info
+	 * should check if all streams are off */
+
+	vfe_dev->hw_info->vfe_ops.core_ops.
+		cfg_rdi_reg(vfe_dev, rdi_cfg, input_src);
+	return rc;
+}
+
 int msm_isp_cfg_input(struct vfe_device *vfe_dev, void *arg)
 {
 	int rc = 0;
@@ -93,6 +105,9 @@
 	case VFE_RAW_0:
 	case VFE_RAW_1:
 	case VFE_RAW_2:
+		msm_isp_cfg_rdi(vfe_dev, &input_cfg->d.rdi_cfg,
+						input_cfg->input_src);
+		break;
 	case VFE_SRC_MAX:
 		break;
 	}
@@ -102,56 +117,59 @@
 long msm_isp_ioctl(struct v4l2_subdev *sd,
 	unsigned int cmd, void *arg)
 {
+	long rc = 0;
 	struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd);
 
 	mutex_lock(&vfe_dev->mutex);
 	ISP_DBG("%s cmd: %d\n", __func__, cmd);
-
 	switch (cmd) {
 	case VIDIOC_MSM_VFE_REG_CFG: {
-		msm_isp_proc_cmd(vfe_dev, arg);
+		rc = msm_isp_proc_cmd(vfe_dev, arg);
 		break;
 	}
 	case VIDIOC_MSM_ISP_REQUEST_BUF:
 	case VIDIOC_MSM_ISP_ENQUEUE_BUF:
 	case VIDIOC_MSM_ISP_RELEASE_BUF: {
-		msm_isp_proc_buf_cmd(vfe_dev->buf_mgr, cmd, arg);
+		rc = msm_isp_proc_buf_cmd(vfe_dev->buf_mgr, cmd, arg);
 		break;
 	}
 	case VIDIOC_MSM_ISP_REQUEST_STREAM:
-		msm_isp_request_axi_stream(vfe_dev, arg);
+		rc = msm_isp_request_axi_stream(vfe_dev, arg);
 		break;
 	case VIDIOC_MSM_ISP_RELEASE_STREAM:
-		msm_isp_release_axi_stream(vfe_dev, arg);
+		rc = msm_isp_release_axi_stream(vfe_dev, arg);
 		break;
 	case VIDIOC_MSM_ISP_CFG_STREAM:
-		msm_isp_cfg_axi_stream(vfe_dev, arg);
+		rc = msm_isp_cfg_axi_stream(vfe_dev, arg);
 		break;
 	case VIDIOC_MSM_ISP_INPUT_CFG:
-		msm_isp_cfg_input(vfe_dev, arg);
+		rc = msm_isp_cfg_input(vfe_dev, arg);
 		break;
 	case VIDIOC_MSM_ISP_SET_SRC_STATE:
 		msm_isp_set_src_state(vfe_dev, arg);
 		break;
 	case VIDIOC_MSM_ISP_REQUEST_STATS_STREAM:
-		msm_isp_request_stats_stream(vfe_dev, arg);
+		rc = msm_isp_request_stats_stream(vfe_dev, arg);
 		break;
 	case VIDIOC_MSM_ISP_RELEASE_STATS_STREAM:
-		msm_isp_release_stats_stream(vfe_dev, arg);
+		rc = msm_isp_release_stats_stream(vfe_dev, arg);
 		break;
 	case VIDIOC_MSM_ISP_CFG_STATS_STREAM:
-		msm_isp_cfg_stats_stream(vfe_dev, arg);
+		rc = msm_isp_cfg_stats_stream(vfe_dev, arg);
 		break;
 	case VIDIOC_MSM_ISP_CFG_STATS_COMP_POLICY:
-		msm_isp_cfg_stats_comp_policy(vfe_dev, arg);
+		rc = msm_isp_cfg_stats_comp_policy(vfe_dev, arg);
 		break;
 	case VIDIOC_MSM_ISP_UPDATE_STREAM:
-		msm_isp_update_axi_stream(vfe_dev, arg);
+		rc = msm_isp_update_axi_stream(vfe_dev, arg);
 		break;
+	default:
+		pr_err("%s: Invalid ISP command\n", __func__);
+		rc = -EINVAL;
 	}
 
 	mutex_unlock(&vfe_dev->mutex);
-	return 0;
+	return rc;
 }
 
 static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
@@ -366,18 +384,34 @@
 	case V4L2_PIX_FMT_SGBRG8:
 	case V4L2_PIX_FMT_SGRBG8:
 	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_QBGGR8:
+	case V4L2_PIX_FMT_QGBRG8:
+	case V4L2_PIX_FMT_QGRBG8:
+	case V4L2_PIX_FMT_QRGGB8:
 		val = CAL_WORD(pixel_per_line, 1, 8);
 		break;
 	case V4L2_PIX_FMT_SBGGR10:
 	case V4L2_PIX_FMT_SGBRG10:
 	case V4L2_PIX_FMT_SGRBG10:
 	case V4L2_PIX_FMT_SRGGB10:
-		val = CAL_WORD(pixel_per_line, 1, 6);
+		val = CAL_WORD(pixel_per_line, 5, 32);
 		break;
 	case V4L2_PIX_FMT_SBGGR12:
 	case V4L2_PIX_FMT_SGBRG12:
 	case V4L2_PIX_FMT_SGRBG12:
 	case V4L2_PIX_FMT_SRGGB12:
+		val = CAL_WORD(pixel_per_line, 3, 16);
+		break;
+	case V4L2_PIX_FMT_QBGGR10:
+	case V4L2_PIX_FMT_QGBRG10:
+	case V4L2_PIX_FMT_QGRBG10:
+	case V4L2_PIX_FMT_QRGGB10:
+		val = CAL_WORD(pixel_per_line, 1, 6);
+		break;
+	case V4L2_PIX_FMT_QBGGR12:
+	case V4L2_PIX_FMT_QGBRG12:
+	case V4L2_PIX_FMT_QGRBG12:
+	case V4L2_PIX_FMT_QRGGB12:
 		val = CAL_WORD(pixel_per_line, 1, 5);
 		break;
 	case V4L2_PIX_FMT_NV12:
@@ -399,16 +433,28 @@
 	case V4L2_PIX_FMT_SGBRG8:
 	case V4L2_PIX_FMT_SGRBG8:
 	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_QBGGR8:
+	case V4L2_PIX_FMT_QGBRG8:
+	case V4L2_PIX_FMT_QGRBG8:
+	case V4L2_PIX_FMT_QRGGB8:
 		return 8;
 	case V4L2_PIX_FMT_SBGGR10:
 	case V4L2_PIX_FMT_SGBRG10:
 	case V4L2_PIX_FMT_SGRBG10:
 	case V4L2_PIX_FMT_SRGGB10:
+	case V4L2_PIX_FMT_QBGGR10:
+	case V4L2_PIX_FMT_QGBRG10:
+	case V4L2_PIX_FMT_QGRBG10:
+	case V4L2_PIX_FMT_QRGGB10:
 		return 10;
 	case V4L2_PIX_FMT_SBGGR12:
 	case V4L2_PIX_FMT_SGBRG12:
 	case V4L2_PIX_FMT_SGRBG12:
 	case V4L2_PIX_FMT_SRGGB12:
+	case V4L2_PIX_FMT_QBGGR12:
+	case V4L2_PIX_FMT_QGBRG12:
+	case V4L2_PIX_FMT_QGRBG12:
+	case V4L2_PIX_FMT_QRGGB12:
 		return 12;
 	case V4L2_PIX_FMT_NV12:
 	case V4L2_PIX_FMT_NV21:
@@ -504,7 +550,7 @@
 	}
 	queue_cmd->vfeInterruptStatus0 = irq_status0;
 	queue_cmd->vfeInterruptStatus1 = irq_status1;
-	msm_isp_gettimeofday(&queue_cmd->tv);
+	msm_isp_get_timestamp(&queue_cmd->ts);
 	queue_cmd->cmd_used = 1;
 	vfe_dev->taskletq_idx =
 		(vfe_dev->taskletq_idx + 1) % MSM_VFE_TASKLETQ_SIZE;
@@ -520,7 +566,7 @@
 	struct vfe_device *vfe_dev = (struct vfe_device *) data;
 	struct msm_vfe_irq_ops *irq_ops = &vfe_dev->hw_info->vfe_ops.irq_ops;
 	struct msm_vfe_tasklet_queue_cmd *queue_cmd;
-	struct timeval tv;
+	struct msm_isp_timestamp ts;
 	uint32_t irq_status0, irq_status1;
 	while (atomic_read(&vfe_dev->irq_cnt)) {
 		spin_lock_irqsave(&vfe_dev->tasklet_lock, flags);
@@ -536,7 +582,7 @@
 		queue_cmd->cmd_used = 0;
 		irq_status0 = queue_cmd->vfeInterruptStatus0;
 		irq_status1 = queue_cmd->vfeInterruptStatus1;
-		tv = queue_cmd->tv;
+		ts = queue_cmd->ts;
 		spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags);
 		ISP_DBG("%s: status0: 0x%x status1: 0x%x\n",
 			__func__, irq_status0, irq_status1);
@@ -545,13 +591,13 @@
 		irq_ops->process_halt_irq(vfe_dev,
 			irq_status0, irq_status1);
 		irq_ops->process_camif_irq(vfe_dev,
-			irq_status0, irq_status1, &tv);
+			irq_status0, irq_status1, &ts);
 		irq_ops->process_axi_irq(vfe_dev,
-			irq_status0, irq_status1, &tv);
+			irq_status0, irq_status1, &ts);
 		irq_ops->process_stats_irq(vfe_dev,
-			irq_status0, irq_status1, &tv);
+			irq_status0, irq_status1, &ts);
 		irq_ops->process_reg_update(vfe_dev,
-			irq_status0, irq_status1, &tv);
+			irq_status0, irq_status1, &ts);
 		msm_isp_process_error_info(vfe_dev);
 	}
 }
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
index 6c2a88c..3dac7e0 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
@@ -22,8 +22,6 @@
 #define ISP_DBG(fmt, args...) pr_debug(fmt, ##args)
 #endif
 
-void msm_isp_gettimeofday(struct timeval *tv);
-
 int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
 	struct v4l2_event_subscription *sub);
 
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 50e685a..7d0f9cb 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -405,10 +405,10 @@
 			} else {
 				/* zero 2 bits */
 				ispif->applied_intf_cmd[vfe_intf].intf_cmd &=
-					~(0x3 << (vc * 2 + vfe_intf * 8));
+					~(0x3 << (vc * 2 + intf_type * 8));
 				/* set cmd bits */
 				ispif->applied_intf_cmd[vfe_intf].intf_cmd |=
-					(cmd_bits << (vc * 2 + vfe_intf * 8));
+					(cmd_bits << (vc * 2 + intf_type * 8));
 			}
 		}
 	}
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index c908333..08a4566 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -66,17 +66,6 @@
 	int stream_id;
 };
 
-struct msm_stream {
-	struct list_head list;
-
-	/* stream index per session, same
-	 * as stream_id but set through s_parm */
-	unsigned int stream_id;
-
-	/* vb2 buffer handling */
-	struct vb2_queue *vb2_q;
-};
-
 struct msm_v4l2_subdev {
 	/* FIXME: for session close and error handling such
 	 * as daemon shutdown */
@@ -275,7 +264,7 @@
 
 	stream->stream_id = stream_id;
 	stream->vb2_q = q;
-
+	spin_lock_init(&stream->stream_lock);
 	msm_enqueue(&session->stream_q, &stream->list);
 	session->stream_q.len++;
 
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index 762203c..bbc2782 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -46,8 +46,11 @@
 	list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
 		if (bufs->vb2_buf->v4l2_buf.index == buf_info->index) {
 			bufs->vb2_buf->v4l2_buf.sequence  = buf_info->frame_id;
+			bufs->vb2_buf->v4l2_buf.timestamp = buf_info->timestamp;
 			ret = buf_mngr_dev->vb2_ops.buf_done
-					(bufs->vb2_buf);
+					(bufs->vb2_buf,
+						buf_info->session_id,
+						buf_info->stream_id);
 			list_del_init(&bufs->entry);
 			kfree(bufs);
 			break;
@@ -65,7 +68,8 @@
 
 	list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
 		if (bufs->vb2_buf->v4l2_buf.index == buf_info->index) {
-			ret = buf_mngr_dev->vb2_ops.put_buf(bufs->vb2_buf);
+			ret = buf_mngr_dev->vb2_ops.put_buf(bufs->vb2_buf,
+				buf_info->session_id, buf_info->stream_id);
 			list_del_init(&bufs->entry);
 			kfree(bufs);
 			break;
diff --git a/drivers/media/platform/msm/camera_v2/msm_sd.h b/drivers/media/platform/msm/camera_v2/msm_sd.h
index aaf3548..958e030 100644
--- a/drivers/media/platform/msm/camera_v2/msm_sd.h
+++ b/drivers/media/platform/msm/camera_v2/msm_sd.h
@@ -65,8 +65,10 @@
 	struct vb2_buffer *(*get_buf)(int session_id, unsigned int stream_id);
 	struct vb2_queue *(*get_vb2_queue)(int session_id,
 		unsigned int stream_id);
-	int (*put_buf)(struct vb2_buffer *vb2_buf);
-	int (*buf_done)(struct vb2_buffer *vb2_buf);
+	int (*put_buf)(struct vb2_buffer *vb2_buf, int session_id,
+		unsigned int stream_id);
+	int (*buf_done)(struct vb2_buffer *vb2_buf, int session_id,
+		unsigned int stream_id);
 };
 
 #define MSM_SD_NOTIFY_GET_SD 0x00000001
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
index 8a572a6..6ea86ae 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
@@ -12,8 +12,6 @@
 
 #include "msm_vb2.h"
 
-static spinlock_t vb2_buf_lock;
-
 static int msm_vb2_queue_setup(struct vb2_queue *q,
 	const struct v4l2_format *fmt,
 	unsigned int *num_buffers, unsigned int *num_planes,
@@ -44,7 +42,6 @@
 
 	msm_vb2_buf = container_of(vb, struct msm_vb2_buffer, vb2_buf);
 	msm_vb2_buf->in_freeq = 0;
-	spin_lock_init(&vb2_buf_lock);
 
 	return 0;
 }
@@ -102,22 +99,23 @@
 static struct vb2_buffer *msm_vb2_get_buf(int session_id,
 	unsigned int stream_id)
 {
-	struct vb2_queue *q;
+	struct msm_stream *stream;
 	struct vb2_buffer *vb2_buf = NULL;
 	struct msm_vb2_buffer *msm_vb2;
 	unsigned long flags;
 
-	spin_lock_irqsave(&vb2_buf_lock, flags);
+	stream = msm_get_stream(session_id, stream_id);
+	if (!stream)
+		return NULL;
 
-	q = msm_get_stream_vb2q(session_id, stream_id);
+	spin_lock_irqsave(&stream->stream_lock, flags);
 
-	/*FIXME: need a check if stream on issue*/
-	if (!q) {
+	if (!stream->vb2_q) {
 		pr_err("%s: stream q not available\n", __func__);
 		goto end;
 	}
 
-	list_for_each_entry(vb2_buf, &(q->queued_list),
+	list_for_each_entry(vb2_buf, &(stream->vb2_q->queued_list),
 		queued_entry) {
 		if (vb2_buf->state != VB2_BUF_STATE_ACTIVE)
 			continue;
@@ -131,11 +129,12 @@
 	}
 	vb2_buf = NULL;
 end:
-	spin_unlock_irqrestore(&vb2_buf_lock, flags);
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
 	return vb2_buf;
 }
 
-static int msm_vb2_put_buf(struct vb2_buffer *vb)
+static int msm_vb2_put_buf(struct vb2_buffer *vb, int session_id,
+				unsigned int stream_id)
 {
 	struct msm_vb2_buffer *msm_vb2;
 	int rc = 0;
@@ -155,13 +154,18 @@
 	return rc;
 }
 
-static int msm_vb2_buf_done(struct vb2_buffer *vb)
+static int msm_vb2_buf_done(struct vb2_buffer *vb, int session_id,
+				unsigned int stream_id)
 {
 	unsigned long flags;
 	struct msm_vb2_buffer *msm_vb2;
+	struct msm_stream *stream;
 	int rc = 0;
 
-	spin_lock_irqsave(&vb2_buf_lock, flags);
+	stream = msm_get_stream(session_id, stream_id);
+	if (!stream)
+		return 0;
+	spin_lock_irqsave(&stream->stream_lock, flags);
 	if (vb) {
 		msm_vb2 =
 			container_of(vb, struct msm_vb2_buffer, vb2_buf);
@@ -176,7 +180,7 @@
 		rc = -EINVAL;
 	}
 
-	spin_unlock_irqrestore(&vb2_buf_lock, flags);
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h
index 148d577..cecc85e 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h
@@ -51,6 +51,17 @@
 	void *alloc_ctx;
 };
 
+struct msm_stream {
+	struct list_head list;
+
+	/* stream index per session, same
+	 * as stream_id but set through s_parm */
+	unsigned int stream_id;
+	/* vb2 buffer handling */
+	struct vb2_queue *vb2_q;
+	spinlock_t stream_lock;
+};
+
 struct vb2_ops *msm_vb2_get_q_ops(void);
 struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void);
 int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req_sd);
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..9f0ad19
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -0,0 +1,1072 @@
+/* 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 void msm_cpp_boot_hw(struct cpp_device *cpp_dev)
+{
+	disable_irq(cpp_dev->irq->start);
+
+	msm_camera_io_w(0x1, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
+	msm_camera_io_w(0x1, cpp_dev->base +
+				 MSM_CPP_MICRO_BOOT_START);
+	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);
+	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);
+}
+
+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);
+	if (cpp_dev->is_firmware_loaded == 1)
+		msm_cpp_boot_hw(cpp_dev);
+	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);
+
+	/*Disable MC clock*/
+	/*msm_camera_io_w(0x0, cpp_dev->base +
+					   MSM_CPP_MICRO_CLKEN_CTL);*/
+}
+
+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);
+		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_LOAD_FIRMWARE: {
+		if (cpp_dev->is_firmware_loaded == 0) {
+			disable_irq(cpp_dev->irq->start);
+			cpp_load_fw(cpp_dev);
+			enable_irq(cpp_dev->irq->start);
+			cpp_dev->is_firmware_loaded = 1;
+		}
+		break;
+	}
+	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;
+	cpp_dev->is_firmware_loaded = 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..e8e37ed
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -0,0 +1,156 @@
+/* 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;
+	uint8_t is_firmware_loaded;
+
+	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/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 4701f69..63ec1cf 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -18,6 +18,8 @@
 #include "mpq_dmx_plugin_common.h"
 #include "mpq_sdmx.h"
 
+#define SDMX_MAJOR_VERSION_MATCH	(2)
+
 #define TS_PACKET_HEADER_LENGTH (4)
 
 /* Length of mandatory fields that must exist in header of video PES */
@@ -776,6 +778,7 @@
 static void mpq_sdmx_check_app_loaded(void)
 {
 	int session;
+	u32 version;
 	int ret;
 
 	ret = sdmx_open_session(&session);
@@ -787,6 +790,24 @@
 		return;
 	}
 
+	/* Check proper sdmx major version */
+	ret = sdmx_get_version(session, &version);
+	if (ret != SDMX_SUCCESS) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: Could not get sdmx version. ret = %d\n",
+			__func__, ret);
+	} else {
+		if ((version >> 8) != SDMX_MAJOR_VERSION_MATCH)
+			MPQ_DVB_ERR_PRINT(
+				"%s: sdmx major version does not match. expected=%d, actual=%d\n",
+				__func__, SDMX_MAJOR_VERSION_MATCH,
+				(version >> 8));
+		else
+			MPQ_DVB_DBG_PRINT(
+				"%s: sdmx major version is ok = %d\n",
+				__func__, SDMX_MAJOR_VERSION_MATCH);
+	}
+
 	mpq_dmx_info.secure_demux_app_loaded = 1;
 	sdmx_close_session(session);
 }
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_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 12469a5..6402437 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -198,13 +198,13 @@
 		.type = V4L2_CTRL_TYPE_MENU,
 		.minimum = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
 		.maximum = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
-		.default_value = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+		.default_value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
 		.step = 0,
 		.menu_skip_mask = ~(
 		(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
 		(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
 		),
-		.qmenu = mpeg_video_rate_control,
+		.qmenu = NULL,
 		.cluster = MSM_VENC_CTRL_CLUSTER_BITRATE,
 	},
 	{
@@ -913,7 +913,7 @@
 		case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
 			return HAL_H264_LEVEL_42;
 		case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
-			return HAL_H264_LEVEL_3;
+			return HAL_H264_LEVEL_5;
 		case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
 			return HAL_H264_LEVEL_51;
 		default:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 3c012e7..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 =
@@ -987,7 +976,7 @@
 
 	rc = call_hfi_op(hdev, unset_ocmem, hdev->hfi_device_data);
 	if (rc) {
-		dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n");
+		dprintk(VIDC_INFO, "Failed to unset OCMEM on driver\n");
 		goto release_ocmem_failed;
 	}
 	rc = wait_for_completion_timeout(
@@ -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 7deef37..52150e9 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;
@@ -2553,17 +2283,25 @@
 	struct vidc_resource_hdr rhdr;
 	struct venus_hfi_device *device = dev;
 	int rc = 0;
-	if (!device || !device->resources.ocmem.buf) {
+	if (!device) {
 		dprintk(VIDC_ERR, "%s Invalid params, device:%p\n",
 			__func__, device);
-		return -EINVAL;
+		rc = -EINVAL;
+		goto ocmem_unset_failed;
 	}
+	if (!device->resources.ocmem.buf) {
+		dprintk(VIDC_INFO, "%s Trying to free OCMEM which is not set",
+			__func__);
+		rc = -EINVAL;
+		goto ocmem_unset_failed;
+	}
+
 	rhdr.resource_id = VIDC_RESOURCE_OCMEM;
 	rhdr.resource_handle = (u32) &device->resources.ocmem;
 	rc = venus_hfi_core_release_resource(device, &rhdr);
 	if (rc)
-		dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n");
-
+		dprintk(VIDC_ERR, "Failed to unset OCMEM on driver\n");
+ocmem_unset_failed:
 	return rc;
 }
 
@@ -2862,6 +2600,12 @@
 		return -EINVAL;
 	}
 
+	rc = venus_hfi_iommu_attach(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to attach iommu");
+		goto fail_iommu_attach;
+	}
+
 	if (!device->resources.fw.cookie)
 		device->resources.fw.cookie = subsystem_get("venus");
 
@@ -2881,21 +2625,18 @@
 	rc = protect_cp_mem(device);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to protect memory\n");
-		goto fail_iommu_attach;
+		goto fail_protect_mem;
 	}
 
-	rc = venus_hfi_iommu_attach(device);
-	if (rc) {
-		dprintk(VIDC_ERR, "Failed to attach iommu");
-		goto fail_iommu_attach;
-	}
 	return rc;
-fail_iommu_attach:
+fail_protect_mem:
 	venus_hfi_disable_clks(device);
 fail_enable_clks:
 	subsystem_put(device->resources.fw.cookie);
 	device->resources.fw.cookie = NULL;
 fail_load_fw:
+	venus_hfi_iommu_detach(device);
+fail_iommu_attach:
 	return rc;
 }
 
@@ -2908,9 +2649,9 @@
 		return;
 	}
 	if (device->resources.fw.cookie) {
-		venus_hfi_iommu_detach(device);
 		venus_hfi_disable_clks(device);
 		subsystem_put(device->resources.fw.cookie);
+		venus_hfi_iommu_detach(device);
 		device->resources.fw.cookie = NULL;
 	}
 }
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/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 4ea7013..6c60e04 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -59,12 +59,12 @@
 };
 
 static char *taiko_supplies[] = {
-	"cdc-vdd-buck", "cdc-vdd-tx-h", "cdc-vdd-rx-h", "cdc-vddpx-1",
+	WCD9XXX_SUPPLY_BUCK_NAME, "cdc-vdd-tx-h", "cdc-vdd-rx-h", "cdc-vddpx-1",
 	"cdc-vdd-a-1p2v", "cdc-vddcx-1", "cdc-vddcx-2",
 };
 
 static char *tapan_supplies[] = {
-	"cdc-vdd-buck", "cdc-vdd-h", "cdc-vdd-px",
+	WCD9XXX_SUPPLY_BUCK_NAME, "cdc-vdd-h", "cdc-vdd-px",
 	"cdc-vdd-a-1p2v", "cdc-vdd-cx"
 };
 
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 0bce766..f2d71b6 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -214,7 +214,7 @@
 	prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
 	prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
 	prop.ratem = (rate/4000);
-	prop.sampleszbits = 16;
+	prop.sampleszbits = bit_width;
 
 	pr_debug("Before slim_define_ch:\n"
 		 "ch_cnt %d,ch_h[0] %d ch_h[1] %d, grph %d\n",
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/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
index 75c75a8..025410a 100644
--- a/drivers/net/wireless/wcnss/wcnss_vreg.c
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.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
@@ -40,6 +40,10 @@
 #define RIVA_PMU_OFFSET         0x28
 #define PRONTO_PMU_OFFSET       0x1004
 
+#define RIVA_SPARE_OFFSET       0x0b4
+#define PRONTO_SPARE_OFFSET     0x1088
+#define NVBIN_DLND_BIT          BIT(25)
+
 #define WCNSS_PMU_CFG_IRIS_XO_CFG          BIT(3)
 #define WCNSS_PMU_CFG_IRIS_XO_EN           BIT(4)
 #define WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP   BIT(5)
@@ -115,13 +119,16 @@
 	int rc = 0;
 	int size = 0;
 	int pmu_offset = 0;
+	int spare_offset = 0;
 	unsigned long wcnss_phys_addr;
 	void __iomem *pmu_conf_reg;
+	void __iomem *spare_reg;
 	struct clk *clk;
 
 	if (wcnss_hardware_type() == WCNSS_PRONTO_HW) {
 		wcnss_phys_addr = MSM_PRONTO_PHYS;
 		pmu_offset = PRONTO_PMU_OFFSET;
+		spare_offset = PRONTO_SPARE_OFFSET;
 		size = 0x3000;
 
 		clk = clk_get(dev, "xo");
@@ -132,6 +139,7 @@
 	} else {
 		wcnss_phys_addr = MSM_RIVA_PHYS;
 		pmu_offset = RIVA_PMU_OFFSET;
+		spare_offset = RIVA_SPARE_OFFSET;
 		size = SZ_256;
 
 		clk = clk_get(dev, "cxo");
@@ -147,6 +155,13 @@
 			pr_err("ioremap wcnss physical failed\n");
 			goto fail;
 		}
+
+		pr_debug("wcnss: Indicate NV bin download\n");
+		spare_reg = msm_wcnss_base + spare_offset;
+		reg = readl_relaxed(spare_reg);
+		reg |= NVBIN_DLND_BIT;
+		writel_relaxed(reg, spare_reg);
+
 		pmu_conf_reg = msm_wcnss_base + pmu_offset;
 
 		/* Enable IRIS XO */
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 55b4192..439b1f8 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.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
@@ -11,6 +11,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/firmware.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
@@ -75,13 +76,16 @@
 #define WCNSS_CTRL_MSG_START	0x01000000
 #define	WCNSS_VERSION_REQ		(WCNSS_CTRL_MSG_START + 0)
 #define	WCNSS_VERSION_RSP		(WCNSS_CTRL_MSG_START + 1)
+#define	WCNSS_NVBIN_DNLD_REQ		(WCNSS_CTRL_MSG_START + 2)
+#define	WCNSS_NVBIN_DNLD_RSP		(WCNSS_CTRL_MSG_START + 3)
+
 
 #define VALID_VERSION(version) \
 	((strncmp(version, "INVALID", WCNSS_VERSION_LEN)) ? 1 : 0)
 
 struct smd_msg_hdr {
-	unsigned int type;
-	unsigned int len;
+	unsigned int msg_type;
+	unsigned int msg_len;
 };
 
 struct wcnss_version {
@@ -92,6 +96,57 @@
 	unsigned char  revision;
 };
 
+#define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin"
+
+/*
+ * On SMD channel 4K of maximum data can be transferred, including message
+ * header, so NV fragment size as next multiple of 1Kb is 3Kb.
+ */
+#define NV_FRAGMENT_SIZE  3072
+
+/* Macro to find the total number fragments of the NV bin Image */
+#define TOTALFRAGMENTS(x) (((x % NV_FRAGMENT_SIZE) == 0) ? \
+	(x / NV_FRAGMENT_SIZE) : ((x / NV_FRAGMENT_SIZE) + 1))
+
+struct nvbin_dnld_req_params {
+	/*
+	 * Fragment sequence number of the NV bin Image. NV Bin Image
+	 * might not fit into one message due to size limitation of
+	 * the SMD channel FIFO so entire NV blob is chopped into
+	 * multiple fragments starting with seqeunce number 0. The
+	 * last fragment is indicated by marking is_last_fragment field
+	 * to 1. At receiving side, NV blobs would be concatenated
+	 * together without any padding bytes in between.
+	 */
+	unsigned short frag_number;
+
+	/*
+	 * When set to 1 it indicates that no more fragments will
+	 * be sent. Receiver shall send back response message after
+	 * the last fragment.
+	 */
+	unsigned short is_last_fragment;
+
+	/* NV Image size (number of bytes) */
+	unsigned int nvbin_buffer_size;
+
+	/*
+	 * Following the 'nvbin_buffer_size', there should be
+	 * nvbin_buffer_size bytes of NV bin Image i.e.
+	 * uint8[nvbin_buffer_size].
+	 */
+};
+
+struct nvbin_dnld_req_msg {
+	/*
+	 * Note: The length specified in nvbin_dnld_req_msg messages
+	 * should be hdr.msg_len = sizeof(nvbin_dnld_req_msg) +
+	 * nvbin_buffer_size.
+	 */
+	struct smd_msg_hdr hdr;
+	struct nvbin_dnld_req_params dnld_req_params;
+};
+
 static struct {
 	struct platform_device *pdev;
 	void		*pil;
@@ -111,6 +166,7 @@
 	struct wcnss_wlan_config wlan_config;
 	struct delayed_work wcnss_work;
 	struct work_struct wcnssctrl_version_work;
+	struct work_struct wcnssctrl_nvbin_dnld_work;
 	struct work_struct wcnssctrl_rx_work;
 	struct wake_lock wcnss_wake_lock;
 	void __iomem *msm_wcnss_base;
@@ -404,7 +460,7 @@
 
 void wcnss_flush_delayed_boot_votes()
 {
-	flush_delayed_work_sync(&penv->wcnss_work);
+	flush_delayed_work(&penv->wcnss_work);
 }
 EXPORT_SYMBOL(wcnss_flush_delayed_boot_votes);
 
@@ -678,7 +734,7 @@
 	ret = smd_write_avail(penv->smd_ch);
 	if (ret < len) {
 		pr_err("wcnss: no space available for smd frame\n");
-		ret =  -ENOSPC;
+		return -ENOSPC;
 	}
 	ret = smd_write(penv->smd_ch, data, len);
 	if (ret < len) {
@@ -695,6 +751,7 @@
 	unsigned char buf[WCNSS_MAX_FRAME_SIZE];
 	struct smd_msg_hdr *phdr;
 	struct wcnss_version *pversion;
+	int hw_type;
 
 	len = smd_read_avail(penv->smd_ch);
 	if (len > WCNSS_MAX_FRAME_SIZE) {
@@ -713,7 +770,7 @@
 
 	phdr = (struct smd_msg_hdr *)buf;
 
-	switch (phdr->type) {
+	switch (phdr->msg_type) {
 
 	case WCNSS_VERSION_RSP:
 		pversion = (struct wcnss_version *)buf;
@@ -726,10 +783,38 @@
 			"%02x%02x%02x%02x", pversion->major, pversion->minor,
 					pversion->version, pversion->revision);
 		pr_info("wcnss: version %s\n", penv->wcnss_version);
+		/* schedule work to download nvbin to ccpu */
+		hw_type = wcnss_hardware_type();
+		switch (hw_type) {
+		case WCNSS_RIVA_HW:
+			/* supported only if riva major >= 1 and minor >= 4 */
+			if ((pversion->major >= 1) && (pversion->minor >= 4)) {
+				pr_info("wcnss: schedule dnld work for riva\n");
+				schedule_work(&penv->wcnssctrl_nvbin_dnld_work);
+			}
+			break;
+
+		case WCNSS_PRONTO_HW:
+			/* supported only if pronto major >= 1 and minor >= 4 */
+			if ((pversion->major >= 1) && (pversion->minor >= 4)) {
+				pr_info("wcnss: schedule dnld work for pronto\n");
+				schedule_work(&penv->wcnssctrl_nvbin_dnld_work);
+			}
+			break;
+
+		default:
+			pr_info("wcnss: unknown hw type (%d), will not schedule dnld work\n",
+				hw_type);
+			break;
+		}
+		break;
+
+	case WCNSS_NVBIN_DNLD_RSP:
+		pr_info("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu\n");
 		break;
 
 	default:
-		pr_err("wcnss: invalid message type %d\n", phdr->type);
+		pr_err("wcnss: invalid message type %d\n", phdr->msg_type);
 	}
 	return;
 }
@@ -739,15 +824,126 @@
 	struct smd_msg_hdr smd_msg;
 	int ret = 0;
 
-	smd_msg.type = WCNSS_VERSION_REQ;
-	smd_msg.len = sizeof(smd_msg);
-	ret = wcnss_smd_tx(&smd_msg, smd_msg.len);
+	smd_msg.msg_type = WCNSS_VERSION_REQ;
+	smd_msg.msg_len = sizeof(smd_msg);
+	ret = wcnss_smd_tx(&smd_msg, smd_msg.msg_len);
 	if (ret < 0)
 		pr_err("wcnss: smd tx failed\n");
 
 	return;
 }
 
+static void wcnss_nvbin_dnld_req(struct work_struct *worker)
+{
+	int ret = 0;
+	struct nvbin_dnld_req_msg *dnld_req_msg;
+	unsigned short total_fragments = 0;
+	unsigned short count = 0;
+	unsigned short retry_count = 0;
+	unsigned short cur_frag_size = 0;
+	unsigned char *outbuffer = NULL;
+	const void *nv_blob_addr = NULL;
+	unsigned int nv_blob_size = 0;
+	const struct firmware *nv = NULL;
+	struct device *dev = NULL;
+
+	dev = wcnss_wlan_get_device();
+
+	ret = request_firmware(&nv, NVBIN_FILE, dev);
+
+	if (ret || !nv || !nv->data || !nv->size) {
+		pr_err("wcnss: wcnss_nvbin_dnld_req: request_firmware failed for %s\n",
+			NVBIN_FILE);
+		return;
+	}
+
+	/*
+	 * First 4 bytes in nv blob is validity bitmap.
+	 * We cannot validate nv, so skip those 4 bytes.
+	 */
+	nv_blob_addr = nv->data + 4;
+	nv_blob_size = nv->size - 4;
+
+	total_fragments = TOTALFRAGMENTS(nv_blob_size);
+
+	pr_info("wcnss: NV bin size: %d, total_fragments: %d\n",
+		nv_blob_size, total_fragments);
+
+	/* get buffer for nv bin dnld req message */
+	outbuffer = kmalloc((sizeof(struct nvbin_dnld_req_msg) +
+		NV_FRAGMENT_SIZE), GFP_KERNEL);
+
+	if (NULL == outbuffer) {
+		pr_err("wcnss: wcnss_nvbin_dnld_req: failed to get buffer\n");
+		goto err_free_nv;
+	}
+
+	dnld_req_msg = (struct nvbin_dnld_req_msg *)outbuffer;
+
+	dnld_req_msg->hdr.msg_type = WCNSS_NVBIN_DNLD_REQ;
+
+	for (count = 0; count < total_fragments; count++) {
+		dnld_req_msg->dnld_req_params.frag_number = count;
+
+		if (count == (total_fragments - 1)) {
+			/* last fragment, take care of boundry condition */
+			cur_frag_size = nv_blob_size % NV_FRAGMENT_SIZE;
+			if (!cur_frag_size)
+				cur_frag_size = NV_FRAGMENT_SIZE;
+
+			dnld_req_msg->dnld_req_params.is_last_fragment = 1;
+		} else {
+			cur_frag_size = NV_FRAGMENT_SIZE;
+			dnld_req_msg->dnld_req_params.is_last_fragment = 0;
+		}
+
+		dnld_req_msg->dnld_req_params.nvbin_buffer_size =
+			cur_frag_size;
+
+		dnld_req_msg->hdr.msg_len =
+			sizeof(struct nvbin_dnld_req_msg) + cur_frag_size;
+
+		/* copy NV fragment */
+		memcpy((outbuffer + sizeof(struct nvbin_dnld_req_msg)),
+			(nv_blob_addr + count * NV_FRAGMENT_SIZE),
+			cur_frag_size);
+
+		ret = wcnss_smd_tx(outbuffer, dnld_req_msg->hdr.msg_len);
+
+		retry_count = 0;
+		while ((ret == -ENOSPC) && (retry_count <= 3)) {
+			pr_debug("wcnss: wcnss_nvbin_dnld_req: smd tx failed, ENOSPC\n");
+			pr_debug("fragment: %d, len: %d, TotFragments: %d, retry_count: %d\n",
+				count, dnld_req_msg->hdr.msg_len,
+				total_fragments, retry_count);
+
+			/* wait and try again */
+			msleep(20);
+			retry_count++;
+			ret = wcnss_smd_tx(outbuffer,
+				dnld_req_msg->hdr.msg_len);
+		}
+
+		if (ret < 0) {
+			pr_err("wcnss: wcnss_nvbin_dnld_req: smd tx failed\n");
+			pr_err("fragment %d, len: %d, TotFragments: %d, retry_count: %d\n",
+				count, dnld_req_msg->hdr.msg_len,
+				total_fragments, retry_count);
+			goto err_dnld;
+		}
+	}
+
+err_dnld:
+	/* free buffer */
+	kfree(outbuffer);
+
+err_free_nv:
+	/* release firmware */
+	release_firmware(nv);
+
+	return;
+}
+
 static int
 wcnss_trigger_config(struct platform_device *pdev)
 {
@@ -832,6 +1028,7 @@
 	}
 	INIT_WORK(&penv->wcnssctrl_rx_work, wcnssctrl_rx_handler);
 	INIT_WORK(&penv->wcnssctrl_version_work, wcnss_send_version_req);
+	INIT_WORK(&penv->wcnssctrl_nvbin_dnld_work, wcnss_nvbin_dnld_req);
 
 	wake_lock_init(&penv->wcnss_wake_lock, WAKE_LOCK_SUSPEND, "wcnss");
 
diff --git a/drivers/platform/msm/ipa/Makefile b/drivers/platform/msm/ipa/Makefile
index ded5b50..c541eb7 100644
--- a/drivers/platform/msm/ipa/Makefile
+++ b/drivers/platform/msm/ipa/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_IPA) += ipat.o
 ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \
-	ipa_utils.o ipa_nat.o rmnet_bridge.o a2_service.o ipa_bridge.o
+	ipa_utils.o ipa_nat.o rmnet_bridge.o a2_service.o ipa_bridge.o ipa_intf.o
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 4a01c44..7690b21 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -23,12 +23,13 @@
 #include <linux/platform_device.h>
 #include <linux/rbtree.h>
 #include <linux/uaccess.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
 #include "ipa_i.h"
 
 #define IPA_SUMMING_THRESHOLD (0x10)
 #define IPA_PIPE_MEM_START_OFST (0x0)
 #define IPA_PIPE_MEM_SIZE (0x0)
-#define IPA_READ_MAX (16)
 #define IPA_MOBILE_AP_MODE(x) (x == IPA_MODE_MOBILE_AP_ETH || \
 			       x == IPA_MODE_MOBILE_AP_WAN || \
 			       x == IPA_MODE_MOBILE_AP_WLAN)
@@ -39,7 +40,6 @@
 #define IPA_DMA_POOL_SIZE (512)
 #define IPA_DMA_POOL_ALIGNMENT (4)
 #define IPA_DMA_POOL_BOUNDARY (1024)
-#define WLAN_AMPDU_TX_EP (15)
 #define IPA_ROUTING_RULE_BYTE_SIZE (4)
 #define IPA_BAM_CNFG_BITS_VAL (0x7FFFE004)
 
@@ -63,8 +63,45 @@
 static struct clk *sys_noc_ipa_axi_clk;
 static struct clk *ipa_cnoc_clk;
 static struct clk *ipa_inactivity_clk;
-static struct device *ipa_dev;
 
+static struct msm_bus_vectors ipa_init_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_IPA,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors ipa_max_perf_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_IPA,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 50000000,
+		.ib = 960000000,
+	},
+};
+
+static struct msm_bus_paths ipa_usecases[]  = {
+	{
+		ARRAY_SIZE(ipa_init_vectors),
+		ipa_init_vectors,
+	},
+	{
+		ARRAY_SIZE(ipa_max_perf_vectors),
+		ipa_max_perf_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata ipa_bus_client_pdata = {
+	ipa_usecases,
+	ARRAY_SIZE(ipa_usecases),
+	.name = "ipa",
+};
+
+static uint32_t ipa_bus_hdl;
+
+static struct device *ipa_dev;
 struct ipa_context *ipa_ctx;
 
 static bool polling_mode;
@@ -103,28 +140,6 @@
 
 static void ipa_set_aggregation_params(void);
 
-static ssize_t ipa_read(struct file *filp, char __user *buf, size_t count,
-		loff_t *f_pos)
-{
-	u32 reg_val = 0xfeedface;
-	char str[IPA_READ_MAX];
-	int result;
-	static int read_cnt;
-
-	if (read_cnt) {
-		IPAERR("only supports one call to read\n");
-		return 0;
-	}
-
-	reg_val = ipa_read_reg(ipa_ctx->mmio, IPA_COMP_HW_VERSION_OFST);
-	result = scnprintf(str, IPA_READ_MAX, "%x\n", reg_val);
-	if (copy_to_user(buf, str, result))
-		return -EFAULT;
-	read_cnt = 1;
-
-	return result;
-}
-
 static int ipa_open(struct inode *inode, struct file *filp)
 {
 	struct ipa_context *ctx = NULL;
@@ -145,6 +160,7 @@
 	struct ipa_ioc_nat_alloc_mem nat_mem;
 	struct ipa_ioc_v4_nat_init nat_init;
 	struct ipa_ioc_v4_nat_del nat_del;
+	size_t sz;
 
 	IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
 
@@ -475,6 +491,107 @@
 			break;
 		}
 		break;
+	case IPA_IOC_QUERY_INTF:
+		if (copy_from_user(header, (u8 *)arg,
+					sizeof(struct ipa_ioc_query_intf))) {
+			retval = -EFAULT;
+			break;
+		}
+		if (ipa_query_intf((struct ipa_ioc_query_intf *)header)) {
+			retval = -1;
+			break;
+		}
+		if (copy_to_user((u8 *)arg, header,
+					sizeof(struct ipa_ioc_query_intf))) {
+			retval = -EFAULT;
+			break;
+		}
+		break;
+	case IPA_IOC_QUERY_INTF_TX_PROPS:
+		sz = sizeof(struct ipa_ioc_query_intf_tx_props);
+		if (copy_from_user(header, (u8 *)arg, sz)) {
+			retval = -EFAULT;
+			break;
+		}
+		pyld_sz = sz + ((struct ipa_ioc_query_intf_tx_props *)
+				header)->num_tx_props *
+			sizeof(struct ipa_ioc_tx_intf_prop);
+		param = kzalloc(pyld_sz, GFP_KERNEL);
+		if (!param) {
+			retval = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
+			retval = -EFAULT;
+			break;
+		}
+		if (ipa_query_intf_tx_props(
+				(struct ipa_ioc_query_intf_tx_props *)param)) {
+			retval = -1;
+			break;
+		}
+		if (copy_to_user((u8 *)arg, param, pyld_sz)) {
+			retval = -EFAULT;
+			break;
+		}
+		break;
+	case IPA_IOC_QUERY_INTF_RX_PROPS:
+		sz = sizeof(struct ipa_ioc_query_intf_rx_props);
+		if (copy_from_user(header, (u8 *)arg, sz)) {
+			retval = -EFAULT;
+			break;
+		}
+		pyld_sz = sz + ((struct ipa_ioc_query_intf_rx_props *)
+				header)->num_rx_props *
+			sizeof(struct ipa_ioc_rx_intf_prop);
+		param = kzalloc(pyld_sz, GFP_KERNEL);
+		if (!param) {
+			retval = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
+			retval = -EFAULT;
+			break;
+		}
+		if (ipa_query_intf_rx_props(
+				(struct ipa_ioc_query_intf_rx_props *)param)) {
+			retval = -1;
+			break;
+		}
+		if (copy_to_user((u8 *)arg, param, pyld_sz)) {
+			retval = -EFAULT;
+			break;
+		}
+		break;
+	case IPA_IOC_PULL_MSG:
+		if (copy_from_user(header, (u8 *)arg,
+					sizeof(struct ipa_msg_meta))) {
+			retval = -EFAULT;
+			break;
+		}
+		pyld_sz = sizeof(struct ipa_msg_meta) +
+		   ((struct ipa_msg_meta *)header)->msg_len;
+		param = kzalloc(pyld_sz, GFP_KERNEL);
+		if (!param) {
+			retval = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
+			retval = -EFAULT;
+			break;
+		}
+		if (ipa_pull_msg((struct ipa_msg_meta *)param,
+				 (char *)param + sizeof(struct ipa_msg_meta),
+				 ((struct ipa_msg_meta *)param)->msg_len) !=
+		       ((struct ipa_msg_meta *)param)->msg_len) {
+			retval = -1;
+			break;
+		}
+		if (copy_to_user((u8 *)arg, param, pyld_sz)) {
+			retval = -EFAULT;
+			break;
+		}
+		break;
 	default:        /* redundant, as cmd was checked against MAXNR */
 		return -ENOTTY;
 	}
@@ -572,7 +689,7 @@
 		hdr_entry->hdr_len = 1;
 		hdr_entry->hdr[0] = 0;
 	} else {
-			hdr_entry->hdr_len = IPA_DEFAULT_HEADER_LENGTH;
+		hdr_entry->hdr_len = IPA_DEFAULT_HEADER_LENGTH;
 	}
 
 	/*
@@ -609,14 +726,16 @@
 	return ret;
 }
 
-static void ipa_handle_tx_poll_for_pipe(struct ipa_sys_context *sys)
+static int ipa_handle_tx_poll_for_pipe(struct ipa_sys_context *sys,
+		bool process_all)
 {
 	struct ipa_tx_pkt_wrapper *tx_pkt, *t;
 	struct sps_iovec iov;
 	unsigned long irq_flags;
 	int ret;
+	int cnt = 0;
 
-	while (1) {
+	do {
 		iov.addr = 0;
 		ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
 		if (ret) {
@@ -633,6 +752,7 @@
 		switch (tx_pkt->cnt) {
 		case 1:
 			ipa_wq_write_done(&tx_pkt->work);
+			++cnt;
 			break;
 		case 0xFFFF:
 			/* reached end of set */
@@ -647,6 +767,7 @@
 					    struct ipa_tx_pkt_wrapper, link);
 			spin_unlock_irqrestore(&sys->spinlock, irq_flags);
 			ipa_wq_write_done(&tx_pkt->work);
+			++cnt;
 			break;
 		default:
 			/* keep looping till reach the end of the set */
@@ -657,9 +778,12 @@
 				      &sys->wait_desc_list);
 			spin_unlock_irqrestore(&sys->spinlock,
 					       irq_flags);
+			++cnt;
 			break;
 		}
-	}
+	} while (process_all);
+
+	return cnt;
 }
 
 static void ipa_poll_function(struct work_struct *work)
@@ -669,19 +793,26 @@
 		IPA_A5_WLAN_AMPDU_OUT };
 	int i;
 	int num_tx_pipes;
-
-	/* check all the system pipes for tx completions and rx available */
-	if (ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep->valid)
-		ipa_handle_rx_core();
+	int cnt;
 
 	num_tx_pipes = sizeof(tx_pipes) / sizeof(tx_pipes[0]);
 
 	if (!IPA_MOBILE_AP_MODE(ipa_ctx->mode))
 		num_tx_pipes--;
 
-	for (i = 0; i < num_tx_pipes; i++)
-		if (ipa_ctx->sys[tx_pipes[i]].ep->valid)
-			ipa_handle_tx_poll_for_pipe(&ipa_ctx->sys[tx_pipes[i]]);
+	do {
+		cnt = 0;
+
+		/* check all the system pipes for tx comp and rx avail */
+		if (ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep->valid)
+			cnt |= ipa_handle_rx_core(false);
+
+		for (i = 0; i < num_tx_pipes; i++)
+			if (ipa_ctx->sys[tx_pipes[i]].ep->valid)
+				cnt |= ipa_handle_tx_poll_for_pipe(
+						&ipa_ctx->sys[tx_pipes[i]],
+						false);
+	} while (cnt);
 
 	/* re-post the poll work */
 	INIT_DELAYED_WORK(&ipa_ctx->poll_work, ipa_poll_function);
@@ -763,6 +894,12 @@
 fail_data_out:
 	ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_data_in);
 fail_schedule_delayed_work:
+	if (ipa_ctx->dflt_v6_rt_rule_hdl)
+		__ipa_del_rt_rule(ipa_ctx->dflt_v6_rt_rule_hdl);
+	if (ipa_ctx->dflt_v4_rt_rule_hdl)
+		__ipa_del_rt_rule(ipa_ctx->dflt_v4_rt_rule_hdl);
+	if (ipa_ctx->excp_hdr_hdl)
+		__ipa_del_hdr(ipa_ctx->excp_hdr_hdl);
 	ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_cmd);
 fail_cmd:
 	return result;
@@ -773,6 +910,9 @@
 	cancel_delayed_work(&ipa_ctx->poll_work);
 	ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_data_out);
 	ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_data_in);
+	__ipa_del_rt_rule(ipa_ctx->dflt_v6_rt_rule_hdl);
+	__ipa_del_rt_rule(ipa_ctx->dflt_v4_rt_rule_hdl);
+	__ipa_del_hdr(ipa_ctx->excp_hdr_hdl);
 	ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_cmd);
 }
 
@@ -1235,6 +1375,9 @@
 		clk_enable(ipa_inactivity_clk);
 	else
 		WARN_ON(1);
+
+	if (msm_bus_scale_client_update_request(ipa_bus_hdl, 1))
+		WARN_ON(1);
 }
 
 /**
@@ -1264,6 +1407,9 @@
 		clk_disable_unprepare(ipa_cnoc_clk);
 	else
 		WARN_ON(1);
+
+	if (msm_bus_scale_client_update_request(ipa_bus_hdl, 0))
+		WARN_ON(1);
 }
 
 static int ipa_setup_bam_cfg(const struct ipa_plat_drv_res *res)
@@ -1282,6 +1428,76 @@
 	}
 	return 0;
 }
+
+static int ipa_init_flt_block(void)
+{
+	int result = 0;
+
+	/*
+	 * SW workaround for Improper Filter Behaviour when neiher Global nor
+	 * Pipe Rules are present => configure dummy global filter rule
+	 * always which results in a miss
+	 */
+	struct ipa_ioc_add_flt_rule *rules;
+	struct ipa_flt_rule_add *rule;
+	struct ipa_ioc_get_rt_tbl rt_lookup;
+	enum ipa_ip_type ip;
+
+	if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1) {
+		size_t sz = sizeof(struct ipa_ioc_add_flt_rule) +
+		   sizeof(struct ipa_flt_rule_add);
+
+		rules = kmalloc(sz, GFP_KERNEL);
+		if (rules == NULL) {
+			IPAERR("fail to alloc mem for dummy filter rule\n");
+			return -ENOMEM;
+		}
+
+		for (ip = IPA_IP_v4; ip < IPA_IP_MAX; ip++) {
+			memset(&rt_lookup, 0,
+					sizeof(struct ipa_ioc_get_rt_tbl));
+			rt_lookup.ip = ip;
+			strlcpy(rt_lookup.name, IPA_DFLT_RT_TBL_NAME,
+					IPA_RESOURCE_NAME_MAX);
+			ipa_get_rt_tbl(&rt_lookup);
+			ipa_put_rt_tbl(rt_lookup.hdl);
+
+			memset(rules, 0, sz);
+			rule = &rules->rules[0];
+			rules->commit = 1;
+			rules->ip = ip;
+			rules->global = 1;
+			rules->num_rules = 1;
+			rule->at_rear = 1;
+			if (ip == IPA_IP_v4) {
+				rule->rule.attrib.attrib_mask =
+					IPA_FLT_PROTOCOL;
+				rule->rule.attrib.u.v4.protocol =
+				   IPA_INVALID_L4_PROTOCOL;
+			} else if (ip == IPA_IP_v6) {
+				rule->rule.attrib.attrib_mask =
+					IPA_FLT_NEXT_HDR;
+				rule->rule.attrib.u.v6.next_hdr =
+				   IPA_INVALID_L4_PROTOCOL;
+			} else {
+				result = -EINVAL;
+				WARN_ON(1);
+				break;
+			}
+			rule->rule.action = IPA_PASS_TO_ROUTING;
+			rule->rule.rt_tbl_hdl = rt_lookup.hdl;
+
+			if (ipa_add_flt_rule(rules) || rules->rules[0].status) {
+				result = -EINVAL;
+				WARN_ON(1);
+				break;
+			}
+		}
+		kfree(rules);
+	}
+	return result;
+}
+
 /**
 * ipa_init() - Initialize the IPA Driver
 *@resource_p:	contain platform specific values from DST file
@@ -1340,8 +1556,10 @@
 	ipa_ctx->ip6_rt_tbl_lcl = ip6_rt_tbl_lcl;
 	ipa_ctx->ip4_flt_tbl_lcl = ip4_flt_tbl_lcl;
 	ipa_ctx->ip6_flt_tbl_lcl = ip6_flt_tbl_lcl;
+
 	ipa_ctx->ipa_wrapper_base = resource_p->ipa_mem_base;
 	ipa_ctx->ipa_hw_type = resource_p->ipa_hw_type;
+	ipa_ctx->ipa_hw_mode = resource_p->ipa_hw_mode;
 
 	/* setup IPA register access */
 	ipa_ctx->mmio = ioremap(resource_p->ipa_mem_base + IPA_REG_BASE_OFST,
@@ -1420,7 +1638,7 @@
 	}
 
 	/* set up the default op mode */
-	ipa_ctx->mode = IPA_MODE_USB_DONGLE;
+	ipa_ctx->mode = IPA_MODE_MOBILE_AP_WAN;
 
 	/* init the lookaside cache */
 	ipa_ctx->flt_rule_cache = kmem_cache_create("IPA FLT",
@@ -1529,6 +1747,12 @@
 	rset = &ipa_ctx->reap_rt_tbl_set[IPA_IP_v6];
 	INIT_LIST_HEAD(&rset->head_rt_tbl_list);
 
+	INIT_LIST_HEAD(&ipa_ctx->intf_list);
+	INIT_LIST_HEAD(&ipa_ctx->msg_list);
+	INIT_LIST_HEAD(&ipa_ctx->pull_msg_list);
+	init_waitqueue_head(&ipa_ctx->msg_waitq);
+	mutex_init(&ipa_ctx->msg_lock);
+
 	mutex_init(&ipa_ctx->lock);
 	mutex_init(&ipa_ctx->nat_mem.lock);
 
@@ -1560,6 +1784,7 @@
 	ipa_ctx->rt_rule_hdl_tree = RB_ROOT;
 	ipa_ctx->rt_tbl_hdl_tree = RB_ROOT;
 	ipa_ctx->flt_rule_hdl_tree = RB_ROOT;
+	ipa_ctx->tag_tree = RB_ROOT;
 
 	atomic_set(&ipa_ctx->ipa_active_clients, 0);
 
@@ -1579,6 +1804,12 @@
 
 	ipa_replenish_rx_cache();
 
+	if (ipa_init_flt_block()) {
+		IPAERR("fail to setup dummy filter rules\n");
+		result = -ENODEV;
+		goto fail_empty_rt_tbl;
+	}
+
 	/*
 	 * setup an empty routing table in system memory, this will be used
 	 * to delete a routing table cleanly and safely
@@ -1634,10 +1865,12 @@
 	ipa_ctx->aggregation_type = IPA_MBIM_16;
 	ipa_ctx->aggregation_byte_limit = 1;
 	ipa_ctx->aggregation_time_limit = 0;
-	IPADBG(":IPA driver init OK.\n");
 
 	/* gate IPA clocks */
-	ipa_disable_clks();
+	if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+		ipa_disable_clks();
+
+	IPADBG(":IPA driver init OK.\n");
 
 	return 0;
 
@@ -1695,7 +1928,8 @@
 	ipa_ctx = NULL;
 fail_mem:
 	/* gate IPA clocks */
-	ipa_disable_clks();
+	if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+		ipa_disable_clks();
 	return result;
 }
 
@@ -1710,6 +1944,7 @@
 	ipa_res.ipa_pipe_mem_start_ofst = IPA_PIPE_MEM_START_OFST;
 	ipa_res.ipa_pipe_mem_size = IPA_PIPE_MEM_SIZE;
 	ipa_res.ipa_hw_type = 0;
+	ipa_res.ipa_hw_mode = 0;
 
 	result = ipa_load_pipe_connection(pdev_p,
 					A2_TO_IPA,
@@ -1789,6 +2024,15 @@
 	}
 	IPADBG(": found ipa_res.ipa_hw_type = %d", ipa_res.ipa_hw_type);
 
+	/* Get IPA HW mode */
+	result = of_property_read_u32(pdev_p->dev.of_node, "ipa-hw-mode",
+			&ipa_res.ipa_hw_mode);
+
+	if (result)
+		IPADBG("using default (IPA_MODE_NORMAL) for ipa-hw-mode\n");
+	else
+		IPADBG(": found ipa_res.ipa_hw_mode = %d", ipa_res.ipa_hw_mode);
+
 	IPADBG(":ipa_mem_base = 0x%x, ipa_mem_size = 0x%x\n",
 	       ipa_res.ipa_mem_base, ipa_res.ipa_mem_size);
 	IPADBG(":bam_mem_base = 0x%x, bam_mem_size = 0x%x\n",
@@ -1802,12 +2046,24 @@
 	/* stash the IPA dev ptr */
 	ipa_dev = &pdev_p->dev;
 
-	/* get IPA clocks */
-	if (ipa_get_clks(ipa_dev) != 0)
-		return -ENODEV;
+	if (ipa_res.ipa_hw_mode == IPA_HW_MODE_NORMAL) {
+		/* get IPA clocks */
+		if (ipa_get_clks(ipa_dev) != 0) {
+			IPAERR(":fail to get clk handle's!\n");
+			return -ENODEV;
+		}
 
-	/* enable IPA clocks */
-	ipa_enable_clks();
+		/* get BUS handle */
+		ipa_bus_hdl =
+			msm_bus_scale_register_client(&ipa_bus_client_pdata);
+		if (!ipa_bus_hdl) {
+			IPAERR(":fail to register with bus mgr!\n");
+			return -ENODEV;
+		}
+
+		/* enable IPA clocks */
+		ipa_enable_clks();
+	}
 
 	/* Proceed to real initialization */
 	result = ipa_init(&ipa_res);
@@ -1841,11 +2097,6 @@
 	},
 };
 
-static int ipa_plat_drv_init(void)
-{
-	return platform_driver_register(&ipa_plat_drv);
-}
-
 struct ipa_context *ipa_get_ctx(void)
 {
 	return ipa_ctx;
@@ -1856,9 +2107,11 @@
 	int result = 0;
 
 	IPADBG("IPA module init\n");
-	ipa_debugfs_init();
+
 	/* Register as a platform device driver */
-	result = ipa_plat_drv_init();
+	platform_driver_register(&ipa_plat_drv);
+
+	ipa_debugfs_init();
 
 	return result;
 }
diff --git a/drivers/platform/msm/ipa/ipa_bridge.c b/drivers/platform/msm/ipa/ipa_bridge.c
index a3de3ac..56e9b0d 100644
--- a/drivers/platform/msm/ipa/ipa_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_bridge.c
@@ -14,23 +14,26 @@
 #include <linux/ratelimit.h>
 #include "ipa_i.h"
 
-enum ipa_bridge_id {
+#define A2_EMBEDDED_PIPE_TX 4
+#define A2_EMBEDDED_PIPE_RX 5
+
+enum ipa_pipe_type {
 	IPA_DL_FROM_A2,
 	IPA_DL_TO_IPA,
 	IPA_UL_FROM_IPA,
 	IPA_UL_TO_A2,
-	IPA_BRIDGE_ID_MAX
+	IPA_PIPE_TYPE_MAX
 };
 
-static int polling_min_sleep[IPA_DIR_MAX] = { 950, 950 };
-static int polling_max_sleep[IPA_DIR_MAX] = { 1050, 1050 };
-static int polling_inactivity[IPA_DIR_MAX] = { 4, 4 };
+static int polling_min_sleep[IPA_BRIDGE_DIR_MAX] = { 950, 950 };
+static int polling_max_sleep[IPA_BRIDGE_DIR_MAX] = { 1050, 1050 };
+static int polling_inactivity[IPA_BRIDGE_DIR_MAX] = { 4, 4 };
 
 struct ipa_pkt_info {
 	void *buffer;
 	dma_addr_t dma_address;
 	uint32_t len;
-	struct list_head list_node;
+	struct list_head link;
 };
 
 struct ipa_bridge_pipe_context {
@@ -45,48 +48,59 @@
 	struct list_head free_desc_list;
 };
 
-static struct ipa_bridge_pipe_context bridge[IPA_BRIDGE_ID_MAX];
+struct ipa_bridge_context {
+	struct ipa_bridge_pipe_context pipe[IPA_PIPE_TYPE_MAX];
+	struct workqueue_struct *ul_wq;
+	struct workqueue_struct *dl_wq;
+	struct work_struct ul_work;
+	struct work_struct dl_work;
+	enum ipa_bridge_type type;
+};
 
-static struct workqueue_struct *ipa_ul_workqueue;
-static struct workqueue_struct *ipa_dl_workqueue;
-static void ipa_do_bridge_work(enum ipa_bridge_dir dir);
+static struct ipa_bridge_context bridge[IPA_BRIDGE_TYPE_MAX];
 
-static u32 alloc_cnt[IPA_DIR_MAX];
+static void ipa_do_bridge_work(enum ipa_bridge_dir dir,
+		struct ipa_bridge_context *ctx);
 
 static void ul_work_func(struct work_struct *work)
 {
-	ipa_do_bridge_work(IPA_UL);
+	struct ipa_bridge_context *ctx = container_of(work,
+			struct ipa_bridge_context, ul_work);
+	ipa_do_bridge_work(IPA_BRIDGE_DIR_UL, ctx);
 }
 
 static void dl_work_func(struct work_struct *work)
 {
-	ipa_do_bridge_work(IPA_DL);
+	struct ipa_bridge_context *ctx = container_of(work,
+			struct ipa_bridge_context, dl_work);
+	ipa_do_bridge_work(IPA_BRIDGE_DIR_DL, ctx);
 }
 
-static DECLARE_WORK(ul_work, ul_work_func);
-static DECLARE_WORK(dl_work, dl_work_func);
-
-static int ipa_switch_to_intr_mode(enum ipa_bridge_dir dir)
+static int ipa_switch_to_intr_mode(enum ipa_bridge_dir dir,
+				    struct ipa_bridge_context *ctx)
 {
 	int ret;
-	struct ipa_bridge_pipe_context *sys = &bridge[2 * dir];
+	struct ipa_bridge_pipe_context *sys = &ctx->pipe[2 * dir];
 
 	ret = sps_get_config(sys->pipe, &sys->connection);
 	if (ret) {
-		IPAERR("sps_get_config() failed %d\n", ret);
+		IPAERR("sps_get_config() failed %d type=%d dir=%d\n",
+				ret, ctx->type, dir);
 		goto fail;
 	}
 	sys->register_event.options = SPS_O_EOT;
 	ret = sps_register_event(sys->pipe, &sys->register_event);
 	if (ret) {
-		IPAERR("sps_register_event() failed %d\n", ret);
+		IPAERR("sps_register_event() failed %d type=%d dir=%d\n",
+				ret, ctx->type, dir);
 		goto fail;
 	}
 	sys->connection.options =
 	   SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_EOT;
 	ret = sps_set_config(sys->pipe, &sys->connection);
 	if (ret) {
-		IPAERR("sps_set_config() failed %d\n", ret);
+		IPAERR("sps_set_config() failed %d type=%d dir=%d\n",
+				ret, ctx->type, dir);
 		goto fail;
 	}
 	ret = 0;
@@ -94,21 +108,24 @@
 	return ret;
 }
 
-static int ipa_switch_to_poll_mode(enum ipa_bridge_dir dir)
+static int ipa_switch_to_poll_mode(enum ipa_bridge_dir dir,
+				    enum ipa_bridge_type type)
 {
 	int ret;
-	struct ipa_bridge_pipe_context *sys = &bridge[2 * dir];
+	struct ipa_bridge_pipe_context *sys = &bridge[type].pipe[2 * dir];
 
 	ret = sps_get_config(sys->pipe, &sys->connection);
 	if (ret) {
-		IPAERR("sps_get_config() failed %d\n", ret);
+		IPAERR("sps_get_config() failed %d type=%d dir=%d\n",
+				ret, type, dir);
 		goto fail;
 	}
 	sys->connection.options =
 	   SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_POLL;
 	ret = sps_set_config(sys->pipe, &sys->connection);
 	if (ret) {
-		IPAERR("sps_set_config() failed %d\n", ret);
+		IPAERR("sps_set_config() failed %d type=%d dir=%d\n",
+				ret, type, dir);
 		goto fail;
 	}
 	ret = 0;
@@ -116,43 +133,47 @@
 	return ret;
 }
 
-static int queue_rx_single(enum ipa_bridge_dir dir)
+static int queue_rx_single(enum ipa_bridge_dir dir, enum ipa_bridge_type type)
 {
-	struct ipa_bridge_pipe_context *sys_rx = &bridge[2 * dir];
+	struct ipa_bridge_pipe_context *sys_rx = &bridge[type].pipe[2 * dir];
 	struct ipa_pkt_info *info;
 	int ret;
 
 	info = kmalloc(sizeof(struct ipa_pkt_info), GFP_KERNEL);
 	if (!info) {
-		IPAERR("unable to alloc rx_pkt_info\n");
+		IPAERR("unable to alloc rx_pkt_info type=%d dir=%d\n",
+				type, dir);
 		goto fail_pkt;
 	}
 
 	info->buffer = kmalloc(IPA_RX_SKB_SIZE, GFP_KERNEL | GFP_DMA);
 	if (!info->buffer) {
-		IPAERR("unable to alloc rx_pkt_buffer\n");
+		IPAERR("unable to alloc rx_pkt_buffer type=%d dir=%d\n",
+				type, dir);
 		goto fail_buffer;
 	}
 
 	info->dma_address = dma_map_single(NULL, info->buffer, IPA_RX_SKB_SIZE,
 					   DMA_BIDIRECTIONAL);
 	if (info->dma_address == 0 || info->dma_address == ~0) {
-		IPAERR("dma_map_single failure %p for %p\n",
-				(void *)info->dma_address, info->buffer);
+		IPAERR("dma_map_single failure %p for %p type=%d dir=%d\n",
+				(void *)info->dma_address, info->buffer,
+				type, dir);
 		goto fail_dma;
 	}
 
 	info->len = ~0;
 
-	list_add_tail(&info->list_node, &sys_rx->head_desc_list);
+	list_add_tail(&info->link, &sys_rx->head_desc_list);
 	ret = sps_transfer_one(sys_rx->pipe, info->dma_address,
 			       IPA_RX_SKB_SIZE, info,
 			       SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT);
 	if (ret) {
-		list_del(&info->list_node);
+		list_del(&info->link);
 		dma_unmap_single(NULL, info->dma_address, IPA_RX_SKB_SIZE,
 				 DMA_BIDIRECTIONAL);
-		IPAERR("sps_transfer_one failed %d\n", ret);
+		IPAERR("sps_transfer_one failed %d type=%d dir=%d\n", ret,
+				type, dir);
 		goto fail_dma;
 	}
 	sys_rx->len++;
@@ -163,7 +184,7 @@
 fail_buffer:
 	kfree(info);
 fail_pkt:
-	IPAERR("failed\n");
+	IPAERR("failed type=%d dir=%d\n", type, dir);
 	return -ENOMEM;
 }
 
@@ -182,8 +203,8 @@
 		} else {
 			tx_pkt = list_first_entry(&sys_tx->head_desc_list,
 						  struct ipa_pkt_info,
-						  list_node);
-			list_move_tail(&tx_pkt->list_node,
+						  link);
+			list_move_tail(&tx_pkt->link,
 					&sys_tx->free_desc_list);
 			sys_tx->len--;
 			sys_tx->free_len++;
@@ -195,10 +216,11 @@
 	return cnt;
 }
 
-static void ipa_do_bridge_work(enum ipa_bridge_dir dir)
+static void ipa_do_bridge_work(enum ipa_bridge_dir dir,
+			       struct ipa_bridge_context *ctx)
 {
-	struct ipa_bridge_pipe_context *sys_rx = &bridge[2 * dir];
-	struct ipa_bridge_pipe_context *sys_tx = &bridge[2 * dir + 1];
+	struct ipa_bridge_pipe_context *sys_rx = &ctx->pipe[2 * dir];
+	struct ipa_bridge_pipe_context *sys_tx = &ctx->pipe[2 * dir + 1];
 	struct ipa_pkt_info *tx_pkt;
 	struct ipa_pkt_info *rx_pkt;
 	struct ipa_pkt_info *tmp_pkt;
@@ -221,8 +243,8 @@
 
 			rx_pkt = list_first_entry(&sys_rx->head_desc_list,
 						  struct ipa_pkt_info,
-						  list_node);
-			list_del(&rx_pkt->list_node);
+						  link);
+			list_del(&rx_pkt->link);
 			sys_rx->len--;
 			rx_pkt->len = iov.size;
 
@@ -231,8 +253,8 @@
 				tmp_pkt = kmalloc(sizeof(struct ipa_pkt_info),
 						GFP_KERNEL);
 				if (!tmp_pkt) {
-					pr_debug_ratelimited("%s: unable to alloc tx_pkt_info\n",
-					       __func__);
+					pr_debug_ratelimited("%s: unable to alloc tx_pkt_info type=%d dir=%d\n",
+					       __func__, ctx->type, dir);
 					usleep_range(polling_min_sleep[dir],
 							polling_max_sleep[dir]);
 					goto retry_alloc_tx;
@@ -241,8 +263,8 @@
 				tmp_pkt->buffer = kmalloc(IPA_RX_SKB_SIZE,
 						GFP_KERNEL | GFP_DMA);
 				if (!tmp_pkt->buffer) {
-					pr_debug_ratelimited("%s: unable to alloc tx_pkt_buffer\n",
-					       __func__);
+					pr_debug_ratelimited("%s: unable to alloc tx_pkt_buffer type=%d dir=%d\n",
+					       __func__, ctx->type, dir);
 					kfree(tmp_pkt);
 					usleep_range(polling_min_sleep[dir],
 							polling_max_sleep[dir]);
@@ -255,28 +277,26 @@
 						DMA_BIDIRECTIONAL);
 				if (tmp_pkt->dma_address == 0 ||
 						tmp_pkt->dma_address == ~0) {
-					pr_debug_ratelimited("%s: dma_map_single failure %p for %p\n",
+					pr_debug_ratelimited("%s: dma_map_single failure %p for %p type=%d dir=%d\n",
 					       __func__,
 					       (void *)tmp_pkt->dma_address,
-					       tmp_pkt->buffer);
+					       tmp_pkt->buffer, ctx->type, dir);
 				}
 
-				list_add_tail(&tmp_pkt->list_node,
+				list_add_tail(&tmp_pkt->link,
 						&sys_tx->free_desc_list);
 				sys_tx->free_len++;
-				alloc_cnt[dir]++;
-
 				tmp_pkt->len = ~0;
 			}
 
 			tx_pkt = list_first_entry(&sys_tx->free_desc_list,
 						  struct ipa_pkt_info,
-						  list_node);
-			list_del(&tx_pkt->list_node);
+						  link);
+			list_del(&tx_pkt->link);
 			sys_tx->free_len--;
 
 retry_add_rx:
-			list_add_tail(&tx_pkt->list_node,
+			list_add_tail(&tx_pkt->link,
 					&sys_rx->head_desc_list);
 			ret = sps_transfer_one(sys_rx->pipe,
 					tx_pkt->dma_address,
@@ -285,9 +305,9 @@
 					SPS_IOVEC_FLAG_INT |
 					SPS_IOVEC_FLAG_EOT);
 			if (ret) {
-				list_del(&tx_pkt->list_node);
-				pr_debug_ratelimited("%s: sps_transfer_one failed %d\n",
-						__func__, ret);
+				list_del(&tx_pkt->link);
+				pr_debug_ratelimited("%s: sps_transfer_one failed %d type=%d dir=%d\n",
+						__func__, ret, ctx->type, dir);
 				usleep_range(polling_min_sleep[dir],
 						polling_max_sleep[dir]);
 				goto retry_add_rx;
@@ -295,7 +315,7 @@
 			sys_rx->len++;
 
 retry_add_tx:
-			list_add_tail(&rx_pkt->list_node,
+			list_add_tail(&rx_pkt->link,
 					&sys_tx->head_desc_list);
 			ret = sps_transfer_one(sys_tx->pipe,
 					       rx_pkt->dma_address,
@@ -304,19 +324,21 @@
 					       SPS_IOVEC_FLAG_INT |
 					       SPS_IOVEC_FLAG_EOT);
 			if (ret) {
-				pr_debug_ratelimited("%s: fail to add to TX dir=%d\n",
-						__func__, dir);
-				list_del(&rx_pkt->list_node);
+				pr_debug_ratelimited("%s: fail to add to TX type=%d dir=%d\n",
+						__func__, ctx->type, dir);
+				list_del(&rx_pkt->link);
 				ipa_reclaim_tx(sys_tx, true);
 				usleep_range(polling_min_sleep[dir],
 						polling_max_sleep[dir]);
 				goto retry_add_tx;
 			}
 			sys_tx->len++;
+			IPA_STATS_INC_BRIDGE_CNT(ctx->type, dir,
+					ipa_ctx->stats.bridged_pkts);
 		}
 
 		if (inactive_cycles >= polling_inactivity[dir]) {
-			ipa_switch_to_intr_mode(dir);
+			ipa_switch_to_intr_mode(dir, ctx);
 			break;
 		}
 	}
@@ -324,47 +346,64 @@
 
 static void ipa_sps_irq_rx_notify(struct sps_event_notify *notify)
 {
+	enum ipa_bridge_type type = (enum ipa_bridge_type) notify->user;
+
 	switch (notify->event_id) {
 	case SPS_EVENT_EOT:
-		ipa_switch_to_poll_mode(IPA_UL);
-		queue_work(ipa_ul_workqueue, &ul_work);
+		ipa_switch_to_poll_mode(IPA_BRIDGE_DIR_UL, type);
+		queue_work(bridge[type].ul_wq, &bridge[type].ul_work);
 		break;
 	default:
-		IPAERR("recieved unexpected event id %d\n", notify->event_id);
+		IPAERR("recieved unexpected event id %d type %d\n",
+				notify->event_id, type);
 	}
 }
 
-static int setup_bridge_to_ipa(enum ipa_bridge_dir dir)
+static int setup_bridge_to_ipa(enum ipa_bridge_dir dir,
+			       enum ipa_bridge_type type,
+			       struct ipa_sys_connect_params *props,
+			       u32 *clnt_hdl)
 {
 	struct ipa_bridge_pipe_context *sys;
-	struct ipa_ep_cfg_mode mode;
 	dma_addr_t dma_addr;
+	enum ipa_pipe_type pipe_type;
 	int ipa_ep_idx;
 	int ret;
 	int i;
 
-	if (dir == IPA_DL) {
-		ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode,
-				IPA_CLIENT_A2_TETHERED_PROD);
-		if (ipa_ep_idx == -1) {
-			IPAERR("Invalid client.\n");
-			ret = -EINVAL;
-			goto tx_alloc_endpoint_failed;
-		}
+	ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode, props->client);
+	if (ipa_ep_idx == -1) {
+		IPAERR("Invalid client=%d mode=%d type=%d dir=%d\n",
+				props->client, ipa_ctx->mode, type, dir);
+		ret = -EINVAL;
+		goto alloc_endpoint_failed;
+	}
 
-		sys = &bridge[IPA_DL_TO_IPA];
-		sys->pipe = sps_alloc_endpoint();
-		if (sys->pipe == NULL) {
-			IPAERR("tx alloc endpoint failed\n");
-			ret = -ENOMEM;
-			goto tx_alloc_endpoint_failed;
-		}
-		ret = sps_get_config(sys->pipe, &sys->connection);
-		if (ret) {
-			IPAERR("tx get config failed %d\n", ret);
-			goto tx_get_config_failed;
-		}
+	if (ipa_ctx->ep[ipa_ep_idx].valid) {
+		IPAERR("EP %d already allocated type=%d dir=%d\n", ipa_ep_idx,
+				type, dir);
+		ret = -EINVAL;
+		goto alloc_endpoint_failed;
+	}
 
+	pipe_type = (dir == IPA_BRIDGE_DIR_DL) ? IPA_DL_TO_IPA :
+						 IPA_UL_FROM_IPA;
+
+	sys = &bridge[type].pipe[pipe_type];
+	sys->pipe = sps_alloc_endpoint();
+	if (sys->pipe == NULL) {
+		IPAERR("alloc endpoint failed type=%d dir=%d\n", type, dir);
+		ret = -ENOMEM;
+		goto alloc_endpoint_failed;
+	}
+	ret = sps_get_config(sys->pipe, &sys->connection);
+	if (ret) {
+		IPAERR("get config failed %d type=%d dir=%d\n", ret, type, dir);
+		ret = -EINVAL;
+		goto get_config_failed;
+	}
+
+	if (dir == IPA_BRIDGE_DIR_DL) {
 		sys->connection.source = SPS_DEV_HANDLE_MEM;
 		sys->connection.src_pipe_index = ipa_ctx->a5_pipe_index++;
 		sys->connection.destination = ipa_ctx->bam_handle;
@@ -372,435 +411,453 @@
 		sys->connection.mode = SPS_MODE_DEST;
 		sys->connection.options =
 		   SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_POLL;
-		sys->desc_mem_buf.size = IPA_SYS_DESC_FIFO_SZ; /* 2k */
-		sys->desc_mem_buf.base = dma_alloc_coherent(NULL,
-				sys->desc_mem_buf.size,
-				&dma_addr,
-				0);
-		if (sys->desc_mem_buf.base == NULL) {
-			IPAERR("tx memory alloc failed\n");
-			ret = -ENOMEM;
-			goto tx_get_config_failed;
-		}
-		sys->desc_mem_buf.phys_base = dma_addr;
-		memset(sys->desc_mem_buf.base, 0x0, sys->desc_mem_buf.size);
-		sys->connection.desc = sys->desc_mem_buf;
-		sys->connection.event_thresh = IPA_EVENT_THRESHOLD;
-
-		ret = sps_connect(sys->pipe, &sys->connection);
-		if (ret < 0) {
-			IPAERR("tx connect error %d\n", ret);
-			goto tx_connect_failed;
-		}
-
-		INIT_LIST_HEAD(&sys->head_desc_list);
-		INIT_LIST_HEAD(&sys->free_desc_list);
-		spin_lock_init(&sys->spinlock);
-
-		ipa_ctx->ep[ipa_ep_idx].valid = 1;
-
-		mode.mode = IPA_DMA;
-		mode.dst = IPA_CLIENT_USB_CONS;
-		ret = ipa_cfg_ep_mode(ipa_ep_idx, &mode);
-		if (ret < 0) {
-			IPAERR("DMA mode set error %d\n", ret);
-			goto tx_mode_set_failed;
-		}
-
-		return 0;
-
-tx_mode_set_failed:
-		sps_disconnect(sys->pipe);
-tx_connect_failed:
-		dma_free_coherent(NULL, sys->desc_mem_buf.size,
-				sys->desc_mem_buf.base,
-				sys->desc_mem_buf.phys_base);
-tx_get_config_failed:
-		sps_free_endpoint(sys->pipe);
-tx_alloc_endpoint_failed:
-		return ret;
 	} else {
-
-		ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode,
-				IPA_CLIENT_A2_TETHERED_CONS);
-		if (ipa_ep_idx == -1) {
-			IPAERR("Invalid client.\n");
-			ret = -EINVAL;
-			goto rx_alloc_endpoint_failed;
-		}
-
-		sys = &bridge[IPA_UL_FROM_IPA];
-		sys->pipe = sps_alloc_endpoint();
-		if (sys->pipe == NULL) {
-			IPAERR("rx alloc endpoint failed\n");
-			ret = -ENOMEM;
-			goto rx_alloc_endpoint_failed;
-		}
-		ret = sps_get_config(sys->pipe, &sys->connection);
-		if (ret) {
-			IPAERR("rx get config failed %d\n", ret);
-			goto rx_get_config_failed;
-		}
-
 		sys->connection.source = ipa_ctx->bam_handle;
-		sys->connection.src_pipe_index = 7;
+		sys->connection.src_pipe_index = ipa_ep_idx;
 		sys->connection.destination = SPS_DEV_HANDLE_MEM;
 		sys->connection.dest_pipe_index = ipa_ctx->a5_pipe_index++;
 		sys->connection.mode = SPS_MODE_SRC;
 		sys->connection.options = SPS_O_AUTO_ENABLE | SPS_O_EOT |
 		      SPS_O_ACK_TRANSFERS;
-		sys->desc_mem_buf.size = IPA_SYS_DESC_FIFO_SZ; /* 2k */
-		sys->desc_mem_buf.base = dma_alloc_coherent(NULL,
-				sys->desc_mem_buf.size,
-				&dma_addr,
-				0);
-		if (sys->desc_mem_buf.base == NULL) {
-			IPAERR("rx memory alloc failed\n");
-			ret = -ENOMEM;
-			goto rx_get_config_failed;
-		}
-		sys->desc_mem_buf.phys_base = dma_addr;
-		memset(sys->desc_mem_buf.base, 0x0, sys->desc_mem_buf.size);
-		sys->connection.desc = sys->desc_mem_buf;
-		sys->connection.event_thresh = IPA_EVENT_THRESHOLD;
+	}
 
-		ret = sps_connect(sys->pipe, &sys->connection);
-		if (ret < 0) {
-			IPAERR("rx connect error %d\n", ret);
-			goto rx_connect_failed;
-		}
+	sys->desc_mem_buf.size = props->desc_fifo_sz;
+	sys->desc_mem_buf.base = dma_alloc_coherent(NULL,
+						    sys->desc_mem_buf.size,
+						    &dma_addr,
+						    0);
+	if (sys->desc_mem_buf.base == NULL) {
+		IPAERR("memory alloc failed type=%d dir=%d\n", type, dir);
+		ret = -ENOMEM;
+		goto get_config_failed;
+	}
+	sys->desc_mem_buf.phys_base = dma_addr;
+	memset(sys->desc_mem_buf.base, 0x0, sys->desc_mem_buf.size);
+	sys->connection.desc = sys->desc_mem_buf;
+	sys->connection.event_thresh = IPA_EVENT_THRESHOLD;
 
+	ret = sps_connect(sys->pipe, &sys->connection);
+	if (ret < 0) {
+		IPAERR("connect error %d type=%d dir=%d\n", ret, type, dir);
+		goto connect_failed;
+	}
+
+	INIT_LIST_HEAD(&sys->head_desc_list);
+	INIT_LIST_HEAD(&sys->free_desc_list);
+	spin_lock_init(&sys->spinlock);
+
+	memset(&ipa_ctx->ep[ipa_ep_idx], 0,
+	       sizeof(struct ipa_ep_context));
+
+	ipa_ctx->ep[ipa_ep_idx].valid = 1;
+	ipa_ctx->ep[ipa_ep_idx].client_notify = props->notify;
+	ipa_ctx->ep[ipa_ep_idx].priv = props->priv;
+
+	ret = ipa_cfg_ep(ipa_ep_idx, &props->ipa_ep_cfg);
+	if (ret < 0) {
+		IPAERR("ep cfg set error %d type=%d dir=%d\n", ret, type, dir);
+		ipa_ctx->ep[ipa_ep_idx].valid = 0;
+		goto event_reg_failed;
+	}
+
+	if (dir == IPA_BRIDGE_DIR_UL) {
 		sys->register_event.options = SPS_O_EOT;
 		sys->register_event.mode = SPS_TRIGGER_CALLBACK;
 		sys->register_event.xfer_done = NULL;
 		sys->register_event.callback = ipa_sps_irq_rx_notify;
-		sys->register_event.user = NULL;
+		sys->register_event.user = (void *)type;
 		ret = sps_register_event(sys->pipe, &sys->register_event);
 		if (ret < 0) {
-			IPAERR("tx register event error %d\n", ret);
-			goto rx_event_reg_failed;
+			IPAERR("register event error %d type=%d dir=%d\n", ret,
+					type, dir);
+			goto event_reg_failed;
 		}
 
-		INIT_LIST_HEAD(&sys->head_desc_list);
-		INIT_LIST_HEAD(&sys->free_desc_list);
-		spin_lock_init(&sys->spinlock);
-
 		for (i = 0; i < IPA_RX_POOL_CEIL; i++) {
-			ret = queue_rx_single(dir);
+			ret = queue_rx_single(dir, type);
 			if (ret < 0)
-				IPAERR("queue fail %d %d\n", dir, i);
+				IPAERR("queue fail dir=%d type=%d iter=%d\n",
+				       dir, type, i);
 		}
-
-		return 0;
-
-rx_event_reg_failed:
-		sps_disconnect(sys->pipe);
-rx_connect_failed:
-		dma_free_coherent(NULL,
-				sys->desc_mem_buf.size,
-				sys->desc_mem_buf.base,
-				sys->desc_mem_buf.phys_base);
-rx_get_config_failed:
-		sps_free_endpoint(sys->pipe);
-rx_alloc_endpoint_failed:
-		return ret;
 	}
+
+	*clnt_hdl = ipa_ep_idx;
+
+	return 0;
+
+event_reg_failed:
+	sps_disconnect(sys->pipe);
+connect_failed:
+	dma_free_coherent(NULL,
+			  sys->desc_mem_buf.size,
+			  sys->desc_mem_buf.base,
+			  sys->desc_mem_buf.phys_base);
+get_config_failed:
+	sps_free_endpoint(sys->pipe);
+alloc_endpoint_failed:
+	return ret;
 }
 
 static void bam_mux_rx_notify(struct sps_event_notify *notify)
 {
+	enum ipa_bridge_type type = (enum ipa_bridge_type) notify->user;
+
 	switch (notify->event_id) {
 	case SPS_EVENT_EOT:
-		ipa_switch_to_poll_mode(IPA_DL);
-		queue_work(ipa_dl_workqueue, &dl_work);
+		ipa_switch_to_poll_mode(IPA_BRIDGE_DIR_DL, type);
+		queue_work(bridge[type].dl_wq, &bridge[type].dl_work);
 		break;
 	default:
-		IPAERR("recieved unexpected event id %d\n", notify->event_id);
+		IPAERR("recieved unexpected event id %d type %d\n",
+				notify->event_id, type);
 	}
 }
 
-static int setup_bridge_to_a2(enum ipa_bridge_dir dir)
+static int setup_bridge_to_a2(enum ipa_bridge_dir dir,
+			      enum ipa_bridge_type type,
+			      u32 desc_fifo_sz)
 {
 	struct ipa_bridge_pipe_context *sys;
-	struct a2_mux_pipe_connection pipe_conn = { 0, };
+	struct a2_mux_pipe_connection pipe_conn = { 0 };
 	dma_addr_t dma_addr;
 	u32 a2_handle;
+	enum a2_mux_pipe_direction pipe_dir;
+	enum ipa_pipe_type pipe_type;
+	u32 pa;
 	int ret;
 	int i;
 
-	if (dir == IPA_UL) {
-		ret = ipa_get_a2_mux_pipe_info(IPA_TO_A2, &pipe_conn);
-		if (ret) {
-			IPAERR("ipa_get_a2_mux_pipe_info failed IPA_TO_A2\n");
-			goto tx_alloc_endpoint_failed;
-		}
+	pipe_dir = (dir == IPA_BRIDGE_DIR_UL) ? IPA_TO_A2 : A2_TO_IPA;
 
-		ret = sps_phy2h(pipe_conn.dst_phy_addr, &a2_handle);
-		if (ret) {
-			IPAERR("sps_phy2h failed (A2 BAM) %d\n", ret);
-			goto tx_alloc_endpoint_failed;
-		}
+	ret = ipa_get_a2_mux_pipe_info(pipe_dir, &pipe_conn);
+	if (ret) {
+		IPAERR("ipa_get_a2_mux_pipe_info failed type=%d dir=%d\n",
+				type, dir);
+		ret = -EINVAL;
+		goto alloc_endpoint_failed;
+	}
 
-		sys = &bridge[IPA_UL_TO_A2];
-		sys->pipe = sps_alloc_endpoint();
-		if (sys->pipe == NULL) {
-			IPAERR("tx alloc endpoint failed\n");
-			ret = -ENOMEM;
-			goto tx_alloc_endpoint_failed;
-		}
-		ret = sps_get_config(sys->pipe, &sys->connection);
-		if (ret) {
-			IPAERR("tx get config failed %d\n", ret);
-			goto tx_get_config_failed;
-		}
+	pa = (dir == IPA_BRIDGE_DIR_UL) ? pipe_conn.dst_phy_addr :
+					  pipe_conn.src_phy_addr;
 
+	ret = sps_phy2h(pa, &a2_handle);
+	if (ret) {
+		IPAERR("sps_phy2h failed (A2 BAM) %d type=%d dir=%d\n",
+				ret, type, dir);
+		ret = -EINVAL;
+		goto alloc_endpoint_failed;
+	}
+
+	pipe_type = (dir == IPA_BRIDGE_DIR_UL) ? IPA_UL_TO_A2 : IPA_DL_FROM_A2;
+
+	sys = &bridge[type].pipe[pipe_type];
+	sys->pipe = sps_alloc_endpoint();
+	if (sys->pipe == NULL) {
+		IPAERR("alloc endpoint failed type=%d dir=%d\n", type, dir);
+		ret = -ENOMEM;
+		goto alloc_endpoint_failed;
+	}
+	ret = sps_get_config(sys->pipe, &sys->connection);
+	if (ret) {
+		IPAERR("get config failed %d type=%d dir=%d\n", ret, type, dir);
+		ret = -EINVAL;
+		goto get_config_failed;
+	}
+
+	if (dir == IPA_BRIDGE_DIR_UL) {
 		sys->connection.source = SPS_DEV_HANDLE_MEM;
 		sys->connection.src_pipe_index = ipa_ctx->a5_pipe_index++;
 		sys->connection.destination = a2_handle;
-		sys->connection.dest_pipe_index = pipe_conn.dst_pipe_index;
+		if (type == IPA_BRIDGE_TYPE_TETHERED)
+			sys->connection.dest_pipe_index =
+			   pipe_conn.dst_pipe_index;
+		else
+			sys->connection.dest_pipe_index = A2_EMBEDDED_PIPE_TX;
 		sys->connection.mode = SPS_MODE_DEST;
 		sys->connection.options =
 		   SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_POLL;
-		sys->desc_mem_buf.size = IPA_SYS_DESC_FIFO_SZ; /* 2k */
-		sys->desc_mem_buf.base = dma_alloc_coherent(NULL,
-				sys->desc_mem_buf.size,
-				&dma_addr,
-				0);
-		if (sys->desc_mem_buf.base == NULL) {
-			IPAERR("tx memory alloc failed\n");
-			ret = -ENOMEM;
-			goto tx_get_config_failed;
-		}
-		sys->desc_mem_buf.phys_base = dma_addr;
-		memset(sys->desc_mem_buf.base, 0x0, sys->desc_mem_buf.size);
-		sys->connection.desc = sys->desc_mem_buf;
-		sys->connection.event_thresh = IPA_EVENT_THRESHOLD;
-
-		ret = sps_connect(sys->pipe, &sys->connection);
-		if (ret < 0) {
-			IPAERR("tx connect error %d\n", ret);
-			goto tx_connect_failed;
-		}
-
-		INIT_LIST_HEAD(&sys->head_desc_list);
-		INIT_LIST_HEAD(&sys->free_desc_list);
-		spin_lock_init(&sys->spinlock);
-
-		return 0;
-
-tx_connect_failed:
-		dma_free_coherent(NULL,
-				sys->desc_mem_buf.size,
-				sys->desc_mem_buf.base,
-				sys->desc_mem_buf.phys_base);
-tx_get_config_failed:
-		sps_free_endpoint(sys->pipe);
-tx_alloc_endpoint_failed:
-		return ret;
-	} else { /* dir == IPA_UL */
-
-		ret = ipa_get_a2_mux_pipe_info(A2_TO_IPA, &pipe_conn);
-		if (ret) {
-			IPAERR("ipa_get_a2_mux_pipe_info failed A2_TO_IPA\n");
-			goto rx_alloc_endpoint_failed;
-		}
-
-		ret = sps_phy2h(pipe_conn.src_phy_addr, &a2_handle);
-		if (ret) {
-			IPAERR("sps_phy2h failed (A2 BAM) %d\n", ret);
-			goto rx_alloc_endpoint_failed;
-		}
-
-		sys = &bridge[IPA_DL_FROM_A2];
-		sys->pipe = sps_alloc_endpoint();
-		if (sys->pipe == NULL) {
-			IPAERR("rx alloc endpoint failed\n");
-			ret = -ENOMEM;
-			goto rx_alloc_endpoint_failed;
-		}
-		ret = sps_get_config(sys->pipe, &sys->connection);
-		if (ret) {
-			IPAERR("rx get config failed %d\n", ret);
-			goto rx_get_config_failed;
-		}
-
+	} else {
 		sys->connection.source = a2_handle;
-		sys->connection.src_pipe_index = pipe_conn.src_pipe_index;
+		if (type == IPA_BRIDGE_TYPE_TETHERED)
+			sys->connection.src_pipe_index =
+			   pipe_conn.src_pipe_index;
+		else
+			sys->connection.src_pipe_index = A2_EMBEDDED_PIPE_RX;
 		sys->connection.destination = SPS_DEV_HANDLE_MEM;
 		sys->connection.dest_pipe_index = ipa_ctx->a5_pipe_index++;
 		sys->connection.mode = SPS_MODE_SRC;
 		sys->connection.options = SPS_O_AUTO_ENABLE | SPS_O_EOT |
 		      SPS_O_ACK_TRANSFERS;
-		sys->desc_mem_buf.size = IPA_SYS_DESC_FIFO_SZ; /* 2k */
-		sys->desc_mem_buf.base = dma_alloc_coherent(NULL,
-				sys->desc_mem_buf.size,
-				&dma_addr,
-				0);
-		if (sys->desc_mem_buf.base == NULL) {
-			IPAERR("rx memory alloc failed\n");
-			ret = -ENOMEM;
-			goto rx_get_config_failed;
-		}
-		sys->desc_mem_buf.phys_base = dma_addr;
-		memset(sys->desc_mem_buf.base, 0x0, sys->desc_mem_buf.size);
-		sys->connection.desc = sys->desc_mem_buf;
-		sys->connection.event_thresh = IPA_EVENT_THRESHOLD;
+	}
 
-		ret = sps_connect(sys->pipe, &sys->connection);
-		if (ret < 0) {
-			IPAERR("rx connect error %d\n", ret);
-			goto rx_connect_failed;
-		}
+	sys->desc_mem_buf.size = desc_fifo_sz;
+	sys->desc_mem_buf.base = dma_alloc_coherent(NULL,
+						    sys->desc_mem_buf.size,
+						    &dma_addr,
+						    0);
+	if (sys->desc_mem_buf.base == NULL) {
+		IPAERR("memory alloc failed type=%d dir=%d\n", type, dir);
+		ret = -ENOMEM;
+		goto get_config_failed;
+	}
+	sys->desc_mem_buf.phys_base = dma_addr;
+	memset(sys->desc_mem_buf.base, 0x0, sys->desc_mem_buf.size);
+	sys->connection.desc = sys->desc_mem_buf;
+	sys->connection.event_thresh = IPA_EVENT_THRESHOLD;
 
+	ret = sps_connect(sys->pipe, &sys->connection);
+	if (ret < 0) {
+		IPAERR("connect error %d type=%d dir=%d\n", ret, type, dir);
+		ret = -EINVAL;
+		goto connect_failed;
+	}
+
+	INIT_LIST_HEAD(&sys->head_desc_list);
+	INIT_LIST_HEAD(&sys->free_desc_list);
+	spin_lock_init(&sys->spinlock);
+
+	if (dir == IPA_BRIDGE_DIR_DL) {
 		sys->register_event.options = SPS_O_EOT;
 		sys->register_event.mode = SPS_TRIGGER_CALLBACK;
 		sys->register_event.xfer_done = NULL;
 		sys->register_event.callback = bam_mux_rx_notify;
-		sys->register_event.user = NULL;
+		sys->register_event.user = (void *)type;
 		ret = sps_register_event(sys->pipe, &sys->register_event);
 		if (ret < 0) {
-			IPAERR("tx register event error %d\n", ret);
-			goto rx_event_reg_failed;
+			IPAERR("register event error %d type=%d dir=%d\n",
+					ret, type, dir);
+			ret = -EINVAL;
+			goto event_reg_failed;
 		}
 
-		INIT_LIST_HEAD(&sys->head_desc_list);
-		INIT_LIST_HEAD(&sys->free_desc_list);
-		spin_lock_init(&sys->spinlock);
-
-
 		for (i = 0; i < IPA_RX_POOL_CEIL; i++) {
-			ret = queue_rx_single(dir);
+			ret = queue_rx_single(dir, type);
 			if (ret < 0)
-				IPAERR("queue fail %d %d\n", dir, i);
+				IPAERR("queue fail dir=%d type=%d iter=%d\n",
+				       dir, type, i);
 		}
-
-		return 0;
-
-rx_event_reg_failed:
-		sps_disconnect(sys->pipe);
-rx_connect_failed:
-		dma_free_coherent(NULL,
-				sys->desc_mem_buf.size,
-				sys->desc_mem_buf.base,
-				sys->desc_mem_buf.phys_base);
-rx_get_config_failed:
-		sps_free_endpoint(sys->pipe);
-rx_alloc_endpoint_failed:
-		return ret;
 	}
+
+	return 0;
+
+event_reg_failed:
+	sps_disconnect(sys->pipe);
+connect_failed:
+	dma_free_coherent(NULL,
+			  sys->desc_mem_buf.size,
+			  sys->desc_mem_buf.base,
+			  sys->desc_mem_buf.phys_base);
+get_config_failed:
+	sps_free_endpoint(sys->pipe);
+alloc_endpoint_failed:
+	return ret;
 }
 
 /**
- * ipa_bridge_init() - initialize the tethered bridge, allocate UL and DL
- * workqueues
+ * ipa_bridge_init() - create workqueues and work items serving SW bridges
  *
  * Return codes: 0: success, -ENOMEM: failure
  */
 int ipa_bridge_init(void)
 {
 	int ret;
+	int i;
 
-	ipa_ul_workqueue = alloc_workqueue("ipa_ul",
+	bridge[IPA_BRIDGE_TYPE_TETHERED].ul_wq = alloc_workqueue("ipa_ul_teth",
 			WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
-	if (!ipa_ul_workqueue) {
-		IPAERR("ipa ul wq alloc failed\n");
+	if (!bridge[IPA_BRIDGE_TYPE_TETHERED].ul_wq) {
+		IPAERR("ipa ul teth wq alloc failed\n");
 		ret = -ENOMEM;
-		goto fail_ul;
+		goto fail_ul_teth;
 	}
 
-	ipa_dl_workqueue = alloc_workqueue("ipa_dl",
+	bridge[IPA_BRIDGE_TYPE_TETHERED].dl_wq = alloc_workqueue("ipa_dl_teth",
 			WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
-	if (!ipa_dl_workqueue) {
-		IPAERR("ipa dl wq alloc failed\n");
+	if (!bridge[IPA_BRIDGE_TYPE_TETHERED].dl_wq) {
+		IPAERR("ipa dl teth wq alloc failed\n");
 		ret = -ENOMEM;
-		goto fail_dl;
+		goto fail_dl_teth;
+	}
+
+	bridge[IPA_BRIDGE_TYPE_EMBEDDED].ul_wq = alloc_workqueue("ipa_ul_emb",
+					 WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
+	if (!bridge[IPA_BRIDGE_TYPE_EMBEDDED].ul_wq) {
+		IPAERR("ipa ul emb wq alloc failed\n");
+		ret = -ENOMEM;
+		goto fail_ul_emb;
+	}
+
+	bridge[IPA_BRIDGE_TYPE_EMBEDDED].dl_wq = alloc_workqueue("ipa_dl_emb",
+					 WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
+	if (!bridge[IPA_BRIDGE_TYPE_EMBEDDED].dl_wq) {
+		IPAERR("ipa dl emb wq alloc failed\n");
+		ret = -ENOMEM;
+		goto fail_dl_emb;
+	}
+
+	for (i = 0; i < IPA_BRIDGE_TYPE_MAX; i++) {
+		INIT_WORK(&bridge[i].ul_work, ul_work_func);
+		INIT_WORK(&bridge[i].dl_work, dl_work_func);
+		bridge[i].type = i;
 	}
 
 	return 0;
-fail_dl:
-	destroy_workqueue(ipa_ul_workqueue);
-fail_ul:
+
+fail_dl_emb:
+	destroy_workqueue(bridge[IPA_BRIDGE_TYPE_EMBEDDED].ul_wq);
+fail_ul_emb:
+	destroy_workqueue(bridge[IPA_BRIDGE_TYPE_TETHERED].dl_wq);
+fail_dl_teth:
+	destroy_workqueue(bridge[IPA_BRIDGE_TYPE_TETHERED].ul_wq);
+fail_ul_teth:
 	return ret;
 }
 
 /**
- * ipa_bridge_setup() - setup tethered SW bridge in specified direction
+ * ipa_bridge_setup() - setup SW bridge leg
  * @dir: downlink or uplink (from air interface perspective)
+ * @type: tethered or embedded bridge
+ * @props: bridge leg properties (EP config, callbacks, etc)
+ * @clnt_hdl: [out] handle of IPA EP belonging to bridge leg
+ *
+ * NOTE: IT IS CALLER'S RESPONSIBILITY TO ENSURE BAMs ARE
+ * OPERATIONAL AS LONG AS BRIDGE REMAINS UP
  *
  * Return codes:
  * 0: success
  * various negative error codes on errors
  */
-int ipa_bridge_setup(enum ipa_bridge_dir dir)
+int ipa_bridge_setup(enum ipa_bridge_dir dir, enum ipa_bridge_type type,
+		     struct ipa_sys_connect_params *props, u32 *clnt_hdl)
 {
 	int ret;
 
-	if (atomic_inc_return(&ipa_ctx->ipa_active_clients) == 1)
-		ipa_enable_clks();
-
-	if (setup_bridge_to_a2(dir)) {
-		IPAERR("fail to setup SYS pipe to A2 %d\n", dir);
-		ret = -EINVAL;
-		goto bail_a2;
+	if (props == NULL || clnt_hdl == NULL ||
+	    type >= IPA_BRIDGE_TYPE_MAX || dir >= IPA_BRIDGE_DIR_MAX ||
+	    props->client >= IPA_CLIENT_MAX || props->desc_fifo_sz == 0) {
+		IPAERR("Bad param props=%p clnt_hdl=%p type=%d dir=%d\n",
+		       props, clnt_hdl, type, dir);
+		return -EINVAL;
 	}
 
-	if (setup_bridge_to_ipa(dir)) {
-		IPAERR("fail to setup SYS pipe to IPA %d\n", dir);
+	if (atomic_inc_return(&ipa_ctx->ipa_active_clients) == 1) {
+		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+			ipa_enable_clks();
+	}
+
+	if (setup_bridge_to_ipa(dir, type, props, clnt_hdl)) {
+		IPAERR("fail to setup SYS pipe to IPA dir=%d type=%d\n",
+		       dir, type);
 		ret = -EINVAL;
 		goto bail_ipa;
 	}
 
-	return 0;
-
-bail_ipa:
-	if (dir == IPA_UL)
-		sps_disconnect(bridge[IPA_UL_TO_A2].pipe);
-	else
-		sps_disconnect(bridge[IPA_DL_FROM_A2].pipe);
-bail_a2:
-	if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0)
-		ipa_disable_clks();
-
-	return ret;
-}
-
-/**
- * ipa_bridge_teardown() - teardown the tethered bridge in the specified dir
- * @dir: downlink or uplink (from air interface perspective)
- *
- * Return codes:
- * 0: always
- */
-int ipa_bridge_teardown(enum ipa_bridge_dir dir)
-{
-	struct ipa_bridge_pipe_context *sys;
-
-	if (dir == IPA_UL) {
-		sys = &bridge[IPA_UL_TO_A2];
-		sps_disconnect(sys->pipe);
-		sys = &bridge[IPA_UL_FROM_IPA];
-		sps_disconnect(sys->pipe);
-	} else {
-		sys = &bridge[IPA_DL_FROM_A2];
-		sps_disconnect(sys->pipe);
-		sys = &bridge[IPA_DL_TO_IPA];
-		sps_disconnect(sys->pipe);
+	if (setup_bridge_to_a2(dir, type, props->desc_fifo_sz)) {
+		IPAERR("fail to setup SYS pipe to A2 dir=%d type=%d\n",
+		       dir, type);
+		ret = -EINVAL;
+		goto bail_a2;
 	}
 
-	if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0)
-		ipa_disable_clks();
 
 	return 0;
+
+bail_a2:
+	ipa_bridge_teardown(dir, type, *clnt_hdl);
+bail_ipa:
+	if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0) {
+		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+			ipa_disable_clks();
+	}
+	return ret;
+}
+EXPORT_SYMBOL(ipa_bridge_setup);
+
+static void ipa_bridge_free_pkt(struct ipa_pkt_info *pkt)
+{
+	list_del(&pkt->link);
+	dma_unmap_single(NULL, pkt->dma_address, IPA_RX_SKB_SIZE,
+			 DMA_BIDIRECTIONAL);
+	kfree(pkt->buffer);
+	kfree(pkt);
+}
+
+static void ipa_bridge_free_resources(struct ipa_bridge_pipe_context *pipe)
+{
+	struct ipa_pkt_info *pkt;
+	struct ipa_pkt_info *n;
+
+	list_for_each_entry_safe(pkt, n, &pipe->head_desc_list, link)
+		ipa_bridge_free_pkt(pkt);
+
+	list_for_each_entry_safe(pkt, n, &pipe->free_desc_list, link)
+		ipa_bridge_free_pkt(pkt);
 }
 
 /**
- * ipa_bridge_cleanup() - de-initialize the tethered bridge
+ * ipa_bridge_teardown() - teardown SW bridge leg
+ * @dir: downlink or uplink (from air interface perspective)
+ * @type: tethered or embedded bridge
+ * @clnt_hdl: handle of IPA EP
+ *
+ * Return codes:
+ * 0: success
+ * various negative error codes on errors
+ */
+int ipa_bridge_teardown(enum ipa_bridge_dir dir, enum ipa_bridge_type type,
+			u32 clnt_hdl)
+{
+	struct ipa_bridge_pipe_context *sys;
+	int lo;
+	int hi;
+
+	if (dir >= IPA_BRIDGE_DIR_MAX || type >= IPA_BRIDGE_TYPE_MAX ||
+	    clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
+		IPAERR("Bad param dir=%d type=%d\n", dir, type);
+		return -EINVAL;
+	}
+
+	if (dir == IPA_BRIDGE_DIR_UL) {
+		lo = IPA_UL_FROM_IPA;
+		hi = IPA_UL_TO_A2;
+	} else {
+		lo = IPA_DL_FROM_A2;
+		hi = IPA_DL_TO_IPA;
+	}
+
+	for (; lo <= hi; lo++) {
+		sys = &bridge[type].pipe[lo];
+		sps_disconnect(sys->pipe);
+		dma_free_coherent(NULL, sys->desc_mem_buf.size,
+				  sys->desc_mem_buf.base,
+				  sys->desc_mem_buf.phys_base);
+		sps_free_endpoint(sys->pipe);
+		ipa_bridge_free_resources(sys);
+	}
+
+	memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context));
+
+	if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0) {
+		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+			ipa_disable_clks();
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ipa_bridge_teardown);
+
+/**
+ * ipa_bridge_cleanup() - destroy workqueues serving the SW bridges
  *
  * Return codes:
  * None
  */
 void ipa_bridge_cleanup(void)
 {
-	destroy_workqueue(ipa_dl_workqueue);
-	destroy_workqueue(ipa_ul_workqueue);
+	int i;
+
+	for (i = 0; i < IPA_BRIDGE_TYPE_MAX; i++) {
+		destroy_workqueue(bridge[i].dl_wq);
+		destroy_workqueue(bridge[i].ul_wq);
+	}
 }
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index caa419b..4b9a0fd 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -10,8 +10,94 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/delay.h>
 #include "ipa_i.h"
 
+static void ipa_enable_data_path(u32 clnt_hdl)
+{
+	struct ipa_ep_context *ep = &ipa_ctx->ep[clnt_hdl];
+
+	if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_VIRTUAL) {
+		/* IPA_HW_MODE_VIRTUAL lacks support for TAG IC & EP suspend */
+		return;
+	}
+
+	if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1 && ep->suspended) {
+		ipa_write_reg(ipa_ctx->mmio,
+				IPA_ENDP_INIT_CTRL_n_OFST(clnt_hdl), 0);
+		ep->suspended = false;
+	}
+}
+
+static int ipa_disable_data_path(u32 clnt_hdl)
+{
+	DECLARE_COMPLETION_ONSTACK(tag_rsp);
+	struct ipa_desc desc = {0};
+	struct ipa_ip_packet_tag cmd;
+	struct ipa_ep_context *ep = &ipa_ctx->ep[clnt_hdl];
+	struct ipa_tree_node *node;
+	int result = 0;
+
+	if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_VIRTUAL) {
+		/* IPA_HW_MODE_VIRTUAL lacks support for TAG IC & EP suspend */
+		return 0;
+	}
+
+	node = kmem_cache_zalloc(ipa_ctx->tree_node_cache, GFP_KERNEL);
+	if (!node) {
+		IPAERR("failed to alloc tree node object\n");
+		result = -ENOMEM;
+		goto fail_alloc;
+	}
+
+	if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1 && !ep->suspended) {
+		ipa_write_reg(ipa_ctx->mmio,
+				IPA_ENDP_INIT_CTRL_n_OFST(clnt_hdl), 1);
+
+		cmd.tag = (u32) &tag_rsp;
+
+		desc.pyld = &cmd;
+		desc.len = sizeof(struct ipa_ip_packet_tag);
+		desc.type = IPA_IMM_CMD_DESC;
+		desc.opcode = IPA_IP_PACKET_TAG;
+
+		IPADBG("Wait on TAG %p clnt=%d\n", &tag_rsp, clnt_hdl);
+
+		node->hdl = cmd.tag;
+		mutex_lock(&ipa_ctx->lock);
+		if (ipa_insert(&ipa_ctx->tag_tree, node)) {
+			IPAERR("failed to add to tree\n");
+			result = -EINVAL;
+			mutex_unlock(&ipa_ctx->lock);
+			goto fail_insert;
+		}
+		mutex_unlock(&ipa_ctx->lock);
+
+		if (ipa_send_cmd(1, &desc)) {
+			ipa_write_reg(ipa_ctx->mmio,
+				IPA_ENDP_INIT_CTRL_n_OFST(clnt_hdl), 0);
+			IPAERR("fail to send TAG command\n");
+			result = -EPERM;
+			goto fail_send;
+		}
+		wait_for_completion(&tag_rsp);
+		if (IPA_CLIENT_IS_CONS(ep->client) &&
+				ep->cfg.aggr.aggr_en == IPA_ENABLE_AGGR &&
+				ep->cfg.aggr.aggr_time_limit)
+			msleep(ep->cfg.aggr.aggr_time_limit);
+		ep->suspended = true;
+	}
+
+	return 0;
+
+fail_send:
+	rb_erase(&node->node, &ipa_ctx->tag_tree);
+fail_insert:
+	kmem_cache_free(ipa_ctx->tree_node_cache, node);
+fail_alloc:
+	return result;
+}
+
 static int ipa_connect_configure_sps(const struct ipa_connect_params *in,
 				     struct ipa_ep_context *ep, int ipa_ep_idx)
 {
@@ -94,7 +180,6 @@
 	return 0;
 }
 
-
 /**
  * ipa_connect() - low-level IPA client connect
  * @in:	[in] input parameters from client
@@ -114,16 +199,15 @@
 		u32 *clnt_hdl)
 {
 	int ipa_ep_idx;
-	int ipa_ep_idx_dst;
 	int result = -EFAULT;
 	struct ipa_ep_context *ep;
 
 	if (atomic_inc_return(&ipa_ctx->ipa_active_clients) == 1)
-		ipa_enable_clks();
+		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+			ipa_enable_clks();
 
 	if (in == NULL || sps == NULL || clnt_hdl == NULL ||
 	    in->client >= IPA_CLIENT_MAX ||
-	    in->ipa_ep_cfg.mode.dst >= IPA_CLIENT_MAX ||
 	    in->desc_fifo_sz == 0 || in->data_fifo_sz == 0) {
 		IPAERR("bad parm.\n");
 		result = -EINVAL;
@@ -143,16 +227,6 @@
 		goto fail;
 	}
 
-	if (IPA_CLIENT_IS_PROD(in->client) &&
-			(in->ipa_ep_cfg.mode.mode == IPA_DMA)) {
-		ipa_ep_idx_dst = ipa_get_ep_mapping(ipa_ctx->mode,
-				in->ipa_ep_cfg.mode.dst);
-		if ((ipa_ep_idx_dst == -1) ||
-				(ipa_ctx->ep[ipa_ep_idx_dst].valid)) {
-			IPADBG("dst EP for IPA input pipe doesn't yet exist\n");
-		}
-	}
-
 	memset(&ipa_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa_ep_context));
 
 	ep->valid = 1;
@@ -247,13 +321,14 @@
 ipa_cfg_ep_fail:
 	memset(&ipa_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa_ep_context));
 fail:
-	if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0)
-		ipa_disable_clks();
+	if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0) {
+		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+			ipa_disable_clks();
+	}
 
 	return result;
 }
 EXPORT_SYMBOL(ipa_connect);
-
 /**
  * ipa_disconnect() - low-level IPA client disconnect
  * @clnt_hdl:	[in] opaque client handle assigned by IPA to client
@@ -278,6 +353,13 @@
 
 	ep = &ipa_ctx->ep[clnt_hdl];
 
+	result = ipa_disable_data_path(clnt_hdl);
+	if (result) {
+		IPAERR("disable data path failed res=%d clnt=%d.\n", result,
+				clnt_hdl);
+		return -EPERM;
+	}
+
 	result = sps_disconnect(ep->ep_hdl);
 	if (result) {
 		IPAERR("SPS disconnect failed.\n");
@@ -314,11 +396,68 @@
 		return -EPERM;
 	}
 
+	ipa_enable_data_path(clnt_hdl);
 	memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context));
 
-	if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0)
-		ipa_disable_clks();
+	if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0) {
+		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+			ipa_disable_clks();
+	}
 
 	return 0;
 }
 EXPORT_SYMBOL(ipa_disconnect);
+
+/**
+ * ipa_connection_suspend() - suspend B2B connection to/from IPA
+ * @clnt_hdl:	[in] opaque client handle assigned by IPA to client
+ *
+ * Should be called by the driver of the peripheral that wants to suspend
+ * its BAM-BAM connection to/from IPA in BAM-BAM mode. The pipe is not
+ * disconnected and must later be resumed before data transfer can begin
+ *
+ * Returns:	0 on success, negative on failure
+ *
+ * Note:	Should not be called from atomic context
+ */
+int ipa_connection_suspend(u32 clnt_hdl)
+{
+	int result;
+
+	if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
+		IPAERR("bad parm.\n");
+		return -EINVAL;
+	}
+	result = ipa_disable_data_path(clnt_hdl);
+	if (result)
+		IPAERR("disable data path failed res=%d clnt=%d.\n", result,
+				clnt_hdl);
+
+	return result;
+}
+EXPORT_SYMBOL(ipa_connection_suspend);
+
+/**
+ * ipa_connection_resume() - resume B2B connection to/from IPA
+ * @clnt_hdl:	[in] opaque client handle assigned by IPA to client
+ *
+ * Should be called by the driver of the peripheral that wants to resume
+ * its previously suspended BAM-BAM connection to/from IPA in BAM-BAM mode.
+ *
+ * Returns:	0 on success, negative on failure
+ *
+ * Note:	Should not be called from atomic context
+ */
+int ipa_connection_resume(u32 clnt_hdl)
+{
+	if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
+		IPAERR("bad parm.\n");
+		return -EINVAL;
+	}
+
+	ipa_enable_data_path(clnt_hdl);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipa_connection_resume);
+
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index 17e9cc0..ec83653 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -13,10 +13,38 @@
 #ifdef CONFIG_DEBUG_FS
 
 #include <linux/debugfs.h>
+#include <linux/stringify.h>
 #include "ipa_i.h"
 
 
-#define IPA_MAX_MSG_LEN 1024
+#define IPA_MAX_MSG_LEN 4096
+
+const char *ipa_client_name[] = {
+	__stringify(IPA_CLIENT_HSIC1_PROD),
+	__stringify(IPA_CLIENT_HSIC2_PROD),
+	__stringify(IPA_CLIENT_HSIC3_PROD),
+	__stringify(IPA_CLIENT_HSIC4_PROD),
+	__stringify(IPA_CLIENT_HSIC5_PROD),
+	__stringify(IPA_CLIENT_USB_PROD),
+	__stringify(IPA_CLIENT_A5_WLAN_AMPDU_PROD),
+	__stringify(IPA_CLIENT_A2_EMBEDDED_PROD),
+	__stringify(IPA_CLIENT_A2_TETHERED_PROD),
+	__stringify(IPA_CLIENT_A5_LAN_WAN_PROD),
+	__stringify(IPA_CLIENT_A5_CMD_PROD),
+	__stringify(IPA_CLIENT_Q6_LAN_PROD),
+	__stringify(IPA_CLIENT_HSIC1_CONS),
+	__stringify(IPA_CLIENT_HSIC2_CONS),
+	__stringify(IPA_CLIENT_HSIC3_CONS),
+	__stringify(IPA_CLIENT_HSIC4_CONS),
+	__stringify(IPA_CLIENT_HSIC5_CONS),
+	__stringify(IPA_CLIENT_USB_CONS),
+	__stringify(IPA_CLIENT_A2_EMBEDDED_CONS),
+	__stringify(IPA_CLIENT_A2_TETHERED_CONS),
+	__stringify(IPA_CLIENT_A5_LAN_WAN_CONS),
+	__stringify(IPA_CLIENT_Q6_LAN_CONS),
+	__stringify(IPA_CLIENT_MAX),
+};
+
 static struct dentry *dent;
 static struct dentry *dfile_gen_reg;
 static struct dentry *dfile_ep_reg;
@@ -25,6 +53,7 @@
 static struct dentry *dfile_ip6_rt;
 static struct dentry *dfile_ip4_flt;
 static struct dentry *dfile_ip6_flt;
+static struct dentry *dfile_stats;
 static char dbg_buff[IPA_MAX_MSG_LEN];
 static s8 ep_reg_idx;
 
@@ -365,9 +394,10 @@
 				hdr_ofst = 0;
 			nbytes = scnprintf(dbg_buff + cnt,
 					IPA_MAX_MSG_LEN - cnt,
-					"tbl_idx:%d tbl_name:%s tbl_ref:%u rule_idx:%d dst:%d ep:%d S:%u hdr_ofst[words]:%u attrib_mask:%08x ",
+					"tbl_idx:%d tbl_name:%s tbl_ref:%u rule_idx:%d dst:%d name:%s ep:%d S:%u hdr_ofst[words]:%u attrib_mask:%08x ",
 					entry->tbl->idx, entry->tbl->name,
 					entry->tbl->ref_cnt, i, entry->rule.dst,
+					ipa_client_name[entry->rule.dst],
 					ipa_get_ep_mapping(ipa_ctx->mode,
 						entry->rule.dst),
 					   !ipa_ctx->hdr_tbl_lcl,
@@ -393,19 +423,25 @@
 	int cnt = 0;
 	int i;
 	int j;
+	int k;
 	struct ipa_flt_tbl *tbl;
 	struct ipa_flt_entry *entry;
 	enum ipa_ip_type ip = (enum ipa_ip_type)file->private_data;
 	struct ipa_rt_tbl *rt_tbl;
+	u32 rt_tbl_idx;
 
 	tbl = &ipa_ctx->glob_flt_tbl[ip];
 	mutex_lock(&ipa_ctx->lock);
 	i = 0;
 	list_for_each_entry(entry, &tbl->head_flt_rule_list, link) {
 		rt_tbl = (struct ipa_rt_tbl *)entry->rule.rt_tbl_hdl;
+		if (rt_tbl == NULL)
+			rt_tbl_idx = ~0;
+		else
+			rt_tbl_idx = rt_tbl->idx;
 		nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
 				   "ep_idx:global rule_idx:%d act:%d rt_tbl_idx:%d attrib_mask:%08x ",
-				   i, entry->rule.action, rt_tbl->idx,
+				   i, entry->rule.action, rt_tbl_idx,
 				   entry->rule.attrib.attrib_mask);
 		cnt += nbytes;
 		cnt += ipa_attrib_dump(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
@@ -418,10 +454,16 @@
 		i = 0;
 		list_for_each_entry(entry, &tbl->head_flt_rule_list, link) {
 			rt_tbl = (struct ipa_rt_tbl *)entry->rule.rt_tbl_hdl;
+			if (rt_tbl == NULL)
+				rt_tbl_idx = ~0;
+			else
+				rt_tbl_idx = rt_tbl->idx;
+			k = ipa_get_client_mapping(ipa_ctx->mode, j);
 			nbytes = scnprintf(dbg_buff + cnt,
 					IPA_MAX_MSG_LEN - cnt,
-					"ep_idx:%d rule_idx:%d act:%d rt_tbl_idx:%d attrib_mask:%08x ",
-					j, i, entry->rule.action, rt_tbl->idx,
+					"ep_idx:%d name:%s rule_idx:%d act:%d rt_tbl_idx:%d attrib_mask:%08x ",
+					j, ipa_client_name[k], i,
+					entry->rule.action, rt_tbl_idx,
 					entry->rule.attrib.attrib_mask);
 			cnt += nbytes;
 			cnt +=
@@ -437,6 +479,51 @@
 	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
 }
 
+static ssize_t ipa_read_stats(struct file *file, char __user *ubuf,
+		size_t count, loff_t *ppos)
+{
+	int nbytes;
+	int i;
+	int cnt = 0;
+
+	nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
+			"sw_tx=%u\n"
+			"hw_tx=%u\n"
+			"rx=%u\n",
+			ipa_ctx->stats.tx_sw_pkts,
+			ipa_ctx->stats.tx_hw_pkts,
+			ipa_ctx->stats.rx_pkts);
+	cnt += nbytes;
+
+	for (i = 0; i < MAX_NUM_EXCP; i++) {
+		nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
+				"rx_excp[%u]=%u\n", i,
+				ipa_ctx->stats.rx_excp_pkts[i]);
+		cnt += nbytes;
+	}
+
+	for (i = 0; i < IPA_BRIDGE_TYPE_MAX; i++) {
+		nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
+				"bridged_pkt[%u][dl]=%u\n"
+				"bridged_pkt[%u][ul]=%u\n",
+				i,
+				ipa_ctx->stats.bridged_pkts[i][0],
+				i,
+				ipa_ctx->stats.bridged_pkts[i][1]);
+		cnt += nbytes;
+	}
+
+	for (i = 0; i < MAX_NUM_IMM_CMD; i++) {
+		nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
+				"IC[%u]=%u\n", i,
+				ipa_ctx->stats.imm_cmds[i]);
+		cnt += nbytes;
+	}
+
+	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
+}
+
+
 const struct file_operations ipa_gen_reg_ops = {
 	.read = ipa_read_gen_reg,
 };
@@ -460,6 +547,10 @@
 	.open = ipa_open_dbg,
 };
 
+const struct file_operations ipa_stats_ops = {
+	.read = ipa_read_stats,
+};
+
 void ipa_debugfs_init(void)
 {
 	const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
@@ -521,6 +612,13 @@
 		goto fail;
 	}
 
+	dfile_stats = debugfs_create_file("stats", read_only_mode, dent, 0,
+			&ipa_stats_ops);
+	if (!dfile_stats || IS_ERR(dfile_stats)) {
+		IPAERR("fail to create file for debug_fs stats\n");
+		goto fail;
+	}
+
 	return;
 
 fail:
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index e4173aa..52ed428 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -18,7 +18,7 @@
 
 #define list_next_entry(pos, member) \
 	list_entry(pos->member.next, typeof(*pos), member)
-#define IPA_LAST_DESC_COOKIE 0xFFFF
+#define IPA_LAST_DESC_CNT 0xFFFF
 /**
  * ipa_write_done() - this function will be (eventually) called when a Tx
  * operation is complete
@@ -49,7 +49,7 @@
 	if (unlikely(cnt == 0))
 		WARN_ON(1);
 
-	if (cnt > 1 && cnt != IPA_LAST_DESC_COOKIE)
+	if (cnt > 1 && cnt != IPA_LAST_DESC_CNT)
 		mult = tx_pkt->mult;
 
 	for (i = 0; i < cnt; i++) {
@@ -93,6 +93,7 @@
  * ipa_send_one() - Send a single descriptor
  * @sys:	system pipe context
  * @desc:	descriptor to send
+ * @in_atomic:  whether caller is in atomic context
  *
  * - Allocate tx_packet wrapper
  * - Allocate a bounce buffer due to HW constrains
@@ -104,7 +105,8 @@
  *
  * Return codes: 0: success, -EFAULT: failure
  */
-int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc)
+int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc,
+		bool in_atomic)
 {
 	struct ipa_tx_pkt_wrapper *tx_pkt;
 	unsigned long irq_flags;
@@ -112,8 +114,12 @@
 	u16 sps_flags = SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_INT;
 	dma_addr_t dma_address;
 	u16 len;
+	u32 mem_flag = GFP_KERNEL;
 
-	tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache, GFP_KERNEL);
+	if (in_atomic)
+		mem_flag = GFP_ATOMIC;
+
+	tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache, mem_flag);
 	if (!tx_pkt) {
 		IPAERR("failed to alloc tx wrapper\n");
 		goto fail_mem_alloc;
@@ -128,7 +134,7 @@
 		 */
 		tx_pkt->bounce = dma_pool_alloc(
 					ipa_ctx->one_kb_no_straddle_pool,
-					GFP_KERNEL, &dma_address);
+					mem_flag, &dma_address);
 		if (!tx_pkt->bounce) {
 			dma_address = 0;
 		} else {
@@ -210,6 +216,7 @@
  * @sys: system pipe context
  * @num_desc: number of packets
  * @desc: packets to send (may be immediate command or data)
+ * @in_atomic:  whether caller is in atomic context
  *
  * This function is used for system-to-bam connection.
  * - SPS driver expect struct sps_transfer which will contain all the data
@@ -226,7 +233,8 @@
  *
  * Return codes: 0: success, -EFAULT: failure
  */
-int ipa_send(struct ipa_sys_context *sys, u16 num_desc, struct ipa_desc *desc)
+int ipa_send(struct ipa_sys_context *sys, u16 num_desc, struct ipa_desc *desc,
+		bool in_atomic)
 {
 	struct ipa_tx_pkt_wrapper *tx_pkt;
 	struct ipa_tx_pkt_wrapper *next_pkt;
@@ -239,6 +247,10 @@
 	int result;
 	int fail_dma_wrap = 0;
 	uint size = num_desc * sizeof(struct sps_iovec);
+	u32 mem_flag = GFP_KERNEL;
+
+	if (likely(in_atomic))
+		mem_flag = GFP_ATOMIC;
 
 	transfer.iovec = dma_alloc_coherent(NULL, size, &dma_addr, 0);
 	transfer.iovec_phys = dma_addr;
@@ -251,7 +263,7 @@
 	for (i = 0; i < num_desc; i++) {
 		fail_dma_wrap = 0;
 		tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache,
-					   GFP_KERNEL);
+					   mem_flag);
 		if (!tx_pkt) {
 			IPAERR("failed to alloc tx wrapper\n");
 			goto failure;
@@ -287,7 +299,8 @@
 			 * packet does not cross a 1KB boundary
 			 */
 			tx_pkt->bounce =
-		   dma_pool_alloc(ipa_ctx->one_kb_no_straddle_pool, GFP_KERNEL,
+			   dma_pool_alloc(ipa_ctx->one_kb_no_straddle_pool,
+					   mem_flag,
 					   &tx_pkt->mem.phys_base);
 			if (!tx_pkt->bounce) {
 				tx_pkt->mem.phys_base = 0;
@@ -341,7 +354,7 @@
 			iovec->flags |= (SPS_IOVEC_FLAG_EOT |
 					SPS_IOVEC_FLAG_INT);
 			/* "mark" the last desc */
-			tx_pkt->cnt = IPA_LAST_DESC_COOKIE;
+			tx_pkt->cnt = IPA_LAST_DESC_CNT;
 		}
 	}
 
@@ -414,6 +427,11 @@
 int ipa_send_cmd(u16 num_desc, struct ipa_desc *descr)
 {
 	struct ipa_desc *desc;
+	int result = 0;
+
+	if (atomic_inc_return(&ipa_ctx->ipa_active_clients) == 1)
+		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+			ipa_enable_clks();
 
 	if (num_desc == 1) {
 		init_completion(&descr->xfer_done);
@@ -423,9 +441,10 @@
 
 		descr->callback = ipa_sps_irq_cmd_ack;
 		descr->user1 = descr;
-		if (ipa_send_one(&ipa_ctx->sys[IPA_A5_CMD], descr)) {
+		if (ipa_send_one(&ipa_ctx->sys[IPA_A5_CMD], descr, false)) {
 			IPAERR("fail to send immediate command\n");
-			return -EFAULT;
+			result = -EFAULT;
+			goto bail;
 		}
 		wait_for_completion(&descr->xfer_done);
 	} else {
@@ -437,14 +456,21 @@
 
 		desc->callback = ipa_sps_irq_cmd_ack;
 		desc->user1 = desc;
-		if (ipa_send(&ipa_ctx->sys[IPA_A5_CMD], num_desc, descr)) {
+		if (ipa_send(&ipa_ctx->sys[IPA_A5_CMD], num_desc,
+					descr, false)) {
 			IPAERR("fail to send multiple immediate command set\n");
-			return -EFAULT;
+			result = -EFAULT;
+			goto bail;
 		}
 		wait_for_completion(&desc->xfer_done);
 	}
 
-	return 0;
+	IPA_STATS_INC_IC_CNT(num_desc, descr, ipa_ctx->stats.imm_cmds);
+bail:
+	if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0)
+		if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+			ipa_disable_clks();
+	return result;
 }
 
 /**
@@ -486,7 +512,7 @@
  *  - Call the endpoints notify function, passing the skb in the parameters
  *  - Replenish the rx cache
  */
-void ipa_handle_rx_core(void)
+int ipa_handle_rx_core(bool process_all)
 {
 	struct ipa_a5_mux_hdr *mux_hdr;
 	struct ipa_rx_pkt_wrapper *rx_pkt;
@@ -498,6 +524,9 @@
 	int ret;
 	struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
 	struct ipa_ep_context *ep;
+	int cnt = 0;
+	struct completion *compl;
+	struct ipa_tree_node *node;
 
 	do {
 		ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
@@ -546,6 +575,38 @@
 
 		IPA_DUMP_BUFF(rx_skb->data, 0, rx_skb->len);
 
+		IPA_STATS_INC_CNT(ipa_ctx->stats.rx_pkts);
+		IPA_STATS_EXCP_CNT(mux_hdr->flags, ipa_ctx->stats.rx_excp_pkts);
+
+		if (unlikely(mux_hdr->flags & IPA_A5_MUX_HDR_EXCP_FLAG_TAG)) {
+			if (ipa_ctx->ipa_hw_mode != IPA_HW_MODE_VIRTUAL) {
+				/* retrieve the compl object from tag value */
+				mux_hdr++;
+				compl = (struct completion *)
+					ntohl(*((u32 *)mux_hdr));
+				IPADBG("%x %x %p\n", *(u32 *)mux_hdr,
+						*((u32 *)mux_hdr + 1), compl);
+
+				mutex_lock(&ipa_ctx->lock);
+				node = ipa_search(&ipa_ctx->tag_tree,
+						(u32)compl);
+				if (node) {
+					complete_all(compl);
+					rb_erase(&node->node,
+							&ipa_ctx->tag_tree);
+					kmem_cache_free(
+						ipa_ctx->tree_node_cache, node);
+				} else {
+					WARN_ON(1);
+				}
+				mutex_unlock(&ipa_ctx->lock);
+			}
+			dev_kfree_skb_any(rx_skb);
+			ipa_replenish_rx_cache();
+			++cnt;
+			continue;
+		}
+
 		if (mux_hdr->src_pipe_index >= IPA_NUM_PIPES ||
 			!ipa_ctx->ep[mux_hdr->src_pipe_index].valid ||
 			!ipa_ctx->ep[mux_hdr->src_pipe_index].client_notify) {
@@ -555,6 +616,7 @@
 			  ipa_ctx->ep[mux_hdr->src_pipe_index].client_notify);
 			dev_kfree_skb_any(rx_skb);
 			ipa_replenish_rx_cache();
+			++cnt;
 			continue;
 		}
 
@@ -575,7 +637,10 @@
 		ep->client_notify(ep->priv, IPA_RECEIVE,
 				(unsigned long)(rx_skb));
 		ipa_replenish_rx_cache();
-	} while (1);
+		cnt++;
+	} while (process_all);
+
+	return cnt;
 }
 
 /**
@@ -612,7 +677,7 @@
 		IPAERR("sps_set_config() failed %d\n", ret);
 		return;
 	}
-	ipa_handle_rx_core();
+	ipa_handle_rx_core(true);
 	ipa_ctx->curr_polling_state = 0;
 }
 
@@ -719,6 +784,8 @@
 
 	ipa_ctx->ep[ipa_ep_idx].valid = 1;
 	ipa_ctx->ep[ipa_ep_idx].client = sys_in->client;
+	ipa_ctx->ep[ipa_ep_idx].client_notify = sys_in->notify;
+	ipa_ctx->ep[ipa_ep_idx].priv = sys_in->priv;
 
 	if (ipa_cfg_ep(ipa_ep_idx, &sys_in->ipa_ep_cfg)) {
 		IPAERR("fail to configure EP.\n");
@@ -795,7 +862,7 @@
 	case 3:
 		sys_idx = ipa_ep_idx;
 		break;
-	case 15:
+	case WLAN_AMPDU_TX_EP:
 		sys_idx = IPA_A5_WLAN_AMPDU_OUT;
 		break;
 	default:
@@ -870,8 +937,7 @@
  * @user1
  * @user2
  *
- * This notified callback (client_notify) is for
- * the destination client.
+ * This notified callback is for the destination client.
  * This function is supplied in ipa_connect.
  */
 static void ipa_tx_comp_usr_notify_release(void *user1, void *user2)
@@ -881,6 +947,9 @@
 
 	IPADBG("skb=%p ep=%d\n", skb, ep_idx);
 
+	IPA_STATS_INC_TX_CNT(ep_idx, ipa_ctx->stats.tx_sw_pkts,
+			ipa_ctx->stats.tx_hw_pkts);
+
 	if (ipa_ctx->ep[ep_idx].client_notify)
 		ipa_ctx->ep[ep_idx].client_notify(ipa_ctx->ep[ep_idx].priv,
 				IPA_WRITE_DONE, (unsigned long)skb);
@@ -888,6 +957,12 @@
 		dev_kfree_skb_any(skb);
 }
 
+static void ipa_tx_cmd_comp(void *user1, void *user2)
+{
+	IPA_STATS_INC_CNT(ipa_ctx->stats.imm_cmds[IPA_IP_PACKET_INIT]);
+	kfree(user1);
+}
+
 /**
  * ipa_tx_dp() - Data-path tx handler
  * @dst:	[in] which IPA destination to route tx packets to
@@ -911,7 +986,7 @@
  * get notified by the supplied callback - ipa_sps_irq_tx_comp()
  *
  * ipa_sps_irq_tx_comp will call to the user supplied
- * callback (supplied in ipa_connect())
+ * callback (from ipa_connect)
  *
  * Returns:	0 on success, negative on failure
  */
@@ -925,23 +1000,22 @@
 	memset(&desc, 0, 2 * sizeof(struct ipa_desc));
 
 	ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode, dst);
-	if (ipa_ep_idx == -1) {
+	if (unlikely(ipa_ep_idx == -1)) {
 		IPAERR("dest EP does not exist.\n");
 		goto fail_gen;
 	}
 
-	if (ipa_ctx->ep[ipa_ep_idx].valid == 0) {
+	if (unlikely(ipa_ctx->ep[ipa_ep_idx].valid == 0)) {
 		IPAERR("dest EP not valid.\n");
 		goto fail_gen;
 	}
 
 	if (IPA_CLIENT_IS_CONS(dst)) {
-		cmd = kzalloc(sizeof(struct ipa_ip_packet_init), GFP_KERNEL);
+		cmd = kzalloc(sizeof(struct ipa_ip_packet_init), GFP_ATOMIC);
 		if (!cmd) {
 			IPAERR("failed to alloc immediate command object\n");
 			goto fail_mem_alloc;
 		}
-		memset(cmd, 0x00, sizeof(*cmd));
 
 		cmd->destination_pipe_index = ipa_ep_idx;
 		if (meta && meta->mbim_stream_id_valid)
@@ -950,6 +1024,8 @@
 		desc[0].pyld = cmd;
 		desc[0].len = sizeof(struct ipa_ip_packet_init);
 		desc[0].type = IPA_IMM_CMD_DESC;
+		desc[0].callback = ipa_tx_cmd_comp;
+		desc[0].user1 = cmd;
 		desc[1].pyld = skb->data;
 		desc[1].len = skb->len;
 		desc[1].type = IPA_DATA_DESC_SKB;
@@ -957,7 +1033,8 @@
 		desc[1].user1 = skb;
 		desc[1].user2 = (void *)ipa_ep_idx;
 
-		if (ipa_send(&ipa_ctx->sys[IPA_A5_LAN_WAN_OUT], 2, desc)) {
+		if (ipa_send(&ipa_ctx->sys[IPA_A5_LAN_WAN_OUT], 2, desc,
+					true)) {
 			IPAERR("fail to send immediate command\n");
 			goto fail_send;
 		}
@@ -970,7 +1047,7 @@
 		desc[0].user2 = (void *)ipa_ep_idx;
 
 		if (ipa_send_one(&ipa_ctx->sys[IPA_A5_WLAN_AMPDU_OUT],
-					&desc[0])) {
+					&desc[0], true)) {
 			IPAERR("fail to send skb\n");
 			goto fail_gen;
 		}
@@ -999,7 +1076,7 @@
  */
 void ipa_wq_handle_rx(struct work_struct *work)
 {
-	ipa_handle_rx_core();
+	ipa_handle_rx_core(true);
 	ipa_rx_switch_to_intr_mode();
 }
 
@@ -1030,8 +1107,7 @@
 	rx_len_cached = sys->len;
 	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
 
-	/* true RX data path is not currently exercised so drop the ceil */
-	while (rx_len_cached < (IPA_RX_POOL_CEIL >> 3)) {
+	while (rx_len_cached < IPA_RX_POOL_CEIL) {
 		rx_pkt = kmem_cache_zalloc(ipa_ctx->rx_pkt_wrapper_cache,
 					   GFP_KERNEL);
 		if (!rx_pkt) {
diff --git a/drivers/platform/msm/ipa/ipa_flt.c b/drivers/platform/msm/ipa/ipa_flt.c
index 337b016..b63b939 100644
--- a/drivers/platform/msm/ipa/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_flt.c
@@ -55,7 +55,11 @@
 	start = buf;
 	hdr = (struct ipa_flt_rule_hw_hdr *)buf;
 	hdr->u.hdr.action = entry->rule.action;
-	hdr->u.hdr.rt_tbl_idx = entry->rt_tbl->idx;
+	if (entry->rt_tbl)
+		hdr->u.hdr.rt_tbl_idx = entry->rt_tbl->idx;
+	else
+		/* for excp action flt rules, rt tbl index is meaningless */
+		hdr->u.hdr.rt_tbl_idx = 0;
 	hdr->u.hdr.rsvd = 0;
 	buf += sizeof(struct ipa_flt_rule_hw_hdr);
 
@@ -505,19 +509,23 @@
 	struct ipa_flt_entry *entry;
 	struct ipa_tree_node *node;
 
-	if (!rule->rt_tbl_hdl) {
-		IPAERR("flt rule does not point to valid RT tbl\n");
-		goto error;
-	}
+	if (rule->action != IPA_PASS_TO_EXCEPTION) {
+		if (!rule->rt_tbl_hdl) {
+			IPAERR("flt rule does not point to valid RT tbl\n");
+			goto error;
+		}
 
-	if (ipa_search(&ipa_ctx->rt_tbl_hdl_tree, rule->rt_tbl_hdl) == NULL) {
-		IPAERR("RT tbl not found\n");
-		goto error;
-	}
+		if (ipa_search(&ipa_ctx->rt_tbl_hdl_tree,
+					rule->rt_tbl_hdl) == NULL) {
+			IPAERR("RT tbl not found\n");
+			goto error;
+		}
 
-	if (((struct ipa_rt_tbl *)rule->rt_tbl_hdl)->cookie != IPA_COOKIE) {
-		IPAERR("flt rule cookie is invalid\n");
-		goto error;
+		if (((struct ipa_rt_tbl *)rule->rt_tbl_hdl)->cookie !=
+				IPA_COOKIE) {
+			IPAERR("RT table cookie is invalid\n");
+			goto error;
+		}
 	}
 
 	node = kmem_cache_zalloc(ipa_ctx->tree_node_cache, GFP_KERNEL);
@@ -541,7 +549,8 @@
 	else
 		list_add(&entry->link, &tbl->head_flt_rule_list);
 	tbl->rule_cnt++;
-	entry->rt_tbl->ref_cnt++;
+	if (entry->rt_tbl)
+		entry->rt_tbl->ref_cnt++;
 	*rule_hdl = (u32)entry;
 	IPADBG("add flt rule rule_cnt=%d\n", tbl->rule_cnt);
 
@@ -565,20 +574,23 @@
 	struct ipa_flt_entry *entry = (struct ipa_flt_entry *)rule_hdl;
 	struct ipa_tree_node *node;
 
+	node = ipa_search(&ipa_ctx->flt_rule_hdl_tree, rule_hdl);
+	if (node == NULL) {
+		IPAERR("lookup failed\n");
+
+		return -EINVAL;
+	}
+
 	if (entry == NULL || (entry->cookie != IPA_COOKIE)) {
 		IPAERR("bad params\n");
 
 		return -EINVAL;
 	}
-	node = ipa_search(&ipa_ctx->flt_rule_hdl_tree, rule_hdl);
-	if (node == NULL) {
-		IPAERR("lookup failed\n");
 
-		return -EPERM;
-	}
 	list_del(&entry->link);
 	entry->tbl->rule_cnt--;
-	entry->rt_tbl->ref_cnt--;
+	if (entry->rt_tbl)
+		entry->rt_tbl->ref_cnt--;
 	IPADBG("del flt rule rule_cnt=%d\n", entry->tbl->rule_cnt);
 	entry->cookie = 0;
 	kmem_cache_free(ipa_ctx->flt_rule_cache, entry);
@@ -595,6 +607,12 @@
 {
 	struct ipa_flt_tbl *tbl;
 
+	if (rule == NULL || rule_hdl == NULL) {
+		IPAERR("bad parms rule=%p rule_hdl=%p\n", rule, rule_hdl);
+
+		return -EINVAL;
+	}
+
 	tbl = &ipa_ctx->glob_flt_tbl[ip];
 	IPADBG("add global flt rule ip=%d\n", ip);
 
@@ -608,16 +626,16 @@
 	struct ipa_flt_tbl *tbl;
 	int ipa_ep_idx;
 
-	if (ip >= IPA_IP_MAX || rule == NULL || rule_hdl == NULL ||
-			ep >= IPA_CLIENT_MAX) {
-		IPAERR("bad parms\n");
+	if (rule == NULL || rule_hdl == NULL || ep >= IPA_CLIENT_MAX) {
+		IPAERR("bad parms rule=%p rule_hdl=%p ep=%d\n", rule,
+				rule_hdl, ep);
 
 		return -EINVAL;
 	}
 	ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode, ep);
 	if (ipa_ep_idx == IPA_FLT_TABLE_INDEX_NOT_FOUND ||
 				ipa_ctx->ep[ipa_ep_idx].valid == 0) {
-		IPAERR("bad parms\n");
+		IPAERR("ep not valid and/or connected ep_idx=%d\n", ipa_ep_idx);
 
 		return -EINVAL;
 	}
@@ -695,7 +713,6 @@
 
 	if (hdls == NULL || hdls->num_hdls == 0 || hdls->ip >= IPA_IP_MAX) {
 		IPAERR("bad parm\n");
-
 		return -EINVAL;
 	}
 
@@ -736,6 +753,11 @@
 {
 	int result;
 
+	if (ip >= IPA_IP_MAX) {
+		IPAERR("bad parm\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&ipa_ctx->lock);
 
 	if (__ipa_commit_flt(ip)) {
@@ -768,6 +790,11 @@
 	struct ipa_tree_node *node;
 	int i;
 
+	if (ip >= IPA_IP_MAX) {
+		IPAERR("bad parm\n");
+		return -EINVAL;
+	}
+
 	tbl = &ipa_ctx->glob_flt_tbl[ip];
 	mutex_lock(&ipa_ctx->lock);
 	IPADBG("reset flt ip=%d\n", ip);
@@ -775,9 +802,21 @@
 		node = ipa_search(&ipa_ctx->flt_rule_hdl_tree, (u32)entry);
 		if (node == NULL)
 			WARN_ON(1);
+
+		if ((ip == IPA_IP_v4 &&
+		     entry->rule.attrib.attrib_mask == IPA_FLT_PROTOCOL &&
+		     entry->rule.attrib.u.v4.protocol ==
+		      IPA_INVALID_L4_PROTOCOL) ||
+		    (ip == IPA_IP_v6 &&
+		     entry->rule.attrib.attrib_mask == IPA_FLT_NEXT_HDR &&
+		     entry->rule.attrib.u.v6.next_hdr ==
+		      IPA_INVALID_L4_PROTOCOL))
+			continue;
+
 		list_del(&entry->link);
 		entry->tbl->rule_cnt--;
-		entry->rt_tbl->ref_cnt--;
+		if (entry->rt_tbl)
+			entry->rt_tbl->ref_cnt--;
 		entry->cookie = 0;
 		kmem_cache_free(ipa_ctx->flt_rule_cache, entry);
 
@@ -796,7 +835,8 @@
 				WARN_ON(1);
 			list_del(&entry->link);
 			entry->tbl->rule_cnt--;
-			entry->rt_tbl->ref_cnt--;
+			if (entry->rt_tbl)
+				entry->rt_tbl->ref_cnt--;
 			entry->cookie = 0;
 			kmem_cache_free(ipa_ctx->flt_rule_cache, entry);
 
diff --git a/drivers/platform/msm/ipa/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_hdr.c
index 4b9a500..0439a69 100644
--- a/drivers/platform/msm/ipa/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_hdr.c
@@ -12,7 +12,7 @@
 
 #include "ipa_i.h"
 
-static const u32 ipa_hdr_bin_sz[IPA_HDR_BIN_MAX] = { 8, 16, 32, 64 };
+static const u32 ipa_hdr_bin_sz[IPA_HDR_BIN_MAX] = { 8, 16, 24, 36 };
 
 /**
  * ipa_generate_hdr_hw_tbl() - generates the headers table
@@ -234,20 +234,21 @@
 	return -EPERM;
 }
 
-static int __ipa_del_hdr(u32 hdr_hdl)
+int __ipa_del_hdr(u32 hdr_hdl)
 {
 	struct ipa_hdr_entry *entry = (struct ipa_hdr_entry *)hdr_hdl;
 	struct ipa_tree_node *node;
 	struct ipa_hdr_tbl *htbl = &ipa_ctx->hdr_tbl;
 
-	if (!entry || (entry->cookie != IPA_COOKIE) || (entry->ref_cnt != 0)) {
-		IPAERR("bad parm\n");
-		return -EINVAL;
-	}
 	node = ipa_search(&ipa_ctx->hdr_hdl_tree, hdr_hdl);
 	if (node == NULL) {
 		IPAERR("lookup failed\n");
-		return -EPERM;
+		return -EINVAL;
+	}
+
+	if (!entry || (entry->cookie != IPA_COOKIE) || (entry->ref_cnt != 0)) {
+		IPAERR("bad parm\n");
+		return -EINVAL;
 	}
 
 	IPADBG("del hdr of sz=%d hdr_cnt=%d ofst=%d\n", entry->hdr_len,
@@ -545,17 +546,21 @@
 	struct ipa_tree_node *node;
 	int result = -EFAULT;
 
-	if (entry == NULL || entry->cookie != IPA_COOKIE ||
-			entry->ref_cnt == 0) {
-		IPAERR("bad params\n");
-		return -EINVAL;
-	}
+	mutex_lock(&ipa_ctx->lock);
 	node = ipa_search(&ipa_ctx->hdr_hdl_tree, hdr_hdl);
 	if (node == NULL) {
 		IPAERR("lookup failed\n");
-		return -EPERM;
+		result = -EINVAL;
+		goto bail;
 	}
-	mutex_lock(&ipa_ctx->lock);
+
+	if (entry == NULL || entry->cookie != IPA_COOKIE ||
+			entry->ref_cnt == 0) {
+		IPAERR("bad params\n");
+		result = -EINVAL;
+		goto bail;
+	}
+
 	entry->ref_cnt--;
 	if (entry->ref_cnt == 0) {
 		if (__ipa_del_hdr(hdr_hdl)) {
diff --git a/drivers/platform/msm/ipa/ipa_hw_defs.h b/drivers/platform/msm/ipa/ipa_hw_defs.h
index 3131a84..3b9ce3d 100644
--- a/drivers/platform/msm/ipa/ipa_hw_defs.h
+++ b/drivers/platform/msm/ipa/ipa_hw_defs.h
@@ -164,12 +164,12 @@
 	u64 rsvd:32;
 };
 
-#define IPA_A5_MUX_HDR_EXCP_FLAG_IP		BIT(0)
-#define IPA_A5_MUX_HDR_EXCP_FLAG_NAT		BIT(1)
-#define IPA_A5_MUX_HDR_EXCP_FLAG_SW_FLT	BIT(2)
-#define IPA_A5_MUX_HDR_EXCP_FLAG_TAG		BIT(3)
-#define IPA_A5_MUX_HDR_EXCP_FLAG_REPLICATED	BIT(4)
-#define IPA_A5_MUX_HDR_EXCP_FLAG_IHL		BIT(5)
+#define IPA_A5_MUX_HDR_EXCP_FLAG_IP		BIT(7)
+#define IPA_A5_MUX_HDR_EXCP_FLAG_NAT		BIT(6)
+#define IPA_A5_MUX_HDR_EXCP_FLAG_SW_FLT	BIT(5)
+#define IPA_A5_MUX_HDR_EXCP_FLAG_TAG		BIT(4)
+#define IPA_A5_MUX_HDR_EXCP_FLAG_REPLICATED	BIT(3)
+#define IPA_A5_MUX_HDR_EXCP_FLAG_IHL		BIT(2)
 
 /**
  * struct ipa_a5_mux_hdr - A5 MUX header definition
@@ -255,4 +255,12 @@
 	u64 public_ip_addr:32;
 };
 
+/**
+ * struct ipa_ip_packet_tag - IPA_IP_PACKET_TAG command payload
+ * @tag: tag value returned with response
+ */
+struct ipa_ip_packet_tag {
+	u32 tag;
+};
+
 #endif /* _IPA_HW_DEFS_H */
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index f6e1cb5..1b5b339 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -34,11 +34,54 @@
 
 #ifdef IPA_DEBUG
 #define IPADBG(fmt, args...) \
-	pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
+	pr_err(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
+/*	pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) */
 #else
 #define IPADBG(fmt, args...)
 #endif
 
+#define WLAN_AMPDU_TX_EP (15)
+#define MAX_NUM_EXCP	 (8)
+#define MAX_NUM_IMM_CMD	 (17)
+
+#define IPA_STATS
+
+#ifdef IPA_STATS
+#define IPA_STATS_INC_CNT(val) do {			\
+				++val;			\
+			} while (0)
+#define IPA_STATS_INC_CNT_SAFE(val) do {		\
+				atomic_inc(&val);	\
+			} while (0)
+#define IPA_STATS_EXCP_CNT(flags, base) do {			\
+			int i;					\
+			for (i = 0; i < MAX_NUM_EXCP; i++)	\
+				if (flags & BIT(i))		\
+					++base[i];		\
+			} while (0)
+#define IPA_STATS_INC_TX_CNT(ep, sw, hw) do {		\
+			if (ep == WLAN_AMPDU_TX_EP)	\
+				++hw;			\
+			else				\
+				++sw;			\
+			} while (0)
+#define IPA_STATS_INC_IC_CNT(num, base, stat_base) do {			\
+			int i;						\
+			for (i = 0; i < num; i++)			\
+				++stat_base[base[i].opcode];		\
+			} while (0)
+#define IPA_STATS_INC_BRIDGE_CNT(type, dir, base) do {		\
+			++base[type][dir];			\
+			} while (0)
+#else
+#define IPA_STATS_INC_CNT(x) do { } while (0)
+#define IPA_STATS_INC_CNT_SAFE(x) do { } while (0)
+#define IPA_STATS_EXCP_CNT(flags, base) do { } while (0)
+#define IPA_STATS_INC_TX_CNT(ep, sw, hw) do { } while (0)
+#define IPA_STATS_INC_IC_CNT(num, base, stat_base) do { } while (0)
+#define IPA_STATS_INC_BRIDGE_CNT(type, dir, base) do { } while (0)
+#endif
+
 #define IPAERR(fmt, args...) \
 	pr_err(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
 
@@ -71,6 +114,8 @@
 #define IPA_RX_SKB_SIZE 2048
 
 #define IPA_DFLT_HDR_NAME "ipa_excp_hdr"
+#define IPA_INVALID_L4_PROTOCOL 0xFF
+
 
 #define IPA_CLIENT_IS_PROD(x) (x >= IPA_CLIENT_PROD && x < IPA_CLIENT_CONS)
 #define IPA_CLIENT_IS_CONS(x) (x >= IPA_CLIENT_CONS && x < IPA_CLIENT_MAX)
@@ -110,17 +155,6 @@
 };
 
 /**
- * enum ipa_bridge_dir - direction of the bridge from air interface perspective
- *
- * IPA bridge direction
- */
-enum ipa_bridge_dir {
-	IPA_DL,
-	IPA_UL,
-	IPA_DIR_MAX
-};
-
-/**
  * struct ipa_mem_buffer - IPA memory buffer
  * @base: base
  * @phys_base: physical base address
@@ -298,13 +332,15 @@
  * @connect: SPS connect
  * @priv: user provided information which will forwarded once the user is
  *        notified for new data avail
- * @client_notify: user provided CB for EP events notification
+ * @client_notify: user provided CB for EP events notification, the event is
+ *                 data revived.
  * @desc_fifo_in_pipe_mem: flag indicating if descriptors FIFO uses pipe memory
  * @data_fifo_in_pipe_mem: flag indicating if data FIFO uses pipe memory
  * @desc_fifo_pipe_mem_ofst: descriptors FIFO pipe memory offset
  * @data_fifo_pipe_mem_ofst: data FIFO pipe memory offset
  * @desc_fifo_client_allocated: if descriptors FIFO was allocated by a client
  * @data_fifo_client_allocated: if data FIFO was allocated by a client
+ * @suspended: valid for B2B pipes, whether IPA EP is suspended
  */
 struct ipa_ep_context {
 	int valid;
@@ -323,6 +359,7 @@
 	u32 data_fifo_pipe_mem_ofst;
 	bool desc_fifo_client_allocated;
 	bool data_fifo_client_allocated;
+	bool suspended;
 };
 
 /**
@@ -358,8 +395,7 @@
 
 /**
  * struct ipa_tx_pkt_wrapper - IPA Tx packet wrapper
- * @type: specify if this packet is a data packet (skb) or
- * an immediate command
+ * @type: specify if this packet is for the skb or immediate command
  * @mem: memory buffer used by this Tx packet
  * @work: work struct for current Tx packet
  * @link: linked to the wrappers on that pipe
@@ -472,6 +508,28 @@
 };
 
 /**
+ * enum ipa_hw_mode - IPA hardware mode
+ * @IPA_HW_Normal: Regular IPA hardware
+ * @IPA_HW_Virtual: IPA hardware supporting virtual memory allocation
+ * @IPA_HW_PCIE: IPA hardware supporting memory allocation over PCIE Bridge
+ */
+enum ipa_hw_mode {
+	IPA_HW_MODE_NORMAL  = 0,
+	IPA_HW_MODE_VIRTUAL = 1,
+	IPA_HW_MODE_PCIE    = 2
+};
+
+
+struct ipa_stats {
+	u32 imm_cmds[MAX_NUM_IMM_CMD];
+	u32 tx_sw_pkts;
+	u32 tx_hw_pkts;
+	u32 rx_pkts;
+	u32 rx_excp_pkts[MAX_NUM_EXCP];
+	u32 bridged_pkts[IPA_BRIDGE_TYPE_MAX][IPA_BRIDGE_DIR_MAX];
+};
+
+/**
  * struct ipa_context - IPA context
  * @class: pointer to the struct class
  * @dev_num: device number
@@ -524,6 +582,8 @@
  * @empty_rt_tbl_mem: empty routing tables memory
  * @pipe_mem_pool: pipe memory pool
  * @one_kb_no_straddle_pool: one kb no straddle pool
+ * @ipa_hw_type: type of IPA HW type (e.g. IPA 1.0, IPA 1.1 etc')
+ * @ipa_hw_mode: mode of IPA HW mode (e.g. Normal, Virtual or over PCIe)
  *
  * IPA context - holds all relevant info about IPA driver and its state
  */
@@ -560,6 +620,7 @@
 	struct rb_root rt_rule_hdl_tree;
 	struct rb_root rt_tbl_hdl_tree;
 	struct rb_root flt_rule_hdl_tree;
+	struct rb_root tag_tree;
 	struct ipa_nat_mem nat_mem;
 	u32 excp_hdr_hdl;
 	u32 dflt_v4_rt_rule_hdl;
@@ -584,7 +645,15 @@
 	u32 clnt_hdl_data_in;
 	u32 clnt_hdl_data_out;
 	u8 a5_pipe_index;
+	struct list_head intf_list;
+	struct list_head msg_list;
+	struct list_head pull_msg_list;
+	struct mutex msg_lock;
+	wait_queue_head_t msg_waitq;
 	enum ipa_hw_type ipa_hw_type;
+	enum ipa_hw_mode ipa_hw_mode;
+	/* featurize if memory footprint becomes a concern */
+	struct ipa_stats stats;
 };
 
 /**
@@ -655,6 +724,7 @@
 	u32 ipa_pipe_mem_start_ofst;
 	u32 ipa_pipe_mem_size;
 	enum ipa_hw_type ipa_hw_type;
+	enum ipa_hw_mode ipa_hw_mode;
 	struct a2_mux_pipe_connection a2_to_ipa_pipe;
 	struct a2_mux_pipe_connection ipa_to_a2_pipe;
 };
@@ -665,10 +735,13 @@
 				struct a2_mux_pipe_connection *pipe_connect);
 void rmnet_bridge_get_client_handles(u32 *producer_handle,
 		u32 *consumer_handle);
-int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc);
-int ipa_send(struct ipa_sys_context *sys, u16 num_desc, struct ipa_desc *desc);
+int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc,
+		bool in_atomic);
+int ipa_send(struct ipa_sys_context *sys, u16 num_desc, struct ipa_desc *desc,
+		bool in_atomic);
 int ipa_get_ep_mapping(enum ipa_operating_mode mode,
 		       enum ipa_client_type client);
+int ipa_get_client_mapping(enum ipa_operating_mode mode, int pipe_idx);
 int ipa_generate_hw_rule(enum ipa_ip_type ip,
 			 const struct ipa_rule_attrib *attrib,
 			 u8 **buf,
@@ -688,30 +761,6 @@
 void ipa_debugfs_init(void);
 void ipa_debugfs_remove(void);
 
-/*
- * below functions read from/write to IPA local memory a.k.a. device memory.
- * the order of the arguments is deliberately different from the ipa_write*
- * functions which operate on system memory
- */
-void ipa_write_dev_8(u8 val, u16 ofst_ipa_sram);
-void ipa_write_dev_16(u16 val, u16 ofst_ipa_sram);
-void ipa_write_dev_32(u32 val, u16 ofst_ipa_sram);
-unsigned int ipa_read_dev_8(u16 ofst_ipa_sram);
-unsigned int ipa_read_dev_16(u16 ofst_ipa_sram);
-unsigned int ipa_read_dev_32(u16 ofst_ipa_sram);
-void ipa_write_dev_8rep(u16 ofst_ipa_sram, const void *buf,
-		unsigned long count);
-void ipa_write_dev_16rep(u16 ofst_ipa_sram, const void *buf,
-		unsigned long count);
-void ipa_write_dev_32rep(u16 ofst_ipa_sram, const void *buf,
-		unsigned long count);
-void ipa_read_dev_8rep(u16 ofst_ipa_sram, void *buf, unsigned long count);
-void ipa_read_dev_16rep(u16 ofst_ipa_sram, void *buf, unsigned long count);
-void ipa_read_dev_32rep(u16 ofst_ipa_sram, void *buf, unsigned long count);
-void ipa_memset_dev(u16 ofst_ipa_sram, u8 value, unsigned int count);
-void ipa_memcpy_from_dev(void *dest, u16 ofst_ipa_sram, unsigned int count);
-void ipa_memcpy_to_dev(u16 ofst_ipa_sram, void *source, unsigned int count);
-
 int ipa_insert(struct rb_root *root, struct ipa_tree_node *data);
 struct ipa_tree_node *ipa_search(struct rb_root *root, u32 hdl);
 void ipa_dump_buff_internal(void *base, dma_addr_t phy_base, u32 size);
@@ -730,7 +779,7 @@
 int ipa_cfg_filter(u32 disable);
 void ipa_wq_write_done(struct work_struct *work);
 void ipa_wq_handle_rx(struct work_struct *work);
-void ipa_handle_rx_core(void);
+int ipa_handle_rx_core(bool process_all);
 int ipa_pipe_mem_init(u32 start_ofst, u32 size);
 int ipa_pipe_mem_alloc(u32 *ofst, u32 size);
 int ipa_pipe_mem_free(u32 ofst, u32 size);
@@ -738,6 +787,8 @@
 struct ipa_context *ipa_get_ctx(void);
 void ipa_enable_clks(void);
 void ipa_disable_clks(void);
+int __ipa_del_rt_rule(u32 rule_hdl);
+int __ipa_del_hdr(u32 hdr_hdl);
 
 static inline u32 ipa_read_reg(void *base, u32 offset)
 {
@@ -756,7 +807,12 @@
 
 int ipa_bridge_init(void);
 void ipa_bridge_cleanup(void);
-int ipa_bridge_setup(enum ipa_bridge_dir dir);
-int ipa_bridge_teardown(enum ipa_bridge_dir dir);
+
+ssize_t ipa_read(struct file *filp, char __user *buf, size_t count,
+		 loff_t *f_pos);
+int ipa_pull_msg(struct ipa_msg_meta *meta, char *buff, size_t count);
+int ipa_query_intf(struct ipa_ioc_query_intf *lookup);
+int ipa_query_intf_tx_props(struct ipa_ioc_query_intf_tx_props *tx);
+int ipa_query_intf_rx_props(struct ipa_ioc_query_intf_rx_props *rx);
 
 #endif /* _IPA_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_intf.c b/drivers/platform/msm/ipa/ipa_intf.c
new file mode 100644
index 0000000..9876650
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_intf.c
@@ -0,0 +1,490 @@
+/* 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/fs.h>
+#include <linux/sched.h>
+#include "ipa_i.h"
+
+struct ipa_intf {
+	char name[IPA_RESOURCE_NAME_MAX];
+	struct list_head link;
+	u32 num_tx_props;
+	u32 num_rx_props;
+	struct ipa_ioc_tx_intf_prop *tx;
+	struct ipa_ioc_rx_intf_prop *rx;
+};
+
+struct ipa_push_msg {
+	struct ipa_msg_meta meta;
+	ipa_msg_free_fn callback;
+	void *buff;
+	struct list_head link;
+};
+
+struct ipa_pull_msg {
+	struct ipa_msg_meta meta;
+	ipa_msg_pull_fn callback;
+	struct list_head link;
+};
+
+/**
+ * ipa_register_intf() - register "logical" interface
+ * @name: [in] interface name
+ * @tx:	[in] TX properties of the interface
+ * @rx:	[in] RX properties of the interface
+ *
+ * Register an interface and its tx and rx properties, this allows
+ * configuration of rules from user-space
+ *
+ * Returns:	0 on success, negative on failure
+ *
+ * Note:	Should not be called from atomic context
+ */
+int ipa_register_intf(const char *name, const struct ipa_tx_intf *tx,
+		       const struct ipa_rx_intf *rx)
+{
+	struct ipa_intf *intf;
+	u32 len;
+
+	if (name == NULL || (tx == NULL && rx == NULL)) {
+		IPAERR("invalid params name=%p tx=%p rx=%p\n", name, tx, rx);
+		return -EINVAL;
+	}
+
+	len = sizeof(struct ipa_intf);
+	intf = kzalloc(len, GFP_KERNEL);
+	if (intf == NULL) {
+		IPAERR("fail to alloc 0x%x bytes\n", len);
+		return -ENOMEM;
+	}
+
+	strlcpy(intf->name, name, IPA_RESOURCE_NAME_MAX);
+
+	if (tx) {
+		intf->num_tx_props = tx->num_props;
+		len = tx->num_props * sizeof(struct ipa_ioc_tx_intf_prop);
+		intf->tx = kzalloc(len, GFP_KERNEL);
+		if (intf->tx == NULL) {
+			IPAERR("fail to alloc 0x%x bytes\n", len);
+			kfree(intf);
+			return -ENOMEM;
+		}
+		memcpy(intf->tx, tx->prop, len);
+	}
+
+	if (rx) {
+		intf->num_rx_props = rx->num_props;
+		len = rx->num_props * sizeof(struct ipa_ioc_rx_intf_prop);
+		intf->rx = kzalloc(len, GFP_KERNEL);
+		if (intf->rx == NULL) {
+			IPAERR("fail to alloc 0x%x bytes\n", len);
+			kfree(intf->tx);
+			kfree(intf);
+			return -ENOMEM;
+		}
+		memcpy(intf->rx, rx->prop, len);
+	}
+
+	mutex_lock(&ipa_ctx->lock);
+	list_add_tail(&intf->link, &ipa_ctx->intf_list);
+	mutex_unlock(&ipa_ctx->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipa_register_intf);
+
+/**
+ * ipa_deregister_intf() - de-register previously registered logical interface
+ * @name: [in] interface name
+ *
+ * De-register a previously registered interface
+ *
+ * Returns:	0 on success, negative on failure
+ *
+ * Note:	Should not be called from atomic context
+ */
+int ipa_deregister_intf(const char *name)
+{
+	struct ipa_intf *entry;
+	struct ipa_intf *next;
+	int result = -EINVAL;
+
+	if (name == NULL) {
+		IPAERR("invalid param name=%p\n", name);
+		return result;
+	}
+
+	mutex_lock(&ipa_ctx->lock);
+	list_for_each_entry_safe(entry, next, &ipa_ctx->intf_list, link) {
+		if (!strncmp(entry->name, name, IPA_RESOURCE_NAME_MAX)) {
+			list_del(&entry->link);
+			kfree(entry->rx);
+			kfree(entry->tx);
+			kfree(entry);
+			result = 0;
+			break;
+		}
+	}
+	mutex_unlock(&ipa_ctx->lock);
+	return result;
+}
+EXPORT_SYMBOL(ipa_deregister_intf);
+
+/**
+ * ipa_query_intf() - query logical interface properties
+ * @lookup:	[inout] interface name and number of properties
+ *
+ * Obtain the handle and number of tx and rx properties for the named
+ * interface, used as part of querying the tx and rx properties for
+ * configuration of various rules from user-space
+ *
+ * Returns:	0 on success, negative on failure
+ *
+ * Note:	Should not be called from atomic context
+ */
+int ipa_query_intf(struct ipa_ioc_query_intf *lookup)
+{
+	struct ipa_intf *entry;
+	int result = -EINVAL;
+
+	if (lookup == NULL) {
+		IPAERR("invalid param lookup=%p\n", lookup);
+		return result;
+	}
+
+	mutex_lock(&ipa_ctx->lock);
+	list_for_each_entry(entry, &ipa_ctx->intf_list, link) {
+		if (!strncmp(entry->name, lookup->name,
+					IPA_RESOURCE_NAME_MAX)) {
+			lookup->num_tx_props = entry->num_tx_props;
+			lookup->num_rx_props = entry->num_rx_props;
+			result = 0;
+			break;
+		}
+	}
+	mutex_unlock(&ipa_ctx->lock);
+	return result;
+}
+
+/**
+ * ipa_query_intf_tx_props() - qeury TX props of an interface
+ * @tx:  [inout] interface tx attributes
+ *
+ * Obtain the tx properties for the specifed interface
+ *
+ * Returns:	0 on success, negative on failure
+ *
+ * Note:	Should not be called from atomic context
+ */
+int ipa_query_intf_tx_props(struct ipa_ioc_query_intf_tx_props *tx)
+{
+	struct ipa_intf *entry;
+	int result = -EINVAL;
+
+	if (tx == NULL) {
+		IPAERR("invalid param tx=%p\n", tx);
+		return result;
+	}
+
+	mutex_lock(&ipa_ctx->lock);
+	list_for_each_entry(entry, &ipa_ctx->intf_list, link) {
+		if (!strncmp(entry->name, tx->name, IPA_RESOURCE_NAME_MAX)) {
+			memcpy(tx->tx, entry->tx, entry->num_tx_props *
+			       sizeof(struct ipa_ioc_tx_intf_prop));
+			result = 0;
+			break;
+		}
+	}
+	mutex_unlock(&ipa_ctx->lock);
+	return result;
+}
+
+/**
+ * ipa_query_intf_rx_props() - qeury RX props of an interface
+ * @rx:  [inout] interface rx attributes
+ *
+ * Obtain the rx properties for the specifed interface
+ *
+ * Returns:	0 on success, negative on failure
+ *
+ * Note:	Should not be called from atomic context
+ */
+int ipa_query_intf_rx_props(struct ipa_ioc_query_intf_rx_props *rx)
+{
+	struct ipa_intf *entry;
+	int result = -EINVAL;
+
+	if (rx == NULL) {
+		IPAERR("invalid param rx=%p\n", rx);
+		return result;
+	}
+
+	mutex_lock(&ipa_ctx->lock);
+	list_for_each_entry(entry, &ipa_ctx->intf_list, link) {
+		if (!strncmp(entry->name, rx->name, IPA_RESOURCE_NAME_MAX)) {
+			memcpy(rx->rx, entry->rx, entry->num_rx_props *
+					sizeof(struct ipa_ioc_rx_intf_prop));
+			result = 0;
+			break;
+		}
+	}
+	mutex_unlock(&ipa_ctx->lock);
+	return result;
+}
+
+/**
+ * ipa_send_msg() - Send "message" from kernel client to IPA driver
+ * @meta: [in] message meta-data
+ * @buff: [in] the payload for message
+ * @callback: [in] free callback
+ *
+ * Client supplies the message meta-data and payload which IPA driver buffers
+ * till read by user-space. After read from user space IPA driver invokes the
+ * callback supplied to free the message payload. Client must not touch/free
+ * the message payload after calling this API.
+ *
+ * Returns:	0 on success, negative on failure
+ *
+ * Note:	Should not be called from atomic context
+ */
+int ipa_send_msg(struct ipa_msg_meta *meta, void *buff,
+		  ipa_msg_free_fn callback)
+{
+	struct ipa_push_msg *msg;
+
+	if (meta == NULL || (buff == NULL && callback != NULL) ||
+	    (buff != NULL && callback == NULL)) {
+		IPAERR("invalid param meta=%p buff=%p, callback=%p\n",
+		       meta, buff, callback);
+		return -EINVAL;
+	}
+
+	msg = kzalloc(sizeof(struct ipa_push_msg), GFP_KERNEL);
+	if (msg == NULL) {
+		IPAERR("fail to alloc ipa_msg container\n");
+		return -ENOMEM;
+	}
+
+	msg->meta = *meta;
+	msg->buff = buff;
+	msg->callback = callback;
+
+	mutex_lock(&ipa_ctx->msg_lock);
+	list_add_tail(&msg->link, &ipa_ctx->msg_list);
+	mutex_unlock(&ipa_ctx->msg_lock);
+
+	wake_up(&ipa_ctx->msg_waitq);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipa_send_msg);
+
+/**
+ * ipa_register_pull_msg() - register pull message type
+ * @meta: [in] message meta-data
+ * @callback: [in] pull callback
+ *
+ * Register message callback by kernel client with IPA driver for IPA driver to
+ * pull message on-demand.
+ *
+ * Returns:	0 on success, negative on failure
+ *
+ * Note:	Should not be called from atomic context
+ */
+int ipa_register_pull_msg(struct ipa_msg_meta *meta, ipa_msg_pull_fn callback)
+{
+	struct ipa_pull_msg *msg;
+
+	if (meta == NULL || callback == NULL) {
+		IPAERR("invalid param meta=%p callback=%p\n", meta, callback);
+		return -EINVAL;
+	}
+
+	msg = kzalloc(sizeof(struct ipa_pull_msg), GFP_KERNEL);
+	if (msg == NULL) {
+		IPAERR("fail to alloc ipa_msg container\n");
+		return -ENOMEM;
+	}
+
+	msg->meta = *meta;
+	msg->callback = callback;
+
+	mutex_lock(&ipa_ctx->msg_lock);
+	list_add_tail(&msg->link, &ipa_ctx->pull_msg_list);
+	mutex_unlock(&ipa_ctx->msg_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipa_register_pull_msg);
+
+/**
+ * ipa_deregister_pull_msg() - De-register pull message type
+ * @meta: [in] message meta-data
+ *
+ * De-register "message" by kernel client from IPA driver
+ *
+ * Returns:	0 on success, negative on failure
+ *
+ * Note:	Should not be called from atomic context
+ */
+int ipa_deregister_pull_msg(struct ipa_msg_meta *meta)
+{
+	struct ipa_pull_msg *entry;
+	struct ipa_pull_msg *next;
+	int result = -EINVAL;
+
+	if (meta == NULL) {
+		IPAERR("invalid param name=%p\n", meta);
+		return result;
+	}
+
+	mutex_lock(&ipa_ctx->msg_lock);
+	list_for_each_entry_safe(entry, next, &ipa_ctx->pull_msg_list, link) {
+		if (entry->meta.msg_len == meta->msg_len &&
+		    entry->meta.msg_type == meta->msg_type) {
+			list_del(&entry->link);
+			kfree(entry);
+			result = 0;
+			break;
+		}
+	}
+	mutex_unlock(&ipa_ctx->msg_lock);
+	return result;
+}
+EXPORT_SYMBOL(ipa_deregister_pull_msg);
+
+/**
+ * ipa_read() - read message from IPA device
+ * @filp:	[in] file pointer
+ * @buf:	[out] buffer to read into
+ * @count:	[in] size of above buffer
+ * @f_pos:	[inout] file position
+ *
+ * Uer-space should continually read from /dev/ipa, read wll block when there
+ * are no messages to read. Upon return, user-space should read the ipa_msg_meta
+ * from the start of the buffer to know what type of message was read and its
+ * length in the remainder of the buffer. Buffer supplied must be big enough to
+ * hold the message meta-data and the largest defined message type
+ *
+ * Returns:	how many bytes copied to buffer
+ *
+ * Note:	Should not be called from atomic context
+ */
+ssize_t ipa_read(struct file *filp, char __user *buf, size_t count,
+		  loff_t *f_pos)
+{
+	char __user *start;
+	struct ipa_push_msg *msg = NULL;
+	int ret;
+	DEFINE_WAIT(wait);
+	int locked;
+
+	start = buf;
+
+	while (1) {
+		prepare_to_wait(&ipa_ctx->msg_waitq, &wait, TASK_INTERRUPTIBLE);
+
+		mutex_lock(&ipa_ctx->msg_lock);
+		locked = 1;
+		if (!list_empty(&ipa_ctx->msg_list)) {
+			msg = list_first_entry(&ipa_ctx->msg_list,
+					struct ipa_push_msg, link);
+			list_del(&msg->link);
+		}
+
+		IPADBG("msg=%p\n", msg);
+
+		if (msg) {
+			locked = 0;
+			mutex_unlock(&ipa_ctx->msg_lock);
+			if (copy_to_user(buf, &msg->meta,
+					  sizeof(struct ipa_msg_meta))) {
+				ret = -EFAULT;
+				break;
+			}
+			buf += sizeof(struct ipa_msg_meta);
+			count -= sizeof(struct ipa_msg_meta);
+			if (msg->buff) {
+				if (copy_to_user(buf, msg->buff,
+						  msg->meta.msg_len)) {
+					ret = -EFAULT;
+					break;
+				}
+				buf += msg->meta.msg_len;
+				count -= msg->meta.msg_len;
+				msg->callback(msg->buff, msg->meta.msg_len,
+					       msg->meta.msg_type);
+			}
+		}
+
+		ret = -EAGAIN;
+		if (filp->f_flags & O_NONBLOCK)
+			break;
+
+		ret = -EINTR;
+		if (signal_pending(current))
+			break;
+
+		if (start != buf)
+			break;
+
+		locked = 0;
+		mutex_unlock(&ipa_ctx->msg_lock);
+		schedule();
+	}
+
+	finish_wait(&ipa_ctx->msg_waitq, &wait);
+	if (start != buf && ret != -EFAULT)
+		ret = buf - start;
+
+	if (locked)
+		mutex_unlock(&ipa_ctx->msg_lock);
+
+	return ret;
+}
+
+/**
+ * ipa_pull_msg() - pull the specified message from client
+ * @meta: [in] message meta-data
+ * @buf:  [out] buffer to read into
+ * @count: [in] size of above buffer
+ *
+ * Populate the supplied buffer with the pull message which is fetched
+ * from client, the message must have previously been registered with
+ * the IPA driver
+ *
+ * Returns:	how many bytes copied to buffer
+ *
+ * Note:	Should not be called from atomic context
+ */
+int ipa_pull_msg(struct ipa_msg_meta *meta, char *buff, size_t count)
+{
+	struct ipa_pull_msg *entry;
+	int result = -EINVAL;
+
+	if (meta == NULL || buff == NULL || !count) {
+		IPAERR("invalid param name=%p buff=%p count=%zu\n",
+				meta, buff, count);
+		return result;
+	}
+
+	mutex_lock(&ipa_ctx->msg_lock);
+	list_for_each_entry(entry, &ipa_ctx->pull_msg_list, link) {
+		if (entry->meta.msg_len == meta->msg_len &&
+		    entry->meta.msg_type == meta->msg_type) {
+			result = entry->callback(buff, count, meta->msg_type);
+			break;
+		}
+	}
+	mutex_unlock(&ipa_ctx->msg_lock);
+	return result;
+}
diff --git a/drivers/platform/msm/ipa/ipa_nat.c b/drivers/platform/msm/ipa/ipa_nat.c
index c13c53a..befa2cf 100644
--- a/drivers/platform/msm/ipa/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_nat.c
@@ -356,11 +356,11 @@
 
 		desc[cnt].len = sizeof(struct ipa_nat_dma);
 		desc[cnt].pyld = (void *)&cmd[cnt];
+
+		ret = ipa_send_cmd(1, &desc[cnt]);
+		if (ret == -EPERM)
+			IPAERR("Fail to send immediate command %d\n", cnt);
 	}
-	IPADBG("posting dma command with entries %d\n", dma->entries);
-	ret = ipa_send_cmd(dma->entries, desc);
-	if (ret == -EPERM)
-		IPAERR("Fail to send immediate command\n");
 
 bail:
 	kfree(cmd);
diff --git a/drivers/platform/msm/ipa/ipa_ram_mmap.h b/drivers/platform/msm/ipa/ipa_ram_mmap.h
index 000718b..7e12b6a 100644
--- a/drivers/platform/msm/ipa/ipa_ram_mmap.h
+++ b/drivers/platform/msm/ipa/ipa_ram_mmap.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
@@ -21,7 +21,7 @@
 #define IPA_RAM_NAT_OFST    0
 #define IPA_RAM_NAT_SIZE    2048
 #define IPA_RAM_HDR_OFST    2048
-#define IPA_RAM_HDR_SIZE    256
+#define IPA_RAM_HDR_SIZE    440
 #define IPA_RAM_V4_FLT_OFST (IPA_RAM_HDR_OFST + IPA_RAM_HDR_SIZE)
 #define IPA_RAM_V4_FLT_SIZE 1024
 #define IPA_RAM_V4_RT_OFST  (IPA_RAM_V4_FLT_OFST + IPA_RAM_V4_FLT_SIZE)
diff --git a/drivers/platform/msm/ipa/ipa_reg.h b/drivers/platform/msm/ipa/ipa_reg.h
index ecc069c..4a2acac 100644
--- a/drivers/platform/msm/ipa/ipa_reg.h
+++ b/drivers/platform/msm/ipa/ipa_reg.h
@@ -162,6 +162,15 @@
 #define IPA_FILTER_FILTER_DIS_SHFT 0x0
 #define IPA_SINGLE_NDP_MODE_OFST 0x00000064
 #define IPA_QCNCM_OFST 0x00000060
+
+#define IPA_SPARE_REG_1_OFST 0x00002090
+
+#define IPA_ENDP_INIT_CTRL_n_OFST(n) (0x00000070 + 0x4 * (n))
+#define IPA_ENDP_INIT_CTRL_n_RMSK 0x1
+#define IPA_ENDP_INIT_CTRL_n_MAXn 19
+#define IPA_ENDP_INIT_CTRL_n_ENDP_SUSPEND_BMSK 0x1
+#define IPA_ENDP_INIT_CTRL_n_ENDP_SUSPEND_SHFT 0x0
+
 #endif
 
 
diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c
index 20f5c24..7d509c6 100644
--- a/drivers/platform/msm/ipa/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_rt.c
@@ -681,19 +681,20 @@
 }
 EXPORT_SYMBOL(ipa_add_rt_rule);
 
-static int __ipa_del_rt_rule(u32 rule_hdl)
+int __ipa_del_rt_rule(u32 rule_hdl)
 {
 	struct ipa_rt_entry *entry = (struct ipa_rt_entry *)rule_hdl;
 	struct ipa_tree_node *node;
 
-	if (entry == NULL || (entry->cookie != IPA_COOKIE)) {
-		IPAERR("bad params\n");
-		return -EINVAL;
-	}
 	node = ipa_search(&ipa_ctx->rt_rule_hdl_tree, rule_hdl);
 	if (node == NULL) {
 		IPAERR("lookup failed\n");
-		return -EPERM;
+		return -EINVAL;
+	}
+
+	if (entry == NULL || (entry->cookie != IPA_COOKIE)) {
+		IPAERR("bad params\n");
+		return -EINVAL;
 	}
 
 	if (entry->hdr)
@@ -770,6 +771,12 @@
 int ipa_commit_rt(enum ipa_ip_type ip)
 {
 	int ret;
+
+	if (ip >= IPA_IP_MAX) {
+		IPAERR("bad parm\n");
+		return -EINVAL;
+	}
+
 	/*
 	 * issue a commit on the filtering module of same IP type since
 	 * filtering rules point to routing tables
@@ -809,6 +816,11 @@
 	struct ipa_tree_node *node;
 	struct ipa_rt_tbl_set *rset;
 
+	if (ip >= IPA_IP_MAX) {
+		IPAERR("bad parm\n");
+		return -EINVAL;
+	}
+
 	/*
 	 * issue a reset on the filtering module of same IP type since
 	 * filtering rules point to routing tables
@@ -930,16 +942,21 @@
 	struct ipa_rt_tbl *entry = (struct ipa_rt_tbl *)rt_tbl_hdl;
 	struct ipa_tree_node *node;
 	enum ipa_ip_type ip = IPA_IP_MAX;
+	int result;
+
+	mutex_lock(&ipa_ctx->lock);
+	node = ipa_search(&ipa_ctx->rt_tbl_hdl_tree, rt_tbl_hdl);
+	if (node == NULL) {
+		IPAERR("lookup failed\n");
+		result = -EINVAL;
+		goto ret;
+	}
 
 	if (entry == NULL || (entry->cookie != IPA_COOKIE) ||
 			entry->ref_cnt == 0) {
 		IPAERR("bad parms\n");
-		return -EINVAL;
-	}
-	node = ipa_search(&ipa_ctx->rt_tbl_hdl_tree, rt_tbl_hdl);
-	if (node == NULL) {
-		IPAERR("lookup failed\n");
-		return -EPERM;
+		result = -EINVAL;
+		goto ret;
 	}
 
 	if (entry->set == &ipa_ctx->rt_tbl_set[IPA_IP_v4])
@@ -949,7 +966,6 @@
 	else
 		WARN_ON(1);
 
-	mutex_lock(&ipa_ctx->lock);
 	entry->ref_cnt--;
 	if (entry->ref_cnt == 0 && entry->rule_cnt == 0) {
 		if (__ipa_del_rt_tbl(entry))
@@ -958,8 +974,12 @@
 		if (__ipa_commit_rt(ip))
 			IPAERR("fail to commit RT tbl\n");
 	}
+
+	result = 0;
+
+ret:
 	mutex_unlock(&ipa_ctx->lock);
 
-	return 0;
+	return result;
 }
 EXPORT_SYMBOL(ipa_put_rt_tbl);
diff --git a/drivers/platform/msm/ipa/ipa_utils.c b/drivers/platform/msm/ipa/ipa_utils.c
index a81aece..264de0d 100644
--- a/drivers/platform/msm/ipa/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_utils.c
@@ -14,7 +14,6 @@
 #include <linux/genalloc.h>	/* gen_pool_alloc() */
 #include <linux/io.h>
 #include "ipa_i.h"
-
 static const int ipa_ofst_meq32[] = { IPA_OFFSET_MEQ32_0,
 					IPA_OFFSET_MEQ32_1, -1 };
 static const int ipa_ofst_meq128[] = { IPA_OFFSET_MEQ128_0,
@@ -123,6 +122,23 @@
 }
 
 /**
+ * ipa_get_client_mapping() - provide client mapping
+ * @mode: IPA operating mode
+ * @pipe_idx: IPA end-point number
+ *
+ * Return value: client mapping
+ */
+int ipa_get_client_mapping(enum ipa_operating_mode mode, int pipe_idx)
+{
+	int i;
+
+	for (i = 0; i < IPA_CLIENT_MAX; i++)
+		if (ep_mapping[mode][i] == pipe_idx)
+			break;
+	return i;
+}
+
+/**
  * ipa_write_32() - convert 32 bit value to byte array
  * @w: 32 bit integer
  * @dest: byte array
@@ -751,6 +767,7 @@
 int ipa_cfg_ep_mode(u32 clnt_hdl, const struct ipa_ep_cfg_mode *ipa_ep_cfg)
 {
 	u32 val;
+	int ep;
 
 	if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0 ||
 			ipa_ep_cfg == NULL) {
@@ -763,10 +780,16 @@
 		return -EINVAL;
 	}
 
+	ep = ipa_get_ep_mapping(ipa_ctx->mode, ipa_ep_cfg->dst);
+	if (ep == -1 && ipa_ep_cfg->mode == IPA_DMA) {
+		IPAERR("dst %d does not exist in mode %d\n", ipa_ep_cfg->dst,
+		       ipa_ctx->mode);
+		return -EINVAL;
+	}
+
 	/* copy over EP cfg */
 	ipa_ctx->ep[clnt_hdl].cfg.mode = *ipa_ep_cfg;
-	ipa_ctx->ep[clnt_hdl].dst_pipe_index = ipa_get_ep_mapping(ipa_ctx->mode,
-			ipa_ep_cfg->dst);
+	ipa_ctx->ep[clnt_hdl].dst_pipe_index = ep;
 
 	val = IPA_SETFIELD(ipa_ctx->ep[clnt_hdl].cfg.mode.mode,
 			   IPA_ENDP_INIT_MODE_n_MODE_SHFT,
@@ -944,206 +967,6 @@
 	mutex_unlock(&ipa_ctx->lock);
 }
 
-/*
- * TODO: add swap if needed, for now assume LE is ok for device memory
- * even though IPA registers are assumed to be BE
- */
-/**
- * ipa_write_dev_8() - writes 8 bit value
- * @val: value
- * @ofst_ipa_sram: address to write to
- */
-void ipa_write_dev_8(u8 val, u16 ofst_ipa_sram)
-{
-	iowrite8(val, (u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram);
-}
-
-/**
- * ipa_write_dev_16() - writes 16 bit value
- * @val: value
- * @ofst_ipa_sram: address to write to
- *
- */
-void ipa_write_dev_16(u16 val, u16 ofst_ipa_sram)
-{
-	iowrite16(val, (u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram);
-}
-
-/**
- * ipa_write_dev_32() - writes 32 bit value
- * @val: value
- * @ofst_ipa_sram: address to write to
- */
-void ipa_write_dev_32(u32 val, u16 ofst_ipa_sram)
-{
-	iowrite32(val, (u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram);
-}
-
-/**
- * ipa_read_dev_8() - reads 8 bit value
- * @ofst_ipa_sram: address to read from
- *
- * Return value: value read
- */
-unsigned int ipa_read_dev_8(u16 ofst_ipa_sram)
-{
-	return ioread8((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram);
-}
-
-/**
- * ipa_read_dev_16() - reads 16 bit value
- * @ofst_ipa_sram: address to read from
- *
- * Return value: value read
- */
-unsigned int ipa_read_dev_16(u16 ofst_ipa_sram)
-{
-	return ioread16((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram);
-}
-
-/**
- * ipa_read_dev_32() - reads 32 bit value
- * @ofst_ipa_sram: address to read from
- *
- * Return value: value read
- */
-unsigned int ipa_read_dev_32(u16 ofst_ipa_sram)
-{
-	return ioread32((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram);
-}
-
-/**
- * ipa_write_dev_8rep() - writes 8 bit value
- * @val: value
- * @ofst_ipa_sram: address to write to
- * @count: num of bytes to write
- */
-void ipa_write_dev_8rep(u16 ofst_ipa_sram, const void *buf, unsigned long count)
-{
-	iowrite8_rep((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram), buf,
-			count);
-}
-
-/**
- * ipa_write_dev_16rep() - writes 16 bit value
- * @val: value
- * @ofst_ipa_sram: address to write to
- * @count: num of bytes to write
- */
-void ipa_write_dev_16rep(u16 ofst_ipa_sram, const void *buf,
-		unsigned long count)
-{
-	iowrite16_rep((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram),
-			buf, count);
-}
-
-/**
- * ipa_write_dev_32rep() - writes 32 bit value
- * @val: value
- * @ofst_ipa_sram: address to write to
- * @count: num of bytes to write
- */
-void ipa_write_dev_32rep(u16 ofst_ipa_sram, const void *buf,
-		unsigned long count)
-{
-	iowrite32_rep((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram),
-			buf, count);
-}
-
-/**
- * ipa_read_dev_8rep() - reads 8 bit value
- * @ofst_ipa_sram: address to read from
- * @buf: buffer to read to
- * @count: number of bytes to read
- */
-void ipa_read_dev_8rep(u16 ofst_ipa_sram, void *buf, unsigned long count)
-{
-	ioread8_rep((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram), buf,
-			count);
-}
-
-/**
- * ipa_read_dev_16rep() - reads 16 bit value
- * @ofst_ipa_sram: address to read from
- * @buf: buffer to read to
- * @count: number of bytes to read
- */
-void ipa_read_dev_16rep(u16 ofst_ipa_sram, void *buf, unsigned long count)
-{
-	ioread16_rep((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram), buf,
-			count);
-}
-
-/**
- * ipa_read_dev_32rep() - reads 32 bit value
- * @ofst_ipa_sram: address to read from
- * @buf: buffer to read to
- * @count: number of bytes to read
- */
-void ipa_read_dev_32rep(u16 ofst_ipa_sram, void *buf, unsigned long count)
-{
-	ioread32_rep((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram), buf,
-			count);
-}
-
-/**
- * ipa_memset_dev() - memset IO
- * @ofst_ipa_sram: address to set
- * @value: value
- * @count: number of bytes to set
- */
-void ipa_memset_dev(u16 ofst_ipa_sram, u8 value, unsigned int count)
-{
-	memset_io((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram), value,
-			count);
-}
-
-/**
- * ipa_memcpy_from_dev() - copy memory from device
- * @dest: buffer to copy to
- * @ofst_ipa_sram: address
- * @count: number of bytes to copy
- */
-void ipa_memcpy_from_dev(void *dest, u16 ofst_ipa_sram, unsigned int count)
-{
-	memcpy_fromio(dest, (void *)((u32)ipa_ctx->mmio + 0x4000 +
-				ofst_ipa_sram), count);
-}
-
-/**
- * ipa_memcpy_to_dev() - copy memory to device
- * @ofst_ipa_sram: address
- * @source: buffer to copy from
- * @count: number of bytes to copy
- */
-void ipa_memcpy_to_dev(u16 ofst_ipa_sram, void *source, unsigned int count)
-{
-	memcpy_toio((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram),
-			source, count);
-}
-
-/**
- * ipa_defrag() - handle de-frag for bridging type of cases
- * @skb: skb
- *
- * Return value:
- * 0: success
- */
-int ipa_defrag(struct sk_buff *skb)
-{
-	/*
-	 * Reassemble IP fragments. TODO: need to setup network_header to
-	 * point to start of IP header
-	 */
-	if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
-		if (ip_defrag(skb, IP_DEFRAG_CONNTRACK_IN))
-			return -EINPROGRESS;
-	}
-
-	/* skb is not fully assembled, send it back out */
-	return 0;
-}
-
 /**
  * ipa_search() - search for handle in RB tree
  * @root: tree root
diff --git a/drivers/platform/msm/ipa/rmnet_bridge.c b/drivers/platform/msm/ipa/rmnet_bridge.c
index 3c7f5ca..e5c7ec2 100644
--- a/drivers/platform/msm/ipa/rmnet_bridge.c
+++ b/drivers/platform/msm/ipa/rmnet_bridge.c
@@ -17,11 +17,12 @@
 #include <mach/ipa.h>
 #include <mach/sps.h>
 #include "a2_service.h"
-#include "ipa_i.h"
 
 static struct rmnet_bridge_cb_type {
 	u32 producer_handle;
 	u32 consumer_handle;
+	u32 ipa_producer_handle;
+	u32 ipa_consumer_handle;
 	bool is_connected;
 } rmnet_bridge_cb;
 
@@ -57,8 +58,10 @@
 
 	rmnet_bridge_cb.is_connected = false;
 
-	ret = ipa_bridge_teardown(IPA_DL);
-	ret = ipa_bridge_teardown(IPA_UL);
+	ret = ipa_bridge_teardown(IPA_BRIDGE_DIR_DL, IPA_BRIDGE_TYPE_TETHERED,
+				  rmnet_bridge_cb.ipa_consumer_handle);
+	ret = ipa_bridge_teardown(IPA_BRIDGE_DIR_UL, IPA_BRIDGE_TYPE_TETHERED,
+				  rmnet_bridge_cb.ipa_producer_handle);
 bail:
 	return ret;
 }
@@ -78,6 +81,7 @@
 			 u32 consumer_hdl,
 			 int wwan_logical_channel_id)
 {
+	struct ipa_sys_connect_params props;
 	int ret = 0;
 
 	if (true == rmnet_bridge_cb.is_connected) {
@@ -91,19 +95,35 @@
 	rmnet_bridge_cb.producer_handle = producer_hdl;
 	rmnet_bridge_cb.is_connected = true;
 
-	ret = ipa_bridge_setup(IPA_DL);
+	memset(&props, 0, sizeof(props));
+	props.ipa_ep_cfg.mode.mode = IPA_DMA;
+	props.ipa_ep_cfg.mode.dst = IPA_CLIENT_USB_CONS;
+	props.client = IPA_CLIENT_A2_TETHERED_PROD;
+	props.desc_fifo_sz = 0x800;
+	/* setup notification callback if needed */
+
+	ret = ipa_bridge_setup(IPA_BRIDGE_DIR_DL, IPA_BRIDGE_TYPE_TETHERED,
+			&props, &rmnet_bridge_cb.ipa_consumer_handle);
 	if (ret) {
 		pr_err("%s: IPA DL bridge setup failure\n", __func__);
 		goto bail_dl;
 	}
-	ret = ipa_bridge_setup(IPA_UL);
+
+	memset(&props, 0, sizeof(props));
+	props.client = IPA_CLIENT_A2_TETHERED_CONS;
+	props.desc_fifo_sz = 0x800;
+	/* setup notification callback if needed */
+
+	ret = ipa_bridge_setup(IPA_BRIDGE_DIR_UL, IPA_BRIDGE_TYPE_TETHERED,
+			&props, &rmnet_bridge_cb.ipa_producer_handle);
 	if (ret) {
 		pr_err("%s: IPA UL bridge setup failure\n", __func__);
 		goto bail_ul;
 	}
 	return 0;
 bail_ul:
-	ipa_bridge_teardown(IPA_DL);
+	ipa_bridge_teardown(IPA_BRIDGE_DIR_DL, IPA_BRIDGE_TYPE_TETHERED,
+			    rmnet_bridge_cb.ipa_consumer_handle);
 bail_dl:
 	rmnet_bridge_cb.is_connected = false;
 bail:
diff --git a/drivers/power/battery_current_limit.c b/drivers/power/battery_current_limit.c
index d1750ec..ecda153 100644
--- a/drivers/power/battery_current_limit.c
+++ b/drivers/power/battery_current_limit.c
@@ -507,12 +507,18 @@
 	return 0;
 }
 
+static struct of_device_id bcl_match_table[] = {
+	{.compatible = "qcom,bcl"},
+	{},
+};
+
 static struct platform_driver bcl_driver = {
 	.probe	= bcl_probe,
 	.remove	= __devexit_p(bcl_remove),
 	.driver	= {
 		.name	= BCL_DEV_NAME,
 		.owner	= THIS_MODULE,
+		.of_match_table = bcl_match_table,
 	},
 };
 
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/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 7478ab9..f87a443 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -294,6 +294,8 @@
 	int				btc_delay_ms;
 	bool				btc_panic_if_cant_stop_chg;
 	int				stop_chg_upon_expiry;
+	bool				disable_aicl;
+	int				usb_type;
 };
 
 /* user space parameter to limit usb current */
@@ -339,38 +341,65 @@
 {
 	int rc;
 	unsigned long flags = 0;
+	u8 temp;
 
 	/* Disable LPM */
 	if (chip->lockup_lpm_wrkarnd) {
 		spin_lock_irqsave(&lpm_lock, flags);
 
 		/*
-		 * This write could have initiated right after a previous write.
-		 * Allow time to settle to go in to lpm from the previous write
+		 * This delay is to prevent exit out of 32khz mode within
+		 * 200uS. It could be that chg was removed just few uS before
+		 * this gets called.
 		 */
 		udelay(200);
-		rc = pm8921_chg_set_lpm(chip, 0);
-		if (rc)
-			goto lpm_err;
+		/* no clks */
+		temp = 0xD1;
+		rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+		if (rc) {
+			pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
+			goto release_lpm_lock;
+		}
 
-		/* Wait to come out of LPM */
+		/* force 19.2Mhz before reading */
+		temp = 0xD3;
+		rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+		if (rc) {
+			pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
+			goto release_lpm_lock;
+		}
+
+		rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
+		if (rc) {
+			pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
+			goto release_lpm_lock;
+		}
+
+		/* no clks */
+		temp = 0xD1;
+		rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+		if (rc) {
+			pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
+			goto release_lpm_lock;
+		}
+
+		/* switch to hw clk selection */
+		temp = 0xD0;
+		rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+		if (rc) {
+			pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
+			goto release_lpm_lock;
+		}
+
 		udelay(200);
-	}
 
-	rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
-	if (rc) {
-		pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
-		goto lpm_err;
-	}
-
-	/* Enable LPM */
-	if (chip->lockup_lpm_wrkarnd)
-		rc = pm8921_chg_set_lpm(chip, 1);
-
-lpm_err:
-	if (chip->lockup_lpm_wrkarnd)
+release_lpm_lock:
 		spin_unlock_irqrestore(&lpm_lock, flags);
-
+	} else {
+		rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
+		if (rc)
+			pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
+	}
 	return rc;
 }
 
@@ -440,68 +469,175 @@
 static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
 {
 	u8 temp;
-	int err, ret = 0;
+	unsigned long flags = 0;
+	int err = 0, ret = 0;
+
+	if (chip->lockup_lpm_wrkarnd) {
+		spin_lock_irqsave(&lpm_lock, flags);
+
+		/*
+		 * This delay is to prevent exit out of 32khz mode within
+		 * 200uS. It could be that chg was removed just few uS before
+		 * this gets called.
+		 */
+		udelay(200);
+		/* no clks */
+		temp = 0xD1;
+		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+		if (err) {
+			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
+			goto err_out;
+		}
+
+		/* force 19.2Mhz before reading */
+		temp = 0xD3;
+		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+		if (err) {
+			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
+			goto err_out;
+		}
+	}
 
 	temp = CAPTURE_FSM_STATE_CMD;
-	err = pm_chg_write(chip, CHG_TEST, temp);
+	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
-		return err;
+		goto err_out;
 	}
 
 	temp = READ_BANK_7;
-	err = pm_chg_write(chip, CHG_TEST, temp);
+	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
-		return err;
+		goto err_out;
 	}
 
 	err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
 	if (err) {
 		pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
-		return err;
+		goto err_out;
 	}
 	/* get the lower 4 bits */
 	ret = temp & 0xF;
 
 	temp = READ_BANK_4;
-	err = pm_chg_write(chip, CHG_TEST, temp);
+	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
-		return err;
+		goto err_out;
 	}
 
 	err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
 	if (err) {
 		pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
-		return err;
+		goto err_out;
 	}
 	/* get the upper 1 bit */
 	ret |= (temp & 0x1) << 4;
+
+	if (chip->lockup_lpm_wrkarnd) {
+		/* no clks */
+		temp = 0xD1;
+		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+		if (err) {
+			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
+			goto err_out;
+		}
+
+		/* switch to hw clk selection */
+		temp = 0xD0;
+		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+		if (err) {
+			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
+			goto err_out;
+		}
+
+		udelay(200);
+	}
+
+err_out:
+	if (chip->lockup_lpm_wrkarnd)
+		spin_unlock_irqrestore(&lpm_lock, flags);
+	if (err)
+		return err;
+
 	return  ret;
 }
 
 #define READ_BANK_6		0x60
 static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
 {
-	u8 temp;
-	int err;
+	u8 temp, data;
+	unsigned long flags = 0;
+	int err = 0;
+
+	if (chip->lockup_lpm_wrkarnd) {
+		spin_lock_irqsave(&lpm_lock, flags);
+
+		/*
+		 * This delay is to prevent exit out of 32khz mode within
+		 * 200uS. It could be that chg was removed just few uS before
+		 * this gets called.
+		 */
+		udelay(200);
+		/* no clks */
+		temp = 0xD1;
+		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+		if (err) {
+			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
+			goto err_out;
+		}
+
+		/* force 19.2Mhz before reading */
+		temp = 0xD3;
+		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+		if (err) {
+			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
+			goto err_out;
+		}
+	}
 
 	temp = READ_BANK_6;
-	err = pm_chg_write(chip, CHG_TEST, temp);
+	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
-		return err;
+		goto err_out;
 	}
 
-	err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
+	err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &data);
 	if (err) {
 		pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
-		return err;
+		goto err_out;
 	}
 
+	if (chip->lockup_lpm_wrkarnd) {
+		/* no clks */
+		temp = 0xD1;
+		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+		if (err) {
+			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
+			goto err_out;
+		}
+
+		/* switch to hw clk selection */
+		temp = 0xD0;
+		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+		if (err) {
+			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
+			goto err_out;
+		}
+
+		udelay(200);
+	}
+
+err_out:
+	if (chip->lockup_lpm_wrkarnd)
+		spin_unlock_irqrestore(&lpm_lock, flags);
+	if (err)
+		return err;
+
 	/* return the lower 4 bits */
-	return temp & CHG_ALL_LOOPS;
+	return data & CHG_ALL_LOOPS;
 }
 
 #define CHG_USB_SUSPEND_BIT  BIT(2)
@@ -1388,6 +1524,7 @@
 	POWER_SUPPLY_PROP_ONLINE,
 	POWER_SUPPLY_PROP_CURRENT_MAX,
 	POWER_SUPPLY_PROP_SCOPE,
+	POWER_SUPPLY_PROP_HEALTH,
 };
 
 static enum power_supply_property pm_power_props_mains[] = {
@@ -1425,7 +1562,7 @@
 			return 0;
 		}
 
-		type = the_chip->usb_psy.type;
+		type = the_chip->usb_type;
 		if (type == POWER_SUPPLY_TYPE_USB_DCP ||
 			type == POWER_SUPPLY_TYPE_USB_ACA ||
 			type == POWER_SUPPLY_TYPE_USB_CDP)
@@ -1438,6 +1575,24 @@
 	return 0;
 }
 
+static int disable_aicl(int disable)
+{
+	if (disable != POWER_SUPPLY_HEALTH_UNKNOWN
+		&& disable != POWER_SUPPLY_HEALTH_GOOD) {
+		pr_err("called with invalid param :%d\n", disable);
+		return -EINVAL;
+	}
+
+	if (!the_chip) {
+		pr_err("%s called before init\n", __func__);
+		return -EINVAL;
+	}
+
+	pr_debug("Disable AICL = %d\n", disable);
+	the_chip->disable_aicl = disable;
+	return 0;
+}
+
 static int switch_usb_to_charge_mode(struct pm8921_chg_chip *chip)
 {
 	int rc;
@@ -1495,12 +1650,28 @@
 		break;
 	case POWER_SUPPLY_PROP_TYPE:
 		return pm8921_set_usb_power_supply_type(val->intval);
+	case POWER_SUPPLY_PROP_HEALTH:
+		/* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
+		return disable_aicl(val->intval);
 	default:
 		return -EINVAL;
 	}
 	return 0;
 }
 
+static int usb_property_is_writeable(struct power_supply *psy,
+						enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_HEALTH:
+		return 1;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 static int pm_power_get_property_usb(struct power_supply *psy,
 				  enum power_supply_property psp,
 				  union power_supply_propval *val)
@@ -1524,7 +1695,7 @@
 	case POWER_SUPPLY_PROP_ONLINE:
 		val->intval = 0;
 
-		if (the_chip->usb_psy.type == POWER_SUPPLY_TYPE_USB)
+		if (the_chip->usb_type == POWER_SUPPLY_TYPE_USB)
 			val->intval = is_usb_chg_plugged_in(the_chip);
 
 		break;
@@ -1535,6 +1706,10 @@
 		else
 			val->intval = POWER_SUPPLY_SCOPE_DEVICE;
 		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		/* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
+		val->intval = the_chip->disable_aicl;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -1830,7 +2005,6 @@
 
 static void (*notify_vbus_state_func_ptr)(int);
 static int usb_chg_current;
-static DEFINE_SPINLOCK(vbus_lock);
 
 int pm8921_charger_register_vbus_sn(void (*callback)(int))
 {
@@ -1859,7 +2033,6 @@
 	}
 }
 
-/* assumes vbus_lock is held */
 static void __pm8921_charger_vbus_draw(unsigned int mA)
 {
 	int i, rc;
@@ -1913,15 +2086,10 @@
 /* USB calls these to tell us how much max usb current the system can draw */
 void pm8921_charger_vbus_draw(unsigned int mA)
 {
-	unsigned long flags;
+	int set_usb_now_ma;
 
 	pr_debug("Enter charge=%d\n", mA);
 
-	if (!the_chip) {
-		pr_err("chip not yet initalized\n");
-		return;
-	}
-
 	/*
 	 * Reject VBUS requests if USB connection is the only available
 	 * power source. This makes sure that if booting without
@@ -1931,7 +2099,7 @@
 	 * This would also apply when the battery has been
 	 * removed from the running system.
 	 */
-	if (!get_prop_batt_present(the_chip)
+	if (the_chip && !get_prop_batt_present(the_chip)
 		&& !is_dc_chg_plugged_in(the_chip)) {
 		if (!the_chip->has_dc_supply) {
 			pr_err("rejected: no other power source connected\n");
@@ -1950,23 +2118,23 @@
 	if (usb_target_ma)
 		usb_target_ma = mA;
 
-	spin_lock_irqsave(&vbus_lock, flags);
-	if (the_chip) {
-		if (mA > USB_WALL_THRESHOLD_MA)
-			__pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
-		else
-			__pm8921_charger_vbus_draw(mA);
-	} else {
+
+	if (mA > USB_WALL_THRESHOLD_MA)
+		set_usb_now_ma = USB_WALL_THRESHOLD_MA;
+	else
+		set_usb_now_ma = mA;
+
+	if (the_chip && the_chip->disable_aicl)
+		set_usb_now_ma = mA;
+
+	if (the_chip)
+		__pm8921_charger_vbus_draw(set_usb_now_ma);
+	else
 		/*
 		 * called before pmic initialized,
 		 * save this value and use it at probe
 		 */
-		if (mA > USB_WALL_THRESHOLD_MA)
-			usb_chg_current = USB_WALL_THRESHOLD_MA;
-		else
-			usb_chg_current = mA;
-	}
-	spin_unlock_irqrestore(&vbus_lock, flags);
+		usb_chg_current = set_usb_now_ma;
 }
 EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
 
@@ -2193,7 +2361,7 @@
 	if (type < POWER_SUPPLY_TYPE_USB && type > POWER_SUPPLY_TYPE_BATTERY)
 		return -EINVAL;
 
-	the_chip->usb_psy.type = type;
+	the_chip->usb_type = type;
 	power_supply_changed(&the_chip->usb_psy);
 	power_supply_changed(&the_chip->dc_psy);
 	return 0;
@@ -2605,7 +2773,8 @@
 	 * The AICL algorithm will step up the current from 500mA to target
 	 */
 	if (is_usb_chg_plugged_in(chip)
-		&& usb_target_ma > USB_WALL_THRESHOLD_MA) {
+		&& usb_target_ma > USB_WALL_THRESHOLD_MA
+		&& !chip->disable_aicl) {
 		/* decrease usb_target_ma */
 		decrease_usb_ma_value(&usb_target_ma);
 		/* reset here, increase in unplug_check_worker */
@@ -2868,7 +3037,8 @@
 	chip->final_kickstart = true;
 
 	/* AICL only for usb wall charger */
-	if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0) {
+	if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0 &&
+		!chip->disable_aicl) {
 		reg_loop = pm_chg_get_regulation_loop(chip);
 		pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
 		if ((reg_loop & VIN_ACTIVE_BIT) &&
@@ -2916,7 +3086,8 @@
 	/* AICL only for usb wall charger */
 	if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)
 		&& usb_target_ma > 0
-		&& !charging_disabled) {
+		&& !charging_disabled
+		&& !chip->disable_aicl) {
 		/* only increase iusb_max if vin loop not active */
 		if (usb_ma < usb_target_ma) {
 			increase_usb_ma_value(&usb_ma);
@@ -3836,7 +4007,6 @@
 /* determines the initial present states */
 static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
 {
-	unsigned long flags;
 	int fsm_state;
 	int is_fast_chg;
 
@@ -3861,12 +4031,16 @@
 	pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
 	pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
 
-	spin_lock_irqsave(&vbus_lock, flags);
-	if (usb_chg_current) {
-		/* reissue a vbus draw call */
-		__pm8921_charger_vbus_draw(usb_chg_current);
-	}
-	spin_unlock_irqrestore(&vbus_lock, flags);
+	if (get_prop_batt_present(the_chip) || is_dc_chg_plugged_in(the_chip))
+		if (usb_chg_current)
+			/*
+			 * Reissue a vbus draw call only if a battery
+			 * or DC is present. We don't want to brown out the
+			 * device if usb is its only source
+			 */
+			__pm8921_charger_vbus_draw(usb_chg_current);
+	usb_chg_current = 0;
+
 	/*
 	 * The bootloader could have started charging, a fastchg interrupt
 	 * might not happen. Check the real time status and if it is fast
@@ -4729,30 +4903,32 @@
 		pm8921_chg_btc_override_init(chip);
 
 	chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
+	chip->usb_type = POWER_SUPPLY_TYPE_UNKNOWN;
 
-	chip->usb_psy.name = "usb",
-	chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
-	chip->usb_psy.supplied_to = pm_power_supplied_to,
-	chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
-	chip->usb_psy.properties = pm_power_props_usb,
-	chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
-	chip->usb_psy.get_property = pm_power_get_property_usb,
-	chip->usb_psy.set_property = pm_power_set_property_usb,
+	chip->usb_psy.name = "usb";
+	chip->usb_psy.type = POWER_SUPPLY_TYPE_USB;
+	chip->usb_psy.supplied_to = pm_power_supplied_to;
+	chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
+	chip->usb_psy.properties = pm_power_props_usb;
+	chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb);
+	chip->usb_psy.get_property = pm_power_get_property_usb;
+	chip->usb_psy.set_property = pm_power_set_property_usb;
+	chip->usb_psy.property_is_writeable = usb_property_is_writeable;
 
-	chip->dc_psy.name = "pm8921-dc",
-	chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
-	chip->dc_psy.supplied_to = pm_power_supplied_to,
-	chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
-	chip->dc_psy.properties = pm_power_props_mains,
-	chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
-	chip->dc_psy.get_property = pm_power_get_property_mains,
+	chip->dc_psy.name = "pm8921-dc";
+	chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
+	chip->dc_psy.supplied_to = pm_power_supplied_to;
+	chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
+	chip->dc_psy.properties = pm_power_props_mains;
+	chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
+	chip->dc_psy.get_property = pm_power_get_property_mains;
 
-	chip->batt_psy.name = "battery",
-	chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
-	chip->batt_psy.properties = msm_batt_power_props,
-	chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
-	chip->batt_psy.get_property = pm_batt_power_get_property,
-	chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
+	chip->batt_psy.name = "battery";
+	chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
+	chip->batt_psy.properties = msm_batt_power_props;
+	chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
+	chip->batt_psy.get_property = pm_batt_power_get_property;
+	chip->batt_psy.external_power_changed = pm_batt_external_power_changed;
 	rc = power_supply_register(chip->dev, &chip->usb_psy);
 	if (rc < 0) {
 		pr_err("power_supply_register usb failed rc = %d\n", rc);
@@ -4774,9 +4950,6 @@
 	platform_set_drvdata(pdev, chip);
 	the_chip = chip;
 
-	/* set initial state of the USB charger type to UNKNOWN */
-	power_supply_set_supply_type(&chip->usb_psy, POWER_SUPPLY_TYPE_UNKNOWN);
-
 	wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
 	INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
 	INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 8d07e55..e2ba042 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -70,7 +70,7 @@
 #define CHGR_CHG_WDOG_PET			0x64
 #define CHGR_CHG_WDOG_EN			0x65
 #define CHGR_IR_DROP_COMPEN			0x67
-#define CHGR_USB_IUSB_MAX			0x44
+#define CHGR_I_MAX_REG			0x44
 #define CHGR_USB_USB_SUSP			0x47
 #define CHGR_USB_USB_OTG_CTL			0x48
 #define CHGR_USB_ENUM_T_STOP			0x4E
@@ -172,6 +172,8 @@
  * @resume_voltage_mv:		voltage at which the battery resumes charging
  * @term_current:		the charging based term current
  * @safe_current:		battery safety current setting
+ * @maxinput_usb_ma:		Maximum Input current USB
+ * @maxinput_dc_ma:		Maximum Input current DC
  * @revision:			PMIC revision
  * @thermal_levels		amount of thermal mitigation levels
  * @thermal_mitigation		thermal mitigation level values
@@ -210,6 +212,8 @@
 	unsigned int			min_voltage_mv;
 	unsigned int			resume_voltage_mv;
 	unsigned int			term_current;
+	unsigned int			maxinput_usb_ma;
+	unsigned int			maxinput_dc_ma;
 	unsigned int			safe_current;
 	unsigned int			revision;
 	unsigned int			thermal_levels;
@@ -348,36 +352,73 @@
 	return (dcin_valid_rt_sts & DCIN_VALID_IRQ) ? 1 : 0;
 }
 
-#define QPNP_CHG_IUSB_MAX_MIN_100		100
-#define QPNP_CHG_IUSB_MAX_MIN_150		150
-#define QPNP_CHG_IUSB_MAX_MIN_MA		200
-#define QPNP_CHG_IUSB_MAX_MAX_MA		2500
-#define QPNP_CHG_IUSB_MAX_STEP_MA		100
+#define QPNP_CHG_I_MAX_MIN_100		100
+#define QPNP_CHG_I_MAX_MIN_150		150
+#define QPNP_CHG_I_MAX_MIN_MA		200
+#define QPNP_CHG_I_MAX_MAX_MA		2500
+#define QPNP_CHG_I_MAXSTEP_MA		100
+static int
+qpnp_chg_idcmax_set(struct qpnp_chg_chip *chip, int mA)
+{
+	int rc = 0;
+	u8 dc = 0;
+
+	if (mA < QPNP_CHG_I_MAX_MIN_100
+			|| mA > QPNP_CHG_I_MAX_MAX_MA) {
+		pr_err("bad mA=%d asked to set\n", mA);
+		return -EINVAL;
+	}
+
+	if (mA == QPNP_CHG_I_MAX_MIN_100) {
+		dc = 0x00;
+		pr_debug("current=%d setting %02x\n", mA, dc);
+		return qpnp_chg_write(chip, &dc,
+			chip->dc_chgpth_base + CHGR_I_MAX_REG, 1);
+	} else if (mA == QPNP_CHG_I_MAX_MIN_150) {
+		dc = 0x01;
+		pr_debug("current=%d setting %02x\n", mA, dc);
+		return qpnp_chg_write(chip, &dc,
+			chip->dc_chgpth_base + CHGR_I_MAX_REG, 1);
+	}
+
+	dc = mA / QPNP_CHG_I_MAXSTEP_MA;
+
+	pr_debug("current=%d setting 0x%x\n", mA, dc);
+	rc = qpnp_chg_write(chip, &dc,
+		chip->dc_chgpth_base + CHGR_I_MAX_REG, 1);
+
+	return rc;
+}
+
 static int
 qpnp_chg_iusbmax_set(struct qpnp_chg_chip *chip, int mA)
 {
 	int rc = 0;
 	u8 usb_reg = 0, temp = 8;
 
-	if (mA == QPNP_CHG_IUSB_MAX_MIN_100) {
-		usb_reg = 0x00;
-		pr_debug("current=%d setting %02x\n", mA, usb_reg);
-		return qpnp_chg_write(chip, &usb_reg,
-		chip->usb_chgpth_base + CHGR_USB_IUSB_MAX, 1);
-	} else if (mA == QPNP_CHG_IUSB_MAX_MIN_150) {
-		usb_reg = 0x01;
-		pr_debug("current=%d setting %02x\n", mA, usb_reg);
-		return qpnp_chg_write(chip, &usb_reg,
-		chip->usb_chgpth_base + CHGR_USB_IUSB_MAX, 1);
-	}
-
-	if (mA < QPNP_CHG_IUSB_MAX_MIN_MA
-			|| mA > QPNP_CHG_IUSB_MAX_MAX_MA) {
+	if (mA < QPNP_CHG_I_MAX_MIN_100
+			|| mA > QPNP_CHG_I_MAX_MAX_MA) {
 		pr_err("bad mA=%d asked to set\n", mA);
 		return -EINVAL;
 	}
 
-	usb_reg = mA / QPNP_CHG_IUSB_MAX_STEP_MA;
+	if (mA == QPNP_CHG_I_MAX_MIN_100) {
+		usb_reg = 0x00;
+		pr_debug("current=%d setting %02x\n", mA, usb_reg);
+		return qpnp_chg_write(chip, &usb_reg,
+		chip->usb_chgpth_base + CHGR_I_MAX_REG, 1);
+	} else if (mA == QPNP_CHG_I_MAX_MIN_150) {
+		usb_reg = 0x01;
+		pr_debug("current=%d setting %02x\n", mA, usb_reg);
+		return qpnp_chg_write(chip, &usb_reg,
+		chip->usb_chgpth_base + CHGR_I_MAX_REG, 1);
+	}
+
+	/* Impose input current limit */
+	if (chip->maxinput_usb_ma)
+		mA = (chip->maxinput_usb_ma) <= mA ? chip->maxinput_usb_ma : mA;
+
+	usb_reg = mA / QPNP_CHG_I_MAXSTEP_MA;
 
 	if (chip->flags & CHG_FLAGS_VCP_WA) {
 		temp = 0xA5;
@@ -390,7 +431,7 @@
 
 	pr_debug("current=%d setting 0x%x\n", mA, usb_reg);
 	rc = qpnp_chg_write(chip, &usb_reg,
-		chip->usb_chgpth_base + CHGR_USB_IUSB_MAX, 1);
+		chip->usb_chgpth_base + CHGR_I_MAX_REG, 1);
 
 	if (chip->flags & CHG_FLAGS_VCP_WA) {
 		temp = 0xA5;
@@ -875,12 +916,12 @@
 		chip->usb_psy->get_property(chip->usb_psy,
 			  POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
 		qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
-		if ((ret.intval / 1000) <= QPNP_CHG_IUSB_MAX_MIN_MA)
+		if ((ret.intval / 1000) <= QPNP_CHG_I_MAX_MIN_MA)
 			qpnp_chg_usb_suspend_enable(chip, 1);
 		else
 			qpnp_chg_usb_suspend_enable(chip, 0);
 	} else {
-		qpnp_chg_iusbmax_set(chip, QPNP_CHG_IUSB_MAX_MIN_100);
+		qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
 		qpnp_chg_usb_suspend_enable(chip, 0);
 	}
 
@@ -1429,6 +1470,33 @@
 		goto fail_chg_enable;
 	}
 
+	/* Get the ibatsafe property */
+	rc = of_property_read_u32(spmi->dev.of_node,
+				"qcom,chg-vbatdet-mv",
+				&chip->resume_voltage_mv);
+	if (rc) {
+		pr_err("Error reading vbatdet property %d\n", rc);
+		goto fail_chg_enable;
+	}
+
+	/* Get the maxinput-dc-ma property */
+	rc = of_property_read_u32(spmi->dev.of_node,
+				"qcom,chg-maxinput-dc-ma",
+				&chip->maxinput_dc_ma);
+	if (rc && rc != -EINVAL) {
+		pr_err("Error reading maxinput-dc-ma property %d\n", rc);
+		goto fail_chg_enable;
+	}
+
+	/* Get the maxinput-usb-ma property */
+	rc = of_property_read_u32(spmi->dev.of_node,
+				"qcom,chg-maxinput-usb-ma",
+				&chip->maxinput_usb_ma);
+	if (rc && rc != -EINVAL) {
+		pr_err("Error reading maxinput-usb-ma property %d\n", rc);
+		goto fail_chg_enable;
+	}
+
 	/* Get the charging-disabled property */
 	chip->charging_disabled = of_property_read_bool(spmi->dev.of_node,
 					"qcom,chg-charging-disabled");
@@ -1578,16 +1646,16 @@
 	chip->batt_psy.external_power_changed =
 				qpnp_batt_external_power_changed;
 
-	rc = power_supply_register(chip->dev, &chip->dc_psy);
-	if (rc < 0) {
-		pr_err("power_supply_register usb failed rc = %d\n", rc);
-		goto fail_chg_enable;
-	}
-
 	rc = power_supply_register(chip->dev, &chip->batt_psy);
 	if (rc < 0) {
 		pr_err("power_supply_register batt failed rc = %d\n", rc);
-		goto unregister_dc;
+		goto fail_chg_enable;
+	}
+
+	rc = power_supply_register(chip->dev, &chip->dc_psy);
+	if (rc < 0) {
+		pr_err("power_supply_register usb failed rc = %d\n", rc);
+		goto unregister_batt;
 	}
 
 	/* Turn on appropriate workaround flags */
@@ -1596,6 +1664,14 @@
 	power_supply_set_present(chip->usb_psy,
 			qpnp_chg_is_usb_chg_plugged_in(chip));
 
+	if (chip->maxinput_dc_ma) {
+		rc = qpnp_chg_idcmax_set(chip, chip->maxinput_dc_ma);
+		if (rc) {
+			pr_err("Error setting idcmax property %d\n", rc);
+			goto fail_chg_enable;
+		}
+	}
+
 	qpnp_chg_charge_en(chip, !chip->charging_disabled);
 	qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
 
@@ -1607,8 +1683,8 @@
 			get_prop_batt_health(chip));
 	return 0;
 
-unregister_dc:
-	power_supply_unregister(&chip->dc_psy);
+unregister_batt:
+	power_supply_unregister(&chip->batt_psy);
 fail_chg_enable:
 	kfree(chip->thermal_mitigation);
 	kfree(chip);
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/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index c2e1731..e37b3c4 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -69,6 +69,10 @@
 #define TSENS_MAIN_CALIB_ADDR_RANGE	6
 #define TSENS_BACKUP_CALIB_ADDR_RANGE	4
 
+#define TSENS_EEPROM_8X26_1(n)		((n) + 0x1c0)
+#define TSENS_EEPROM_8X26_2(n)		((n) + 0x444)
+#define TSENS_8X26_MAIN_CALIB_ADDR_RANGE	4
+
 /* TSENS calibration Mask data */
 #define TSENS_BASE1_MASK		0xff
 #define TSENS0_POINT1_MASK		0x3f00
@@ -151,6 +155,41 @@
 #define TSENS10_POINT2_MASK		0xfc0000
 #define TSENS10_POINT2_BACKUP_MASK	0x3f000000
 
+#define TSENS_8X26_BASE0_MASK		0x1fe000
+#define TSENS0_8X26_POINT1_MASK		0x7f00000
+#define TSENS1_8X26_POINT1_MASK		0x3f
+#define TSENS2_8X26_POINT1_MASK		0xfc0
+#define TSENS3_8X26_POINT1_MASK		0x3f000
+#define TSENS4_8X26_POINT1_MASK		0xfc0000
+#define TSENS5_8X26_POINT1_MASK		0x3f000000
+#define TSENS6_8X26_POINT1_MASK		0x3f00000
+#define TSENS_8X26_TSENS_CAL_SEL	0xe0000000
+#define TSENS_8X26_BASE1_MASK		0xff
+#define TSENS0_8X26_POINT2_MASK		0x3f00
+#define TSENS1_8X26_POINT2_MASK		0xfc00
+#define TSENS2_8X26_POINT2_MASK		0x3f00000
+#define TSENS3_8X26_POINT2_MASK		0xfc000000
+#define TSENS4_8X26_POINT2_MASK		0xfc000000
+#define TSENS5_8X26_POINT2_MASK		0x3f00000
+#define TSENS6_8X26_POINT2_MASK		0x7e0000
+
+#define TSENS_8X26_CAL_SEL_SHIFT	29
+#define TSENS_8X26_BASE0_SHIFT		13
+#define TSENS0_8X26_POINT1_SHIFT	21
+#define TSENS2_8X26_POINT1_SHIFT	6
+#define TSENS3_8X26_POINT1_SHIFT	12
+#define TSENS4_8X26_POINT1_SHIFT	18
+#define TSENS5_8X26_POINT1_SHIFT	24
+#define TSENS6_8X26_POINT1_SHIFT	20
+
+#define TSENS0_8X26_POINT2_SHIFT	8
+#define TSENS1_8X26_POINT2_SHIFT	14
+#define TSENS2_8X26_POINT2_SHIFT	20
+#define TSENS3_8X26_POINT2_SHIFT	26
+#define TSENS4_8X26_POINT2_SHIFT	20
+#define TSENS5_8X26_POINT2_SHIFT	26
+#define TSENS6_8X26_POINT2_SHIFT	17
+
 #define TSENS_BIT_APPEND		0x3
 #define TSENS_CAL_DEGC_POINT1		30
 #define TSENS_CAL_DEGC_POINT2		120
@@ -171,6 +210,13 @@
 #define TSENS_QFPROM_BACKUP_REDUN_SEL	0xe0000000
 #define TSENS_QFPROM_BACKUP_REDUN_SHIFT	29
 
+enum tsens_calib_fuse_map_type {
+	TSENS_CALIB_FUSE_MAP_8974 = 0,
+	TSENS_CALIB_FUSE_MAP_8X26,
+	TSENS_CALIB_FUSE_MAP_8X10,
+	TSENS_CALIB_FUSE_MAP_NUM,
+};
+
 /* Trips: warm and cool */
 enum tsens_trip_type {
 	TSENS_TRIP_WARM = 0,
@@ -203,6 +249,7 @@
 	struct resource			*res_tsens_mem;
 	struct resource			*res_calib_mem;
 	struct work_struct		tsens_work;
+	uint32_t			calib_mode;
 	struct tsens_tm_device_sensor	sensor[0];
 };
 
@@ -546,7 +593,162 @@
 		TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr));
 }
 
-static int tsens_calib_sensors(void)
+static int tsens_calib_8x26_sensors(void)
+{
+	int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
+	int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
+	int tsens5_point1 = 0, tsens6_point1 = 0, tsens6_point2 = 0;
+	int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
+	int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
+	int tsens_base1_data = 0, tsens_calibration_mode = 0;
+	uint32_t calib_data[6];
+	uint32_t calib_tsens_point1_data[7], calib_tsens_point2_data[7];
+
+	if (tmdev->calibration_less_mode)
+		goto calibration_less_mode;
+
+	for (i = 0; i < TSENS_8X26_MAIN_CALIB_ADDR_RANGE; i++)
+		calib_data[i] = readl_relaxed(
+			(TSENS_EEPROM_8X26_1(tmdev->tsens_calib_addr))
+					+ (i * TSENS_SN_ADDR_OFFSET));
+	calib_data[4] = readl_relaxed(
+			(TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)));
+	calib_data[5] = readl_relaxed(
+			(TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)) + 0x8);
+
+	tsens_calibration_mode = calib_data[5] & TSENS_8X26_TSENS_CAL_SEL;
+
+	if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
+		(tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
+		pr_debug("backup one point calibrationless mode\n");
+		tsens_base0_data = (calib_data[0] & TSENS_8X26_BASE0_MASK)
+				>> TSENS_8X26_BASE0_SHIFT;
+		tsens0_point1 = (calib_data[0] & TSENS0_8X26_POINT1_MASK) >>
+				TSENS0_8X26_POINT1_SHIFT;
+		tsens1_point1 = calib_data[1] & TSENS1_8X26_POINT1_MASK;
+		tsens2_point1 = (calib_data[1] & TSENS2_8X26_POINT1_MASK) >>
+				TSENS2_8X26_POINT1_SHIFT;
+		tsens3_point1 = (calib_data[1] & TSENS3_8X26_POINT1_MASK) >>
+				TSENS3_8X26_POINT1_SHIFT;
+		tsens4_point1 = (calib_data[1] & TSENS4_8X26_POINT1_MASK) >>
+				TSENS4_8X26_POINT1_SHIFT;
+		tsens5_point1 = (calib_data[1] & TSENS5_8X26_POINT1_MASK) >>
+				TSENS5_8X26_POINT1_SHIFT;
+		tsens6_point1 = (calib_data[2] & TSENS6_8X26_POINT1_MASK) >>
+				TSENS6_8X26_POINT1_SHIFT;
+	} else
+		goto calibration_less_mode;
+
+	if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+		pr_debug("backup two point calibrationless mode\n");
+		tsens_base1_data = (calib_data[3] & TSENS_8X26_BASE1_MASK);
+		tsens0_point2 = (calib_data[3] & TSENS0_8X26_POINT2_MASK) >>
+				TSENS0_8X26_POINT2_SHIFT;
+		tsens1_point2 = (calib_data[3] & TSENS1_8X26_POINT2_MASK) >>
+				TSENS1_8X26_POINT2_SHIFT;
+		tsens2_point2 = (calib_data[3] & TSENS2_8X26_POINT2_MASK) >>
+				TSENS2_8X26_POINT2_SHIFT;
+		tsens3_point2 = (calib_data[3] & TSENS3_8X26_POINT2_MASK) >>
+				TSENS3_8X26_POINT2_SHIFT;
+		tsens4_point2 = (calib_data[4] & TSENS4_8X26_POINT2_MASK) >>
+				TSENS4_8X26_POINT2_SHIFT;
+		tsens5_point2 = (calib_data[4] & TSENS5_8X26_POINT2_MASK) >>
+				TSENS5_8X26_POINT2_SHIFT;
+		tsens6_point2 = (calib_data[5] & TSENS6_8X26_POINT2_MASK) >>
+				TSENS6_8X26_POINT2_SHIFT;
+	}
+
+	if (tsens_calibration_mode == 0) {
+calibration_less_mode:
+		pr_debug("TSENS is calibrationless mode\n");
+		for (i = 0; i < tmdev->tsens_num_sensor; i++)
+			calib_tsens_point2_data[i] = 780;
+		calib_tsens_point1_data[0] = 502;
+		calib_tsens_point1_data[1] = 509;
+		calib_tsens_point1_data[2] = 503;
+		calib_tsens_point1_data[3] = 509;
+		calib_tsens_point1_data[4] = 505;
+		calib_tsens_point1_data[5] = 509;
+		calib_tsens_point1_data[6] = 507;
+		goto compute_intercept_slope;
+	}
+
+	if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
+			(tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
+		pr_debug("one and two point calibration calculation\n");
+		calib_tsens_point1_data[0] =
+			((((tsens_base0_data) + tsens0_point1) << 2) |
+						TSENS_BIT_APPEND);
+		calib_tsens_point1_data[1] =
+			((((tsens_base0_data) + tsens1_point1) << 2) |
+						TSENS_BIT_APPEND);
+		calib_tsens_point1_data[2] =
+			((((tsens_base0_data) + tsens2_point1) << 2) |
+						TSENS_BIT_APPEND);
+		calib_tsens_point1_data[3] =
+			((((tsens_base0_data) + tsens3_point1) << 2) |
+						TSENS_BIT_APPEND);
+		calib_tsens_point1_data[4] =
+			((((tsens_base0_data) + tsens4_point1) << 2) |
+						TSENS_BIT_APPEND);
+		calib_tsens_point1_data[5] =
+			((((tsens_base0_data) + tsens5_point1) << 2) |
+						TSENS_BIT_APPEND);
+		calib_tsens_point1_data[6] =
+			((((tsens_base0_data) + tsens6_point1) << 2) |
+						TSENS_BIT_APPEND);
+	}
+
+	if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+		pr_debug("two point calibration calculation\n");
+		calib_tsens_point2_data[0] =
+			(((tsens_base1_data + tsens0_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[1] =
+			(((tsens_base1_data + tsens1_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[2] =
+			(((tsens_base1_data + tsens2_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[3] =
+			(((tsens_base1_data + tsens3_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[4] =
+			(((tsens_base1_data + tsens4_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[5] =
+			(((tsens_base1_data + tsens5_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[6] =
+			(((tsens_base1_data + tsens6_point2) << 2) |
+					TSENS_BIT_APPEND);
+	}
+
+compute_intercept_slope:
+	for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+		int32_t num = 0, den = 0;
+		tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
+		tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
+		if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+			/* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
+				temp_120_degc - temp_30_degc (x2 - x1) */
+			num = tmdev->sensor[i].calib_data_point2 -
+					tmdev->sensor[i].calib_data_point1;
+			num *= tmdev->tsens_factor;
+			den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
+			tmdev->sensor[i].slope_mul_tsens_factor = num/den;
+		}
+		tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
+			tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
+				tmdev->sensor[i].slope_mul_tsens_factor);
+		INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
+		tmdev->prev_reading_avail = false;
+	}
+
+	return 0;
+}
+
+static int tsens_calib_8974_sensors(void)
 {
 	int i, tsens_base1_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
 	int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
@@ -877,12 +1079,30 @@
 	return 0;
 }
 
+static int tsens_calib_sensors(void)
+{
+	int rc = 0;
+
+	if (!tmdev)
+		return -ENODEV;
+
+	if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8974)
+		rc = tsens_calib_8974_sensors();
+	else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X26)
+		rc = tsens_calib_8x26_sensors();
+	else
+		rc = -ENODEV;
+
+	return rc;
+}
+
 static int get_device_tree_data(struct platform_device *pdev)
 {
 	const struct device_node *of_node = pdev->dev.of_node;
 	struct resource *res_mem = NULL;
 	u32 *tsens_slope_data;
-	u32 rc = 0, i, tsens_num_sensors;
+	u32 rc = 0, i, tsens_num_sensors, calib_type;
+	const char *tsens_calib_mode;
 
 	rc = of_property_read_u32(of_node,
 			"qcom,sensors", &tsens_num_sensors);
@@ -905,6 +1125,19 @@
 		return rc;
 	};
 
+	tsens_calib_mode = of_get_property(of_node,
+			"qcom,calib-mode", NULL);
+	if (!strncmp(tsens_calib_mode, "fuse_map1", 9))
+		calib_type = TSENS_CALIB_FUSE_MAP_8974;
+	else if (!strncmp(tsens_calib_mode, "fuse_map2", 9))
+		calib_type = TSENS_CALIB_FUSE_MAP_8X26;
+	else if (!strncmp(tsens_calib_mode, "fuse_map3", 9))
+		calib_type = TSENS_CALIB_FUSE_MAP_8X10;
+	else {
+		pr_err("%s: Invalid calibration property\n", __func__);
+		return -EINVAL;
+	}
+
 	tmdev = devm_kzalloc(&pdev->dev,
 			sizeof(struct tsens_tm_device) +
 			tsens_num_sensors *
@@ -921,6 +1154,7 @@
 	tmdev->tsens_num_sensor = tsens_num_sensors;
 	tmdev->calibration_less_mode = of_property_read_bool(of_node,
 				"qcom,calibration-less-mode");
+	tmdev->calib_mode = calib_type;
 
 	tmdev->tsens_irq = platform_get_irq(pdev, 0);
 	if (tmdev->tsens_irq < 0) {
@@ -1085,6 +1319,8 @@
 		for (i = 0; i < tmdev->tsens_num_sensor; i++)
 			thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
 		goto fail;
+	} else {
+		enable_irq_wake(tmdev->tsens_irq);
 	}
 	platform_set_drvdata(pdev, tmdev);
 
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/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 4b6ba67..a27322e 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -1060,6 +1060,14 @@
 	}
 	if (!is_blsp_uart(msm_uport) && msm_uport->rx.flush != FLUSH_SHUTDOWN)
 		msm_uport->rx.flush = FLUSH_STOP;
+
+	/* During uart port close, due to spurious rx stale interrupt,
+	 * the rx state machine is causing BUG_ON to be hit in
+	 * msm_hs_shutdown causing kernel panic.
+	 * Hence fixing the same by handling the rx state machine.
+	 */
+	if (is_blsp_uart(msm_uport) && msm_uport->rx.flush == FLUSH_DATA_READY)
+		msm_uport->rx.flush = FLUSH_SHUTDOWN;
 }
 
 /*  Transmit the next chunk of data */
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/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 2db9eea..0664376 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1205,7 +1205,10 @@
 
 	int				ret;
 
+	spin_lock_irqsave(&dwc->lock, flags);
+
 	if (!dep->endpoint.desc) {
+		spin_unlock_irqrestore(&dwc->lock, flags);
 		dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
 				request, ep->name);
 		return -ESHUTDOWN;
@@ -1217,7 +1220,6 @@
 	WARN(!dep->direction && (request->length % ep->desc->wMaxPacketSize),
 		"trying to queue unaligned request (%d)\n", request->length);
 
-	spin_lock_irqsave(&dwc->lock, flags);
 	ret = __dwc3_gadget_ep_queue(dep, req);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 6df0c96..76d75ea 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -60,6 +60,7 @@
 #include "u_smd.c"
 #include "u_bam.c"
 #include "u_rmnet_ctrl_smd.c"
+#include "u_rmnet_ctrl_qti.c"
 #include "u_ctrl_hsic.c"
 #include "u_data_hsic.c"
 #include "u_ctrl_hsuart.c"
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index daa981f..d69e850 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 {
@@ -223,6 +224,16 @@
 	.bmNetworkCapabilities = 0x20,
 };
 
+static struct usb_cdc_ext_mbb_desc ext_mbb_desc = {
+	.bLength =	sizeof ext_mbb_desc,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_EXT_MBB_TYPE,
+
+	.bcdMbbExtendedVersion =	cpu_to_le16(0x0100),
+	.bMaxOutstandingCmdMsges =	64,
+	.wMTU =	1500,
+};
+
 /* the default data interface has no endpoints ... */
 static struct usb_interface_descriptor mbim_data_nop_intf = {
 	.bLength =		sizeof mbim_data_nop_intf,
@@ -285,6 +296,7 @@
 	(struct usb_descriptor_header *) &mbim_control_intf,
 	(struct usb_descriptor_header *) &mbim_header_desc,
 	(struct usb_descriptor_header *) &mbb_desc,
+	(struct usb_descriptor_header *) &ext_mbb_desc,
 	(struct usb_descriptor_header *) &fs_mbim_notify_desc,
 	/* data interface, altsettings 0 and 1 */
 	(struct usb_descriptor_header *) &mbim_data_nop_intf,
@@ -329,6 +341,7 @@
 	(struct usb_descriptor_header *) &mbim_control_intf,
 	(struct usb_descriptor_header *) &mbim_header_desc,
 	(struct usb_descriptor_header *) &mbb_desc,
+	(struct usb_descriptor_header *) &ext_mbb_desc,
 	(struct usb_descriptor_header *) &hs_mbim_notify_desc,
 	/* data interface, altsettings 0 and 1 */
 	(struct usb_descriptor_header *) &mbim_data_nop_intf,
@@ -571,6 +584,7 @@
 		return;
 	}
 
+	req->length = sizeof *event;
 	event = req->buf;
 	event->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
 			| USB_RECIP_INTERFACE;
@@ -581,7 +595,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 +624,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 +771,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 +807,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 +859,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 +1394,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);
 
@@ -1674,7 +1705,7 @@
 	}
 
 	while (list_empty(&dev->cpkt_req_q)) {
-		pr_err("Requests list is empty. Wait.\n");
+		pr_debug("Requests list is empty. Wait.\n");
 		ret = wait_event_interruptible(dev->read_wq,
 			!list_empty(&dev->cpkt_req_q));
 		if (ret < 0) {
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index e6613e8..0d8fa0f 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -55,6 +55,7 @@
 #define NR_RMNET_PORTS	3
 static unsigned int nr_rmnet_ports;
 static unsigned int no_ctrl_smd_ports;
+static unsigned int no_ctrl_qti_ports;
 static unsigned int no_ctrl_hsic_ports;
 static unsigned int no_ctrl_hsuart_ports;
 static unsigned int no_data_bam_ports;
@@ -402,6 +403,14 @@
 			return ret;
 		}
 		break;
+	case USB_GADGET_XPORT_QTI:
+		ret = gqti_ctrl_connect(&dev->port);
+		if (ret) {
+			pr_err("%s: gqti_ctrl_connect failed: err:%d\n",
+					__func__, ret);
+			return ret;
+		}
+		break;
 	case USB_GADGET_XPORT_HSIC:
 		ret = ghsic_ctrl_connect(&dev->port, port_num);
 		if (ret) {
@@ -436,7 +445,10 @@
 		if (ret) {
 			pr_err("%s: gbam_connect failed: err:%d\n",
 					__func__, ret);
-			gsmd_ctrl_disconnect(&dev->port, port_num);
+			if (cxport == USB_GADGET_XPORT_QTI)
+				gqti_ctrl_disconnect(&dev->port);
+			else
+				gsmd_ctrl_disconnect(&dev->port, port_num);
 			return ret;
 		}
 		break;
@@ -484,6 +496,9 @@
 	case USB_GADGET_XPORT_SMD:
 		gsmd_ctrl_disconnect(&dev->port, port_num);
 		break;
+	case USB_GADGET_XPORT_QTI:
+		gqti_ctrl_disconnect(&dev->port);
+		break;
 	case USB_GADGET_XPORT_HSIC:
 		ghsic_ctrl_disconnect(&dev->port, port_num);
 		break;
@@ -1170,6 +1185,7 @@
 
 	nr_rmnet_ports = 0;
 	no_ctrl_smd_ports = 0;
+	no_ctrl_qti_ports = 0;
 	no_data_bam_ports = 0;
 	no_data_bam2bam_ports = 0;
 	no_ctrl_hsic_ports = 0;
@@ -1215,6 +1231,10 @@
 		rmnet_port->ctrl_xport_num = no_ctrl_smd_ports;
 		no_ctrl_smd_ports++;
 		break;
+	case USB_GADGET_XPORT_QTI:
+		rmnet_port->ctrl_xport_num = no_ctrl_qti_ports;
+		no_ctrl_qti_ports++;
+		break;
 	case USB_GADGET_XPORT_HSIC:
 		rmnet_port->ctrl_xport_num = no_ctrl_hsic_ports;
 		no_ctrl_hsic_ports++;
@@ -1268,6 +1288,7 @@
 
 	nr_rmnet_ports = 0;
 	no_ctrl_smd_ports = 0;
+	no_ctrl_qti_ports = 0;
 	no_data_bam_ports = 0;
 	no_ctrl_hsic_ports = 0;
 	no_data_hsic_ports = 0;
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index 81ba223..cea9369 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -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
@@ -55,5 +55,7 @@
 int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
 void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num);
 int gsmd_ctrl_setup(unsigned int count);
+int gqti_ctrl_connect(struct grmnet *gr);
+void gqti_ctrl_disconnect(struct grmnet *gr);
 
 #endif /* __U_RMNET_H*/
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_qti.c b/drivers/usb/gadget/u_rmnet_ctrl_qti.c
new file mode 100644
index 0000000..e92978f
--- /dev/null
+++ b/drivers/usb/gadget/u_rmnet_ctrl_qti.c
@@ -0,0 +1,519 @@
+/*
+ * 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/wait.h>
+#include <linux/poll.h>
+#include <linux/usb/rmnet_ctrl_qti.h>
+
+#include "u_rmnet.h"
+
+struct rmnet_ctrl_qti_port {
+	struct grmnet		*port_usb;
+
+	bool		is_open;
+
+	atomic_t	connected;
+	atomic_t	line_state;
+
+	atomic_t	open_excl;
+	atomic_t	read_excl;
+	atomic_t	write_excl;
+	atomic_t	ioctl_excl;
+
+	wait_queue_head_t read_wq;
+
+	struct list_head	cpkt_req_q;
+
+	spinlock_t			lock;
+};
+static struct rmnet_ctrl_qti_port *ctrl_port;
+
+static inline int rmnet_ctrl_lock(atomic_t *excl)
+{
+	if (atomic_inc_return(excl) == 1) {
+		return 0;
+	} else {
+		atomic_dec(excl);
+		return -EBUSY;
+	}
+}
+
+static inline void rmnet_ctrl_unlock(atomic_t *excl)
+{
+	atomic_dec(excl);
+}
+
+static void rmnet_ctrl_queue_notify(struct rmnet_ctrl_qti_port *port)
+{
+	unsigned long		flags;
+	struct rmnet_ctrl_pkt	*cpkt = NULL;
+
+	pr_debug("%s: Queue empty packet for QTI", __func__);
+
+	spin_lock_irqsave(&port->lock, flags);
+	if (!port->is_open) {
+		pr_err("%s: rmnet ctrl file handler %p is not open",
+			   __func__, port);
+		spin_unlock_irqrestore(&port->lock, flags);
+		return;
+	}
+
+	cpkt = alloc_rmnet_ctrl_pkt(0, GFP_ATOMIC);
+	if (!cpkt) {
+		pr_err("%s: Unable to allocate reset function pkt\n", __func__);
+		spin_unlock_irqrestore(&port->lock, flags);
+		return;
+	}
+
+	list_add_tail(&cpkt->list, &port->cpkt_req_q);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	pr_debug("%s: Wake up read queue", __func__);
+	wake_up(&port->read_wq);
+}
+
+static int grmnet_ctrl_qti_send_cpkt_tomodem(u8 portno,
+	void *buf, size_t len)
+{
+	unsigned long		flags;
+	struct rmnet_ctrl_qti_port	*port = ctrl_port;
+	struct rmnet_ctrl_pkt *cpkt;
+
+	if (len > MAX_QTI_PKT_SIZE) {
+		pr_err("given pkt size too big:%d > max_pkt_size:%d\n",
+				len, MAX_QTI_PKT_SIZE);
+		return -EINVAL;
+	}
+
+	cpkt = alloc_rmnet_ctrl_pkt(len, GFP_ATOMIC);
+	if (IS_ERR(cpkt)) {
+		pr_err("%s: Unable to allocate ctrl pkt\n", __func__);
+		return -ENOMEM;
+	}
+
+	memcpy(cpkt->buf, buf, len);
+	cpkt->len = len;
+
+	pr_debug("%s: Add to cpkt_req_q packet with len = %d\n", __func__, len);
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* drop cpkt if port is not open */
+	if (!port->is_open) {
+		pr_err("rmnet file handler %p is not open", port);
+		spin_unlock_irqrestore(&port->lock, flags);
+		free_rmnet_ctrl_pkt(cpkt);
+		return 0;
+	}
+
+	list_add_tail(&cpkt->list, &port->cpkt_req_q);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	/* wakeup read thread */
+	pr_debug("%s: Wake up read queue", __func__);
+	wake_up(&port->read_wq);
+
+	return 0;
+}
+
+static void
+gqti_ctrl_notify_modem(void *gptr, u8 portno, int val)
+{
+	struct rmnet_ctrl_qti_port	*port = ctrl_port;
+
+	atomic_set(&port->line_state, val);
+
+	/* send 0 len pkt to qti to notify state change */
+	rmnet_ctrl_queue_notify(port);
+}
+
+int gqti_ctrl_connect(struct grmnet *gr)
+{
+	struct rmnet_ctrl_qti_port	*port;
+	unsigned long		flags;
+
+	pr_debug("%s: grmnet:%p\n", __func__, gr);
+
+	if (!gr) {
+		pr_err("%s: grmnet port is null\n", __func__);
+		return -ENODEV;
+	}
+
+	port = ctrl_port;
+
+	spin_lock_irqsave(&port->lock, flags);
+	port->port_usb = gr;
+	gr->send_encap_cmd = grmnet_ctrl_qti_send_cpkt_tomodem;
+	gr->notify_modem = gqti_ctrl_notify_modem;
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	atomic_set(&port->connected, 1);
+	wake_up(&port->read_wq);
+
+	if (port && port->port_usb && port->port_usb->connect)
+		port->port_usb->connect(port->port_usb);
+
+	return 0;
+}
+
+void gqti_ctrl_disconnect(struct grmnet *gr)
+{
+	struct rmnet_ctrl_qti_port	*port = ctrl_port;
+	unsigned long		flags;
+	struct rmnet_ctrl_pkt	*cpkt;
+
+	pr_debug("%s: grmnet:%p\n", __func__, gr);
+
+	if (!gr) {
+		pr_err("%s: grmnet port is null\n", __func__);
+		return;
+	}
+
+	if (port && port->port_usb && port->port_usb->disconnect)
+		port->port_usb->disconnect(port->port_usb);
+
+	atomic_set(&port->connected, 0);
+	atomic_set(&port->line_state, 0);
+	spin_lock_irqsave(&port->lock, flags);
+	port->port_usb = 0;
+	gr->send_encap_cmd = 0;
+	gr->notify_modem = 0;
+
+	while (!list_empty(&port->cpkt_req_q)) {
+		cpkt = list_first_entry(&port->cpkt_req_q,
+					struct rmnet_ctrl_pkt, list);
+
+		list_del(&cpkt->list);
+		free_rmnet_ctrl_pkt(cpkt);
+	}
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	/* send 0 len pkt to qti to notify state change */
+	rmnet_ctrl_queue_notify(port);
+}
+
+static int rmnet_ctrl_open(struct inode *ip, struct file *fp)
+{
+	unsigned long		flags;
+
+	pr_debug("Open rmnet_ctrl_qti device file\n");
+
+	if (rmnet_ctrl_lock(&ctrl_port->open_excl)) {
+		pr_debug("Already opened\n");
+		return -EBUSY;
+	}
+
+	fp->private_data = ctrl_port;
+
+	spin_lock_irqsave(&ctrl_port->lock, flags);
+	ctrl_port->is_open = true;
+	spin_unlock_irqrestore(&ctrl_port->lock, flags);
+
+	return 0;
+}
+
+static int rmnet_ctrl_release(struct inode *ip, struct file *fp)
+{
+	unsigned long		flags;
+	struct rmnet_ctrl_qti_port *port = fp->private_data;
+
+	pr_debug("Close rmnet control file");
+
+	spin_lock_irqsave(&port->lock, flags);
+	port->is_open = false;
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	rmnet_ctrl_unlock(&port->open_excl);
+
+	return 0;
+}
+
+static ssize_t
+rmnet_ctrl_read(struct file *fp, char __user *buf, size_t count, loff_t *pos)
+{
+	struct rmnet_ctrl_qti_port *port = fp->private_data;
+	struct rmnet_ctrl_pkt *cpkt = NULL;
+	unsigned long flags;
+	int ret = 0;
+
+	pr_debug("%s: Enter(%d)\n", __func__, count);
+
+	if (count > MAX_QTI_PKT_SIZE) {
+		pr_err("Buffer size is too big %d, should be at most %d\n",
+			count, MAX_QTI_PKT_SIZE);
+		return -EINVAL;
+	}
+
+	if (rmnet_ctrl_lock(&port->read_excl)) {
+		pr_err("Previous reading is not finished yet\n");
+		return -EBUSY;
+	}
+
+	/* block until online */
+	while (!(atomic_read(&port->connected))) {
+		pr_debug("Not connected. Wait.\n");
+		ret = wait_event_interruptible(port->read_wq,
+			atomic_read(&port->connected));
+		if (ret < 0) {
+			rmnet_ctrl_unlock(&port->read_excl);
+			if (ret == -ERESTARTSYS)
+				return -ERESTARTSYS;
+			else
+				return -EINTR;
+		}
+	}
+
+	/* block until a new packet is available */
+	do {
+		spin_lock_irqsave(&port->lock, flags);
+		if (!list_empty(&port->cpkt_req_q))
+			break;
+		spin_unlock_irqrestore(&port->lock, flags);
+
+		pr_debug("%s: Requests list is empty. Wait.\n", __func__);
+		ret = wait_event_interruptible(port->read_wq,
+					!list_empty(&port->cpkt_req_q));
+		if (ret < 0) {
+			pr_debug("Waiting failed\n");
+			rmnet_ctrl_unlock(&port->read_excl);
+			return -ERESTARTSYS;
+		}
+	} while (1);
+
+	cpkt = list_first_entry(&port->cpkt_req_q, struct rmnet_ctrl_pkt,
+							list);
+	list_del(&cpkt->list);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	if (cpkt->len > count) {
+		pr_err("cpkt size too big:%d > buf size:%d\n",
+				cpkt->len, count);
+		rmnet_ctrl_unlock(&port->read_excl);
+		free_rmnet_ctrl_pkt(cpkt);
+		return -ENOMEM;
+	}
+
+	pr_debug("%s: cpkt size:%d\n", __func__, cpkt->len);
+
+
+	rmnet_ctrl_unlock(&port->read_excl);
+
+	ret = copy_to_user(buf, cpkt->buf, cpkt->len);
+	if (ret) {
+		pr_err("copy_to_user failed: err %d\n", ret);
+		ret = -EFAULT;
+	} else {
+		pr_debug("%s: copied %d bytes to user\n", __func__, cpkt->len);
+		ret = cpkt->len;
+	}
+
+	free_rmnet_ctrl_pkt(cpkt);
+
+	return ret;
+}
+
+static ssize_t
+rmnet_ctrl_write(struct file *fp, const char __user *buf, size_t count,
+		   loff_t *pos)
+{
+	struct rmnet_ctrl_qti_port *port = fp->private_data;
+	void *kbuf;
+	unsigned long flags;
+	int ret = 0;
+
+	pr_debug("%s: Enter(%d)", __func__, count);
+
+	if (!count) {
+		pr_debug("zero length ctrl pkt\n");
+		return -EINVAL;
+	}
+
+	if (count > MAX_QTI_PKT_SIZE) {
+		pr_debug("given pkt size too big:%d > max_pkt_size:%d\n",
+				count, MAX_QTI_PKT_SIZE);
+		return -EINVAL;
+	}
+
+	if (rmnet_ctrl_lock(&port->write_excl)) {
+		pr_err("Previous writing not finished yet\n");
+		return -EBUSY;
+	}
+
+	if (!atomic_read(&port->connected)) {
+		pr_debug("USB cable not connected\n");
+		rmnet_ctrl_unlock(&port->write_excl);
+		return -EPIPE;
+	}
+
+	kbuf = kmalloc(count, GFP_KERNEL);
+	if (!kbuf) {
+		pr_err("failed to allocate ctrl pkt\n");
+		rmnet_ctrl_unlock(&port->write_excl);
+		return -ENOMEM;
+	}
+	ret = copy_from_user(kbuf, buf, count);
+	if (ret) {
+		pr_err("copy_from_user failed err:%d\n", ret);
+		kfree(kbuf);
+		rmnet_ctrl_unlock(&port->write_excl);
+		return -EFAULT;
+	}
+
+	spin_lock_irqsave(&port->lock, flags);
+	if (port->port_usb && port->port_usb->send_cpkt_response) {
+		ret = port->port_usb->send_cpkt_response(port->port_usb,
+							kbuf, count);
+		if (ret) {
+			pr_err("failed to send ctrl packet. error=%d\n", ret);
+			spin_unlock_irqrestore(&port->lock, flags);
+			kfree(kbuf);
+			rmnet_ctrl_unlock(&port->write_excl);
+			return ret;
+		}
+	} else {
+		pr_err("send_cpkt_response callback is NULL\n");
+		spin_unlock_irqrestore(&port->lock, flags);
+		kfree(kbuf);
+		rmnet_ctrl_unlock(&port->write_excl);
+		return -EINVAL;
+	}
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	kfree(kbuf);
+	rmnet_ctrl_unlock(&port->write_excl);
+
+	pr_debug("%s: Exit(%d)", __func__, count);
+
+	return count;
+
+}
+
+static long rmnet_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
+{
+	struct rmnet_ctrl_qti_port *port = fp->private_data;
+	int val, ret = 0;
+
+	pr_debug("%s: Received command %d", __func__, cmd);
+
+	if (rmnet_ctrl_lock(&port->ioctl_excl))
+		return -EBUSY;
+
+	switch (cmd) {
+	case FRMNET_CTRL_GET_LINE_STATE:
+		val = atomic_read(&port->line_state);
+		ret = copy_to_user((void __user *)arg, &val, sizeof(val));
+		if (ret) {
+			pr_err("copying to user space failed");
+			ret = -EFAULT;
+		}
+		pr_debug("%s: Sent line_state: %d", __func__,
+				 atomic_read(&port->line_state));
+		break;
+	default:
+		pr_err("wrong parameter");
+		ret = -EINVAL;
+	}
+
+	rmnet_ctrl_unlock(&port->ioctl_excl);
+
+	return ret;
+}
+
+static unsigned int rmnet_ctrl_poll(struct file *file, poll_table *wait)
+{
+	struct rmnet_ctrl_qti_port *port = file->private_data;
+	unsigned long flags;
+	unsigned int mask = 0;
+
+	if (!port) {
+		pr_err("%s on a NULL device\n", __func__);
+		return POLLERR;
+	}
+
+	poll_wait(file, &port->read_wq, wait);
+
+	spin_lock_irqsave(&port->lock, flags);
+	if (!list_empty(&port->cpkt_req_q)) {
+		mask |= POLLIN | POLLRDNORM;
+		pr_debug("%s sets POLLIN for rmnet_ctrl_qti_port\n", __func__);
+	}
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return mask;
+}
+
+/* file operations for rmnet device /dev/rmnet_ctrl */
+static const struct file_operations rmnet_ctrl_fops = {
+	.owner = THIS_MODULE,
+	.open = rmnet_ctrl_open,
+	.release = rmnet_ctrl_release,
+	.read = rmnet_ctrl_read,
+	.write = rmnet_ctrl_write,
+	.unlocked_ioctl = rmnet_ctrl_ioctl,
+	.poll = rmnet_ctrl_poll,
+};
+
+static struct miscdevice rmnet_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "rmnet_ctrl",
+	.fops = &rmnet_ctrl_fops,
+};
+
+static int __init gqti_ctrl_init(void)
+{
+	int ret;
+	struct rmnet_ctrl_qti_port *port = NULL;
+
+	port = kzalloc(sizeof(struct rmnet_ctrl_qti_port), GFP_KERNEL);
+	if (!port) {
+		pr_err("Failed to allocate rmnet control device\n");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&port->cpkt_req_q);
+	spin_lock_init(&port->lock);
+
+	atomic_set(&port->open_excl, 0);
+	atomic_set(&port->read_excl, 0);
+	atomic_set(&port->write_excl, 0);
+	atomic_set(&port->ioctl_excl, 0);
+	atomic_set(&port->connected, 0);
+	atomic_set(&port->line_state, 0);
+
+	init_waitqueue_head(&port->read_wq);
+
+	ctrl_port = port;
+
+	ret = misc_register(&rmnet_device);
+	if (ret) {
+		pr_err("rmnet control driver failed to register");
+		goto fail_init;
+	}
+
+	return ret;
+
+fail_init:
+	kfree(port);
+	ctrl_port = NULL;
+	return ret;
+}
+module_init(gqti_ctrl_init);
+
+static void __exit gqti_ctrl_cleanup(void)
+{
+	misc_deregister(&rmnet_device);
+
+	kfree(ctrl_port);
+	ctrl_port = NULL;
+}
+module_exit(gqti_ctrl_cleanup);
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..8e32aa9 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;
@@ -834,7 +805,7 @@
 
 	wake_unlock(&mehci->wlock);
 
-	dev_info(mehci->dev, "HSIC-USB in low power mode\n");
+	dev_dbg(mehci->dev, "HSIC-USB in low power mode\n");
 
 	return 0;
 }
@@ -936,7 +907,7 @@
 	}
 
 	enable_irq(hcd->irq);
-	dev_info(mehci->dev, "HSIC-USB exited from low power mode\n");
+	dev_dbg(mehci->dev, "HSIC-USB exited from low power mode\n");
 
 	return 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/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 4d5bbf84..c69071d 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -1008,9 +1008,11 @@
 	}
 
 	if (device_may_wakeup(phy->dev)) {
-		enable_irq_wake(motg->irq);
 		if (motg->async_irq)
 			enable_irq_wake(motg->async_irq);
+		else
+			enable_irq_wake(motg->irq);
+
 		if (motg->pdata->pmic_id_irq)
 			enable_irq_wake(motg->pdata->pmic_id_irq);
 		if (pdata->otg_control == OTG_PHY_CONTROL &&
@@ -1117,9 +1119,11 @@
 
 skip_phy_resume:
 	if (device_may_wakeup(phy->dev)) {
-		disable_irq_wake(motg->irq);
 		if (motg->async_irq)
 			disable_irq_wake(motg->async_irq);
+		else
+			disable_irq_wake(motg->irq);
+
 		if (motg->pdata->pmic_id_irq)
 			disable_irq_wake(motg->pdata->pmic_id_irq);
 		if (pdata->otg_control == OTG_PHY_CONTROL &&
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 0922f44..fbae011 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-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
@@ -780,6 +780,7 @@
 		case MDP_ARGB_8888:
 		case MDP_RGBA_8888:
 		case MDP_BGRA_8888:
+		case MDP_BGRX_8888:
 		case MDP_RGBX_8888:
 		case MDP_RGB_565:
 		case MDP_BGR_565:
@@ -967,6 +968,7 @@
 	case MDP_ARGB_8888:
 	case MDP_RGBA_8888:
 	case MDP_BGRA_8888:
+	case MDP_BGRX_8888:
 	case MDP_RGBX_8888:
 		return OVERLAY_TYPE_RGB;
 	case MDP_YCRYCB_H2V1:
@@ -1137,6 +1139,23 @@
 		pipe->element0 = C1_B_Cb;	/* B */
 		pipe->bpp = 4;		/* 4 bpp */
 		break;
+	case MDP_BGRX_8888:
+		pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
+		pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED;
+		pipe->a_bit = 3;        /* alpha, 4 bits */
+		pipe->r_bit = 3;        /* R, 8 bits */
+		pipe->b_bit = 3;        /* B, 8 bits */
+		pipe->g_bit = 3;        /* G, 8 bits */
+		pipe->alpha_enable = 0;
+		pipe->unpack_tight = 1;
+		pipe->unpack_align_msb = 0;
+		pipe->unpack_count = 3;
+		pipe->element3 = C3_ALPHA;      /* alpha */
+		pipe->element2 = C2_R_Cr;       /* R */
+		pipe->element1 = C0_G_Y;        /* G */
+		pipe->element0 = C1_B_Cb;       /* B */
+		pipe->bpp = 4;          /* 4 bpp */
+		break;
 	case MDP_YCRYCB_H2V1:
 		pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
 		pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED;
@@ -1324,6 +1343,7 @@
 	case MDP_XRGB_8888:
 	case MDP_ARGB_8888:
 	case MDP_BGRA_8888:
+	case MDP_BGRX_8888:
 		b_start = 0;
 		g_start = 8;
 		r_start = 16;
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 5070b03..b6882b8 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -57,13 +57,12 @@
 };
 
 struct mdss_data_type {
-	u32 rev;
 	u32 mdp_rev;
 	struct clk *mdp_clk[MDSS_MAX_CLK];
 	struct regulator *fs;
 
 	struct workqueue_struct *clk_ctrl_wq;
-	struct delayed_work clk_ctrl_worker;
+	struct work_struct clk_ctrl_worker;
 	struct platform_device *pdev;
 	char __iomem *mdp_base;
 	size_t mdp_reg_size;
@@ -80,6 +79,7 @@
 	u32 suspend;
 	u32 timeout;
 
+	atomic_t clk_ref;
 	u8 clk_ena;
 	u8 fs_ena;
 	u8 vsync_ena;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 79115d8..5c89938 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -417,9 +417,6 @@
 					mfd->op_enable);
 		if (ret)
 			pr_warn("can't turn on display!\n");
-
-		if (mfd->vsync_pending)
-			mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
 	}
 	mfd->is_power_setting = false;
 	complete_all(&mfd->power_set_comp);
@@ -618,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)
@@ -1037,16 +1040,23 @@
 
 void mdss_fb_wait_for_fence(struct msm_fb_data_type *mfd)
 {
-	int i, ret;
+	int i, ret = 0;
 	/* buf sync */
 	for (i = 0; i < mfd->acq_fen_cnt; i++) {
 		ret = sync_fence_wait(mfd->acq_fen[i], WAIT_FENCE_TIMEOUT);
-		sync_fence_put(mfd->acq_fen[i]);
 		if (ret < 0) {
 			pr_err("%s: sync_fence_wait failed! ret = %x\n",
 				__func__, ret);
 			break;
 		}
+		sync_fence_put(mfd->acq_fen[i]);
+	}
+
+	if (ret < 0) {
+		while (i < mfd->acq_fen_cnt) {
+			sync_fence_put(mfd->acq_fen[i]);
+			i++;
+		}
 	}
 	mfd->acq_fen_cnt = 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 31b80b1..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);
@@ -514,15 +514,19 @@
 	return clk_rate;
 }
 
-static void mdss_mdp_clk_ctrl_update(int enable)
+static void mdss_mdp_clk_ctrl_update(struct mdss_data_type *mdata)
 {
-	if (mdss_res->clk_ena == enable)
-		return;
-
-	pr_debug("MDP CLKS %s\n", (enable ? "Enable" : "Disable"));
+	int enable;
 
 	mutex_lock(&mdp_clk_lock);
-	mdss_res->clk_ena = enable;
+	enable = atomic_read(&mdata->clk_ref) > 0;
+	if (mdata->clk_ena == enable) {
+		mutex_unlock(&mdp_clk_lock);
+		return;
+	}
+	mdata->clk_ena = enable;
+
+	pr_debug("MDP CLKS %s\n", (enable ? "Enable" : "Disable"));
 	mb();
 
 	mdss_mdp_clk_update(MDSS_CLK_AHB, enable);
@@ -530,7 +534,7 @@
 
 	mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, enable);
 	mdss_mdp_clk_update(MDSS_CLK_MDP_LUT, enable);
-	if (mdss_res->vsync_ena)
+	if (mdata->vsync_ena)
 		mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, enable);
 
 	mutex_unlock(&mdp_clk_lock);
@@ -538,65 +542,37 @@
 
 static void mdss_mdp_clk_ctrl_workqueue_handler(struct work_struct *work)
 {
-	mdss_mdp_clk_ctrl(MDP_BLOCK_MASTER_OFF, false);
+	struct mdss_data_type *mdata;
+
+	mdata = container_of(work, struct mdss_data_type, clk_ctrl_worker);
+	mdss_mdp_clk_ctrl_update(mdata);
 }
 
 void mdss_mdp_clk_ctrl(int enable, int isr)
 {
-	static atomic_t clk_ref = ATOMIC_INIT(0);
-	static DEFINE_MUTEX(clk_ctrl_lock);
-	int force_off = 0;
+	struct mdss_data_type *mdata = mdss_res;
 
-	pr_debug("clk enable=%d isr=%d clk_ref=%d\n", enable, isr,
-			atomic_read(&clk_ref));
-	/*
-	 * It is assumed that if isr = TRUE then start = OFF
-	 * if start = ON when isr = TRUE it could happen that the usercontext
-	 * could turn off the clocks while the interrupt is updating the
-	 * power to ON
-	 */
-	WARN_ON(isr == true && enable);
+	pr_debug("clk enable=%d isr=%d ref= %d\n", enable, isr,
+			atomic_read(&mdata->clk_ref));
 
 	if (enable == MDP_BLOCK_POWER_ON) {
-		atomic_inc(&clk_ref);
-	} else if (!atomic_add_unless(&clk_ref, -1, 0)) {
-		if (enable == MDP_BLOCK_MASTER_OFF) {
-			pr_debug("master power-off req\n");
-			force_off = 1;
-		} else {
-			WARN(1, "too many mdp clock off call\n");
-		}
-	}
+		BUG_ON(isr);
 
-	WARN_ON(enable == MDP_BLOCK_MASTER_OFF && !force_off);
-
-	if (isr) {
-		/* if it's power off send workqueue to turn off clocks */
-		if (mdss_res->clk_ena && !atomic_read(&clk_ref))
-			queue_delayed_work(mdss_res->clk_ctrl_wq,
-					   &mdss_res->clk_ctrl_worker,
-					   mdss_res->timeout);
+		if (atomic_inc_return(&mdata->clk_ref) == 1)
+			mdss_mdp_clk_ctrl_update(mdata);
 	} else {
-		mutex_lock(&clk_ctrl_lock);
-		if (delayed_work_pending(&mdss_res->clk_ctrl_worker))
-			cancel_delayed_work(&mdss_res->clk_ctrl_worker);
+		BUG_ON(atomic_read(&mdata->clk_ref) == 0);
 
-		if (atomic_read(&clk_ref)) {
-			mdss_mdp_clk_ctrl_update(true);
-		} else if (mdss_res->clk_ena) {
-			mutex_lock(&mdp_suspend_mutex);
-			if (force_off || mdss_res->suspend) {
-				mdss_mdp_clk_ctrl_update(false);
-			} else {
-				/* send workqueue to turn off mdp power */
-				queue_delayed_work(mdss_res->clk_ctrl_wq,
-						   &mdss_res->clk_ctrl_worker,
-						   mdss_res->timeout);
-			}
-			mutex_unlock(&mdp_suspend_mutex);
+		if (atomic_dec_and_test(&mdata->clk_ref)) {
+			if (isr)
+				queue_work(mdata->clk_ctrl_wq,
+						&mdata->clk_ctrl_worker);
+			else
+				mdss_mdp_clk_ctrl_update(mdata);
 		}
-		mutex_unlock(&clk_ctrl_lock);
 	}
+
+
 }
 
 static inline int mdss_mdp_irq_clk_register(struct mdss_data_type *mdata,
@@ -636,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) ||
@@ -697,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;
 	}
 
@@ -778,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;
@@ -790,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");
 
@@ -817,14 +805,11 @@
 		return rc;
 
 	mdata->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq");
-	INIT_DELAYED_WORK(&mdata->clk_ctrl_worker,
-			  mdss_mdp_clk_ctrl_workqueue_handler);
+	INIT_WORK(&mdata->clk_ctrl_worker, mdss_mdp_clk_ctrl_workqueue_handler);
 
 	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)) {
@@ -834,10 +819,6 @@
 	}
 
 	rc = mdss_iommu_init(mdata);
-	if (!IS_ERR_VALUE(rc))
-		mdss_iommu_attach(mdata);
-
-	rc = mdss_hw_init(mdata);
 
 	return rc;
 }
@@ -935,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)) {
@@ -1345,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");
@@ -1362,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)
@@ -1375,22 +1354,6 @@
 		return ret;
 	}
 
-	cancel_delayed_work(&mdata->clk_ctrl_worker);
-
-	flush_workqueue(mdata->clk_ctrl_wq);
-
-	mdss_mdp_clk_ctrl(MDP_BLOCK_MASTER_OFF, false);
-
-	mutex_lock(&mdp_suspend_mutex);
-	mdata->suspend = true;
-	mutex_unlock(&mdp_suspend_mutex);
-
-	if (mdata->clk_ena) {
-		pr_err("MDP suspend failed\n");
-		return -EBUSY;
-	}
-	mdss_mdp_footswitch_ctrl(mdata, false);
-
 	pr_debug("suspend done\n");
 
 	return 0;
@@ -1400,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);
@@ -1414,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);
@@ -1422,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);
 }
@@ -1434,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)
 {
@@ -1499,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;
 }
@@ -1523,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.h b/drivers/video/msm/mdss/mdss_mdp.h
index 30b7695..5158974 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -32,8 +32,6 @@
 #define MAX_MIXER_HEIGHT	2400
 #define MAX_IMG_WIDTH		0x3FFF
 #define MAX_IMG_HEIGHT		0x3FFF
-#define MIN_DST_W		10
-#define MIN_DST_H		10
 #define MAX_DST_W		MAX_MIXER_WIDTH
 #define MAX_DST_H		MAX_MIXER_HEIGHT
 #define MAX_PLANES		4
@@ -66,7 +64,6 @@
 #endif
 
 enum mdss_mdp_block_power_state {
-	MDP_BLOCK_MASTER_OFF = -1,
 	MDP_BLOCK_POWER_OFF = 0,
 	MDP_BLOCK_POWER_ON = 1,
 };
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 63a1aa4..0f52125 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -267,6 +267,13 @@
 
 	mutex_lock(&mdss_mdp_ctl_lock);
 	ctl->ref_cnt--;
+	ctl->mixer_left = NULL;
+	ctl->mixer_right = NULL;
+	ctl->power_on = false;
+	ctl->start_fnc = NULL;
+	ctl->stop_fnc = NULL;
+	ctl->prepare_fnc = NULL;
+	ctl->display_fnc = NULL;
 	mutex_unlock(&mdss_mdp_ctl_lock);
 
 	return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 1aea4e0..0d4037c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -251,6 +251,7 @@
 				   NULL, NULL);
 
 	ctx->ref_cnt--;
+	ctl->priv_data = NULL;
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 283d3f0..2ae4830 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>
@@ -56,10 +57,19 @@
 				      struct mdss_mdp_format_params *fmt)
 {
 	u32 xres, yres;
+	u32 min_src_size, min_dst_size;
 
 	xres = mfd->fbi->var.xres;
 	yres = mfd->fbi->var.yres;
 
+	if (mfd->mdata->mdp_rev >= MDSS_MDP_HW_REV_102) {
+		min_src_size = fmt->is_yuv ? 2 : 1;
+		min_dst_size = 1;
+	} else {
+		min_src_size = fmt->is_yuv ? 10 : 5;
+		min_dst_size = 2;
+	}
+
 	if (req->z_order >= MDSS_MDP_MAX_STAGE) {
 		pr_err("zorder %d out of range\n", req->z_order);
 		return -ERANGE;
@@ -67,7 +77,7 @@
 
 	if (req->src.width > MAX_IMG_WIDTH ||
 	    req->src.height > MAX_IMG_HEIGHT ||
-	    req->src_rect.w == 0 || req->src_rect.h == 0 ||
+	    req->src_rect.w < min_src_size || req->src_rect.h < min_src_size ||
 	    CHECK_BOUNDS(req->src_rect.x, req->src_rect.w, req->src.width) ||
 	    CHECK_BOUNDS(req->src_rect.y, req->src_rect.h, req->src.height)) {
 		pr_err("invalid source image img wh=%dx%d rect=%d,%d,%d,%d\n",
@@ -77,18 +87,14 @@
 		return -EOVERFLOW;
 	}
 
-	if (req->dst_rect.w < MIN_DST_W || req->dst_rect.h < MIN_DST_H ||
+	if (req->dst_rect.w < min_dst_size || req->dst_rect.h < min_dst_size ||
 	    req->dst_rect.w > MAX_DST_W || req->dst_rect.h > MAX_DST_H) {
 		pr_err("invalid destination resolution (%dx%d)",
 		       req->dst_rect.w, req->dst_rect.h);
 		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) ||
@@ -154,10 +160,6 @@
 			pr_err("invalid odd src resolution or coordinates\n");
 			return -EINVAL;
 		}
-		if ((req->dst_rect.w & 0x1) || (req->dst_rect.h & 0x1)) {
-			pr_err("invalid odd dst resolution\n");
-			return -EINVAL;
-		}
 	}
 
 	return 0;
@@ -268,14 +270,16 @@
 		pipe->params_changed = true;
 	}
 
-	if (req->id == MSMFB_NEW_REQUEST) {
-		mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
-		if (!mixer) {
-			pr_err("unable to get mixer\n");
-			return -ENODEV;
-		}
+	mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
+	if (!mixer) {
+		pr_err("unable to get mixer\n");
+		return -ENODEV;
+	}
 
-		if (fmt->is_yuv || (req->flags & MDP_OV_PIPE_SHARE))
+	if (req->id == MSMFB_NEW_REQUEST) {
+		if (req->flags & MDP_OV_PIPE_FORCE_DMA)
+			pipe_type = MDSS_MDP_PIPE_TYPE_DMA;
+		else if (fmt->is_yuv || (req->flags & MDP_OV_PIPE_SHARE))
 			pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
 		else
 			pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
@@ -311,6 +315,21 @@
 			pr_err("invalid pipe ndx=%x\n", req->id);
 			return pipe ? PTR_ERR(pipe) : -ENODEV;
 		}
+
+		if (pipe->mixer != mixer) {
+			if (!mixer->ctl || (mixer->ctl->mfd != mfd)) {
+				pr_err("Can't switch mixer %d->%d pnum %d!\n",
+						pipe->mixer->num, mixer->num,
+						pipe->num);
+				mdss_mdp_pipe_unmap(pipe);
+				return -EINVAL;
+			}
+			pr_debug("switching pipe mixer %d->%d pnum %d\n",
+					pipe->mixer->num, mixer->num,
+					pipe->num);
+			mdss_mdp_mixer_pipe_unstage(pipe);
+			pipe->mixer = mixer;
+		}
 	}
 
 	pipe->flags = req->flags;
@@ -418,25 +437,28 @@
 					   int num_planes,
 					   u32 flags)
 {
-	int i;
+	int i, rc = 0;
+
+	if ((num_planes <= 0) || (num_planes > MAX_PLANES))
+		return -EINVAL;
 
 	memset(data, 0, sizeof(*data));
 	for (i = 0; i < num_planes; i++) {
 		data->p[i].flags = flags;
-		mdss_mdp_get_img(&planes[i], &data->p[i]);
-		if (data->p[0].len == 0)
+		rc = mdss_mdp_get_img(&planes[i], &data->p[i]);
+		if (rc) {
+			pr_err("failed to map buf p=%d flags=%x\n", i, flags);
+			while (i > 0) {
+				i--;
+				mdss_mdp_put_img(&data->p[i]);
+			}
 			break;
+		}
 	}
 
-	if (i != num_planes) {
-		for (; i >= 0; i--)
-			mdss_mdp_put_img(&data->p[i]);
-		return -ENOMEM;
-	}
+	data->num_planes = i;
 
-	data->num_planes = num_planes;
-
-	return 0;
+	return rc;
 }
 
 static inline int mdss_mdp_overlay_free_buf(struct mdss_mdp_data *data)
@@ -479,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);
@@ -580,6 +615,13 @@
 		unset_ndx |= pipe->ndx;
 		cnt++;
 	}
+
+	if (cnt == 0 && !list_empty(&mfd->pipes_cleanup)) {
+		pr_warn("overlay release on fb%d called without commit!",
+			mfd->index);
+		cnt++;
+	}
+
 	mutex_unlock(&mfd->lock);
 
 	if (unset_ndx) {
@@ -628,32 +670,29 @@
 	ret = mdss_mdp_overlay_get_buf(mfd, &src_data, &req->data, 1, flgs);
 	if (ret) {
 		pr_err("src_data pmem error\n");
-		goto rotate_done;
+		return ret;
 	}
 
 	ret = mdss_mdp_overlay_get_buf(mfd, &dst_data, &req->dst_data, 1, flgs);
 	if (ret) {
 		pr_err("dst_data pmem error\n");
-		goto rotate_done;
+		goto dst_buf_fail;
 	}
 
 	ret = mdss_mdp_rotator_queue(rot, &src_data, &dst_data);
-	if (ret) {
+	if (ret)
 		pr_err("rotator queue error session id=%x\n", req->id);
-		goto rotate_done;
-	}
 
-rotate_done:
 	mdss_mdp_overlay_free_buf(&dst_data);
+dst_buf_fail:
 	mdss_mdp_overlay_free_buf(&src_data);
 
-	return 0;
+	return ret;
 }
 
 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;
@@ -679,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;
@@ -714,12 +748,6 @@
 		ret = mdss_mdp_overlay_free_fb_pipe(mfd);
 	} else {
 		ret = mdss_mdp_overlay_queue(mfd, req);
-
-		if ((ret == 0) && (mfd->panel.type == WRITEBACK_PANEL)) {
-			mutex_unlock(&mfd->ov_lock);
-			ret = mdss_mdp_overlay_kickoff(mfd->ctl);
-			return ret;
-		}
 	}
 
 	mutex_unlock(&mfd->ov_lock);
@@ -1291,12 +1319,21 @@
 		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);
+
+		if (mfd->vsync_pending) {
+			mfd->vsync_pending = 0;
+			mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
+		}
 	} else {
 		mdss_mdp_ctl_destroy(mfd->ctl);
 		mfd->ctl = NULL;
+
+		pm_runtime_put(&mfd->pdev->dev);
 	}
 
 	return rc;
@@ -1329,6 +1366,8 @@
 
 		if (atomic_dec_return(&ov_active_panels) == 0)
 			mdss_mdp_rotator_release_all();
+
+		pm_runtime_put(&mfd->pdev->dev);
 	}
 
 	return rc;
@@ -1369,6 +1408,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/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 83e89c5..3b6fc38 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -296,7 +296,6 @@
 	pd = ((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db;
 
 	/* Strength ctrl 0 */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, 0x07);
 	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, pd->strength[0]);
 
 	/* phy regulator ctrl settings. Both the DSI controller
@@ -306,8 +305,11 @@
 	else
 		off = 0x0580 - 0x600;
 
-	/* Regulator ctrl - CAL_PWD_CFG */
+	/* Regulator ctrl 0 */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 0), 0x0);
+	/* Regulator ctrl - CAL_PWR_CFG */
 	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 6), pd->regulator[6]);
+
 	/* Regulator ctrl - TEST */
 	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 5), pd->regulator[5]);
 	/* Regulator ctrl 3 */
@@ -321,6 +323,12 @@
 	/* Regulator ctrl 4 */
 	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 4), pd->regulator[4]);
 
+	/* LDO ctrl 0 */
+	if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1)
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x4dc, 0x00);
+	else
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x4dc, 0x00);
+
 	off = 0x0440;	/* phy timing ctrl 0 - 11 */
 	for (i = 0; i < 12; i++) {
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->timing[i]);
@@ -352,7 +360,7 @@
 	}
 
 	/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x7f);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x5f);
 	wmb();
 
 	/* DSI_0_PHY_DSIPHY_GLBL_TEST_CTRL */
diff --git a/include/drm/kgsl_drm.h b/include/drm/kgsl_drm.h
index 7ffae9d..41f7c29 100644
--- a/include/drm/kgsl_drm.h
+++ b/include/drm/kgsl_drm.h
@@ -20,6 +20,7 @@
 #define DRM_KGSL_GEM_UNLOCK_ON_TS 0x0D
 #define DRM_KGSL_GEM_CREATE_FD 0x0E
 #define DRM_KGSL_GEM_GET_ION_FD 0x0F
+#define DRM_KGSL_GEM_CREATE_FROM_ION 0x10
 
 #define DRM_IOCTL_KGSL_GEM_CREATE \
 DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE, struct drm_kgsl_gem_create)
@@ -80,6 +81,10 @@
 DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_GET_ION_FD, \
 struct drm_kgsl_gem_get_ion_fd)
 
+#define DRM_IOCTL_KGSL_GEM_CREATE_FROM_ION \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE_FROM_ION, \
+struct drm_kgsl_gem_create_from_ion)
+
 /* Maximum number of sub buffers per GEM object */
 #define DRM_KGSL_GEM_MAX_BUFFERS 2
 
@@ -199,4 +204,9 @@
 	uint32_t handle;
 };
 
+struct drm_kgsl_gem_create_from_ion {
+	uint32_t ion_fd;
+	uint32_t handle;
+};
+
 #endif
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 1e49be4..7b3823e 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -23,6 +23,7 @@
 #define ___GFP_REPEAT		0x400u
 #define ___GFP_NOFAIL		0x800u
 #define ___GFP_NORETRY		0x1000u
+#define ___GFP_CMA		0x2000u
 #define ___GFP_COMP		0x4000u
 #define ___GFP_ZERO		0x8000u
 #define ___GFP_NOMEMALLOC	0x10000u
@@ -51,7 +52,9 @@
 #define __GFP_HIGHMEM	((__force gfp_t)___GFP_HIGHMEM)
 #define __GFP_DMA32	((__force gfp_t)___GFP_DMA32)
 #define __GFP_MOVABLE	((__force gfp_t)___GFP_MOVABLE)  /* Page is movable */
-#define GFP_ZONEMASK	(__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE)
+#define __GFP_CMA	((__force gfp_t)___GFP_CMA)
+#define GFP_ZONEMASK	(__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE| \
+			__GFP_CMA)
 /*
  * Action modifiers - doesn't change the zoning
  *
@@ -124,7 +127,7 @@
 #endif
 
 /* This mask makes up all the page movable related flags */
-#define GFP_MOVABLE_MASK (__GFP_RECLAIMABLE|__GFP_MOVABLE)
+#define GFP_MOVABLE_MASK (__GFP_RECLAIMABLE|__GFP_MOVABLE|__GFP_CMA)
 
 /* Control page allocator reclaim behavior */
 #define GFP_RECLAIM_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS|\
@@ -157,8 +160,14 @@
 		return MIGRATE_UNMOVABLE;
 
 	/* Group based on mobility */
+#ifndef CONFIG_CMA
 	return (((gfp_flags & __GFP_MOVABLE) != 0) << 1) |
 		((gfp_flags & __GFP_RECLAIMABLE) != 0);
+#else
+	return (((gfp_flags & __GFP_MOVABLE) != 0) << 1) |
+		(((gfp_flags & __GFP_CMA) != 0) << 1) |
+		((gfp_flags & __GFP_RECLAIMABLE) != 0);
+#endif
 }
 
 #ifdef CONFIG_HIGHMEM
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index d3999b4..c737eb7 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -211,9 +211,24 @@
 alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
 					unsigned long vaddr)
 {
+#ifndef CONFIG_CMA
 	return __alloc_zeroed_user_highpage(__GFP_MOVABLE, vma, vaddr);
+#else
+	return __alloc_zeroed_user_highpage(__GFP_MOVABLE|__GFP_CMA, vma,
+						vaddr);
+#endif
 }
 
+#ifdef CONFIG_CMA
+static inline struct page *
+alloc_zeroed_user_highpage_movable_cma(struct vm_area_struct *vma,
+						unsigned long vaddr)
+{
+	return __alloc_zeroed_user_highpage(__GFP_MOVABLE|__GFP_CMA, vma,
+						vaddr);
+}
+#endif
+
 static inline void clear_highpage(struct page *page)
 {
 	void *kaddr = kmap_atomic(page);
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/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 3ebf091..aed549e 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -29,6 +29,8 @@
 	(((ver == TABLA_VERSION_1_0) || (ver == TABLA_VERSION_1_1)) ? 1 : 0)
 #define TABLA_IS_2_0(ver) ((ver == TABLA_VERSION_2_0) ? 1 : 0)
 
+#define WCD9XXX_SUPPLY_BUCK_NAME "cdc-vdd-buck"
+
 #define SITAR_VERSION_1P0 0
 #define SITAR_VERSION_1P1 1
 #define SITAR_IS_1P0(ver) \
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
index 9c44e8b..412341a 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
@@ -196,4 +196,85 @@
 #define WCD9XXX_A_MAD_ANA_CTRL			(0x150)
 #define WCD9XXX_A_MAD_ANA_CTRL__POR		(0xF1)
 
+
+#define WCD9XXX_A_CDC_CLK_OTHR_CTL			(0x30C)
+#define WCD9XXX_A_CDC_CLK_OTHR_CTL__POR				(0x00)
+
+/* Class H related common registers */
+#define WCD9XXX_A_BUCK_MODE_1			(0x181)
+#define WCD9XXX_A_BUCK_MODE_1__POR				(0x21)
+#define WCD9XXX_A_BUCK_MODE_2			(0x182)
+#define WCD9XXX_A_BUCK_MODE_2__POR				(0xFF)
+#define WCD9XXX_A_BUCK_MODE_3			(0x183)
+#define WCD9XXX_A_BUCK_MODE_3__POR				(0xCC)
+#define WCD9XXX_A_BUCK_MODE_4			(0x184)
+#define WCD9XXX_A_BUCK_MODE_4__POR				(0x3A)
+#define WCD9XXX_A_BUCK_MODE_5			(0x185)
+#define WCD9XXX_A_BUCK_MODE_5__POR				(0x00)
+#define WCD9XXX_A_BUCK_CTRL_VCL_1			(0x186)
+#define WCD9XXX_A_BUCK_CTRL_VCL_1__POR				(0x48)
+#define WCD9XXX_A_BUCK_CTRL_VCL_2			(0x187)
+#define WCD9XXX_A_BUCK_CTRL_VCL_2__POR				(0xA3)
+#define WCD9XXX_A_BUCK_CTRL_VCL_3			(0x188)
+#define WCD9XXX_A_BUCK_CTRL_VCL_3__POR				(0x82)
+#define WCD9XXX_A_BUCK_CTRL_CCL_1			(0x189)
+#define WCD9XXX_A_BUCK_CTRL_CCL_1__POR				(0xAB)
+#define WCD9XXX_A_BUCK_CTRL_CCL_2			(0x18A)
+#define WCD9XXX_A_BUCK_CTRL_CCL_2__POR				(0xDC)
+#define WCD9XXX_A_BUCK_CTRL_CCL_3			(0x18B)
+#define WCD9XXX_A_BUCK_CTRL_CCL_3__POR				(0x6A)
+#define WCD9XXX_A_BUCK_CTRL_CCL_4			(0x18C)
+#define WCD9XXX_A_BUCK_CTRL_CCL_4__POR				(0x58)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_1			(0x18D)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_1__POR				(0x50)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_2			(0x18E)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_2__POR				(0x64)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_3			(0x18F)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_3__POR				(0x77)
+#define WCD9XXX_A_BUCK_TMUX_A_D			(0x190)
+#define WCD9XXX_A_BUCK_TMUX_A_D__POR				(0x00)
+#define WCD9XXX_A_NCP_EN			(0x192)
+#define WCD9XXX_A_NCP_EN__POR				(0xFE)
+#define WCD9XXX_A_NCP_STATIC			(0x194)
+#define WCD9XXX_A_NCP_STATIC__POR				(0x28)
+#define WCD9XXX_A_NCP_BUCKREF			(0x191)
+#define WCD9XXX_A_NCP_BUCKREF__POR				(0x00)
+#define WCD9XXX_A_CDC_CLSH_B1_CTL			(0x320)
+#define WCD9XXX_A_CDC_CLSH_B1_CTL__POR				(0xE4)
+#define WCD9XXX_A_CDC_CLSH_B2_CTL			(0x321)
+#define WCD9XXX_A_CDC_CLSH_B2_CTL__POR				(0x00)
+#define WCD9XXX_A_CDC_CLSH_B3_CTL			(0x322)
+#define WCD9XXX_A_CDC_CLSH_B3_CTL__POR				(0x00)
+#define WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS			(0x323)
+#define WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS__POR			(0x00)
+#define WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD			(0x324)
+#define WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD__POR			(0x12)
+#define WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD			(0x325)
+#define WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD__POR			(0x0C)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD			(0x326)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD__POR		(0x18)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD			(0x327)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD__POR		(0x23)
+#define WCD9XXX_A_CDC_CLSH_K_ADDR			(0x328)
+#define WCD9XXX_A_CDC_CLSH_K_ADDR__POR				(0x00)
+#define WCD9XXX_A_CDC_CLSH_K_DATA			(0x329)
+#define WCD9XXX_A_CDC_CLSH_K_DATA__POR				(0xA4)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L			(0x32A)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L__POR				(0xD7)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U			(0x32B)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U__POR				(0x05)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L			(0x32C)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L__POR				(0x60)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U			(0x32D)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U__POR				(0x09)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR			(0x32E)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR__POR				(0x00)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH			(0x32F)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH__POR				(0x00)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR			(0x330)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR__POR				(0x00)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH			(0x331)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH__POR				(0x00)
+
+
 #endif
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 90980b7..6e12694 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -390,6 +390,7 @@
 	 * process to make sure that the system is not starved.
 	 */
 	unsigned long		min_cma_pages;
+	bool			cma_alloc;
 #endif
 	struct free_area	free_area[MAX_ORDER];
 
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index 471f10a..f0c4915 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -49,6 +49,10 @@
 			(AUDIO_MAX_COMMON_IOCTL_NUM+21), unsigned)
 #define AUDIO_SET_LSM_CAL		_IOW(AUDIO_IOCTL_MAGIC, \
 			(AUDIO_MAX_COMMON_IOCTL_NUM+22), unsigned)
+#define AUDIO_SET_ADM_CUSTOM_TOPOLOGY	_IOW(AUDIO_IOCTL_MAGIC, \
+			(AUDIO_MAX_COMMON_IOCTL_NUM+23), unsigned)
+#define AUDIO_SET_ASM_CUSTOM_TOPOLOGY	_IOW(AUDIO_IOCTL_MAGIC, \
+			(AUDIO_MAX_COMMON_IOCTL_NUM+24), unsigned)
 
 #define	AUDIO_MAX_ACDB_IOCTL	(AUDIO_MAX_COMMON_IOCTL_NUM+30)
 
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index ffa819f..409bcc8 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -22,6 +22,7 @@
 	ION_HEAP_TYPE_MSM_START = ION_HEAP_TYPE_CUSTOM + 1,
 	ION_HEAP_TYPE_IOMMU = ION_HEAP_TYPE_MSM_START,
 	ION_HEAP_TYPE_CP,
+	ION_HEAP_TYPE_SECURE_DMA,
 };
 
 /**
diff --git a/include/linux/msm_ipa.h b/include/linux/msm_ipa.h
index 613cd9f..1b869b1 100644
--- a/include/linux/msm_ipa.h
+++ b/include/linux/msm_ipa.h
@@ -47,7 +47,7 @@
 #define IPA_IOCTL_V4_INIT_NAT    23
 #define IPA_IOCTL_NAT_DMA        24
 #define IPA_IOCTL_V4_DEL_NAT     26
-#define IPA_IOCTL_GET_ASYNC_MSG  27
+#define IPA_IOCTL_PULL_MSG       27
 #define IPA_IOCTL_GET_NAT_OFFSET 28
 #define IPA_IOCTL_MAX            29
 
@@ -62,6 +62,11 @@
 #define IPA_RESOURCE_NAME_MAX 20
 
 /**
+ * size of the mac address
+ */
+#define IPA_MAC_ADDR_SIZE  6
+
+/**
  * the attributes of the rule (routing or filtering)
  */
 #define IPA_FLT_TOS            (1ul << 0)
@@ -142,6 +147,26 @@
 };
 
 /**
+ * enum ipa_wlan_event - Events for wlan client
+ *
+ * wlan client connect: New wlan client connected
+ * wlan client disconnect: wlan client disconnected
+ * wlan client power save: wlan client moved to power save
+ * wlan client normal: wlan client moved out of power save
+ * sw routing enable: ipa routing is disabled
+ * sw routing disable: ipa routing is enabled
+ */
+enum ipa_wlan_event {
+	WLAN_CLIENT_CONNECT,
+	WLAN_CLIENT_DISCONNECT,
+	WLAN_CLIENT_POWER_SAVE_MODE,
+	WLAN_CLIENT_NORMAL_MODE,
+	SW_ROUTING_ENABLE,
+	SW_ROUTING_DISABLE,
+};
+
+
+/**
  * struct ipa_rule_attrib - attributes of a routing/filtering
  * rule, all in LE
  * @attrib_mask: what attributes are valid
@@ -501,10 +526,12 @@
 /**
  * struct ipa_ioc_query_intf_tx_props - interface tx propertie
  * @name: name of interface
+ * @num_tx_props: number of TX properties
  * @tx[0]: output parameter, the tx properties go here back to back
  */
 struct ipa_ioc_query_intf_tx_props {
 	char name[IPA_RESOURCE_NAME_MAX];
+	uint32_t num_tx_props;
 	struct ipa_ioc_tx_intf_prop tx[0];
 };
 
@@ -523,10 +550,12 @@
 /**
  * struct ipa_ioc_query_intf_rx_props - interface rx propertie
  * @name: name of interface
+ * @num_rx_props: number of RX properties
  * @rx: output parameter, the rx properties go here back to back
  */
 struct ipa_ioc_query_intf_rx_props {
 	char name[IPA_RESOURCE_NAME_MAX];
+	uint32_t num_rx_props;
 	struct ipa_ioc_rx_intf_prop rx[0];
 };
 
@@ -609,24 +638,45 @@
 /**
  * struct ipa_msg_meta - Format of the message meta-data.
  * @msg_type: the type of the message
- * @msg_len: the length of the message in bytes
  * @rsvd: reserved bits for future use.
+ * @msg_len: the length of the message in bytes
  *
+ * For push model:
  * Client in user-space should issue a read on the device (/dev/ipa) with a
- * buffer of atleast this size in an continuous loop, call will block when there
- * is no pending async message.
+ * sufficiently large buffer in a continuous loop, call will block when there is
+ * no message to read. Upon return, client can read the ipa_msg_meta from start
+ * of buffer to find out type and length of message
+ * size of buffer supplied >= (size of largest message + size of metadata)
  *
- * After reading a message's meta-data using above scheme, client should issue a
- * GET_MSG IOCTL to actually read the message itself into the buffer of
- * "msg_len" immediately following the ipa_msg_meta itself in the IOCTL payload
+ * For pull model:
+ * Client in user-space can also issue a pull msg IOCTL to device (/dev/ipa)
+ * with a payload containing space for the ipa_msg_meta and the message specific
+ * payload length.
+ * size of buffer supplied == (len of specific message  + size of metadata)
  */
 struct ipa_msg_meta {
 	uint8_t msg_type;
-	uint16_t msg_len;
 	uint8_t rsvd;
+	uint16_t msg_len;
 };
 
 /**
+ * struct ipa_wlan_msg - To hold information about wlan client
+ * @name: name of the wlan interface
+ * @mac_addr: mac address of wlan client
+ *
+ * wlan drivers need to pass name of wlan iface and mac address of
+ * wlan client along with ipa_wlan_event, whenever a wlan client is
+ * connected/disconnected/moved to power save/come out of power save
+ */
+struct ipa_wlan_msg {
+	char name[IPA_RESOURCE_NAME_MAX];
+	uint8_t mac_addr[IPA_MAC_ADDR_SIZE];
+};
+
+
+
+/**
  *   actual IOCTLs supported by IPA driver
  */
 #define IPA_IOC_ADD_HDR _IOWR(IPA_IOC_MAGIC, \
@@ -707,8 +757,8 @@
 #define IPA_IOC_SET_FLT _IOW(IPA_IOC_MAGIC, \
 			IPA_IOCTL_SET_FLT, \
 			uint32_t)
-#define IPA_IOC_GET_ASYNC_MSG _IOWR(IPA_IOC_MAGIC, \
-				IPA_IOCTL_GET_ASYNC_MSG, \
+#define IPA_IOC_PULL_MSG _IOWR(IPA_IOC_MAGIC, \
+				IPA_IOCTL_PULL_MSG, \
 				struct ipa_msg_meta *)
 
 #endif /* _MSM_IPA_H_ */
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 3ec966b..bc35d14 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -114,6 +114,7 @@
 	MDP_BGR_565,      /* BGR 565 planer */
 	MDP_BGR_888,      /* BGR 888 */
 	MDP_Y_CBCR_H2V2_VENUS,
+	MDP_BGRX_8888,   /* BGRX 8888 */
 	MDP_IMGTYPE_LIMIT,
 	MDP_RGB_BORDERFILL,	/* border fill pipe */
 	MDP_FB_FORMAT = MDP_IMGTYPE2_START,    /* framebuffer format */
@@ -166,6 +167,7 @@
 #define MDP_BACKEND_COMPOSITION		0x00040000
 #define MDP_BORDERFILL_SUPPORTED	0x00010000
 #define MDP_SECURE_OVERLAY_SESSION      0x00008000
+#define MDP_OV_PIPE_FORCE_DMA		0x00004000
 #define MDP_MEMORY_ID_TYPE_FB		0x00001000
 
 #define MDP_TRANSP_NOP 0xffffffff
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/cdc.h b/include/linux/usb/cdc.h
index 2b39f69..478734f 100644
--- a/include/linux/usb/cdc.h
+++ b/include/linux/usb/cdc.h
@@ -54,6 +54,7 @@
 #define USB_CDC_OBEX_TYPE		0x15
 #define USB_CDC_NCM_TYPE		0x1a
 #define USB_CDC_MBB_TYPE		0x1b	/* mbb_desc */
+#define USB_CDC_EXT_MBB_TYPE		0x1c
 
 /* "Header Functional Descriptor" from CDC spec  5.2.3.1 */
 struct usb_cdc_header_desc {
@@ -203,6 +204,17 @@
 	__u8	bmNetworkCapabilities;
 } __packed;
 
+/* "Extended MBIM Functional Descriptor" */
+struct usb_cdc_ext_mbb_desc {
+	__u8	bLength;
+	__u8	bDescriptorType;
+	__u8	bDescriptorSubType;
+
+	__le16	bcdMbbExtendedVersion;
+	__u8	bMaxOutstandingCmdMsges;
+	__le16	wMTU;
+} __packed;
+
 /*-------------------------------------------------------------------------*/
 
 /*
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/linux/usb/rmnet_ctrl_qti.h b/include/linux/usb/rmnet_ctrl_qti.h
new file mode 100644
index 0000000..5038396
--- /dev/null
+++ b/include/linux/usb/rmnet_ctrl_qti.h
@@ -0,0 +1,12 @@
+#ifndef __LINUX_USB_U_RMNET_CTRL_QTI_H
+#define __LINUX_USB_U_RMNET_CTRL_QTI_H
+
+#include <linux/ioctl.h>
+
+#define MAX_QTI_PKT_SIZE 2048
+
+#define FRMNET_CTRL_IOCTL_MAGIC	'r'
+#define FRMNET_CTRL_GET_LINE_STATE	_IOR(FRMNET_CTRL_IOCTL_MAGIC, 2, int)
+
+
+#endif /* __LINUX_USB_U_RMNET_CTRL_QTI_H */
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_generic_buf_mgr.h b/include/media/msmb_generic_buf_mgr.h
index 13844a3..17cb947 100644
--- a/include/media/msmb_generic_buf_mgr.h
+++ b/include/media/msmb_generic_buf_mgr.h
@@ -5,6 +5,7 @@
 	uint32_t session_id;
 	uint32_t stream_id;
 	uint32_t frame_id;
+	struct timeval timestamp;
 	uint32_t index;
 };
 
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index c9d3f15..34b3139 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -45,7 +45,9 @@
 	PIX_VIEWFINDER,
 	CAMIF_RAW,
 	IDEAL_RAW,
-	RDI,
+	RDI_INTF_0,
+	RDI_INTF_1,
+	RDI_INTF_2,
 	VFE_AXI_SRC_MAX
 };
 
@@ -94,12 +96,17 @@
 	enum ISP_START_PIXEL_PATTERN pixel_pattern;
 };
 
+struct msm_vfe_rdi_cfg {
+	uint8_t cid;
+	uint8_t frame_based;
+};
+
 struct msm_vfe_input_cfg {
 	union {
 		struct msm_vfe_pix_cfg pix_cfg;
+		struct msm_vfe_rdi_cfg rdi_cfg;
 	} d;
 	enum msm_vfe_input_src input_src;
-
 };
 
 struct msm_vfe_axi_plane_cfg {
@@ -281,14 +288,15 @@
 	ISP_WM_BUS_OVERFLOW = 4,
 	ISP_STATS_OVERFLOW  = 5,
 	ISP_CAMIF_ERROR     = 6,
-	ISP_STATS_NOTIFY    = 7,
-	ISP_SOF             = 8,
-	ISP_EOF             = 9,
-	ISP_BUF_DIVERT      = 10,
-	ISP_EVENT_MAX       = 11
+	ISP_SOF             = 7,
+	ISP_EOF             = 8,
+	ISP_EVENT_MAX       = 9
 };
 
-#define ISP_EVENT_BASE            (V4L2_EVENT_PRIVATE_START + 1)
+#define ISP_EVENT_OFFSET          8
+#define ISP_EVENT_BASE            (V4L2_EVENT_PRIVATE_START)
+#define ISP_BUF_EVENT_BASE        (ISP_EVENT_BASE + (1 << ISP_EVENT_OFFSET))
+#define ISP_STATS_EVENT_BASE      (ISP_EVENT_BASE + (2 << ISP_EVENT_OFFSET))
 #define ISP_EVENT_REG_UPDATE      (ISP_EVENT_BASE + ISP_REG_UPDATE)
 #define ISP_EVENT_START_ACK       (ISP_EVENT_BASE + ISP_START_ACK)
 #define ISP_EVENT_STOP_ACK        (ISP_EVENT_BASE + ISP_STOP_ACK)
@@ -296,11 +304,10 @@
 #define ISP_EVENT_WM_BUS_OVERFLOW (ISP_EVENT_BASE + ISP_WM_BUS_OVERFLOW)
 #define ISP_EVENT_STATS_OVERFLOW  (ISP_EVENT_BASE + ISP_STATS_OVERFLOW)
 #define ISP_EVENT_CAMIF_ERROR     (ISP_EVENT_BASE + ISP_CAMIF_ERROR)
-#define ISP_EVENT_STATS_NOTIFY    (ISP_EVENT_BASE + ISP_STATS_NOTIFY)
 #define ISP_EVENT_SOF             (ISP_EVENT_BASE + ISP_SOF)
 #define ISP_EVENT_EOF             (ISP_EVENT_BASE + ISP_EOF)
-#define ISP_EVENT_BUF_DIVERT      (ISP_EVENT_BASE + ISP_BUF_DIVERT)
-
+#define ISP_EVENT_BUF_DIVERT      (ISP_BUF_EVENT_BASE)
+#define ISP_EVENT_STATS_NOTIFY    (ISP_STATS_EVENT_BASE)
 
 /* The msm_v4l2_event_data structure should match the
  * v4l2_event.u.data field.
@@ -324,6 +331,9 @@
 };
 
 struct msm_isp_event_data {
+	/*Wall clock except for buffer divert events
+	 *which use monotonic clock
+	 */
 	struct timeval timestamp;
 	/* if pix is a src frame_id is from camif */
 	uint32_t frame_id;
@@ -340,6 +350,19 @@
 	} u; /* union can have max 52 bytes */
 };
 
+#define V4L2_PIX_FMT_QBGGR8  v4l2_fourcc('Q', 'B', 'G', '8')
+#define V4L2_PIX_FMT_QGBRG8  v4l2_fourcc('Q', 'G', 'B', '8')
+#define V4L2_PIX_FMT_QGRBG8  v4l2_fourcc('Q', 'G', 'R', '8')
+#define V4L2_PIX_FMT_QRGGB8  v4l2_fourcc('Q', 'R', 'G', '8')
+#define V4L2_PIX_FMT_QBGGR10 v4l2_fourcc('Q', 'B', 'G', '0')
+#define V4L2_PIX_FMT_QGBRG10 v4l2_fourcc('Q', 'G', 'B', '0')
+#define V4L2_PIX_FMT_QGRBG10 v4l2_fourcc('Q', 'G', 'R', '0')
+#define V4L2_PIX_FMT_QRGGB10 v4l2_fourcc('Q', 'R', 'G', '0')
+#define V4L2_PIX_FMT_QBGGR12 v4l2_fourcc('Q', 'B', 'G', '2')
+#define V4L2_PIX_FMT_QGBRG12 v4l2_fourcc('Q', 'G', 'B', '2')
+#define V4L2_PIX_FMT_QGRBG12 v4l2_fourcc('Q', 'G', 'R', '2')
+#define V4L2_PIX_FMT_QRGGB12 v4l2_fourcc('Q', 'R', 'G', '2')
+
 #define VIDIOC_MSM_VFE_REG_CFG \
 	_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_vfe_cfg_cmd2)
 
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
new file mode 100644
index 0000000..b003f99
--- /dev/null
+++ b/include/media/msmb_pproc.h
@@ -0,0 +1,117 @@
+#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 VIDIOC_MSM_CPP_LOAD_FIRMWARE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 3, 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/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index badbd8e..e909195 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (c) 2000-2001, 2010-2012 The Linux Foundation.  All rights reserved.
+   Copyright (c) 2000-2001, 2010-2013 The Linux Foundation. All rights reserved.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -63,6 +63,7 @@
 #define BT_SECURITY_LOW		1
 #define BT_SECURITY_MEDIUM	2
 #define BT_SECURITY_HIGH	3
+#define BT_SECURITY_VERY_HIGH	4
 
 #define BT_DEFER_SETUP	7
 #define BT_FLUSHABLE	8
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 4555b08..93f0aa90 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -82,6 +82,14 @@
 */
 #define ADM_CMD_DEVICE_OPEN_V5                          0x00010326
 
+#define ADM_BIT_SHIFT_DEVICE_PERF_MODE_FLAG                           13
+
+/* Definition for a legacy device session. */
+#define ADM_LEGACY_DEVICE_SESSION                                      0
+
+/* Definition for a low latency stream session. */
+#define ADM_LOW_LATENCY_DEVICE_SESSION                                 1
+
 /* Indicates that endpoint_id_2 is to be ignored.*/
 #define ADM_CMD_COPP_OPEN_END_POINT_ID_2_IGNORE				0xFFFF
 
@@ -3794,8 +3802,15 @@
 
 /* adsp_asm_session_command.h*/
 #define ASM_STREAM_CMD_OPEN_WRITE_V2       0x00010D8F
+#define ASM_STREAM_CMD_OPEN_WRITE_V3       0x00010DB3
 
-struct asm_stream_cmd_open_write_v2 {
+#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_WRITE                     28
+
+#define ASM_LEGACY_STREAM_SESSION                                      0
+
+#define ASM_LOW_LATENCY_STREAM_SESSION                                  1
+
+struct asm_stream_cmd_open_write_v3 {
 	struct apr_hdr			hdr;
 	uint32_t                    mode_flags;
 /* Mode flags that configure the stream to notify the client
@@ -3878,6 +3893,9 @@
 } __packed;
 
 #define ASM_STREAM_CMD_OPEN_READ_V2                 0x00010D8C
+
+#define ASM_STREAM_CMD_OPEN_READ_V3                 0x00010DB4
+
 /* Definition of the timestamp type flag bitmask */
 #define ASM_BIT_MASKIMESTAMPYPE_FLAG        (0x00000020UL)
 
@@ -3890,8 +3908,10 @@
 /* Absolute timestamp is identified by this value.*/
 #define ASM_ABSOLUTEIMESTAMP      1
 
+/* Bit shift for the stream_perf_mode subfield. */
+#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ              29
 
-struct asm_stream_cmd_open_read_v2 {
+struct asm_stream_cmd_open_read_v3 {
 	struct apr_hdr hdr;
 	u32                    mode_flags;
 /* Mode flags that indicate whether meta information per encoded
@@ -6215,6 +6235,22 @@
 #define VOICE_CMD_GET_PARAM				0x0001133E
 #define VOICE_EVT_GET_PARAM_ACK				0x00011008
 
+/* Set Q6 topologies */
+#define ASM_CMD_ADD_TOPOLOGIES				0x00010DBE
+#define ADM_CMD_ADD_TOPOLOGIES				0x00010335
+
+/* structure used for both ioctls */
+struct cmd_set_topologies {
+	struct apr_hdr hdr;
+	u32		payload_addr_lsw;
+	/* LSW of parameter data payload address.*/
+	u32		payload_addr_msw;
+	/* MSW of parameter data payload address.*/
+	u32		mem_map_handle;
+	/* Memory map handle returned by mem map command */
+	u32		payload_size;
+	/* Size in bytes of the variable payload in shared memory */
+} __packed;
 
 /* SRS TRUMEDIA start */
 /* topology */
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 6e5e649..77a805c 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -29,10 +29,11 @@
 
 int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params);
 
-int adm_open(int port, int path, int rate, int mode, int topology);
+int adm_open(int port, int path, int rate, int mode, int topology,
+				bool perf_mode, uint16_t bits_per_sample);
 
 int adm_multi_ch_copp_open(int port, int path, int rate, int mode,
-				int topology);
+			int topology, bool perf_mode, uint16_t bits_per_sample);
 
 int adm_memory_map_regions(int port_id, uint32_t *buf_add, uint32_t mempool_id,
 				uint32_t *bufsz, uint32_t bufcnt);
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 984571b..dc30cd6 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -139,7 +139,7 @@
 	app_cb		       cb;
 	atomic_t	       cmd_state;
 	/* Relative or absolute TS */
-	uint32_t	       time_flag;
+	atomic_t	       time_flag;
 	atomic_t	       nowait_cmd_cnt;
 	void		       *priv;
 	uint32_t               io_mode;
@@ -150,6 +150,8 @@
 	/* idx:1 out port, 0: in port*/
 	struct audio_port_data port[2];
 	wait_queue_head_t      cmd_wait;
+	wait_queue_head_t      time_wait;
+	bool                   perf_mode;
 };
 
 void q6asm_audio_client_free(struct audio_client *ac);
@@ -177,6 +179,9 @@
 int q6asm_open_write(struct audio_client *ac, uint32_t format
 		/*, uint16_t bits_per_sample*/);
 
+int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
+			uint16_t bits_per_sample);
+
 int q6asm_open_read_write(struct audio_client *ac,
 			uint32_t rd_format,
 			uint32_t wr_format);
@@ -261,10 +266,20 @@
 int q6asm_media_format_block_pcm(struct audio_client *ac,
 			uint32_t rate, uint32_t channels);
 
+int q6asm_media_format_block_pcm_format_support(struct audio_client *ac,
+			uint32_t rate, uint32_t channels,
+			uint16_t bits_per_sample);
+
 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
 			uint32_t rate, uint32_t channels,
 			bool use_default_chmap, char *channel_map);
 
+int q6asm_media_format_block_multi_ch_pcm_v2(
+			struct audio_client *ac,
+			uint32_t rate, uint32_t channels,
+			bool use_default_chmap, char *channel_map,
+			uint16_t bits_per_sample);
+
 int q6asm_media_format_block_aac(struct audio_client *ac,
 			struct asm_aac_cfg *cfg);
 
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 1de24ac..d6dd07a 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1121,6 +1121,37 @@
 	return page;
 }
 
+static struct page *__rmqueue_cma(struct zone *zone, unsigned int order,
+							int migratetype)
+{
+	struct page *page = 0;
+#ifdef CONFIG_CMA
+	if (migratetype == MIGRATE_MOVABLE && !zone->cma_alloc)
+		page = __rmqueue_smallest(zone, order, MIGRATE_CMA);
+	else
+#endif
+retry_reserve :
+		page = __rmqueue_smallest(zone, order, migratetype);
+
+
+	if (unlikely(!page) && migratetype != MIGRATE_RESERVE) {
+		page = __rmqueue_fallback(zone, order, migratetype);
+
+		/*
+		 * Use MIGRATE_RESERVE rather than fail an allocation. goto
+		 * is used because __rmqueue_smallest is an inline function
+		 * and we want just one call site
+		 */
+		if (!page) {
+			migratetype = MIGRATE_RESERVE;
+			goto retry_reserve;
+		}
+	}
+
+	trace_mm_page_alloc_zone_locked(page, order, migratetype);
+	return page;
+}
+
 /*
  * Obtain a specified number of elements from the buddy allocator, all under
  * a single hold of the lock, for efficiency.  Add them to the supplied list.
@@ -1128,13 +1159,17 @@
  */
 static int rmqueue_bulk(struct zone *zone, unsigned int order,
 			unsigned long count, struct list_head *list,
-			int migratetype, int cold)
+			int migratetype, int cold, int cma)
 {
 	int mt = migratetype, i;
 
 	spin_lock(&zone->lock);
 	for (i = 0; i < count; ++i) {
-		struct page *page = __rmqueue(zone, order, migratetype);
+		struct page *page;
+		if (cma)
+			page = __rmqueue_cma(zone, order, migratetype);
+		else
+			page = __rmqueue(zone, order, migratetype);
 		if (unlikely(page == NULL))
 			break;
 
@@ -1338,7 +1373,8 @@
 	 * excessively into the page allocator
 	 */
 	if (migratetype >= MIGRATE_PCPTYPES) {
-		if (unlikely(migratetype == MIGRATE_ISOLATE)) {
+		if (unlikely(migratetype == MIGRATE_ISOLATE) ||
+			     is_migrate_cma(migratetype)) {
 			free_one_page(zone, page, 0, migratetype);
 			goto out;
 		}
@@ -1480,7 +1516,8 @@
 		if (list_empty(list)) {
 			pcp->count += rmqueue_bulk(zone, 0,
 					pcp->batch, list,
-					migratetype, cold);
+					migratetype, cold,
+					gfp_flags & __GFP_CMA);
 			if (unlikely(list_empty(list)))
 				goto failed;
 		}
@@ -1507,7 +1544,10 @@
 			WARN_ON_ONCE(order > 1);
 		}
 		spin_lock_irqsave(&zone->lock, flags);
-		page = __rmqueue(zone, order, migratetype);
+		if (gfp_flags & __GFP_CMA)
+			page = __rmqueue_cma(zone, order, migratetype);
+		else
+			page = __rmqueue(zone, order, migratetype);
 		spin_unlock(&zone->lock);
 		if (!page)
 			goto failed;
@@ -5884,6 +5924,8 @@
 	if (ret)
 		goto done;
 
+	zone->cma_alloc = 1;
+
 	ret = __alloc_contig_migrate_range(start, end);
 	if (ret)
 		goto done;
@@ -5948,6 +5990,7 @@
 done:
 	undo_isolate_page_range(pfn_max_align_down(start),
 				pfn_max_align_up(end), migratetype);
+	zone->cma_alloc = 0;
 	return ret;
 }
 
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 15d3585..198773c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved.
+   Copyright (c) 2000-2001, 2010-2013 The Linux Foundation. All rights reserved.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -2046,7 +2046,7 @@
 							sizeof(cp), &cp);
 		goto unlock;
 	} else  if (!(lmp_ssp_capable(conn)) && conn->auth_initiator &&
-		(conn->pending_sec_level == BT_SECURITY_HIGH)) {
+		(conn->pending_sec_level == BT_SECURITY_VERY_HIGH)) {
 		conn->pending_sec_level = BT_SECURITY_MEDIUM;
 	}
 
@@ -2669,6 +2669,12 @@
 		BT_DBG("Conn pending sec level is %d, ssp is %d, key len is %d",
 			conn->pending_sec_level, conn->ssp_mode, key->pin_len);
 	}
+	if (conn && (conn->ssp_mode == 0) &&
+		(conn->pending_sec_level == BT_SECURITY_VERY_HIGH) &&
+		(key->pin_len != 16)) {
+		BT_DBG("Security is high ignoring this key");
+		goto not_found;
+	}
 
 	if (key->key_type == 0x04 && conn && conn->auth_type != 0xff &&
 						(conn->auth_type & 0x01)) {
@@ -2853,14 +2859,14 @@
 
 		conn->ssp_mode = (ev->features[0] & 0x01);
 		/*In case if remote device ssp supported/2.0 device
-		reduce the security level to MEDIUM if it is HIGH*/
+		reduce the security level to MEDIUM if it is VERY HIGH*/
 		if (!conn->ssp_mode && conn->auth_initiator &&
-			(conn->pending_sec_level == BT_SECURITY_HIGH))
+			(conn->pending_sec_level == BT_SECURITY_VERY_HIGH))
 			conn->pending_sec_level = BT_SECURITY_MEDIUM;
 
 		if (conn->ssp_mode && conn->auth_initiator &&
 			conn->io_capability != 0x03) {
-			conn->pending_sec_level = BT_SECURITY_HIGH;
+			conn->pending_sec_level = BT_SECURITY_VERY_HIGH;
 			conn->auth_type = HCI_AT_DEDICATED_BONDING_MITM;
 		}
 	}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 6eab6d0..fd9088a 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (c) 2000-2001, 2010-2012 The Linux Foundation.  All rights reserved.
+   Copyright (c) 2000-2001, 2010-2013 The Linux Foundation. All rights reserved.
    Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
    Copyright (C) 2010 Google Inc.
 
@@ -610,6 +610,7 @@
 {
 	if (sk->sk_type == SOCK_RAW) {
 		switch (l2cap_pi(sk)->sec_level) {
+		case BT_SECURITY_VERY_HIGH:
 		case BT_SECURITY_HIGH:
 			return HCI_AT_DEDICATED_BONDING_MITM;
 		case BT_SECURITY_MEDIUM:
@@ -621,12 +622,14 @@
 		if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
 			l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
 
-		if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+		if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH ||
+			l2cap_pi(sk)->sec_level == BT_SECURITY_VERY_HIGH)
 			return HCI_AT_NO_BONDING_MITM;
 		else
 			return HCI_AT_NO_BONDING;
 	} else {
 		switch (l2cap_pi(sk)->sec_level) {
+		case BT_SECURITY_VERY_HIGH:
 		case BT_SECURITY_HIGH:
 			return HCI_AT_GENERAL_BONDING_MITM;
 		case BT_SECURITY_MEDIUM:
@@ -7533,7 +7536,8 @@
 		if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) {
 			l2cap_sock_clear_timer(sk);
 			l2cap_sock_set_timer(sk, HZ * 5);
-		} else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+		} else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH ||
+			l2cap_pi(sk)->sec_level == BT_SECURITY_VERY_HIGH)
 			__l2cap_sock_close(sk, ECONNREFUSED);
 	} else {
 		if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index dc4bf2f..d1914ea 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -262,6 +262,7 @@
 	__u8 auth_type;
 
 	switch (d->sec_level) {
+	case BT_SECURITY_VERY_HIGH:
 	case BT_SECURITY_HIGH:
 		auth_type = HCI_AT_GENERAL_BONDING_MITM;
 		break;
@@ -2163,7 +2164,8 @@
 				set_bit(RFCOMM_SEC_PENDING, &d->flags);
 				rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
 				continue;
-			} else if (d->sec_level == BT_SECURITY_HIGH) {
+			} else if (d->sec_level == BT_SECURITY_HIGH ||
+				d->sec_level == BT_SECURITY_VERY_HIGH) {
 				__rfcomm_dlc_close(d, ECONNREFUSED);
 				continue;
 			}
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 66cc1f0..216068f 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -707,12 +707,13 @@
 			break;
 		}
 
-		if (sec.level > BT_SECURITY_HIGH) {
+		if (sec.level > BT_SECURITY_VERY_HIGH) {
 			err = -EINVAL;
 			break;
 		}
 
 		rfcomm_pi(sk)->sec_level = sec.level;
+		BT_DBG("set to %d", sec.level);
 		break;
 
 	case BT_DEFER_SETUP:
@@ -763,6 +764,7 @@
 			opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
 			break;
 		case BT_SECURITY_HIGH:
+		case BT_SECURITY_VERY_HIGH:
 			opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
 							RFCOMM_LM_SECURE;
 			break;
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 517779f..4a83020 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -213,6 +213,7 @@
 static __u8 seclevel_to_authreq(__u8 level)
 {
 	switch (level) {
+	case BT_SECURITY_VERY_HIGH:
 	case BT_SECURITY_HIGH:
 		return SMP_AUTH_MITM | SMP_AUTH_BONDING;
 
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index df34213..155585a 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -298,6 +298,9 @@
 config SND_SOC_WCD9306
         tristate
 
+config SND_SOC_MSM8X10_WCD
+	tristate
+
 config SND_SOC_WL1273
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 11338aa..a09dab3 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -51,8 +51,9 @@
 snd-soc-wcd9304-objs := wcd9304.o wcd9304-tables.o
 snd-soc-wcd9310-objs := wcd9310.o wcd9310-tables.o
 snd-soc-cs8427-objs := cs8427.o
-snd-soc-wcd9320-objs := wcd9xxx-resmgr.o wcd9320.o wcd9320-tables.o wcd9xxx-mbhc.o
-snd-soc-wcd9306-objs := wcd9xxx-resmgr.o wcd9306.o wcd9306-tables.o wcd9xxx-mbhc.o
+snd-soc-wcd9320-objs := wcd9xxx-resmgr.o wcd9320.o wcd9320-tables.o wcd9xxx-mbhc.o wcd9xxx-common.o
+snd-soc-wcd9306-objs := wcd9306.o wcd9306-tables.o
+snd-soc-msm8x10-wcd-objs := msm8x10-wcd.o msm8x10-wcd-tables.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm1250-ev1-objs := wm1250-ev1.o
 snd-soc-wm2000-objs := wm2000.o
@@ -163,7 +164,8 @@
 obj-$(CONFIG_SND_SOC_WCD9310)	+= snd-soc-wcd9310.o
 obj-$(CONFIG_SND_SOC_CS8427)	+= snd-soc-cs8427.o
 obj-$(CONFIG_SND_SOC_WCD9320)	+= snd-soc-wcd9320.o
-obj-$(CONFIG_SND_SOC_WCD9306)	+= snd-soc-wcd9306.o
+obj-$(CONFIG_SND_SOC_WCD9306)	+= snd-soc-wcd9306.o wcd9xxx-resmgr.o wcd9xxx-mbhc.o
+obj-$(CONFIG_SND_SOC_MSM8X10_WCD)	+= snd-soc-msm8x10-wcd.o wcd9xxx-resmgr.o
 obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
 obj-$(CONFIG_SND_SOC_WM2000)	+= snd-soc-wm2000.o
diff --git a/sound/soc/codecs/msm8x10-wcd-tables.c b/sound/soc/codecs/msm8x10-wcd-tables.c
new file mode 100644
index 0000000..7e0263d
--- /dev/null
+++ b/sound/soc/codecs/msm8x10-wcd-tables.c
@@ -0,0 +1,794 @@
+/* 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 <msm8x10_wcd_registers.h>
+#include "msm8x10-wcd.h"
+
+const u8 msm8x10_wcd_reg_readable[MSM8X10_WCD_CACHE_SIZE] = {
+	[MSM8X10_WCD_A_CHIP_CTL] = 1,
+	[MSM8X10_WCD_A_CHIP_STATUS] = 1,
+	[MSM8X10_WCD_A_CDC_TLMM_MODE_SELECT] = 1,
+	[MSM8X10_WCD_A_MODE_LOCK] = 0,
+	[MSM8X10_WCD_A_CHIP_ID_BYTE_0] = 1,
+	[MSM8X10_WCD_A_CHIP_ID_BYTE_1] = 1,
+	[MSM8X10_WCD_A_CHIP_ID_BYTE_2] = 1,
+	[MSM8X10_WCD_A_CHIP_ID_BYTE_3] = 1,
+	[MSM8X10_WCD_A_CHIP_VERSION] = 1,
+	[MSM8X10_WCD_A_ANALOG_SLAVE_ID] = 1,
+	[MSM8X10_WCD_A_PIN_CTL_OE] = 1,
+	[MSM8X10_WCD_A_PIN_CTL_DATA] = 1,
+	[MSM8X10_WCD_A_PIN_STATUS] = 1,
+	[MSM8X10_WCD_A_HDRIVE_CTL] = 1,
+	[MSM8X10_WCD_A_HDRIVE_I2C_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RST_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_TOP_CLK_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_ANA_CLK_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_DIG_CLK_CTL] = 1,
+	[MSM8X10_WCD_A_PROCESS_MONITOR_CTL0] = 1,
+	[MSM8X10_WCD_A_PROCESS_MONITOR_CTL1] = 1,
+	[MSM8X10_WCD_A_PROCESS_MONITOR_CTL2] = 1,
+	[MSM8X10_WCD_A_PROCESS_MONITOR_CTL3] = 1,
+	[MSM8X10_WCD_A_QFUSE_CTL] = 1,
+	[MSM8X10_WCD_A_QFUSE_STATUS] = 1,
+	[MSM8X10_WCD_A_QFUSE_DATA_OUT0] = 1,
+	[MSM8X10_WCD_A_QFUSE_DATA_OUT1] = 1,
+	[MSM8X10_WCD_A_QFUSE_DATA_OUT2] = 1,
+	[MSM8X10_WCD_A_QFUSE_DATA_OUT3] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_TX1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_TX2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_HPHR_DAC_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_LO_DAC_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_RX1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_RX2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_RX3_CTL] = 1,
+	[MSM8X10_WCD_A_DIGITAL_DEBUG_CTL] = 1,
+	[MSM8X10_WCD_A_ANALOG_DEBUG_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX3_CTL] = 1,
+	[MSM8X10_WCD_A_DEM_BYPASS_DATA0] = 1,
+	[MSM8X10_WCD_A_DEM_BYPASS_DATA1] = 1,
+	[MSM8X10_WCD_A_DEM_BYPASS_DATA2] = 1,
+	[MSM8X10_WCD_A_DEM_BYPASS_DATA3] = 1,
+	[MSM8X10_WCD_A_SPARE_0] = 1,
+	[MSM8X10_WCD_A_SPARE_1] = 1,
+	[MSM8X10_WCD_A_SPARE_2] = 1,
+	[MSM8X10_WCD_A_INTR_MODE] = 1,
+	[MSM8X10_WCD_A_INTR_MASK0] = 1,
+	[MSM8X10_WCD_A_INTR_MASK1] = 1,
+	[MSM8X10_WCD_A_INTR_MASK2] = 1,
+	[MSM8X10_WCD_A_INTR_STATUS0] = 1,
+	[MSM8X10_WCD_A_INTR_STATUS1] = 1,
+	[MSM8X10_WCD_A_INTR_STATUS2] = 1,
+	[MSM8X10_WCD_A_INTR_CLEAR0] = 0,
+	[MSM8X10_WCD_A_INTR_CLEAR1] = 0,
+	[MSM8X10_WCD_A_INTR_CLEAR2] = 0,
+	[MSM8X10_WCD_A_INTR_TEST0] = 1,
+	[MSM8X10_WCD_A_INTR_TEST1] = 1,
+	[MSM8X10_WCD_A_INTR_TEST2] = 1,
+	[MSM8X10_WCD_A_INTR_SET0] = 1,
+	[MSM8X10_WCD_A_INTR_SET1] = 1,
+	[MSM8X10_WCD_A_INTR_SET2] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_EN_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_FIR_B1_CFG] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_FIR_B2_CFG] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_TIMER_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_TIMER_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_TIMER_B3_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_TIMER_B4_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_TIMER_B5_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_TIMER_B6_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_B1_STATUS] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_B2_STATUS] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_B3_STATUS] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_B4_STATUS] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_B5_STATUS] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B3_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B4_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B5_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B6_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B7_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B8_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B9_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B10_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B11_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B12_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_CLK_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_INT_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_DEBUG_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_MBHC_SPARE] = 1,
+	[MSM8X10_WCD_A_BIAS_REF_CTL] = 1,
+	[MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL] = 1,
+	[MSM8X10_WCD_A_BIAS_PRECHRG_CTL] = 1,
+	[MSM8X10_WCD_A_BIAS_CURR_CTL_1] = 1,
+	[MSM8X10_WCD_A_BIAS_CURR_CTL_2] = 1,
+	[MSM8X10_WCD_A_BIAS_OSC_BG_CTL] = 1,
+	[MSM8X10_WCD_A_MICB_CFILT_1_CTL] = 1,
+	[MSM8X10_WCD_A_MICB_CFILT_1_VAL] = 1,
+	[MSM8X10_WCD_A_MICB_CFILT_1_PRECHRG] = 1,
+	[MSM8X10_WCD_A_MICB_1_CTL] = 1,
+	[MSM8X10_WCD_A_MICB_1_INT_RBIAS] = 1,
+	[MSM8X10_WCD_A_MICB_1_MBHC] = 1,
+	[MSM8X10_WCD_A_MBHC_INSERT_DETECT] = 1,
+	[MSM8X10_WCD_A_MBHC_INSERT_DET_STATUS] = 1,
+	[MSM8X10_WCD_A_TX_COM_BIAS] = 1,
+	[MSM8X10_WCD_A_MBHC_SCALING_MUX_1] = 1,
+	[MSM8X10_WCD_A_MBHC_SCALING_MUX_2] = 1,
+	[MSM8X10_WCD_A_RESERVED_MAD_ANA_CTRL] = 1,
+	[MSM8X10_WCD_A_TX_SUP_SWITCH_CTRL_1] = 1,
+	[MSM8X10_WCD_A_TX_SUP_SWITCH_CTRL_2] = 1,
+	[MSM8X10_WCD_A_TX_1_EN] = 1,
+	[MSM8X10_WCD_A_TX_2_EN] = 1,
+	[MSM8X10_WCD_A_TX_1_2_ADC_CH1] = 1,
+	[MSM8X10_WCD_A_TX_1_2_ADC_CH2] = 1,
+	[MSM8X10_WCD_A_TX_1_2_ATEST_REFCTRL] = 1,
+	[MSM8X10_WCD_A_TX_1_2_TEST_CTL] = 1,
+	[MSM8X10_WCD_A_TX_1_2_TEST_BLOCK_EN] = 1,
+	[MSM8X10_WCD_A_TX_1_2_TXFE_CLKDIV] = 1,
+	[MSM8X10_WCD_A_TX_1_2_SAR_ERR_CH1] = 1,
+	[MSM8X10_WCD_A_TX_1_2_SAR_ERR_CH2] = 1,
+	[MSM8X10_WCD_A_TX_3_EN] = 1,
+	[MSM8X10_WCD_A_TX_1_2_TEST_EN] = 1,
+	[MSM8X10_WCD_A_TX_7_MBHC_EN_ATEST_CTRL] = 1,
+	[MSM8X10_WCD_A_TX_7_MBHC_SAR_ERR] = 1,
+	[MSM8X10_WCD_A_CP_EN] = 1,
+	[MSM8X10_WCD_A_CP_CLK] = 1,
+	[MSM8X10_WCD_A_CP_STATIC] = 1,
+	[MSM8X10_WCD_A_CP_DCC1] = 1,
+	[MSM8X10_WCD_A_CP_DCC3] = 1,
+	[MSM8X10_WCD_A_CP_ATEST] = 1,
+	[MSM8X10_WCD_A_CP_DTEST] = 1,
+	[MSM8X10_WCD_A_RX_AUX_SW_CTL] = 1,
+	[MSM8X10_WCD_A_RX_PA_AUX_IN_CONN] = 1,
+	[MSM8X10_WCD_A_RX_COM_TIMER_DIV] = 1,
+	[MSM8X10_WCD_A_RX_COM_OCP_CTL] = 1,
+	[MSM8X10_WCD_A_RX_COM_OCP_COUNT] = 1,
+	[MSM8X10_WCD_A_RX_COM_DAC_CTL] = 1,
+	[MSM8X10_WCD_A_RX_COM_BIAS] = 1,
+	[MSM8X10_WCD_A_RX_HPH_AUTO_CHOP] = 1,
+	[MSM8X10_WCD_A_RX_HPH_CHOP_CTL] = 1,
+	[MSM8X10_WCD_A_RX_HPH_BIAS_PA] = 1,
+	[MSM8X10_WCD_A_RX_HPH_BIAS_LDO] = 1,
+	[MSM8X10_WCD_A_RX_HPH_BIAS_CNP] = 1,
+	[MSM8X10_WCD_A_RX_HPH_BIAS_WG_OCP] = 1,
+	[MSM8X10_WCD_A_RX_HPH_OCP_CTL] = 1,
+	[MSM8X10_WCD_A_RX_HPH_CNP_EN] = 1,
+	[MSM8X10_WCD_A_RX_HPH_CNP_WG_CTL] = 1,
+	[MSM8X10_WCD_A_RX_HPH_CNP_WG_TIME] = 1,
+	[MSM8X10_WCD_A_RX_HPH_L_GAIN] = 1,
+	[MSM8X10_WCD_A_RX_HPH_L_TEST] = 1,
+	[MSM8X10_WCD_A_RX_HPH_L_PA_CTL] = 1,
+	[MSM8X10_WCD_A_RX_HPH_L_DAC_CTL] = 1,
+	[MSM8X10_WCD_A_RX_HPH_L_ATEST] = 1,
+	[MSM8X10_WCD_A_RX_HPH_L_STATUS] = 1,
+	[MSM8X10_WCD_A_RX_HPH_R_GAIN] = 1,
+	[MSM8X10_WCD_A_RX_HPH_R_TEST] = 1,
+	[MSM8X10_WCD_A_RX_HPH_R_PA_CTL] = 1,
+	[MSM8X10_WCD_A_RX_HPH_R_DAC_CTL] = 1,
+	[MSM8X10_WCD_A_RX_HPH_R_ATEST] = 1,
+	[MSM8X10_WCD_A_RX_HPH_R_STATUS] = 1,
+	[MSM8X10_WCD_A_RX_EAR_BIAS_PA] = 1,
+	[MSM8X10_WCD_A_RX_EAR_BIAS_CMBUFF] = 1,
+	[MSM8X10_WCD_A_RX_EAR_EN] = 1,
+	[MSM8X10_WCD_A_RX_EAR_GAIN] = 1,
+	[MSM8X10_WCD_A_RX_EAR_CMBUFF] = 1,
+	[MSM8X10_WCD_A_RX_EAR_ICTL] = 1,
+	[MSM8X10_WCD_A_RX_EAR_CCOMP] = 1,
+	[MSM8X10_WCD_A_RX_EAR_VCM] = 1,
+	[MSM8X10_WCD_A_RX_EAR_CNP] = 1,
+	[MSM8X10_WCD_A_RX_EAR_DAC_CTL_ATEST] = 1,
+	[MSM8X10_WCD_A_RX_EAR_STATUS] = 1,
+	[MSM8X10_WCD_A_RX_LINE_BIAS_PA] = 1,
+	[MSM8X10_WCD_A_RX_BUCK_BIAS1] = 1,
+	[MSM8X10_WCD_A_RX_BUCK_BIAS2] = 1,
+	[MSM8X10_WCD_A_RX_LINE_COM] = 1,
+	[MSM8X10_WCD_A_RX_LINE_CNP_EN] = 1,
+	[MSM8X10_WCD_A_RX_LINE_CNP_WG_CTL] = 1,
+	[MSM8X10_WCD_A_RX_LINE_CNP_WG_TIME] = 1,
+	[MSM8X10_WCD_A_RX_LINE_1_GAIN] = 1,
+	[MSM8X10_WCD_A_RX_LINE_1_TEST] = 1,
+	[MSM8X10_WCD_A_RX_LINE_1_DAC_CTL] = 1,
+	[MSM8X10_WCD_A_RX_LINE_1_STATUS] = 1,
+	[MSM8X10_WCD_A_RX_LINE_CNP_DBG] = 1,
+	[MSM8X10_WCD_A_SPKR_DRV_EN] = 1,
+	[MSM8X10_WCD_A_SPKR_DRV_GAIN] = 1,
+	[MSM8X10_WCD_A_SPKR_DRV_DAC_CTL] = 1,
+	[MSM8X10_WCD_A_SPKR_DRV_OCP_CTL] = 1,
+	[MSM8X10_WCD_A_SPKR_DRV_CLIP_DET] = 1,
+	[MSM8X10_WCD_A_SPKR_DRV_IEC] = 1,
+	[MSM8X10_WCD_A_SPKR_DRV_DBG_DAC] = 1,
+	[MSM8X10_WCD_A_SPKR_DRV_DBG_PA] = 1,
+	[MSM8X10_WCD_A_SPKR_DRV_DBG_PWRSTG] = 1,
+	[MSM8X10_WCD_A_SPKR_DRV_BIAS_LDO] = 1,
+	[MSM8X10_WCD_A_SPKR_DRV_BIAS_INT] = 1,
+	[MSM8X10_WCD_A_SPKR_DRV_BIAS_PA] = 1,
+	[MSM8X10_WCD_A_SPKR_DRV_STATUS_OCP] = 1,
+	[MSM8X10_WCD_A_SPKR_DRV_STATUS_PA] = 1,
+	[MSM8X10_WCD_A_RC_OSC_FREQ] = 1,
+	[MSM8X10_WCD_A_RC_OSC_TEST] = 1,
+	[MSM8X10_WCD_A_RC_OSC_STATUS] = 1,
+	[MSM8X10_WCD_A_RC_OSC_TUNER] = 1,
+	[MSM8X10_WCD_A_MBHC_HPH] = 1,
+	[MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLK_TX_RESET_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLK_RX_I2S_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLK_TX_I2S_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLK_OTHR_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLK_MCLK_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLK_PDM_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLK_SD_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX1_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX2_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX3_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX1_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX2_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX3_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX1_B3_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX2_B3_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX3_B3_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX1_B4_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX2_B4_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX3_B4_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX1_B5_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX2_B5_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX3_B5_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX1_B6_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX2_B6_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX3_B6_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B3_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B4_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLSG_GAIN_THRESH_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CLSG_TIMER_B1_CFG] = 1,
+	[MSM8X10_WCD_A_CDC_CLSG_TIMER_B2_CFG] = 1,
+	[MSM8X10_WCD_A_CDC_CLSG_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_TX1_VOL_CTL_TIMER] = 1,
+	[MSM8X10_WCD_A_CDC_TX2_VOL_CTL_TIMER] = 1,
+	[MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN] = 1,
+	[MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN] = 1,
+	[MSM8X10_WCD_A_CDC_TX1_VOL_CTL_CFG] = 1,
+	[MSM8X10_WCD_A_CDC_TX2_VOL_CTL_CFG] = 1,
+	[MSM8X10_WCD_A_CDC_TX1_MUX_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_TX2_MUX_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_TX1_CLK_FS_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_TX2_CLK_FS_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_TX1_DMIC_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_TX2_DMIC_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B3_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B3_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B4_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B5_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B5_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B6_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B6_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B7_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B7_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B8_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B8_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_TIMER_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_TIMER_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR2_COEF_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_IIR2_COEF_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_RX1_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_RX1_B3_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_RX2_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_RX2_B3_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_RX3_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_EQ1_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_EQ1_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_EQ1_B3_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_EQ1_B4_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_EQ2_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_EQ2_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_EQ2_B3_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_EQ2_B4_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_CONN_TX_I2S_SD1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_TOP_GAIN_UPDATE] = 1,
+	[MSM8X10_WCD_A_CDC_TOP_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_DEBUG_DESER1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_DEBUG_DESER2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_DEBUG_B1_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_DEBUG_B2_CTL] = 1,
+	[MSM8X10_WCD_A_CDC_DEBUG_B3_CTL] = 1,
+};
+
+const u8 msm8x10_wcd_reset_reg_defaults[MSM8X10_WCD_CACHE_SIZE] = {
+	[MSM8X10_WCD_A_CHIP_CTL] = MSM8X10_WCD_A_CHIP_CTL__POR,
+	[MSM8X10_WCD_A_CHIP_STATUS] = MSM8X10_WCD_A_CHIP_STATUS__POR,
+	[MSM8X10_WCD_A_CDC_TLMM_MODE_SELECT] =
+			MSM8X10_WCD_A_CDC_TLMM_MODE_SELECT__POR,
+	[MSM8X10_WCD_A_MODE_LOCK] = MSM8X10_WCD_A_MODE_LOCK__POR,
+	[MSM8X10_WCD_A_CHIP_ID_BYTE_0] = MSM8X10_WCD_A_CHIP_ID_BYTE_0__POR,
+	[MSM8X10_WCD_A_CHIP_ID_BYTE_1] = MSM8X10_WCD_A_CHIP_ID_BYTE_1__POR,
+	[MSM8X10_WCD_A_CHIP_ID_BYTE_2] = MSM8X10_WCD_A_CHIP_ID_BYTE_2__POR,
+	[MSM8X10_WCD_A_CHIP_ID_BYTE_3] = MSM8X10_WCD_A_CHIP_ID_BYTE_3__POR,
+	[MSM8X10_WCD_A_CHIP_VERSION] = MSM8X10_WCD_A_CHIP_VERSION__POR,
+	[MSM8X10_WCD_A_ANALOG_SLAVE_ID] = MSM8X10_WCD_A_ANALOG_SLAVE_ID__POR,
+	[MSM8X10_WCD_A_PIN_CTL_OE] = MSM8X10_WCD_A_PIN_CTL_OE__POR,
+	[MSM8X10_WCD_A_PIN_CTL_DATA] = MSM8X10_WCD_A_PIN_CTL_DATA__POR,
+	[MSM8X10_WCD_A_PIN_STATUS] = MSM8X10_WCD_A_PIN_STATUS__POR,
+	[MSM8X10_WCD_A_HDRIVE_CTL] = MSM8X10_WCD_A_HDRIVE_CTL__POR,
+	[MSM8X10_WCD_A_HDRIVE_I2C_CTL] = MSM8X10_WCD_A_HDRIVE_I2C_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RST_CTL] = MSM8X10_WCD_A_CDC_RST_CTL__POR,
+	[MSM8X10_WCD_A_CDC_TOP_CLK_CTL] = MSM8X10_WCD_A_CDC_TOP_CLK_CTL__POR,
+	[MSM8X10_WCD_A_CDC_ANA_CLK_CTL] = MSM8X10_WCD_A_CDC_ANA_CLK_CTL__POR,
+	[MSM8X10_WCD_A_CDC_DIG_CLK_CTL] = MSM8X10_WCD_A_CDC_DIG_CLK_CTL__POR,
+	[MSM8X10_WCD_A_PROCESS_MONITOR_CTL0] =
+			MSM8X10_WCD_A_PROCESS_MONITOR_CTL0__POR,
+	[MSM8X10_WCD_A_PROCESS_MONITOR_CTL1] =
+			MSM8X10_WCD_A_PROCESS_MONITOR_CTL1__POR,
+	[MSM8X10_WCD_A_PROCESS_MONITOR_CTL2] =
+			MSM8X10_WCD_A_PROCESS_MONITOR_CTL2__POR,
+	[MSM8X10_WCD_A_PROCESS_MONITOR_CTL3] =
+			MSM8X10_WCD_A_PROCESS_MONITOR_CTL3__POR,
+	[MSM8X10_WCD_A_QFUSE_CTL] = MSM8X10_WCD_A_QFUSE_CTL__POR,
+	[MSM8X10_WCD_A_QFUSE_STATUS] = MSM8X10_WCD_A_QFUSE_STATUS__POR,
+	[MSM8X10_WCD_A_QFUSE_DATA_OUT0] = MSM8X10_WCD_A_QFUSE_DATA_OUT0__POR,
+	[MSM8X10_WCD_A_QFUSE_DATA_OUT1] = MSM8X10_WCD_A_QFUSE_DATA_OUT1__POR,
+	[MSM8X10_WCD_A_QFUSE_DATA_OUT2] = MSM8X10_WCD_A_QFUSE_DATA_OUT2__POR,
+	[MSM8X10_WCD_A_QFUSE_DATA_OUT3] = MSM8X10_WCD_A_QFUSE_DATA_OUT3__POR,
+	[MSM8X10_WCD_A_CDC_CONN_TX1_CTL] = MSM8X10_WCD_A_CDC_CONN_TX1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_TX2_CTL] = MSM8X10_WCD_A_CDC_CONN_TX2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_HPHR_DAC_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_HPHR_DAC_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_LO_DAC_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_LO_DAC_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_RX1_CTL] = MSM8X10_WCD_A_CDC_CONN_RX1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_RX2_CTL] = MSM8X10_WCD_A_CDC_CONN_RX2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_RX3_CTL] = MSM8X10_WCD_A_CDC_CONN_RX3_CTL__POR,
+	[MSM8X10_WCD_A_DIGITAL_DEBUG_CTL] =
+			MSM8X10_WCD_A_DIGITAL_DEBUG_CTL__POR,
+	[MSM8X10_WCD_A_ANALOG_DEBUG_CTL] = MSM8X10_WCD_A_ANALOG_DEBUG_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX1_CTL] = MSM8X10_WCD_A_CDC_RX1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX2_CTL] = MSM8X10_WCD_A_CDC_RX2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX3_CTL] = MSM8X10_WCD_A_CDC_RX3_CTL__POR,
+	[MSM8X10_WCD_A_DEM_BYPASS_DATA0] = MSM8X10_WCD_A_DEM_BYPASS_DATA0__POR,
+	[MSM8X10_WCD_A_DEM_BYPASS_DATA1] = MSM8X10_WCD_A_DEM_BYPASS_DATA1__POR,
+	[MSM8X10_WCD_A_DEM_BYPASS_DATA2] = MSM8X10_WCD_A_DEM_BYPASS_DATA2__POR,
+	[MSM8X10_WCD_A_DEM_BYPASS_DATA3] = MSM8X10_WCD_A_DEM_BYPASS_DATA3__POR,
+	[MSM8X10_WCD_A_SPARE_0] = MSM8X10_WCD_A_SPARE_0__POR,
+	[MSM8X10_WCD_A_SPARE_1] = MSM8X10_WCD_A_SPARE_1__POR,
+	[MSM8X10_WCD_A_SPARE_2] = MSM8X10_WCD_A_SPARE_2__POR,
+	[MSM8X10_WCD_A_INTR_MODE] = MSM8X10_WCD_A_INTR_MODE__POR,
+	[MSM8X10_WCD_A_INTR_MASK0] = MSM8X10_WCD_A_INTR_MASK0__POR,
+	[MSM8X10_WCD_A_INTR_MASK1] = MSM8X10_WCD_A_INTR_MASK1__POR,
+	[MSM8X10_WCD_A_INTR_MASK2] = MSM8X10_WCD_A_INTR_MASK2__POR,
+	[MSM8X10_WCD_A_INTR_STATUS0] = MSM8X10_WCD_A_INTR_STATUS0__POR,
+	[MSM8X10_WCD_A_INTR_STATUS1] = MSM8X10_WCD_A_INTR_STATUS1__POR,
+	[MSM8X10_WCD_A_INTR_STATUS2] = MSM8X10_WCD_A_INTR_STATUS2__POR,
+	[MSM8X10_WCD_A_INTR_CLEAR0] = MSM8X10_WCD_A_INTR_CLEAR0__POR,
+	[MSM8X10_WCD_A_INTR_CLEAR1] = MSM8X10_WCD_A_INTR_CLEAR1__POR,
+	[MSM8X10_WCD_A_INTR_CLEAR2] = MSM8X10_WCD_A_INTR_CLEAR2__POR,
+	[MSM8X10_WCD_A_INTR_TEST0] = MSM8X10_WCD_A_INTR_TEST0__POR,
+	[MSM8X10_WCD_A_INTR_TEST1] = MSM8X10_WCD_A_INTR_TEST1__POR,
+	[MSM8X10_WCD_A_INTR_TEST2] = MSM8X10_WCD_A_INTR_TEST2__POR,
+	[MSM8X10_WCD_A_INTR_SET0] = MSM8X10_WCD_A_INTR_SET0__POR,
+	[MSM8X10_WCD_A_INTR_SET1] = MSM8X10_WCD_A_INTR_SET1__POR,
+	[MSM8X10_WCD_A_INTR_SET2] = MSM8X10_WCD_A_INTR_SET2__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_EN_CTL] = MSM8X10_WCD_A_CDC_MBHC_EN_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_FIR_B1_CFG] =
+			MSM8X10_WCD_A_CDC_MBHC_FIR_B1_CFG__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_FIR_B2_CFG] =
+			MSM8X10_WCD_A_CDC_MBHC_FIR_B2_CFG__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_TIMER_B1_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_TIMER_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_TIMER_B2_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_TIMER_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_TIMER_B3_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_TIMER_B3_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_TIMER_B4_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_TIMER_B4_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_TIMER_B5_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_TIMER_B5_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_TIMER_B6_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_TIMER_B6_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_B1_STATUS] =
+			MSM8X10_WCD_A_CDC_MBHC_B1_STATUS__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_B2_STATUS] =
+			MSM8X10_WCD_A_CDC_MBHC_B2_STATUS__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_B3_STATUS] =
+			MSM8X10_WCD_A_CDC_MBHC_B3_STATUS__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_B4_STATUS] =
+			MSM8X10_WCD_A_CDC_MBHC_B4_STATUS__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_B5_STATUS] =
+			MSM8X10_WCD_A_CDC_MBHC_B5_STATUS__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_B1_CTL] = MSM8X10_WCD_A_CDC_MBHC_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_B2_CTL] = MSM8X10_WCD_A_CDC_MBHC_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B1_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_VOLT_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B2_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_VOLT_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B3_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_VOLT_B3_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B4_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_VOLT_B4_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B5_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_VOLT_B5_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B6_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_VOLT_B6_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B7_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_VOLT_B7_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B8_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_VOLT_B8_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B9_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_VOLT_B9_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B10_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_VOLT_B10_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B11_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_VOLT_B11_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_VOLT_B12_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_VOLT_B12_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_CLK_CTL] = MSM8X10_WCD_A_CDC_MBHC_CLK_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_INT_CTL] = MSM8X10_WCD_A_CDC_MBHC_INT_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_DEBUG_CTL] =
+			MSM8X10_WCD_A_CDC_MBHC_DEBUG_CTL__POR,
+	[MSM8X10_WCD_A_CDC_MBHC_SPARE] = MSM8X10_WCD_A_CDC_MBHC_SPARE__POR,
+	[MSM8X10_WCD_A_BIAS_REF_CTL] = MSM8X10_WCD_A_BIAS_REF_CTL__POR,
+	[MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL] =
+			MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL__POR,
+	[MSM8X10_WCD_A_BIAS_PRECHRG_CTL] = MSM8X10_WCD_A_BIAS_PRECHRG_CTL__POR,
+	[MSM8X10_WCD_A_BIAS_CURR_CTL_1] = MSM8X10_WCD_A_BIAS_CURR_CTL_1__POR,
+	[MSM8X10_WCD_A_BIAS_CURR_CTL_2] = MSM8X10_WCD_A_BIAS_CURR_CTL_2__POR,
+	[MSM8X10_WCD_A_BIAS_OSC_BG_CTL] = MSM8X10_WCD_A_BIAS_OSC_BG_CTL__POR,
+	[MSM8X10_WCD_A_MICB_CFILT_1_CTL] = MSM8X10_WCD_A_MICB_CFILT_1_CTL__POR,
+	[MSM8X10_WCD_A_MICB_CFILT_1_VAL] = MSM8X10_WCD_A_MICB_CFILT_1_VAL__POR,
+	[MSM8X10_WCD_A_MICB_CFILT_1_PRECHRG] =
+			MSM8X10_WCD_A_MICB_CFILT_1_PRECHRG__POR,
+	[MSM8X10_WCD_A_MICB_1_CTL] = MSM8X10_WCD_A_MICB_1_CTL__POR,
+	[MSM8X10_WCD_A_MICB_1_INT_RBIAS] = MSM8X10_WCD_A_MICB_1_INT_RBIAS__POR,
+	[MSM8X10_WCD_A_MICB_1_MBHC] = MSM8X10_WCD_A_MICB_1_MBHC__POR,
+	[MSM8X10_WCD_A_MBHC_INSERT_DETECT] =
+			MSM8X10_WCD_A_MBHC_INSERT_DETECT__POR,
+	[MSM8X10_WCD_A_MBHC_INSERT_DET_STATUS] =
+			MSM8X10_WCD_A_MBHC_INSERT_DET_STATUS__POR,
+	[MSM8X10_WCD_A_TX_COM_BIAS] = MSM8X10_WCD_A_TX_COM_BIAS__POR,
+	[MSM8X10_WCD_A_MBHC_SCALING_MUX_1] =
+			MSM8X10_WCD_A_MBHC_SCALING_MUX_1__POR,
+	[MSM8X10_WCD_A_MBHC_SCALING_MUX_2] =
+			MSM8X10_WCD_A_MBHC_SCALING_MUX_2__POR,
+	[MSM8X10_WCD_A_RESERVED_MAD_ANA_CTRL] =
+			MSM8X10_WCD_A_RESERVED_MAD_ANA_CTRL__POR,
+	[MSM8X10_WCD_A_TX_SUP_SWITCH_CTRL_1] =
+			MSM8X10_WCD_A_TX_SUP_SWITCH_CTRL_1__POR,
+	[MSM8X10_WCD_A_TX_SUP_SWITCH_CTRL_2] =
+			MSM8X10_WCD_A_TX_SUP_SWITCH_CTRL_2__POR,
+	[MSM8X10_WCD_A_TX_1_EN] = MSM8X10_WCD_A_TX_1_EN__POR,
+	[MSM8X10_WCD_A_TX_2_EN] = MSM8X10_WCD_A_TX_2_EN__POR,
+	[MSM8X10_WCD_A_TX_1_2_ADC_CH1] = MSM8X10_WCD_A_TX_1_2_ADC_CH1__POR,
+	[MSM8X10_WCD_A_TX_1_2_ADC_CH2] = MSM8X10_WCD_A_TX_1_2_ADC_CH2__POR,
+	[MSM8X10_WCD_A_TX_1_2_ATEST_REFCTRL] =
+			MSM8X10_WCD_A_TX_1_2_ATEST_REFCTRL__POR,
+	[MSM8X10_WCD_A_TX_1_2_TEST_CTL] =
+			MSM8X10_WCD_A_TX_1_2_TEST_CTL__POR,
+	[MSM8X10_WCD_A_TX_1_2_TEST_BLOCK_EN] =
+			MSM8X10_WCD_A_TX_1_2_TEST_BLOCK_EN__POR,
+	[MSM8X10_WCD_A_TX_1_2_TXFE_CLKDIV] =
+			MSM8X10_WCD_A_TX_1_2_TXFE_CLKDIV__POR,
+	[MSM8X10_WCD_A_TX_1_2_SAR_ERR_CH1] =
+			MSM8X10_WCD_A_TX_1_2_SAR_ERR_CH1__POR,
+	[MSM8X10_WCD_A_TX_1_2_SAR_ERR_CH2] =
+			MSM8X10_WCD_A_TX_1_2_SAR_ERR_CH2__POR,
+	[MSM8X10_WCD_A_TX_3_EN] = MSM8X10_WCD_A_TX_3_EN__POR,
+	[MSM8X10_WCD_A_TX_1_2_TEST_EN] = MSM8X10_WCD_A_TX_1_2_TEST_EN__POR,
+	[MSM8X10_WCD_A_TX_7_MBHC_EN_ATEST_CTRL] =
+			MSM8X10_WCD_A_TX_7_MBHC_EN_ATEST_CTRL__POR,
+	[MSM8X10_WCD_A_TX_7_MBHC_SAR_ERR] =
+			MSM8X10_WCD_A_TX_7_MBHC_SAR_ERR__POR,
+	[MSM8X10_WCD_A_CP_EN] = MSM8X10_WCD_A_CP_EN__POR,
+	[MSM8X10_WCD_A_CP_CLK] = MSM8X10_WCD_A_CP_CLK__POR,
+	[MSM8X10_WCD_A_CP_STATIC] = MSM8X10_WCD_A_CP_STATIC__POR,
+	[MSM8X10_WCD_A_CP_DCC1] = MSM8X10_WCD_A_CP_DCC1__POR,
+	[MSM8X10_WCD_A_CP_DCC3] = MSM8X10_WCD_A_CP_DCC3__POR,
+	[MSM8X10_WCD_A_CP_ATEST] = MSM8X10_WCD_A_CP_ATEST__POR,
+	[MSM8X10_WCD_A_CP_DTEST] = MSM8X10_WCD_A_CP_DTEST__POR,
+	[MSM8X10_WCD_A_RX_AUX_SW_CTL] = MSM8X10_WCD_A_RX_AUX_SW_CTL__POR,
+	[MSM8X10_WCD_A_RX_PA_AUX_IN_CONN] =
+			MSM8X10_WCD_A_RX_PA_AUX_IN_CONN__POR,
+	[MSM8X10_WCD_A_RX_COM_TIMER_DIV] = MSM8X10_WCD_A_RX_COM_TIMER_DIV__POR,
+	[MSM8X10_WCD_A_RX_COM_OCP_CTL] = MSM8X10_WCD_A_RX_COM_OCP_CTL__POR,
+	[MSM8X10_WCD_A_RX_COM_OCP_COUNT] = MSM8X10_WCD_A_RX_COM_OCP_COUNT__POR,
+	[MSM8X10_WCD_A_RX_COM_DAC_CTL] = MSM8X10_WCD_A_RX_COM_DAC_CTL__POR,
+	[MSM8X10_WCD_A_RX_COM_BIAS] = MSM8X10_WCD_A_RX_COM_BIAS__POR,
+	[MSM8X10_WCD_A_RX_HPH_AUTO_CHOP] = MSM8X10_WCD_A_RX_HPH_AUTO_CHOP__POR,
+	[MSM8X10_WCD_A_RX_HPH_CHOP_CTL] = MSM8X10_WCD_A_RX_HPH_CHOP_CTL__POR,
+	[MSM8X10_WCD_A_RX_HPH_BIAS_PA] = MSM8X10_WCD_A_RX_HPH_BIAS_PA__POR,
+	[MSM8X10_WCD_A_RX_HPH_BIAS_LDO] = MSM8X10_WCD_A_RX_HPH_BIAS_LDO__POR,
+	[MSM8X10_WCD_A_RX_HPH_BIAS_CNP] = MSM8X10_WCD_A_RX_HPH_BIAS_CNP__POR,
+	[MSM8X10_WCD_A_RX_HPH_BIAS_WG_OCP] =
+			MSM8X10_WCD_A_RX_HPH_BIAS_WG_OCP__POR,
+	[MSM8X10_WCD_A_RX_HPH_OCP_CTL] = MSM8X10_WCD_A_RX_HPH_OCP_CTL__POR,
+	[MSM8X10_WCD_A_RX_HPH_CNP_EN] = MSM8X10_WCD_A_RX_HPH_CNP_EN__POR,
+	[MSM8X10_WCD_A_RX_HPH_CNP_WG_CTL] =
+			MSM8X10_WCD_A_RX_HPH_CNP_WG_CTL__POR,
+	[MSM8X10_WCD_A_RX_HPH_CNP_WG_TIME] =
+			MSM8X10_WCD_A_RX_HPH_CNP_WG_TIME__POR,
+	[MSM8X10_WCD_A_RX_HPH_L_GAIN] = MSM8X10_WCD_A_RX_HPH_L_GAIN__POR,
+	[MSM8X10_WCD_A_RX_HPH_L_TEST] = MSM8X10_WCD_A_RX_HPH_L_TEST__POR,
+	[MSM8X10_WCD_A_RX_HPH_L_PA_CTL] = MSM8X10_WCD_A_RX_HPH_L_PA_CTL__POR,
+	[MSM8X10_WCD_A_RX_HPH_L_DAC_CTL] =
+			MSM8X10_WCD_A_RX_HPH_L_DAC_CTL__POR,
+	[MSM8X10_WCD_A_RX_HPH_L_ATEST] = MSM8X10_WCD_A_RX_HPH_L_ATEST__POR,
+	[MSM8X10_WCD_A_RX_HPH_L_STATUS] = MSM8X10_WCD_A_RX_HPH_L_STATUS__POR,
+	[MSM8X10_WCD_A_RX_HPH_R_GAIN] = MSM8X10_WCD_A_RX_HPH_R_GAIN__POR,
+	[MSM8X10_WCD_A_RX_HPH_R_TEST] = MSM8X10_WCD_A_RX_HPH_R_TEST__POR,
+	[MSM8X10_WCD_A_RX_HPH_R_PA_CTL] = MSM8X10_WCD_A_RX_HPH_R_PA_CTL__POR,
+	[MSM8X10_WCD_A_RX_HPH_R_DAC_CTL] = MSM8X10_WCD_A_RX_HPH_R_DAC_CTL__POR,
+	[MSM8X10_WCD_A_RX_HPH_R_ATEST] = MSM8X10_WCD_A_RX_HPH_R_ATEST__POR,
+	[MSM8X10_WCD_A_RX_HPH_R_STATUS] = MSM8X10_WCD_A_RX_HPH_R_STATUS__POR,
+	[MSM8X10_WCD_A_RX_EAR_BIAS_PA] = MSM8X10_WCD_A_RX_EAR_BIAS_PA__POR,
+	[MSM8X10_WCD_A_RX_EAR_BIAS_CMBUFF] =
+			MSM8X10_WCD_A_RX_EAR_BIAS_CMBUFF__POR,
+	[MSM8X10_WCD_A_RX_EAR_EN] = MSM8X10_WCD_A_RX_EAR_EN__POR,
+	[MSM8X10_WCD_A_RX_EAR_GAIN] = MSM8X10_WCD_A_RX_EAR_GAIN__POR,
+	[MSM8X10_WCD_A_RX_EAR_CMBUFF] = MSM8X10_WCD_A_RX_EAR_CMBUFF__POR,
+	[MSM8X10_WCD_A_RX_EAR_ICTL] = MSM8X10_WCD_A_RX_EAR_ICTL__POR,
+	[MSM8X10_WCD_A_RX_EAR_CCOMP] = MSM8X10_WCD_A_RX_EAR_CCOMP__POR,
+	[MSM8X10_WCD_A_RX_EAR_VCM] = MSM8X10_WCD_A_RX_EAR_VCM__POR,
+	[MSM8X10_WCD_A_RX_EAR_CNP] = MSM8X10_WCD_A_RX_EAR_CNP__POR,
+	[MSM8X10_WCD_A_RX_EAR_DAC_CTL_ATEST] =
+			MSM8X10_WCD_A_RX_EAR_DAC_CTL_ATEST__POR,
+	[MSM8X10_WCD_A_RX_EAR_STATUS] = MSM8X10_WCD_A_RX_EAR_STATUS__POR,
+	[MSM8X10_WCD_A_RX_LINE_BIAS_PA] =
+			MSM8X10_WCD_A_RX_LINE_BIAS_PA__POR,
+	[MSM8X10_WCD_A_RX_BUCK_BIAS1] = MSM8X10_WCD_A_RX_BUCK_BIAS1__POR,
+	[MSM8X10_WCD_A_RX_BUCK_BIAS2] = MSM8X10_WCD_A_RX_BUCK_BIAS2__POR,
+	[MSM8X10_WCD_A_RX_LINE_COM] = MSM8X10_WCD_A_RX_LINE_COM__POR,
+	[MSM8X10_WCD_A_RX_LINE_CNP_EN] = MSM8X10_WCD_A_RX_LINE_CNP_EN__POR,
+	[MSM8X10_WCD_A_RX_LINE_CNP_WG_CTL] =
+			MSM8X10_WCD_A_RX_LINE_CNP_WG_CTL__POR,
+	[MSM8X10_WCD_A_RX_LINE_CNP_WG_TIME] =
+			MSM8X10_WCD_A_RX_LINE_CNP_WG_TIME__POR,
+	[MSM8X10_WCD_A_RX_LINE_1_GAIN] = MSM8X10_WCD_A_RX_LINE_1_GAIN__POR,
+	[MSM8X10_WCD_A_RX_LINE_1_TEST] = MSM8X10_WCD_A_RX_LINE_1_TEST__POR,
+	[MSM8X10_WCD_A_RX_LINE_1_DAC_CTL] =
+			MSM8X10_WCD_A_RX_LINE_1_DAC_CTL__POR,
+	[MSM8X10_WCD_A_RX_LINE_1_STATUS] =
+			MSM8X10_WCD_A_RX_LINE_1_STATUS__POR,
+	[MSM8X10_WCD_A_RX_LINE_CNP_DBG] = MSM8X10_WCD_A_RX_LINE_CNP_DBG__POR,
+	[MSM8X10_WCD_A_SPKR_DRV_EN] = MSM8X10_WCD_A_SPKR_DRV_EN__POR,
+	[MSM8X10_WCD_A_SPKR_DRV_GAIN] = MSM8X10_WCD_A_SPKR_DRV_GAIN__POR,
+	[MSM8X10_WCD_A_SPKR_DRV_DAC_CTL] = MSM8X10_WCD_A_SPKR_DRV_DAC_CTL__POR,
+	[MSM8X10_WCD_A_SPKR_DRV_OCP_CTL] = MSM8X10_WCD_A_SPKR_DRV_OCP_CTL__POR,
+	[MSM8X10_WCD_A_SPKR_DRV_CLIP_DET] =
+			MSM8X10_WCD_A_SPKR_DRV_CLIP_DET__POR,
+	[MSM8X10_WCD_A_SPKR_DRV_IEC] = MSM8X10_WCD_A_SPKR_DRV_IEC__POR,
+	[MSM8X10_WCD_A_SPKR_DRV_DBG_DAC] = MSM8X10_WCD_A_SPKR_DRV_DBG_DAC__POR,
+	[MSM8X10_WCD_A_SPKR_DRV_DBG_PA] = MSM8X10_WCD_A_SPKR_DRV_DBG_PA__POR,
+	[MSM8X10_WCD_A_SPKR_DRV_DBG_PWRSTG] =
+			MSM8X10_WCD_A_SPKR_DRV_DBG_PWRSTG__POR,
+	[MSM8X10_WCD_A_SPKR_DRV_BIAS_LDO] =
+			MSM8X10_WCD_A_SPKR_DRV_BIAS_LDO__POR,
+	[MSM8X10_WCD_A_SPKR_DRV_BIAS_INT] =
+			MSM8X10_WCD_A_SPKR_DRV_BIAS_INT__POR,
+	[MSM8X10_WCD_A_SPKR_DRV_BIAS_PA] = MSM8X10_WCD_A_SPKR_DRV_BIAS_PA__POR,
+	[MSM8X10_WCD_A_SPKR_DRV_STATUS_OCP] =
+			MSM8X10_WCD_A_SPKR_DRV_STATUS_OCP__POR,
+	[MSM8X10_WCD_A_SPKR_DRV_STATUS_PA] =
+			MSM8X10_WCD_A_SPKR_DRV_STATUS_PA__POR,
+	[MSM8X10_WCD_A_RC_OSC_FREQ] = MSM8X10_WCD_A_RC_OSC_FREQ__POR,
+	[MSM8X10_WCD_A_RC_OSC_TEST] = MSM8X10_WCD_A_RC_OSC_TEST__POR,
+	[MSM8X10_WCD_A_RC_OSC_STATUS] = MSM8X10_WCD_A_RC_OSC_STATUS__POR,
+	[MSM8X10_WCD_A_RC_OSC_TUNER] = MSM8X10_WCD_A_RC_OSC_TUNER__POR,
+	[MSM8X10_WCD_A_MBHC_HPH] = MSM8X10_WCD_A_MBHC_HPH__POR,
+	[MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL] =
+			MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLK_TX_RESET_B1_CTL] =
+			MSM8X10_WCD_A_CDC_CLK_TX_RESET_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL] =
+			MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLK_RX_I2S_CTL] =
+			MSM8X10_WCD_A_CDC_CLK_RX_I2S_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLK_TX_I2S_CTL] =
+			MSM8X10_WCD_A_CDC_CLK_TX_I2S_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL] =
+			MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL] =
+			MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLK_OTHR_CTL] = MSM8X10_WCD_A_CDC_CLK_OTHR_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL] =
+			MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLK_MCLK_CTL] = MSM8X10_WCD_A_CDC_CLK_MCLK_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLK_PDM_CTL] = MSM8X10_WCD_A_CDC_CLK_PDM_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLK_SD_CTL] = MSM8X10_WCD_A_CDC_CLK_SD_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX1_B1_CTL] = MSM8X10_WCD_A_CDC_RX1_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX2_B1_CTL] = MSM8X10_WCD_A_CDC_RX2_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX3_B1_CTL] = MSM8X10_WCD_A_CDC_RX3_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX1_B2_CTL] = MSM8X10_WCD_A_CDC_RX1_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX2_B2_CTL] = MSM8X10_WCD_A_CDC_RX2_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX3_B2_CTL] = MSM8X10_WCD_A_CDC_RX3_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX1_B3_CTL] = MSM8X10_WCD_A_CDC_RX1_B3_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX2_B3_CTL] = MSM8X10_WCD_A_CDC_RX2_B3_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX3_B3_CTL] = MSM8X10_WCD_A_CDC_RX3_B3_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX1_B4_CTL] = MSM8X10_WCD_A_CDC_RX1_B4_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX2_B4_CTL] = MSM8X10_WCD_A_CDC_RX2_B4_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX3_B4_CTL] = MSM8X10_WCD_A_CDC_RX3_B4_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX1_B5_CTL] = MSM8X10_WCD_A_CDC_RX1_B5_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX2_B5_CTL] = MSM8X10_WCD_A_CDC_RX2_B5_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX3_B5_CTL] = MSM8X10_WCD_A_CDC_RX3_B5_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX1_B6_CTL] = MSM8X10_WCD_A_CDC_RX1_B6_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX2_B6_CTL] = MSM8X10_WCD_A_CDC_RX2_B6_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX3_B6_CTL] = MSM8X10_WCD_A_CDC_RX3_B6_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B1_CTL] =
+			MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B1_CTL] =
+			MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B1_CTL] =
+			MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL] =
+			MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL] =
+			MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL] =
+			MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B1_CTL] =
+			MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B2_CTL] =
+			MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B3_CTL] =
+			MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B3_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B4_CTL] =
+			MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B4_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLSG_GAIN_THRESH_CTL] =
+			MSM8X10_WCD_A_CDC_CLSG_GAIN_THRESH_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CLSG_TIMER_B1_CFG] =
+			MSM8X10_WCD_A_CDC_CLSG_TIMER_B1_CFG__POR,
+	[MSM8X10_WCD_A_CDC_CLSG_TIMER_B2_CFG] =
+			MSM8X10_WCD_A_CDC_CLSG_TIMER_B2_CFG__POR,
+	[MSM8X10_WCD_A_CDC_CLSG_CTL] = MSM8X10_WCD_A_CDC_CLSG_CTL__POR,
+	[MSM8X10_WCD_A_CDC_TX1_VOL_CTL_TIMER] =
+			MSM8X10_WCD_A_CDC_TX1_VOL_CTL_TIMER__POR,
+	[MSM8X10_WCD_A_CDC_TX2_VOL_CTL_TIMER] =
+			MSM8X10_WCD_A_CDC_TX2_VOL_CTL_TIMER__POR,
+	[MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN] =
+			MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN__POR,
+	[MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN] =
+			MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN__POR,
+	[MSM8X10_WCD_A_CDC_TX1_VOL_CTL_CFG] =
+			MSM8X10_WCD_A_CDC_TX1_VOL_CTL_CFG__POR,
+	[MSM8X10_WCD_A_CDC_TX2_VOL_CTL_CFG] =
+			MSM8X10_WCD_A_CDC_TX2_VOL_CTL_CFG__POR,
+	[MSM8X10_WCD_A_CDC_TX1_MUX_CTL] =
+			MSM8X10_WCD_A_CDC_TX1_MUX_CTL__POR,
+	[MSM8X10_WCD_A_CDC_TX2_MUX_CTL] =
+			MSM8X10_WCD_A_CDC_TX2_MUX_CTL__POR,
+	[MSM8X10_WCD_A_CDC_TX1_CLK_FS_CTL] =
+			MSM8X10_WCD_A_CDC_TX1_CLK_FS_CTL__POR,
+	[MSM8X10_WCD_A_CDC_TX2_CLK_FS_CTL] =
+			MSM8X10_WCD_A_CDC_TX2_CLK_FS_CTL__POR,
+	[MSM8X10_WCD_A_CDC_TX1_DMIC_CTL] =
+			MSM8X10_WCD_A_CDC_TX1_DMIC_CTL__POR,
+	[MSM8X10_WCD_A_CDC_TX2_DMIC_CTL] =
+			MSM8X10_WCD_A_CDC_TX2_DMIC_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B1_CTL] =
+			MSM8X10_WCD_A_CDC_IIR1_GAIN_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B1_CTL] =
+			MSM8X10_WCD_A_CDC_IIR2_GAIN_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B2_CTL] =
+			MSM8X10_WCD_A_CDC_IIR1_GAIN_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B2_CTL] =
+			MSM8X10_WCD_A_CDC_IIR2_GAIN_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B3_CTL] =
+			MSM8X10_WCD_A_CDC_IIR1_GAIN_B3_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B3_CTL] =
+			MSM8X10_WCD_A_CDC_IIR2_GAIN_B3_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL] =
+			MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B4_CTL] =
+			MSM8X10_WCD_A_CDC_IIR2_GAIN_B4_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B5_CTL] =
+			MSM8X10_WCD_A_CDC_IIR1_GAIN_B5_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B5_CTL] =
+			MSM8X10_WCD_A_CDC_IIR2_GAIN_B5_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B6_CTL] =
+			MSM8X10_WCD_A_CDC_IIR1_GAIN_B6_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B6_CTL] =
+			MSM8X10_WCD_A_CDC_IIR2_GAIN_B6_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B7_CTL] =
+			MSM8X10_WCD_A_CDC_IIR1_GAIN_B7_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B7_CTL] =
+			MSM8X10_WCD_A_CDC_IIR2_GAIN_B7_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_B8_CTL] =
+			MSM8X10_WCD_A_CDC_IIR1_GAIN_B8_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_B8_CTL] =
+			MSM8X10_WCD_A_CDC_IIR2_GAIN_B8_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR1_CTL] = MSM8X10_WCD_A_CDC_IIR1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR2_CTL] = MSM8X10_WCD_A_CDC_IIR2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR1_GAIN_TIMER_CTL] =
+			MSM8X10_WCD_A_CDC_IIR1_GAIN_TIMER_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR2_GAIN_TIMER_CTL] =
+			MSM8X10_WCD_A_CDC_IIR2_GAIN_TIMER_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL] =
+			MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR2_COEF_B1_CTL] =
+			MSM8X10_WCD_A_CDC_IIR2_COEF_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL] =
+			MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_IIR2_COEF_B2_CTL] =
+			MSM8X10_WCD_A_CDC_IIR2_COEF_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_RX1_B2_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_RX1_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_RX1_B3_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_RX1_B3_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_RX2_B2_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_RX2_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_RX2_B3_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_RX2_B3_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_RX3_B2_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_RX3_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_EQ1_B1_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_EQ1_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_EQ1_B2_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_EQ1_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_EQ1_B3_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_EQ1_B3_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_EQ1_B4_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_EQ1_B4_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_EQ2_B1_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_EQ2_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_EQ2_B2_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_EQ2_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_EQ2_B3_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_EQ2_B3_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_EQ2_B4_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_EQ2_B4_CTL__POR,
+	[MSM8X10_WCD_A_CDC_CONN_TX_I2S_SD1_CTL] =
+			MSM8X10_WCD_A_CDC_CONN_TX_I2S_SD1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_TOP_GAIN_UPDATE] =
+			MSM8X10_WCD_A_CDC_TOP_GAIN_UPDATE__POR,
+	[MSM8X10_WCD_A_CDC_TOP_CTL] = MSM8X10_WCD_A_CDC_TOP_CTL__POR,
+	[MSM8X10_WCD_A_CDC_DEBUG_DESER1_CTL] =
+			MSM8X10_WCD_A_CDC_DEBUG_DESER1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_DEBUG_DESER2_CTL] =
+			MSM8X10_WCD_A_CDC_DEBUG_DESER2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_DEBUG_B1_CTL] =
+			MSM8X10_WCD_A_CDC_DEBUG_B1_CTL__POR,
+	[MSM8X10_WCD_A_CDC_DEBUG_B2_CTL] =
+			MSM8X10_WCD_A_CDC_DEBUG_B2_CTL__POR,
+	[MSM8X10_WCD_A_CDC_DEBUG_B3_CTL] =
+			MSM8X10_WCD_A_CDC_DEBUG_B3_CTL__POR,
+};
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
new file mode 100644
index 0000000..4bcea07
--- /dev/null
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -0,0 +1,2427 @@
+/* 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/module.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "msm8x10-wcd.h"
+#include "wcd9xxx-resmgr.h"
+#include "msm8x10_wcd_registers.h"
+
+#define MSM8X10_WCD_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+#define MSM8X10_WCD_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
+#define NUM_DECIMATORS		2
+#define NUM_INTERPOLATORS	3
+#define BITS_PER_REG		8
+#define MSM8X10_WCD_TX_PORT_NUMBER	4
+
+#define MSM8X10_WCD_I2S_MASTER_MODE_MASK	0x08
+#define MSM8X10_DINO_CODEC_BASE_ADDR		0xFE043000
+
+#define MAX_MSM8X10_WCD_DEVICE	2
+#define CODEC_DT_MAX_PROP_SIZE	40
+#define MSM8X10_WCD_I2C_GSBI_SLAVE_ID "2-000d"
+
+enum {
+	MSM8X10_WCD_I2C_TOP_LEVEL = 0,
+	MSM8X10_WCD_I2C_ANALOG,
+	MSM8X10_WCD_I2C_DIGITAL_1,
+	MSM8X10_WCD_I2C_DIGITAL_2,
+};
+
+enum {
+	AIF1_PB = 0,
+	AIF1_CAP,
+	NUM_CODEC_DAIS,
+};
+
+enum {
+	RX_MIX1_INP_SEL_ZERO = 0,
+	RX_MIX1_INP_SEL_IIR1,
+	RX_MIX1_INP_SEL_IIR2,
+	RX_MIX1_INP_SEL_RX1,
+	RX_MIX1_INP_SEL_RX2,
+	RX_MIX1_INP_SEL_RX3,
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[];
+static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
+
+/* Codec supports 2 IIR filters */
+enum {
+	IIR1 = 0,
+	IIR2,
+	IIR_MAX,
+};
+/* Codec supports 5 bands */
+enum {
+	BAND1 = 0,
+	BAND2,
+	BAND3,
+	BAND4,
+	BAND5,
+	BAND_MAX,
+};
+
+struct hpf_work {
+	struct msm8x10_wcd_priv *msm8x10_wcd;
+	u32 decimator;
+	u8 tx_hpf_cut_of_freq;
+	struct delayed_work dwork;
+};
+
+static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
+
+struct msm8x10_wcd_priv {
+	struct snd_soc_codec *codec;
+	u32 adc_count;
+	u32 rx_bias_count;
+	s32 dmic_1_2_clk_cnt;
+
+	/* resmgr module */
+	struct wcd9xxx_resmgr resmgr;
+	/* mbhc module */
+	struct wcd9xxx_mbhc mbhc;
+};
+
+
+static unsigned short rx_digital_gain_reg[] = {
+	MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
+	MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
+	MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL,
+};
+
+static unsigned short tx_digital_gain_reg[] = {
+	MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN,
+	MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN,
+};
+
+struct msm8x10_wcd_i2c {
+	struct i2c_client *client;
+	struct i2c_msg xfer_msg[2];
+	struct mutex xfer_lock;
+	int mod_id;
+};
+
+static char *msm8x10_wcd_supplies[] = {
+	"cdc-vdd-mic-bias", "cdc-vdda-h", "cdc-vdd-1p2", "cdc-vdd-px",
+	"cdc-vdda-cp",
+};
+
+static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
+	struct msm8x10_wcd_regulator *vreg, const char *vreg_name);
+static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
+	struct msm8x10_wcd_micbias_setting *micbias);
+static struct msm8x10_wcd_pdata *msm8x10_wcd_populate_dt_pdata(
+	struct device *dev);
+
+struct msm8x10_wcd_i2c msm8x10_wcd_modules[MAX_MSM8X10_WCD_DEVICE];
+
+
+static int get_i2c_msm8x10_wcd_device_info(u16 reg,
+					   struct msm8x10_wcd_i2c **msm8x10_wcd)
+{
+	int rtn = 0;
+	int value = ((reg & 0x0f00) >> 8) & 0x000f;
+	pr_debug("%s: reg(0x%x) value(%d)\n", __func__, reg, value);
+	switch (value) {
+	case 0:
+	case 1:
+		*msm8x10_wcd = &msm8x10_wcd_modules[value];
+		break;
+	default:
+		rtn = -EINVAL;
+		break;
+	}
+	return rtn;
+}
+
+static int msm8x10_wcd_abh_write_device(u16 reg, u8 *value, u32 bytes)
+{
+	u32 temp = ((u32)(*value)) & 0x000000FF;
+	u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
+	iowrite32(temp, ioremap(MSM8X10_DINO_CODEC_BASE_ADDR + offset, 4));
+	return 0;
+}
+
+static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, u8 *value)
+{
+	u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
+	*value = (u8)ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
+				      offset, 4));
+	return 0;
+}
+
+static int msm8x10_wcd_i2c_write_device(u16 reg, u8 *value, u32 bytes)
+{
+
+	struct i2c_msg *msg;
+	int ret;
+	u8 reg_addr = 0;
+	u8 data[bytes + 1];
+	struct msm8x10_wcd_i2c *msm8x10_wcd;
+
+	ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
+	if (!ret) {
+		pr_err("%s: Invalid register address\n", __func__);
+		return ret;
+	}
+
+	if (msm8x10_wcd == NULL || msm8x10_wcd->client == NULL) {
+		pr_err("%s: Failed to get device info\n", __func__);
+		return -ENODEV;
+	}
+	reg_addr = (u8)reg;
+	msg = &msm8x10_wcd->xfer_msg[0];
+	msg->addr = msm8x10_wcd->client->addr;
+	msg->len = bytes + 1;
+	msg->flags = 0;
+	data[0] = reg;
+	data[1] = *value;
+	msg->buf = data;
+	ret = i2c_transfer(msm8x10_wcd->client->adapter,
+			   msm8x10_wcd->xfer_msg, 1);
+	/* Try again if the write fails */
+	if (ret != 1) {
+		ret = i2c_transfer(msm8x10_wcd->client->adapter,
+						msm8x10_wcd->xfer_msg, 1);
+		if (ret != 1) {
+			pr_err("failed to write the device\n");
+			return ret;
+		}
+	}
+	pr_debug("write sucess register = %x val = %x\n", reg, data[1]);
+	return 0;
+}
+
+
+int msm8x10_wcd_i2c_read_device(u32 reg, u32 bytes, u8 *dest)
+{
+	struct i2c_msg *msg;
+	int ret = 0;
+	u8 reg_addr = 0;
+	struct msm8x10_wcd_i2c *msm8x10_wcd;
+	u8 i = 0;
+
+	ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
+	if (!ret) {
+		pr_err("%s: Invalid register address\n", __func__);
+		return ret;
+	}
+
+	if (msm8x10_wcd == NULL || msm8x10_wcd->client == NULL) {
+		pr_err("%s: Failed to get device info\n", __func__);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < bytes; i++) {
+		reg_addr = (u8)reg++;
+		msg = &msm8x10_wcd->xfer_msg[0];
+		msg->addr = msm8x10_wcd->client->addr;
+		msg->len = 1;
+		msg->flags = 0;
+		msg->buf = &reg_addr;
+
+		msg = &msm8x10_wcd->xfer_msg[1];
+		msg->addr = msm8x10_wcd->client->addr;
+		msg->len = 1;
+		msg->flags = I2C_M_RD;
+		msg->buf = dest++;
+		ret = i2c_transfer(msm8x10_wcd->client->adapter,
+				msm8x10_wcd->xfer_msg, 2);
+
+		/* Try again if read fails first time */
+		if (ret != 2) {
+			ret = i2c_transfer(msm8x10_wcd->client->adapter,
+					   msm8x10_wcd->xfer_msg, 2);
+			if (ret != 2) {
+				pr_err("failed to read msm8x10_wcd register\n");
+				return ret;
+			}
+		}
+	}
+	return 0;
+}
+
+static int msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd, u16 reg)
+{
+	u8 val;
+	int ret = -EINVAL;
+
+	/* check if use I2C interface for Helicon or AHB for Dino */
+	mutex_lock(&msm8x10_wcd->io_lock);
+	if (MSM8X10_WCD_IS_HELICON_REG(reg))
+		ret = msm8x10_wcd_i2c_read_device(reg, 1, &val);
+	else if (MSM8X10_WCD_IS_DINO_REG(reg))
+		ret = msm8x10_wcd_abh_read_device(reg, 1, &val);
+	mutex_unlock(&msm8x10_wcd->io_lock);
+
+	if (ret < 0)
+		return ret;
+	else
+		return val;
+}
+
+
+static int msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd, u16  reg,
+				 u8 val)
+{
+	int ret = -EINVAL;
+
+	/* check if use I2C interface for Helicon or AHB for Dino */
+	mutex_lock(&msm8x10_wcd->io_lock);
+	if (MSM8X10_WCD_IS_HELICON_REG(reg))
+		ret = msm8x10_wcd_i2c_write_device(reg, &val, 1);
+	else if (MSM8X10_WCD_IS_DINO_REG(reg))
+		ret = msm8x10_wcd_abh_write_device(reg, &val, 1);
+	mutex_unlock(&msm8x10_wcd->io_lock);
+
+	return ret;
+}
+
+static bool msm8x10_wcd_is_digital_gain_register(unsigned int reg)
+{
+	bool rtn = false;
+	switch (reg) {
+	case MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL:
+	case MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL:
+	case MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL:
+	case MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN:
+	case MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN:
+		rtn = true;
+		break;
+	default:
+		break;
+	}
+	return rtn;
+}
+
+static int msm8x10_wcd_volatile(struct snd_soc_codec *ssc, unsigned int reg)
+{
+	/*
+	 * Registers lower than 0x100 are top level registers which can be
+	 * written by the Taiko core driver.
+	 */
+
+	if ((reg >= MSM8X10_WCD_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
+		return 1;
+
+	/* IIR Coeff registers are not cacheable */
+	if ((reg >= MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL) &&
+		(reg <= MSM8X10_WCD_A_CDC_IIR2_COEF_B2_CTL))
+		return 1;
+
+	/*
+	 * Digital gain register is not cacheable so we have to write
+	 * the setting even it is the same
+	 */
+	if (msm8x10_wcd_is_digital_gain_register(reg))
+		return 1;
+
+	/* HPH status registers */
+	if (reg == MSM8X10_WCD_A_RX_HPH_L_STATUS ||
+	    reg == MSM8X10_WCD_A_RX_HPH_R_STATUS)
+		return 1;
+
+	if (reg == MSM8X10_WCD_A_MBHC_INSERT_DET_STATUS)
+		return 1;
+
+	return 0;
+}
+
+static int msm8x10_wcd_readable(struct snd_soc_codec *ssc, unsigned int reg)
+{
+	return msm8x10_wcd_reg_readable[reg];
+}
+
+static int msm8x10_wcd_write(struct snd_soc_codec *codec, unsigned int reg,
+			     unsigned int value)
+{
+	int ret;
+
+	if (reg == SND_SOC_NOPM)
+		return 0;
+
+	BUG_ON(reg > MSM8X10_WCD_MAX_REGISTER);
+
+	if (!msm8x10_wcd_volatile(codec, reg)) {
+		ret = snd_soc_cache_write(codec, reg, value);
+		if (ret != 0)
+			dev_err(codec->dev, "Cache write to %x failed: %d\n",
+				reg, ret);
+	}
+
+	return msm8x10_wcd_reg_write(codec->control_data, reg, value);
+}
+
+static unsigned int msm8x10_wcd_read(struct snd_soc_codec *codec,
+				unsigned int reg)
+{
+	unsigned int val;
+	int ret;
+
+	if (reg == SND_SOC_NOPM)
+		return 0;
+
+	BUG_ON(reg > MSM8X10_WCD_MAX_REGISTER);
+
+	if (!msm8x10_wcd_volatile(codec, reg) &&
+	    msm8x10_wcd_readable(codec, reg) &&
+		reg < codec->driver->reg_cache_size) {
+		ret = snd_soc_cache_read(codec, reg, &val);
+		if (ret >= 0) {
+			return val;
+		} else
+			dev_err(codec->dev, "Cache read from %x failed: %d\n",
+				reg, ret);
+	}
+
+	val = msm8x10_wcd_reg_read(codec->control_data, reg);
+	return val;
+}
+
+
+static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
+	struct msm8x10_wcd_regulator *vreg, const char *vreg_name)
+{
+	int len, ret = 0;
+	const __be32 *prop;
+	char prop_name[CODEC_DT_MAX_PROP_SIZE];
+	struct device_node *regnode = NULL;
+	u32 prop_val;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply",
+		vreg_name);
+	regnode = of_parse_phandle(dev->of_node, prop_name, 0);
+
+	if (!regnode) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+				prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+	vreg->name = vreg_name;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+		"qcom,%s-voltage", vreg_name);
+	prop = of_get_property(dev->of_node, prop_name, &len);
+
+	if (!prop || (len != (2 * sizeof(__be32)))) {
+		dev_err(dev, "%s %s property\n",
+				prop ? "invalid format" : "no", prop_name);
+		return -ENODEV;
+	} else {
+		vreg->min_uV = be32_to_cpup(&prop[0]);
+		vreg->max_uV = be32_to_cpup(&prop[1]);
+	}
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+			"qcom,%s-current", vreg_name);
+
+	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+				prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+	vreg->optimum_uA = prop_val;
+
+	dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA\n", vreg->name,
+		vreg->min_uV, vreg->max_uV, vreg->optimum_uA);
+	return 0;
+}
+
+static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
+	struct msm8x10_wcd_micbias_setting *micbias)
+{
+	int ret = 0;
+	char prop_name[CODEC_DT_MAX_PROP_SIZE];
+	u32 prop_val;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+			"qcom,cdc-micbias-ldoh-v");
+	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+	micbias->ldoh_v = (u8)prop_val;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+			"qcom,cdc-micbias-cfilt1-mv");
+	ret = of_property_read_u32(dev->of_node, prop_name,
+				   &micbias->cfilt1_mv);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+			"qcom,cdc-micbias1-cfilt-sel");
+	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+	micbias->bias1_cfilt_sel = (u8)prop_val;
+
+	/* micbias external cap */
+	micbias->bias1_cap_mode =
+	    (of_property_read_bool(dev->of_node, "qcom,cdc-micbias1-ext-cap") ?
+	     MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+
+	dev_dbg(dev, "ldoh_v  %u cfilt1_mv %u\n",
+			(u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv);
+	dev_dbg(dev, "bias1_cfilt_sel %u\n", (u32)micbias->bias1_cfilt_sel);
+	dev_dbg(dev, "bias1_ext_cap %d\n", micbias->bias1_cap_mode);
+
+	return 0;
+}
+
+static struct msm8x10_wcd_pdata *msm8x10_wcd_populate_dt_pdata(
+						struct device *dev)
+{
+	struct msm8x10_wcd_pdata *pdata;
+	int ret, i;
+	char **codec_supplies;
+	u32 num_of_supplies = 0;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(dev, "could not allocate memory for platform data\n");
+		return NULL;
+	}
+	if ((!strcmp(dev_name(dev), MSM8X10_WCD_I2C_GSBI_SLAVE_ID))) {
+		codec_supplies = msm8x10_wcd_supplies;
+		num_of_supplies = ARRAY_SIZE(msm8x10_wcd_supplies);
+	} else {
+		dev_err(dev, "%s unsupported device %s\n",
+				__func__, dev_name(dev));
+		goto err;
+	}
+
+	if (num_of_supplies > ARRAY_SIZE(pdata->regulator)) {
+		dev_err(dev, "%s: Num of supplies %u > max supported %u\n",
+		      __func__, num_of_supplies, ARRAY_SIZE(pdata->regulator));
+
+		goto err;
+	}
+
+	for (i = 0; i < num_of_supplies; i++) {
+		ret = msm8x10_wcd_dt_parse_vreg_info(dev, &pdata->regulator[i],
+			codec_supplies[i]);
+		if (ret)
+			goto err;
+	}
+
+	ret = msm8x10_wcd_dt_parse_micbias_info(dev, &pdata->micbias);
+	if (ret)
+		goto err;
+
+	pdata->reset_gpio = of_get_named_gpio(dev->of_node,
+				"qcom,cdc-reset-gpio", 0);
+	if (pdata->reset_gpio < 0) {
+		dev_err(dev, "Looking up %s property in node %s failed %d\n",
+			"qcom, cdc-reset-gpio", dev->of_node->full_name,
+			pdata->reset_gpio);
+		goto err;
+	}
+	dev_dbg(dev, "%s: reset gpio %d", __func__, pdata->reset_gpio);
+	return pdata;
+err:
+	devm_kfree(dev, pdata);
+	return NULL;
+}
+
+static int msm8x10_wcd_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_debug("%s %d\n", __func__, event);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* Enable charge pump clock*/
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_OTHR_CTL,
+				    0x01, 0x01);
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLSG_CTL,
+				    0x08, 0x08);
+		usleep_range(200, 300);
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_CP_STATIC,
+				    0x10, 0x00);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec,
+				    MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
+				    0x01, 0x01);
+		usleep_range(20, 100);
+		snd_soc_update_bits(codec,
+				    MSM8X10_WCD_A_CP_STATIC, 0x08, 0x08);
+		snd_soc_update_bits(codec,
+				    MSM8X10_WCD_A_CP_STATIC, 0x10, 0x10);
+		snd_soc_update_bits(codec,
+				    MSM8X10_WCD_A_CDC_CLSG_CTL, 0x08, 0x00);
+		snd_soc_update_bits(codec,
+				    MSM8X10_WCD_A_CDC_CLK_OTHR_CTL, 0x01,
+				    0x00);
+		snd_soc_update_bits(codec,
+				    MSM8X10_WCD_A_CP_STATIC, 0x08, 0x00);
+		break;
+	}
+	return 0;
+}
+
+static int msm8x10_wcd_pa_gain_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u8 ear_pa_gain;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	ear_pa_gain = snd_soc_read(codec, MSM8X10_WCD_A_RX_EAR_GAIN);
+
+	ear_pa_gain = ear_pa_gain >> 5;
+
+	if (ear_pa_gain == 0x00) {
+		ucontrol->value.integer.value[0] = 0;
+	} else if (ear_pa_gain == 0x04) {
+		ucontrol->value.integer.value[0] = 1;
+	} else  {
+		pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
+				__func__, ear_pa_gain);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
+
+	return 0;
+}
+
+static int msm8x10_wcd_pa_gain_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u8 ear_pa_gain;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	pr_debug("%s: ucontrol->value.integer.value[0]  = %ld\n",
+		 __func__, ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		ear_pa_gain = 0x00;
+		break;
+	case 1:
+		ear_pa_gain = 0x80;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_RX_EAR_GAIN,
+			    0xE0, ear_pa_gain);
+	return 0;
+}
+
+static int msm8x10_wcd_get_iir_enable_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	ucontrol->value.integer.value[0] =
+		snd_soc_read(codec,
+			    (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx)) &
+		(1 << band_idx);
+
+	pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
+		iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int msm8x10_wcd_put_iir_enable_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+
+	/* Mask first 5 bits, 6-8 are reserved */
+	snd_soc_update_bits(codec, (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx),
+		(1 << band_idx), (value << band_idx));
+
+	pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
+		iir_idx, band_idx, value);
+	return 0;
+}
+static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
+				int iir_idx, int band_idx,
+				int coeff_idx)
+{
+	/* Address does not automatically update if reading */
+	snd_soc_write(codec,
+		(MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
+		(band_idx * BAND_MAX + coeff_idx) & 0x1F);
+
+	/* Mask bits top 2 bits since they are reserved */
+	return ((snd_soc_read(codec,
+		(MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 24)) &
+		0x3FFFFFFF;
+}
+
+static int msm8x10_wcd_get_iir_band_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	ucontrol->value.integer.value[0] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 0);
+	ucontrol->value.integer.value[1] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 1);
+	ucontrol->value.integer.value[2] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 2);
+	ucontrol->value.integer.value[3] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 3);
+	ucontrol->value.integer.value[4] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 4);
+
+	pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
+		"%s: IIR #%d band #%d b1 = 0x%x\n"
+		"%s: IIR #%d band #%d b2 = 0x%x\n"
+		"%s: IIR #%d band #%d a1 = 0x%x\n"
+		"%s: IIR #%d band #%d a2 = 0x%x\n",
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[0],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[1],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[2],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[3],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[4]);
+	return 0;
+}
+
+static void set_iir_band_coeff(struct snd_soc_codec *codec,
+				int iir_idx, int band_idx,
+				int coeff_idx, uint32_t value)
+{
+	/* Mask top 3 bits, 6-8 are reserved */
+	/* Update address manually each time */
+	snd_soc_write(codec,
+		(MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
+		(band_idx * BAND_MAX + coeff_idx) & 0x1F);
+
+	/* Mask top 2 bits, 7-8 are reserved */
+	snd_soc_write(codec,
+		(MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
+		(value >> 24) & 0x3F);
+
+}
+
+static int msm8x10_wcd_put_iir_band_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	set_iir_band_coeff(codec, iir_idx, band_idx, 0,
+				ucontrol->value.integer.value[0]);
+	set_iir_band_coeff(codec, iir_idx, band_idx, 1,
+				ucontrol->value.integer.value[1]);
+	set_iir_band_coeff(codec, iir_idx, band_idx, 2,
+				ucontrol->value.integer.value[2]);
+	set_iir_band_coeff(codec, iir_idx, band_idx, 3,
+				ucontrol->value.integer.value[3]);
+	set_iir_band_coeff(codec, iir_idx, band_idx, 4,
+				ucontrol->value.integer.value[4]);
+
+	pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
+		"%s: IIR #%d band #%d b1 = 0x%x\n"
+		"%s: IIR #%d band #%d b2 = 0x%x\n"
+		"%s: IIR #%d band #%d a1 = 0x%x\n"
+		"%s: IIR #%d band #%d a2 = 0x%x\n",
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 0),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 1),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 2),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 3),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 4));
+	return 0;
+}
+
+static const char * const msm8x10_wcd_ear_pa_gain_text[] = {
+		"POS_6_DB", "POS_2_DB"};
+static const struct soc_enum msm8x10_wcd_ear_pa_gain_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, msm8x10_wcd_ear_pa_gain_text),
+};
+
+/*cut of frequency for high pass filter*/
+static const char * const cf_text[] = {
+	"MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
+};
+
+static const struct soc_enum cf_dec1_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec2_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_rxmix1_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
+
+static const struct soc_enum cf_rxmix2_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
+
+static const struct soc_enum cf_rxmix3_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
+
+static const struct snd_kcontrol_new msm8x10_wcd_snd_controls[] = {
+
+	SOC_ENUM_EXT("EAR PA Gain", msm8x10_wcd_ear_pa_gain_enum[0],
+		msm8x10_wcd_pa_gain_get, msm8x10_wcd_pa_gain_put),
+
+	SOC_SINGLE_TLV("LINEOUT1 Volume", MSM8X10_WCD_A_RX_LINE_1_GAIN,
+		       0, 12, 1, line_gain),
+
+	SOC_SINGLE_TLV("HPHL Volume", MSM8X10_WCD_A_RX_HPH_L_GAIN,
+		       0, 12, 1, line_gain),
+	SOC_SINGLE_TLV("HPHR Volume", MSM8X10_WCD_A_RX_HPH_R_GAIN,
+		       0, 12, 1, line_gain),
+
+	SOC_SINGLE_S8_TLV("RX1 Digital Volume",
+			  MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX2 Digital Volume",
+			  MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX3 Digital Volume",
+			  MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL,
+			  -84, 40, digital_gain),
+
+	SOC_SINGLE_S8_TLV("DEC1 Volume",
+			  MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("DEC2 Volume",
+			  MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN,
+			  -84, 40, digital_gain),
+
+	SOC_SINGLE_S8_TLV("IIR1 INP1 Volume",
+			  MSM8X10_WCD_A_CDC_IIR1_GAIN_B1_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP2 Volume",
+			  MSM8X10_WCD_A_CDC_IIR1_GAIN_B2_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP3 Volume",
+			  MSM8X10_WCD_A_CDC_IIR1_GAIN_B3_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP4 Volume",
+			  MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL,
+			  -84,	40, digital_gain),
+
+	SOC_SINGLE("MICBIAS1 CAPLESS Switch",
+		   MSM8X10_WCD_A_MICB_1_CTL, 4, 1, 1),
+
+	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
+	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
+
+	SOC_SINGLE("TX1 HPF Switch", MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 3, 1, 0),
+	SOC_SINGLE("TX2 HPF Switch", MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 3, 1, 0),
+
+	SOC_SINGLE("RX1 HPF Switch", MSM8X10_WCD_A_CDC_RX1_B5_CTL, 2, 1, 0),
+	SOC_SINGLE("RX2 HPF Switch", MSM8X10_WCD_A_CDC_RX2_B5_CTL, 2, 1, 0),
+	SOC_SINGLE("RX3 HPF Switch", MSM8X10_WCD_A_CDC_RX3_B5_CTL, 2, 1, 0),
+
+	SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
+	SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
+	SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
+
+	SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
+	msm8x10_wcd_get_iir_enable_audio_mixer,
+	msm8x10_wcd_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
+	msm8x10_wcd_get_iir_enable_audio_mixer,
+	msm8x10_wcd_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
+	msm8x10_wcd_get_iir_enable_audio_mixer,
+	msm8x10_wcd_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
+	msm8x10_wcd_get_iir_enable_audio_mixer,
+	msm8x10_wcd_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
+	msm8x10_wcd_get_iir_enable_audio_mixer,
+	msm8x10_wcd_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
+	msm8x10_wcd_get_iir_enable_audio_mixer,
+	msm8x10_wcd_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
+	msm8x10_wcd_get_iir_enable_audio_mixer,
+	msm8x10_wcd_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
+	msm8x10_wcd_get_iir_enable_audio_mixer,
+	msm8x10_wcd_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
+	msm8x10_wcd_get_iir_enable_audio_mixer,
+	msm8x10_wcd_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
+	msm8x10_wcd_get_iir_enable_audio_mixer,
+	msm8x10_wcd_put_iir_enable_audio_mixer),
+
+	SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
+	msm8x10_wcd_get_iir_band_audio_mixer,
+	msm8x10_wcd_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
+	msm8x10_wcd_get_iir_band_audio_mixer,
+	msm8x10_wcd_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
+	msm8x10_wcd_get_iir_band_audio_mixer,
+	msm8x10_wcd_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
+	msm8x10_wcd_get_iir_band_audio_mixer,
+	msm8x10_wcd_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
+	msm8x10_wcd_get_iir_band_audio_mixer,
+	msm8x10_wcd_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
+	msm8x10_wcd_get_iir_band_audio_mixer,
+	msm8x10_wcd_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
+	msm8x10_wcd_get_iir_band_audio_mixer,
+	msm8x10_wcd_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
+	msm8x10_wcd_get_iir_band_audio_mixer,
+	msm8x10_wcd_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
+	msm8x10_wcd_get_iir_band_audio_mixer,
+	msm8x10_wcd_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
+	msm8x10_wcd_get_iir_band_audio_mixer,
+	msm8x10_wcd_put_iir_band_audio_mixer),
+
+};
+
+static const char * const rx_mix1_text[] = {
+	"ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
+};
+
+static const char * const rx_mix2_text[] = {
+	"ZERO", "IIR1", "IIR2"
+};
+
+static const char * const dec_mux_text[] = {
+	"ZERO", "ADC1", "ADC2", "DMIC1", "DMIC2"
+};
+
+
+static const char * const anc_mux_text[] = {
+	"ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
+		"RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
+};
+
+static const char * const anc1_fb_mux_text[] = {
+	"ZERO", "EAR_HPH_L", "EAR_LINE_1",
+};
+
+static const char * const iir1_inp1_text[] = {
+	"ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
+};
+
+static const struct soc_enum rx_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text);
+
+static const struct soc_enum rx_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 3, 6, rx_mix1_text);
+
+static const struct soc_enum rx_mix1_inp3_chain_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text);
+
+static const struct soc_enum rx1_mix2_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text);
+
+static const struct soc_enum rx2_mix2_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text);
+
+static const struct soc_enum dec1_mux_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL, 0, 5, dec_mux_text);
+
+static const struct soc_enum dec2_mux_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL, 3, 5, dec_mux_text);
+
+static const struct soc_enum iir1_inp1_mux_enum =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_EQ1_B1_CTL, 0, 6,
+	iir1_inp1_text);
+
+static const struct snd_kcontrol_new rx_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp3_mux =
+	SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
+	SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
+	SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
+
+static int msm8x10_wcd_put_dec_enum(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *w = wlist->widgets[0];
+	struct snd_soc_codec *codec = w->codec;
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int dec_mux, decimator;
+	char *dec_name = NULL;
+	char *widget_name = NULL;
+	char *temp;
+	u16 tx_mux_ctl_reg;
+	u8 adc_dmic_sel = 0x0;
+	int ret = 0;
+
+	if (ucontrol->value.enumerated.item[0] > e->max - 1)
+		return -EINVAL;
+
+	dec_mux = ucontrol->value.enumerated.item[0];
+
+	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+	if (!widget_name)
+		return -ENOMEM;
+	temp = widget_name;
+
+	dec_name = strsep(&widget_name, " ");
+	widget_name = temp;
+	if (!dec_name) {
+		pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
+		ret =  -EINVAL;
+		goto out;
+	}
+
+	ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
+	if (ret < 0) {
+		pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
+		ret =  -EINVAL;
+		goto out;
+	}
+
+	dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
+		, __func__, w->name, decimator, dec_mux);
+
+	switch (decimator) {
+	case 1:
+	case 2:
+		if (dec_mux == 1)
+			adc_dmic_sel = 0x1;
+		else
+			adc_dmic_sel = 0x0;
+		break;
+	default:
+		pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL + 32 * (decimator - 1);
+
+	snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
+
+	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+out:
+	kfree(widget_name);
+	return ret;
+}
+
+#define MSM8X10_WCD_DEC_ENUM(xname, xenum) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_enum_double, \
+	.get = snd_soc_dapm_get_enum_double, \
+	.put = msm8x10_wcd_put_dec_enum, \
+	.private_value = (unsigned long)&xenum }
+
+static const struct snd_kcontrol_new dec1_mux =
+	MSM8X10_WCD_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
+
+static const struct snd_kcontrol_new dec2_mux =
+	MSM8X10_WCD_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp1_mux =
+	SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
+
+static const struct snd_kcontrol_new dac1_switch[] = {
+	SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_EAR_EN, 5, 1, 0)
+};
+static const struct snd_kcontrol_new hphl_switch[] = {
+	SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
+};
+
+/* virtual port entries */
+static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+
+	ucontrol->value.integer.value[0] = widget->value;
+	return 0;
+}
+
+static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	return 0;
+}
+
+static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+
+	ucontrol->value.enumerated.item[0] = widget->value;
+	return 0;
+}
+
+static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	return 0;
+}
+
+
+static const char *const slim_rx_mux_text[] = {
+	"ZERO", "AIF1_PB"
+};
+
+static const struct soc_enum slim_rx_mux_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
+
+static const struct snd_kcontrol_new slim_rx_mux[MSM8X10_WCD_RX_MAX] = {
+	SOC_DAPM_ENUM_EXT("I2S RX1 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("I2S RX2 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("I2S RX3 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+};
+
+static const struct snd_kcontrol_new aif_cap_mixer[] = {
+	SOC_SINGLE_EXT("I2S TX1", SND_SOC_NOPM, MSM8X10_WCD_TX1, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("I2S TX2", SND_SOC_NOPM, MSM8X10_WCD_TX2, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("I2S TX3", SND_SOC_NOPM, MSM8X10_WCD_TX3, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("I2S TX4", SND_SOC_NOPM, MSM8X10_WCD_TX4, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
+
+static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
+					 int enable)
+{
+	struct msm8x10_wcd_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s %d\n", __func__, enable);
+
+	if (enable) {
+		taiko->adc_count++;
+		snd_soc_update_bits(codec,
+				    MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+				    0x20, 0x20);
+	} else {
+		taiko->adc_count--;
+		if (!taiko->adc_count)
+			snd_soc_update_bits(codec,
+					    MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+					    0x20, 0x0);
+	}
+}
+
+static int msm8x10_wcd_codec_enable_adc(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 adc_reg;
+	u8 init_bit_shift;
+
+	pr_debug("%s %d\n", __func__, event);
+	adc_reg = MSM8X10_WCD_A_TX_1_2_TEST_CTL;
+
+	if (w->reg == MSM8X10_WCD_A_TX_1_EN)
+		init_bit_shift = 7;
+	else if (adc_reg == MSM8X10_WCD_A_TX_2_EN)
+		init_bit_shift = 6;
+	else {
+		pr_err("%s: Error, invalid adc register\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		msm8x10_wcd_codec_enable_adc_block(codec, 1);
+		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
+				1 << init_bit_shift);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		msm8x10_wcd_codec_enable_adc_block(codec, 0);
+		break;
+	}
+	return 0;
+}
+
+static int msm8x10_wcd_codec_enable_lineout(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 lineout_gain_reg;
+
+	pr_debug("%s %d %s\n", __func__, event, w->name);
+
+	switch (w->shift) {
+	case 0:
+		lineout_gain_reg = MSM8X10_WCD_A_RX_LINE_1_GAIN;
+		break;
+	default:
+		pr_err("%s: Error, incorrect lineout register value\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
+				__func__, w->name);
+		usleep_range(16000, 16100);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
+		break;
+	}
+	return 0;
+}
+
+static int msm8x10_wcd_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol, int event)
+{
+	pr_debug("%s %d %s\n", __func__, event, w->name);
+	return 0;
+}
+
+static int msm8x10_wcd_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+	u8  dmic_clk_en;
+	u16 dmic_clk_reg;
+	s32 *dmic_clk_cnt;
+	unsigned int dmic;
+	int ret;
+
+	ret = kstrtouint(strpbrk(w->name, "12"), 10, &dmic);
+	if (ret < 0) {
+		pr_err("%s: Invalid DMIC line on the codec\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (dmic) {
+	case 1:
+	case 2:
+		dmic_clk_en = 0x01;
+		dmic_clk_cnt = &(msm8x10_wcd->dmic_1_2_clk_cnt);
+		dmic_clk_reg = MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL;
+		pr_debug("%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
+			__func__, event,  dmic, *dmic_clk_cnt);
+		break;
+	default:
+		pr_err("%s: Invalid DMIC Selection\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+
+		(*dmic_clk_cnt)++;
+		if (*dmic_clk_cnt == 1)
+			snd_soc_update_bits(codec, dmic_clk_reg,
+					dmic_clk_en, dmic_clk_en);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+
+		(*dmic_clk_cnt)--;
+		if (*dmic_clk_cnt  == 0)
+			snd_soc_update_bits(codec, dmic_clk_reg,
+					dmic_clk_en, 0);
+		break;
+	}
+	return 0;
+}
+
+static int msm8x10_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+	u16 micb_int_reg;
+	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 MSM8X10_WCD_A_MICB_1_CTL:
+		micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
+		cfilt_sel_val =
+			msm8x10_wcd->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;
+	default:
+		pr_err("%s: Error, invalid micbias register\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Let MBHC module know so micbias switch to be off */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
+
+		/* Get cfilt */
+		wcd9xxx_resmgr_cfilt_get(&msm8x10_wcd->resmgr, cfilt_sel_val);
+
+		if (strnstr(w->name, internal1_text, 30))
+			snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
+		else if (strnstr(w->name, internal2_text, 30))
+			snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
+		else if (strnstr(w->name, internal3_text, 30))
+			snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(20000, 20100);
+		/* Let MBHC module know so micbias is on */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_on);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Let MBHC module know so micbias switch to be off */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
+
+		if (strnstr(w->name, internal1_text, 30))
+			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
+		else if (strnstr(w->name, internal2_text, 30))
+			snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
+		else if (strnstr(w->name, internal3_text, 30))
+			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
+
+		/* Put cfilt */
+		wcd9xxx_resmgr_cfilt_put(&msm8x10_wcd->resmgr, cfilt_sel_val);
+		break;
+	}
+
+	return 0;
+}
+
+#define  TX_MUX_CTL_CUT_OFF_FREQ_MASK	0x30
+#define  CF_MIN_3DB_4HZ			0x0
+#define  CF_MIN_3DB_75HZ		0x1
+#define  CF_MIN_3DB_150HZ		0x2
+
+static int msm8x10_wcd_codec_enable_dec(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	unsigned int decimator;
+	char *dec_name = NULL;
+	char *widget_name = NULL;
+	char *temp;
+	int ret = 0;
+	u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
+	u8 dec_hpf_cut_of_freq;
+	int offset;
+
+	pr_debug("%s %d\n", __func__, event);
+
+	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+	if (!widget_name)
+		return -ENOMEM;
+	temp = widget_name;
+
+	dec_name = strsep(&widget_name, " ");
+	widget_name = temp;
+	if (!dec_name) {
+		pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
+	if (ret < 0) {
+		pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
+			w->name, dec_name, decimator);
+
+	if (w->reg == MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
+		dec_reset_reg = MSM8X10_WCD_A_CDC_CLK_TX_RESET_B1_CTL;
+		offset = 0;
+	} else {
+		pr_err("%s: Error, incorrect dec\n", __func__);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	tx_vol_ctl_reg = MSM8X10_WCD_A_CDC_TX1_VOL_CTL_CFG +
+			 32 * (decimator - 1);
+	tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
+			  32 * (decimator - 1);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Enableable TX digital mute */
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+
+		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
+			1 << w->shift);
+		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
+
+		dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
+
+		dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
+
+		tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
+			dec_hpf_cut_of_freq;
+
+		if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
+
+			/* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
+			snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
+					    CF_MIN_3DB_150HZ << 4);
+		}
+
+		/* enable HPF */
+		snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* Disable TX digital mute */
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
+
+		if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
+				CF_MIN_3DB_150HZ) {
+
+			schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
+					msecs_to_jiffies(300));
+		}
+		/* apply the digital gain after the decimator is enabled*/
+		if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg))
+			snd_soc_write(codec,
+				  tx_digital_gain_reg[w->shift + offset],
+				  snd_soc_read(codec,
+				  tx_digital_gain_reg[w->shift + offset])
+				  );
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+		cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
+			(tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
+		break;
+	}
+out:
+	kfree(widget_name);
+	return ret;
+}
+
+static int msm8x10_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_debug("%s %d %s\n", __func__, event, w->name);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL,
+			1 << w->shift, 1 << w->shift);
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL,
+			1 << w->shift, 0x0);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* apply the digital gain after the interpolator is enabled*/
+		if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
+			snd_soc_write(codec,
+				  rx_digital_gain_reg[w->shift],
+				  snd_soc_read(codec,
+				  rx_digital_gain_reg[w->shift])
+				  );
+		break;
+	}
+	return 0;
+}
+
+
+/* The register address is the same as other codec so it can use resmgr */
+static int msm8x10_wcd_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd9xxx_resmgr_enable_rx_bias(&msm8x10_wcd->resmgr, 1);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd9xxx_resmgr_enable_rx_bias(&msm8x10_wcd->resmgr, 0);
+		break;
+	}
+	return 0;
+}
+
+static int msm8x10_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_debug("%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
+		break;
+	}
+	return 0;
+}
+
+static int msm8x10_wcd_hph_pa_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+	enum wcd9xxx_notify_event e_pre_on, e_post_off;
+
+	pr_debug("%s: %s event = %d\n", __func__, w->name, event);
+	if (w->shift == 5) {
+		e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
+		e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
+	} else if (w->shift == 4) {
+		e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
+		e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
+	} else {
+		pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Let MBHC module know PA is turning on */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(10000, 10100);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		/* Let MBHC module know PA turned off */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
+
+		/*
+		 * schedule work is required because at the time HPH PA DAPM
+		 * event callback is called by DAPM framework, CODEC dapm mutex
+		 * would have been locked while snd_soc_jack_report also
+		 * attempts to acquire same lock.
+		 */
+		pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
+			 w->name);
+		usleep_range(10000, 10100);
+		break;
+	}
+	return 0;
+}
+
+static int msm8x10_wcd_lineout_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_debug("%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
+		break;
+	}
+	return 0;
+}
+
+static int msm8x10_wcd_spk_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	pr_debug("%s %s %d\n", __func__, w->name, event);
+	return 0;
+}
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	{"RX_I2S_CLK", NULL, "CDC_CONN"},
+	{"I2S RX1", NULL, "RX_I2S_CLK"},
+	{"I2S RX2", NULL, "RX_I2S_CLK"},
+	{"I2S RX3", NULL, "RX_I2S_CLK"},
+
+	{"I2S TX1", NULL, "TX_I2S_CLK"},
+	{"I2S TX2", NULL, "TX_I2S_CLK"},
+	{"I2S TX3", NULL, "TX_I2S_CLK"},
+	{"I2S TX4", NULL, "TX_I2S_CLK"},
+
+	{"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
+
+	{"AIF1_CAP Mixer", "I2S TX1", "I2S TX1 MUX"},
+	{"AIF1_CAP Mixer", "I2S TX2", "I2S TX2 MUX"},
+	{"AIF1_CAP Mixer", "I2S TX3", "I2S TX3 MUX"},
+	{"AIF1_CAP Mixer", "I2S TX4", "I2S TX4 MUX"},
+
+	{"I2S TX1 MUX", NULL, "DEC1 MUX"},
+	{"I2S TX2 MUX", NULL, "DEC2 MUX"},
+	{"I2S TX3 MUX", NULL, "RX1 MIX1"},
+	{"I2S TX4 MUX", "RMIX2", "RX1 MIX2"},
+	{"I2S TX4 MUX", "RMIX3", "RX1 MIX3"},
+
+	/* Earpiece (RX MIX1) */
+	{"EAR", NULL, "EAR PA"},
+	{"EAR PA", NULL, "DAC1"},
+	{"DAC1", NULL, "CP"},
+
+	/* Headset (RX MIX1 and RX MIX2) */
+	{"HEADPHONE", NULL, "HPHL"},
+	{"HEADPHONE", NULL, "HPHR"},
+
+	{"HPHL", NULL, "HPHL DAC"},
+
+	{"HPHR", NULL, "HPHR DAC"},
+	{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
+
+	{"HPHL DAC", NULL, "CP"},
+
+	{"HPHR DAC", NULL, "CP"},
+
+	{"DAC1", "Switch", "RX1 CHAIN"},
+	{"HPHL DAC", "Switch", "RX1 CHAIN"},
+	{"HPHR DAC", NULL, "RX2 CHAIN"},
+
+	{"LINEOUT1", NULL, "LINEOUT1 PA"},
+	{"SPK_OUT", NULL, "SPK PA"},
+
+	{"LINEOUT1 PA", NULL, "CP"},
+	{"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
+
+	{"LINEOUT1 DAC", "RX2 INPUT", "RX2 MIX1"},
+	{"LINEOUT1 DAC", "RX3 INPUT", "RX3 MIX1"},
+
+	{"SPK PA", NULL, "SPK DAC"},
+	{"SPK DAC", NULL, "RX7 MIX2"},
+
+	{"RX1 CHAIN", NULL, "RX1 MIX2"},
+	{"RX2 CHAIN", NULL, "RX2 MIX2"},
+
+	{"LINEOUT1 DAC", NULL, "RX_BIAS"},
+	{"SPK DAC", NULL, "RX_BIAS"},
+
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
+	{"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
+	{"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
+	{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
+	{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
+	{"RX1 MIX2", NULL, "RX1 MIX1"},
+	{"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
+	{"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
+	{"RX2 MIX2", NULL, "RX2 MIX1"},
+	{"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
+	{"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
+
+	{"I2S RX1 MUX", "AIF1_PB", "AIF1 PB"},
+	{"I2S RX2 MUX", "AIF1_PB", "AIF1 PB"},
+	{"I2S RX3 MUX", "AIF1_PB", "AIF1 PB"},
+
+	{"I2S RX1", NULL, "I2S RX1 MUX"},
+	{"I2S RX2", NULL, "I2S RX2 MUX"},
+	{"I2S RX3", NULL, "I2S RX3 MUX"},
+
+	{"RX1 MIX1 INP1", "RX1", "I2S RX1"},
+	{"RX1 MIX1 INP1", "RX2", "I2S RX2"},
+	{"RX1 MIX1 INP1", "RX3", "I2S RX3"},
+	{"RX1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX1 MIX1 INP2", "RX1", "I2S RX1"},
+	{"RX1 MIX1 INP2", "RX2", "I2S RX2"},
+	{"RX1 MIX1 INP2", "RX3", "I2S RX3"},
+	{"RX1 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX1 MIX1 INP3", "RX1", "I2S RX1"},
+	{"RX1 MIX1 INP3", "RX2", "I2S RX2"},
+	{"RX1 MIX1 INP3", "RX3", "I2S RX3"},
+
+	{"RX2 MIX1 INP1", "RX1", "I2S RX1"},
+	{"RX2 MIX1 INP1", "RX2", "I2S RX2"},
+	{"RX2 MIX1 INP1", "RX3", "I2S RX3"},
+	{"RX2 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX2 MIX1 INP2", "RX1", "I2S RX1"},
+	{"RX2 MIX1 INP2", "RX2", "I2S RX2"},
+	{"RX2 MIX1 INP2", "RX3", "I2S RX3"},
+	{"RX2 MIX1 INP2", "IIR1", "IIR1"},
+
+	{"RX3 MIX1 INP1", "RX1", "I2S RX1"},
+	{"RX3 MIX1 INP1", "RX2", "I2S RX2"},
+	{"RX3 MIX1 INP1", "RX3", "I2S RX3"},
+	{"RX3 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX3 MIX1 INP2", "RX1", "I2S RX1"},
+	{"RX3 MIX1 INP2", "RX2", "I2S RX2"},
+	{"RX3 MIX1 INP2", "RX3", "I2S RX3"},
+	{"RX3 MIX1 INP2", "IIR1", "IIR1"},
+
+	/* Decimator Inputs */
+	{"DEC1 MUX", "DMIC1", "DMIC1"},
+	{"DEC1 MUX", "DMIC2", "DMIC2"},
+	{"DEC1 MUX", "ADC1", "ADC1"},
+	{"DEC1 MUX", "ADC2", "ADC2"},
+	{"DEC1 MUX", NULL, "CDC_CONN"},
+
+	{"DEC2 MUX", "DMIC1", "DMIC1"},
+	{"DEC2 MUX", "DMIC2", "DMIC2"},
+	{"DEC2 MUX", "ADC1", "ADC1"},
+	{"DEC2 MUX", "ADC2", "ADC2"},
+	{"DEC2 MUX", NULL, "CDC_CONN"},
+
+	/* ADC Connections */
+	{"ADC1", NULL, "AMIC1"},
+	{"ADC2", NULL, "AMIC2"},
+
+	{"IIR1", NULL, "IIR1 INP1 MUX"},
+	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
+	{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
+
+	/* There is no LDO_H in Helicon */
+	{"MIC BIAS1 Internal1", NULL, "LDO_H"},
+	{"MIC BIAS1 Internal2", NULL, "LDO_H"},
+	{"MIC BIAS1 External", NULL, "LDO_H"},
+};
+
+
+static int msm8x10_wcd_startup(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct msm8x10_wcd *msm8x10_wcd_core =
+		dev_get_drvdata(dai->codec->dev);
+	pr_debug("%s(): substream = %s  stream = %d\n" , __func__,
+		 substream->name, substream->stream);
+	if ((msm8x10_wcd_core != NULL) &&
+	    (msm8x10_wcd_core->dev != NULL))
+		pm_runtime_get_sync(msm8x10_wcd_core->dev);
+
+	return 0;
+}
+
+static void msm8x10_wcd_shutdown(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct msm8x10_wcd *msm8x10_wcd_core =
+		dev_get_drvdata(dai->codec->dev);
+	pr_debug("%s(): substream = %s  stream = %d\n" , __func__,
+		 substream->name, substream->stream);
+	if ((msm8x10_wcd_core != NULL) &&
+	    (msm8x10_wcd_core->dev != NULL)) {
+		pm_runtime_mark_last_busy(msm8x10_wcd_core->dev);
+		pm_runtime_put(msm8x10_wcd_core->dev);
+	}
+}
+
+int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec,
+			    int mclk_enable, bool dapm)
+{
+	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: mclk_enable = %u, dapm = %d\n", __func__, mclk_enable,
+		 dapm);
+
+	WCD9XXX_BCL_LOCK(&msm8x10_wcd->resmgr);
+	if (mclk_enable) {
+		wcd9xxx_resmgr_get_bandgap(&msm8x10_wcd->resmgr,
+					   WCD9XXX_BANDGAP_AUDIO_MODE);
+		wcd9xxx_resmgr_get_clk_block(&msm8x10_wcd->resmgr,
+					     WCD9XXX_CLK_MCLK);
+	} else {
+		/* Put clock and BG */
+		wcd9xxx_resmgr_put_clk_block(&msm8x10_wcd->resmgr,
+					     WCD9XXX_CLK_MCLK);
+		wcd9xxx_resmgr_put_bandgap(&msm8x10_wcd->resmgr,
+					   WCD9XXX_BANDGAP_AUDIO_MODE);
+	}
+	WCD9XXX_BCL_UNLOCK(&msm8x10_wcd->resmgr);
+
+	return 0;
+}
+
+static int msm8x10_wcd_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static int msm8x10_wcd_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static int msm8x10_wcd_set_channel_map(struct snd_soc_dai *dai,
+				unsigned int tx_num, unsigned int *tx_slot,
+				unsigned int rx_num, unsigned int *rx_slot)
+
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static int msm8x10_wcd_get_channel_map(struct snd_soc_dai *dai,
+				 unsigned int *tx_num, unsigned int *tx_slot,
+				 unsigned int *rx_num, unsigned int *rx_slot)
+
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static int msm8x10_wcd_set_interpolator_rate(struct snd_soc_dai *dai,
+	u8 rx_fs_rate_reg_val, u32 sample_rate)
+{
+	return 0;
+}
+
+static int msm8x10_wcd_set_decimator_rate(struct snd_soc_dai *dai,
+	u8 tx_fs_rate_reg_val, u32 sample_rate)
+{
+	return 0;
+}
+
+static int msm8x10_wcd_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	u8 tx_fs_rate, rx_fs_rate;
+	int ret;
+
+	pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
+		 dai->name, dai->id, params_rate(params),
+		 params_channels(params));
+
+	switch (params_rate(params)) {
+	case 8000:
+		tx_fs_rate = 0x00;
+		rx_fs_rate = 0x00;
+		break;
+	case 16000:
+		tx_fs_rate = 0x01;
+		rx_fs_rate = 0x20;
+		break;
+	case 32000:
+		tx_fs_rate = 0x02;
+		rx_fs_rate = 0x40;
+		break;
+	case 48000:
+		tx_fs_rate = 0x03;
+		rx_fs_rate = 0x60;
+		break;
+	case 96000:
+		tx_fs_rate = 0x04;
+		rx_fs_rate = 0x80;
+		break;
+	case 192000:
+		tx_fs_rate = 0x05;
+		rx_fs_rate = 0xA0;
+		break;
+	default:
+		pr_err("%s: Invalid sampling rate %d\n", __func__,
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_CAPTURE:
+		ret = msm8x10_wcd_set_decimator_rate(dai, tx_fs_rate,
+					       params_rate(params));
+		if (ret < 0) {
+			pr_err("%s: set decimator rate failed %d\n", __func__,
+				ret);
+			return ret;
+		}
+		break;
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		ret = msm8x10_wcd_set_interpolator_rate(dai, rx_fs_rate,
+						  params_rate(params));
+		if (ret < 0) {
+			pr_err("%s: set decimator rate failed %d\n", __func__,
+				ret);
+			return ret;
+		}
+		break;
+	default:
+		pr_err("%s: Invalid stream type %d\n", __func__,
+			substream->stream);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops msm8x10_wcd_dai_ops = {
+	.startup = msm8x10_wcd_startup,
+	.shutdown = msm8x10_wcd_shutdown,
+	.hw_params = msm8x10_wcd_hw_params,
+	.set_sysclk = msm8x10_wcd_set_dai_sysclk,
+	.set_fmt = msm8x10_wcd_set_dai_fmt,
+	.set_channel_map = msm8x10_wcd_set_channel_map,
+	.get_channel_map = msm8x10_wcd_get_channel_map,
+};
+
+static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[] = {
+	{
+		.name = "msm8x10_wcd_i2s_rx1",
+		.id = AIF1_PB,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.rates = MSM8X10_WCD_RATES,
+			.formats = MSM8X10_WCD_FORMATS,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &msm8x10_wcd_dai_ops,
+	},
+	{
+		.name = "msm8x10_wcd_i2s_tx1",
+		.id = AIF1_CAP,
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.rates = MSM8X10_WCD_RATES,
+			.formats = MSM8X10_WCD_FORMATS,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &msm8x10_wcd_dai_ops,
+	},
+};
+
+static int msm8x10_wcd_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		pr_debug("%s: Sleeping 20ms after enabling EAR PA\n",
+				 __func__);
+		msleep(20);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		pr_debug("%s: Sleeping 20ms after disabling EAR PA\n",
+				 __func__);
+		msleep(20);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget msm8x10_wcd_dapm_widgets[] = {
+	/*RX stuff */
+	SND_SOC_DAPM_OUTPUT("EAR"),
+
+	SND_SOC_DAPM_PGA_E("EAR PA", MSM8X10_WCD_A_RX_EAR_EN, 4, 0, NULL, 0,
+			msm8x10_wcd_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MIXER("DAC1", MSM8X10_WCD_A_RX_EAR_EN, 6, 0, dac1_switch,
+		ARRAY_SIZE(dac1_switch)),
+
+	SND_SOC_DAPM_AIF_IN("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
+				AIF1_PB, 0),
+
+	SND_SOC_DAPM_MUX("I2S RX1 MUX", SND_SOC_NOPM, MSM8X10_WCD_RX1, 0,
+				&slim_rx_mux[MSM8X10_WCD_RX1]),
+	SND_SOC_DAPM_MUX("I2S RX2 MUX", SND_SOC_NOPM, MSM8X10_WCD_RX2, 0,
+				&slim_rx_mux[MSM8X10_WCD_RX2]),
+	SND_SOC_DAPM_MUX("I2S RX3 MUX", SND_SOC_NOPM, MSM8X10_WCD_RX3, 0,
+				&slim_rx_mux[MSM8X10_WCD_RX3]),
+
+	SND_SOC_DAPM_MIXER("I2S RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I2S RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I2S RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I2S RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I2S RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Headphone */
+	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
+	SND_SOC_DAPM_PGA_E("HPHL", MSM8X10_WCD_A_RX_HPH_CNP_EN,
+		5, 0, NULL, 0,
+		msm8x10_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER("HPHL DAC", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL,
+		7, 0,
+		hphl_switch, ARRAY_SIZE(hphl_switch)),
+
+	SND_SOC_DAPM_PGA_E("HPHR", MSM8X10_WCD_A_RX_HPH_CNP_EN,
+		4, 0, NULL, 0,
+		msm8x10_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU |	SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, MSM8X10_WCD_A_RX_HPH_R_DAC_CTL,
+		7, 0,
+		msm8x10_wcd_hphr_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* Speaker */
+	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+
+	SND_SOC_DAPM_PGA_E("LINEOUT1 PA", MSM8X10_WCD_A_RX_LINE_CNP_EN,
+			0, 0, NULL, 0, msm8x10_wcd_codec_enable_lineout,
+			SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("SPK PA", MSM8X10_WCD_A_SPKR_DRV_EN,
+			7, 0 , NULL, 0, msm8x10_wcd_codec_enable_spk_pa,
+			SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL,
+		MSM8X10_WCD_A_RX_LINE_1_DAC_CTL, 7, 0,
+		msm8x10_wcd_lineout_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_DAC_E("SPK DAC", NULL, SND_SOC_NOPM, 0, 0,
+			   msm8x10_wcd_spk_dac_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER_E("RX1 MIX2",
+		MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
+		0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MIXER_E("RX2 MIX2",
+		MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
+		0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MIXER_E("RX3 MIX1",
+		MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
+		0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MIXER("RX1 CHAIN", MSM8X10_WCD_A_CDC_RX1_B6_CTL,
+		5, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX2 CHAIN", MSM8X10_WCD_A_CDC_RX2_B6_CTL,
+		5, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp3_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx2_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx2_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx3_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx3_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+		&rx1_mix2_inp1_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+		&rx2_mix2_inp1_mux),
+
+	SND_SOC_DAPM_SUPPLY("CP", MSM8X10_WCD_A_CP_EN, 0, 0,
+		msm8x10_wcd_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
+		msm8x10_wcd_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	/* TX */
+
+	SND_SOC_DAPM_SUPPLY("CDC_CONN", MSM8X10_WCD_A_CDC_CLK_OTHR_CTL,
+		2, 0, NULL, 0),
+
+
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External",
+		MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
+		msm8x10_wcd_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",
+		MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
+		msm8x10_wcd_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",
+		MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
+		msm8x10_wcd_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, MSM8X10_WCD_A_TX_1_EN, 7, 0,
+		msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
+		msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("AMIC3"),
+
+	SND_SOC_DAPM_MUX_E("DEC1 MUX",
+		MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
+		&dec1_mux, msm8x10_wcd_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC2 MUX",
+		MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
+		&dec2_mux, msm8x10_wcd_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("AMIC2"),
+	SND_SOC_DAPM_AIF_OUT("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
+		AIF1_CAP, 0),
+
+	SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
+		aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
+
+	/* Digital Mic Inputs */
+	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+		msm8x10_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+		msm8x10_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	/* Sidetone */
+	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+	SND_SOC_DAPM_PGA("IIR1", MSM8X10_WCD_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", MSM8X10_WCD_A_CDC_CLK_RX_I2S_CTL,
+		4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", MSM8X10_WCD_A_CDC_CLK_TX_I2S_CTL, 4,
+		0, NULL, 0),
+};
+
+static const struct msm8x10_wcd_reg_mask_val msm8x10_wcd_reg_defaults[] = {
+
+	/* set MCLk to 9.6 */
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CHIP_CTL, 0x0A),
+
+	/* EAR PA deafults  */
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_CMBUFF, 0x05),
+
+	/* RX deafults */
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX1_B5_CTL, 0x78),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX2_B5_CTL, 0x78),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX3_B5_CTL, 0x78),
+
+	/* RX1 and RX2 defaults */
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX1_B6_CTL, 0xA0),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xA0),
+
+	/* RX3 to RX7 defaults */
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX3_B6_CTL, 0x80),
+
+	/* Reduce HPH DAC bias to 70% */
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_HPH_BIAS_PA, 0x7A),
+	/*Reduce EAR DAC bias to 70% */
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_BIAS_PA, 0x76),
+	/* Reduce LINE DAC bias to 70% */
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_LINE_BIAS_PA, 0x78),
+
+
+	/* Disable TX7 internal biasing path which can cause leakage */
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_SUP_SWITCH_CTRL_1, 0xBF),
+};
+
+static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
+{
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(msm8x10_wcd_reg_defaults); i++)
+		snd_soc_write(codec, msm8x10_wcd_reg_defaults[i].reg,
+				msm8x10_wcd_reg_defaults[i].val);
+}
+
+static const struct msm8x10_wcd_reg_mask_val
+	msm8x10_wcd_codec_reg_init_val[] = {
+	/* Initialize current threshold to 350MA
+	 * number of wait and run cycles to 4096
+	 */
+	{MSM8X10_WCD_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
+	{MSM8X10_WCD_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
+
+	/* Initialize gain registers to use register gain */
+	{MSM8X10_WCD_A_RX_HPH_L_GAIN, 0x20, 0x20},
+	{MSM8X10_WCD_A_RX_HPH_R_GAIN, 0x20, 0x20},
+	{MSM8X10_WCD_A_RX_LINE_1_GAIN, 0x20, 0x20},
+
+	/*enable HPF filter for TX paths */
+	{MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
+	{MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
+
+	/* config Decimator for DMIC CLK_MODE_1(3.2Mhz@9.6Mhz mclk) */
+	{MSM8X10_WCD_A_CDC_TX1_DMIC_CTL, 0x7, 0x1},
+	{MSM8X10_WCD_A_CDC_TX2_DMIC_CTL, 0x7, 0x1},
+
+	/* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
+	{MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
+
+};
+
+static void msm8x10_wcd_codec_init_reg(struct snd_soc_codec *codec)
+{
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(msm8x10_wcd_codec_reg_init_val); i++)
+		snd_soc_update_bits(codec,
+				    msm8x10_wcd_codec_reg_init_val[i].reg,
+				    msm8x10_wcd_codec_reg_init_val[i].mask,
+				    msm8x10_wcd_codec_reg_init_val[i].val);
+}
+
+int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
+		    struct msm8x10_wcd_mbhc_config *mbhc_cfg)
+{
+	return 0;
+}
+EXPORT_SYMBOL_GPL(msm8x10_wcd_hs_detect);
+
+static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
+{
+	msm8x10_wcd_codec_init_reg(codec);
+
+	msm8x10_wcd_update_reg_defaults(codec);
+
+	dev_dbg(codec->dev, "%s()\n", __func__);
+
+	return 0;
+}
+
+static int msm8x10_wcd_codec_remove(struct snd_soc_codec *codec)
+{
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_msm8x10_wcd = {
+	.probe	= msm8x10_wcd_codec_probe,
+	.remove	= msm8x10_wcd_codec_remove,
+
+	.read = msm8x10_wcd_read,
+	.write = msm8x10_wcd_write,
+
+	.readable_register = msm8x10_wcd_readable,
+	.volatile_register = msm8x10_wcd_volatile,
+
+	.reg_cache_size = MSM8X10_WCD_CACHE_SIZE,
+	.reg_cache_default = msm8x10_wcd_reset_reg_defaults,
+	.reg_word_size = 1,
+
+	.controls = msm8x10_wcd_snd_controls,
+	.num_controls = ARRAY_SIZE(msm8x10_wcd_snd_controls),
+	.dapm_widgets = msm8x10_wcd_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(msm8x10_wcd_dapm_widgets),
+	.dapm_routes = audio_map,
+	.num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int ret;
+	struct msm8x10_wcd_pdata *pdata;
+	if (client->dev.of_node) {
+		dev_dbg(&client->dev, "%s:Platform data from device tree\n",
+			__func__);
+		pdata = msm8x10_wcd_populate_dt_pdata(&client->dev);
+		client->dev.platform_data = pdata;
+	} else {
+		dev_dbg(&client->dev, "%s:Platform data from board file\n",
+			__func__);
+		pdata = client->dev.platform_data;
+	}
+
+	ret = snd_soc_register_codec(&client->dev,
+		&soc_codec_dev_msm8x10_wcd,
+		msm8x10_wcd_i2s_dai, ARRAY_SIZE(msm8x10_wcd_i2s_dai));
+	dev_dbg(&client->dev, "%s:ret = 0x%x\n", __func__, ret);
+
+	return ret;
+}
+
+static int __devexit msm8x10_wcd_i2c_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static struct i2c_device_id msm8x10_wcd_id_table[] = {
+	{"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_TOP_LEVEL},
+	{"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_ANALOG},
+	{"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_DIGITAL_1},
+	{"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_DIGITAL_2},
+	{}
+};
+
+static struct of_device_id msm8x10_wcd_of_match[] = {
+	{ .compatible = "qcom,msm8x10-wcd-i2c",},
+	{ },
+};
+
+
+static struct i2c_driver msm8x10_wcd_i2c_driver = {
+	.driver                 = {
+		.owner          = THIS_MODULE,
+		.name           = "msm8x10-wcd-i2c-core",
+		.of_match_table = msm8x10_wcd_of_match
+	},
+	.id_table               = msm8x10_wcd_id_table,
+	.probe                  = msm8x10_wcd_i2c_probe,
+	.remove                 = __devexit_p(msm8x10_wcd_i2c_remove),
+};
+
+static int __init msm8x10_wcd_codec_init(void)
+{
+	int ret;
+
+	pr_debug("%s:\n", __func__);
+	ret = i2c_add_driver(&msm8x10_wcd_i2c_driver);
+	if (ret != 0)
+		pr_err("%s: Failed to add msm8x10 wcd I2C driver - error code %d\n",
+			   __func__, ret);
+	return ret;
+}
+
+static void __exit msm8x10_wcd_codec_exit(void)
+{
+	i2c_del_driver(&msm8x10_wcd_i2c_driver);
+}
+
+
+module_init(msm8x10_wcd_codec_init);
+module_exit(msm8x10_wcd_codec_exit);
+
+MODULE_DESCRIPTION("MSM8x10 Audio codec driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(i2c, msm8x10_wcd_id_table);
+
diff --git a/sound/soc/codecs/msm8x10-wcd.h b/sound/soc/codecs/msm8x10-wcd.h
new file mode 100644
index 0000000..365d526
--- /dev/null
+++ b/sound/soc/codecs/msm8x10-wcd.h
@@ -0,0 +1,226 @@
+/* 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 MSM8X10_WCD_H
+#define MSM8X10_WCD_H
+
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "wcd9xxx-mbhc.h"
+#include "wcd9xxx-resmgr.h"
+
+#define MSM8X10_WCD_NUM_REGISTERS	0x600
+#define MSM8X10_WCD_MAX_REGISTER	(MSM8X10_WCD_NUM_REGISTERS-1)
+#define MSM8X10_WCD_CACHE_SIZE		MSM8X10_WCD_NUM_REGISTERS
+#define MSM8X10_WCD_NUM_IRQ_REGS	3
+#define MAX_REGULATOR				7
+#define MSM8X10_WCD_REG_VAL(reg, val)		{reg, 0, val}
+
+#define MSM8X10_WCD_IS_DINO_REG(reg) \
+	(((reg >= 0x400) && (reg <= 0x5FF)) ? 1 : 0)
+#define MSM8X10_WCD_IS_HELICON_REG(reg) \
+	(((reg >= 0x000) && (reg <= 0x1FF)) ? 1 : 0)
+extern const u8 msm8x10_wcd_reg_readable[MSM8X10_WCD_CACHE_SIZE];
+extern const u8 msm8x10_wcd_reset_reg_defaults[MSM8X10_WCD_CACHE_SIZE];
+struct msm8x10_wcd_codec_dai_data {
+	u32 rate;
+	u32 *ch_num;
+	u32 ch_act;
+	u32 ch_tot;
+};
+
+enum msm8x10_wcd_pid_current {
+	MSM8X10_WCD_PID_MIC_2P5_UA,
+	MSM8X10_WCD_PID_MIC_5_UA,
+	MSM8X10_WCD_PID_MIC_10_UA,
+	MSM8X10_WCD_PID_MIC_20_UA,
+};
+
+struct msm8x10_wcd_reg_mask_val {
+	u16	reg;
+	u8	mask;
+	u8	val;
+};
+
+enum msm8x10_wcd_mbhc_analog_pwr_cfg {
+	MSM8X10_WCD_ANALOG_PWR_COLLAPSED = 0,
+	MSM8X10_WCD_ANALOG_PWR_ON,
+	MSM8X10_WCD_NUM_ANALOG_PWR_CONFIGS,
+};
+
+/* Number of input and output Slimbus port */
+enum {
+	MSM8X10_WCD_RX1 = 0,
+	MSM8X10_WCD_RX2,
+	MSM8X10_WCD_RX3,
+	MSM8X10_WCD_RX_MAX,
+};
+
+enum {
+	MSM8X10_WCD_TX1 = 0,
+	MSM8X10_WCD_TX2,
+	MSM8X10_WCD_TX3,
+	MSM8X10_WCD_TX4,
+	MSM8X10_WCD_TX_MAX,
+};
+
+enum {
+	/* INTR_REG 0 */
+	MSM8X10_WCD_IRQ_RESERVED_0 = 0,
+	MSM8X10_WCD_IRQ_MBHC_REMOVAL,
+	MSM8X10_WCD_IRQ_MBHC_SHORT_TERM,
+	MSM8X10_WCD_IRQ_MBHC_PRESS,
+	MSM8X10_WCD_IRQ_MBHC_RELEASE,
+	MSM8X10_WCD_IRQ_MBHC_POTENTIAL,
+	MSM8X10_WCD_IRQ_MBHC_INSERTION,
+	MSM8X10_WCD_IRQ_MBHC_HS_DET,
+	/* INTR_REG 1 */
+	MSM8X10_WCD_IRQ_PA_STARTUP,
+	MSM8X10_WCD_IRQ_BG_PRECHARGE,
+	MSM8X10_WCD_IRQ_RESERVED_1,
+	MSM8X10_WCD_IRQ_EAR_PA_OCPL_FAULT,
+	MSM8X10_WCD_IRQ_EAR_PA_STARTUP,
+	MSM8X10_WCD_IRQ_SPKR_PA_OCPL_FAULT,
+	MSM8X10_WCD_IRQ_SPKR_CLIP_FAULT,
+	MSM8X10_WCD_IRQ_RESERVED_2,
+	/* INTR_REG 2 */
+	MSM8X10_WCD_IRQ_HPH_L_PA_STARTUP,
+	MSM8X10_WCD_IRQ_HPH_R_PA_STARTUP,
+	MSM8X10_WCD_IRQ_HPH_PA_OCPL_FAULT,
+	MSM8X10_WCD_IRQ_HPH_PA_OCPR_FAULT,
+	MSM8X10_WCD_IRQ_RESERVED_3,
+	MSM8X10_WCD_IRQ_RESERVED_4,
+	MSM8X10_WCD_IRQ_RESERVED_5,
+	MSM8X10_WCD_IRQ_RESERVED_6,
+	MSM8X10_WCD_NUM_IRQS,
+};
+
+/*
+ * Each micbias can be assigned to one of three cfilters
+ * Vbatt_min >= .15V + ldoh_v
+ * ldoh_v >= .15v + cfiltx_mv
+ * If ldoh_v = 1.95 160 mv < cfiltx_mv < 1800 mv
+ * If ldoh_v = 2.35 200 mv < cfiltx_mv < 2200 mv
+ * If ldoh_v = 2.75 240 mv < cfiltx_mv < 2600 mv
+ * If ldoh_v = 2.85 250 mv < cfiltx_mv < 2700 mv
+ */
+struct msm8x10_wcd_micbias_setting {
+	u8 ldoh_v;
+	u32 cfilt1_mv; /* in mv */
+	/*
+	 * Different WCD9xxx series codecs may not
+	 * have 4 mic biases. If a codec has fewer
+	 * mic biases, some of these properties will
+	 * not be used.
+	 */
+	u8 bias1_cfilt_sel;
+	u8 bias1_cap_mode;
+};
+
+struct msm8x10_wcd_ocp_setting {
+	unsigned int	use_pdata:1; /* 0 - use sys default as recommended */
+	unsigned int	num_attempts:4; /* up to 15 attempts */
+	unsigned int	run_time:4; /* in duty cycle */
+	unsigned int	wait_time:4; /* in duty cycle */
+	unsigned int	hph_ocp_limit:3; /* Headphone OCP current limit */
+};
+
+struct msm8x10_wcd_regulator {
+	const char *name;
+	int min_uV;
+	int max_uV;
+	int optimum_uA;
+	struct regulator *regulator;
+};
+
+struct msm8x10_wcd_pdata {
+	int irq;
+	int irq_base;
+	int num_irqs;
+	int reset_gpio;
+	void *msm8x10_wcd_ahb_base_vaddr;
+	struct msm8x10_wcd_micbias_setting micbias;
+	struct msm8x10_wcd_ocp_setting ocp;
+	struct msm8x10_wcd_regulator regulator[MAX_REGULATOR];
+	u32 mclk_rate;
+};
+
+enum msm8x10_wcd_micbias_num {
+	MSM8X10_WCD_MICBIAS1 = 0,
+};
+
+struct msm8x10_wcd_mbhc_config {
+	struct snd_soc_jack *headset_jack;
+	struct snd_soc_jack *button_jack;
+	bool read_fw_bin;
+	/*
+	 * void* calibration contains:
+	 *  struct msm8x10_wcd_mbhc_general_cfg generic;
+	 *  struct msm8x10_wcd_mbhc_plug_detect_cfg plug_det;
+	 *  struct msm8x10_wcd_mbhc_plug_type_cfg plug_type;
+	 *  struct msm8x10_wcd_mbhc_btn_detect_cfg btn_det;
+	 *  struct msm8x10_wcd_mbhc_imped_detect_cfg imped_det;
+	 * Note: various size depends on btn_det->num_btn
+	 */
+	void *calibration;
+	enum msm8x10_wcd_micbias_num micbias;
+	int (*mclk_cb_fn) (struct snd_soc_codec*, int, bool);
+	unsigned int mclk_rate;
+	unsigned int gpio;
+	unsigned int gpio_irq;
+	int gpio_level_insert;
+	bool detect_extn_cable;
+	/* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
+	bool (*swap_gnd_mic) (struct snd_soc_codec *);
+};
+
+enum msm8x10_wcd_pm_state {
+	MSM8X10_WCD_PM_SLEEPABLE,
+	MSM8X10_WCD_PM_AWAKE,
+	MSM8X10_WCD_PM_ASLEEP,
+};
+
+struct msm8x10_wcd {
+	struct device *dev;
+	struct mutex io_lock;
+	struct mutex xfer_lock;
+	struct mutex irq_lock;
+	u8 version;
+
+	int reset_gpio;
+
+	u32 num_of_supplies;
+	struct regulator_bulk_data *supplies;
+
+	enum msm8x10_wcd_pm_state pm_state;
+	struct mutex pm_lock;
+	/* pm_wq notifies change of pm_state */
+	wait_queue_head_t pm_wq;
+	struct pm_qos_request pm_qos_req;
+	int wlock_holders;
+
+	u8 idbyte[4];
+
+	unsigned int irq_base;
+	unsigned int irq;
+	u8 irq_masks_cur[MSM8X10_WCD_NUM_IRQ_REGS];
+	u8 irq_masks_cache[MSM8X10_WCD_NUM_IRQ_REGS];
+	bool irq_level_high[MSM8X10_WCD_NUM_IRQS];
+	int num_irqs;
+	u32 mclk_rate;
+};
+
+extern int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
+			     bool dapm);
+extern int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
+			   struct msm8x10_wcd_mbhc_config *mbhc_cfg);
+
+#endif
diff --git a/sound/soc/codecs/msm8x10_wcd_registers.h b/sound/soc/codecs/msm8x10_wcd_registers.h
new file mode 100644
index 0000000..a10f31f
--- /dev/null
+++ b/sound/soc/codecs/msm8x10_wcd_registers.h
@@ -0,0 +1,641 @@
+ /* 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 MSM8X10_WCD_REGISTERS_H
+#define MSM8X10_WCD_REGISTERS_H
+
+#define MSM8X10_WCD_A_CHIP_CTL			(0x000)
+#define MSM8X10_WCD_A_CHIP_CTL__POR				(0x04)
+#define MSM8X10_WCD_A_CHIP_STATUS			(0x001)
+#define MSM8X10_WCD_A_CHIP_STATUS__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_TLMM_MODE_SELECT			(0x002)
+#define MSM8X10_WCD_A_CDC_TLMM_MODE_SELECT__POR				(0x00)
+#define MSM8X10_WCD_A_MODE_LOCK			(0x003)
+#define MSM8X10_WCD_A_MODE_LOCK__POR				(0x00)
+#define MSM8X10_WCD_A_CHIP_ID_BYTE_0			(0x004)
+#define MSM8X10_WCD_A_CHIP_ID_BYTE_0__POR				(0x00)
+#define MSM8X10_WCD_A_CHIP_ID_BYTE_1			(0x005)
+#define MSM8X10_WCD_A_CHIP_ID_BYTE_1__POR				(0x00)
+#define MSM8X10_WCD_A_CHIP_ID_BYTE_2			(0x006)
+#define MSM8X10_WCD_A_CHIP_ID_BYTE_2__POR				(0x04)
+#define MSM8X10_WCD_A_CHIP_ID_BYTE_3			(0x007)
+#define MSM8X10_WCD_A_CHIP_ID_BYTE_3__POR				(0x01)
+#define MSM8X10_WCD_A_CHIP_VERSION			(0x008)
+#define MSM8X10_WCD_A_CHIP_VERSION__POR				(0x00)
+#define MSM8X10_WCD_A_ANALOG_SLAVE_ID			(0x00C)
+#define MSM8X10_WCD_A_ANALOG_SLAVE_ID__POR				(0x77)
+#define MSM8X10_WCD_A_PIN_CTL_OE			(0x010)
+#define MSM8X10_WCD_A_PIN_CTL_OE__POR				(0x07)
+#define MSM8X10_WCD_A_PIN_CTL_DATA			(0x012)
+#define MSM8X10_WCD_A_PIN_CTL_DATA__POR				(0x00)
+#define MSM8X10_WCD_A_PIN_STATUS			(0x014)
+#define MSM8X10_WCD_A_PIN_STATUS__POR				(0x00)
+#define MSM8X10_WCD_A_HDRIVE_CTL			(0x018)
+#define MSM8X10_WCD_A_HDRIVE_CTL__POR				(0x01)
+#define MSM8X10_WCD_A_HDRIVE_I2C_CTL			(0x019)
+#define MSM8X10_WCD_A_HDRIVE_I2C_CTL__POR				(0x01)
+#define MSM8X10_WCD_A_CDC_RST_CTL			(0x020)
+#define MSM8X10_WCD_A_CDC_RST_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_TOP_CLK_CTL			(0x022)
+#define MSM8X10_WCD_A_CDC_TOP_CLK_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_ANA_CLK_CTL			(0x023)
+#define MSM8X10_WCD_A_CDC_ANA_CLK_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_DIG_CLK_CTL			(0x024)
+#define MSM8X10_WCD_A_CDC_DIG_CLK_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_PROCESS_MONITOR_CTL0			(0x030)
+#define MSM8X10_WCD_A_PROCESS_MONITOR_CTL0__POR				(0x80)
+#define MSM8X10_WCD_A_PROCESS_MONITOR_CTL1			(0x031)
+#define MSM8X10_WCD_A_PROCESS_MONITOR_CTL1__POR				(0x00)
+#define MSM8X10_WCD_A_PROCESS_MONITOR_CTL2			(0x032)
+#define MSM8X10_WCD_A_PROCESS_MONITOR_CTL2__POR				(0x00)
+#define MSM8X10_WCD_A_PROCESS_MONITOR_CTL3			(0x033)
+#define MSM8X10_WCD_A_PROCESS_MONITOR_CTL3__POR				(0x01)
+#define MSM8X10_WCD_A_QFUSE_CTL			(0x034)
+#define MSM8X10_WCD_A_QFUSE_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_QFUSE_STATUS			(0x035)
+#define MSM8X10_WCD_A_QFUSE_STATUS__POR				(0x00)
+#define MSM8X10_WCD_A_QFUSE_DATA_OUT0			(0x036)
+#define MSM8X10_WCD_A_QFUSE_DATA_OUT0__POR				(0x00)
+#define MSM8X10_WCD_A_QFUSE_DATA_OUT1			(0x037)
+#define MSM8X10_WCD_A_QFUSE_DATA_OUT1__POR				(0x00)
+#define MSM8X10_WCD_A_QFUSE_DATA_OUT2			(0x038)
+#define MSM8X10_WCD_A_QFUSE_DATA_OUT2__POR				(0x00)
+#define MSM8X10_WCD_A_QFUSE_DATA_OUT3			(0x039)
+#define MSM8X10_WCD_A_QFUSE_DATA_OUT3__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_TX1_CTL			(0x040)
+#define MSM8X10_WCD_A_CDC_CONN_TX1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_TX2_CTL			(0x041)
+#define MSM8X10_WCD_A_CDC_CONN_TX2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_HPHR_DAC_CTL			(0x042)
+#define MSM8X10_WCD_A_CDC_CONN_HPHR_DAC_CTL__POR			(0x01)
+#define MSM8X10_WCD_A_CDC_CONN_LO_DAC_CTL			(0x043)
+#define MSM8X10_WCD_A_CDC_CONN_LO_DAC_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_RX1_CTL			(0x044)
+#define MSM8X10_WCD_A_CDC_CONN_RX1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_RX2_CTL			(0x045)
+#define MSM8X10_WCD_A_CDC_CONN_RX2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_RX3_CTL			(0x046)
+#define MSM8X10_WCD_A_CDC_CONN_RX3_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_DIGITAL_DEBUG_CTL			(0x048)
+#define MSM8X10_WCD_A_DIGITAL_DEBUG_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_ANALOG_DEBUG_CTL			(0x049)
+#define MSM8X10_WCD_A_ANALOG_DEBUG_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX1_CTL			(0x050)
+#define MSM8X10_WCD_A_CDC_RX1_CTL__POR				(0x7C)
+#define MSM8X10_WCD_A_CDC_RX2_CTL			(0x058)
+#define MSM8X10_WCD_A_CDC_RX2_CTL__POR				(0x7C)
+#define MSM8X10_WCD_A_CDC_RX3_CTL			(0x060)
+#define MSM8X10_WCD_A_CDC_RX3_CTL__POR				(0x7C)
+#define MSM8X10_WCD_A_DEM_BYPASS_DATA0			(0x070)
+#define MSM8X10_WCD_A_DEM_BYPASS_DATA0__POR				(0x00)
+#define MSM8X10_WCD_A_DEM_BYPASS_DATA1			(0x071)
+#define MSM8X10_WCD_A_DEM_BYPASS_DATA1__POR				(0x00)
+#define MSM8X10_WCD_A_DEM_BYPASS_DATA2			(0x072)
+#define MSM8X10_WCD_A_DEM_BYPASS_DATA2__POR				(0x00)
+#define MSM8X10_WCD_A_DEM_BYPASS_DATA3			(0x073)
+#define MSM8X10_WCD_A_DEM_BYPASS_DATA3__POR				(0x00)
+#define MSM8X10_WCD_A_SPARE_0			(0x080)
+#define MSM8X10_WCD_A_SPARE_0__POR				(0x00)
+#define MSM8X10_WCD_A_SPARE_1			(0x082)
+#define MSM8X10_WCD_A_SPARE_1__POR				(0x00)
+#define MSM8X10_WCD_A_SPARE_2			(0x084)
+#define MSM8X10_WCD_A_SPARE_2__POR				(0x00)
+#define MSM8X10_WCD_A_INTR_MODE			(0x090)
+#define MSM8X10_WCD_A_INTR_MODE__POR				(0x00)
+#define MSM8X10_WCD_A_INTR_MASK0			(0x094)
+#define MSM8X10_WCD_A_INTR_MASK0__POR				(0xFF)
+#define MSM8X10_WCD_A_INTR_MASK1			(0x095)
+#define MSM8X10_WCD_A_INTR_MASK1__POR				(0xFF)
+#define MSM8X10_WCD_A_INTR_MASK2			(0x096)
+#define MSM8X10_WCD_A_INTR_MASK2__POR				(0x3F)
+#define MSM8X10_WCD_A_INTR_STATUS0			(0x098)
+#define MSM8X10_WCD_A_INTR_STATUS0__POR				(0x00)
+#define MSM8X10_WCD_A_INTR_STATUS1			(0x099)
+#define MSM8X10_WCD_A_INTR_STATUS1__POR				(0x00)
+#define MSM8X10_WCD_A_INTR_STATUS2			(0x09A)
+#define MSM8X10_WCD_A_INTR_STATUS2__POR				(0x00)
+#define MSM8X10_WCD_A_INTR_CLEAR0			(0x09C)
+#define MSM8X10_WCD_A_INTR_CLEAR0__POR				(0x00)
+#define MSM8X10_WCD_A_INTR_CLEAR1			(0x09D)
+#define MSM8X10_WCD_A_INTR_CLEAR1__POR				(0x00)
+#define MSM8X10_WCD_A_INTR_CLEAR2			(0x09E)
+#define MSM8X10_WCD_A_INTR_CLEAR2__POR				(0x00)
+#define MSM8X10_WCD_A_INTR_TEST0			(0x0A4)
+#define MSM8X10_WCD_A_INTR_TEST0__POR				(0x00)
+#define MSM8X10_WCD_A_INTR_TEST1			(0x0A5)
+#define MSM8X10_WCD_A_INTR_TEST1__POR				(0x00)
+#define MSM8X10_WCD_A_INTR_TEST2			(0x0A6)
+#define MSM8X10_WCD_A_INTR_TEST2__POR				(0x00)
+#define MSM8X10_WCD_A_INTR_SET0			(0x0A8)
+#define MSM8X10_WCD_A_INTR_SET0__POR				(0x00)
+#define MSM8X10_WCD_A_INTR_SET1			(0x0A9)
+#define MSM8X10_WCD_A_INTR_SET1__POR				(0x00)
+#define MSM8X10_WCD_A_INTR_SET2			(0x0AA)
+#define MSM8X10_WCD_A_INTR_SET2__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_EN_CTL			(0x0C0)
+#define MSM8X10_WCD_A_CDC_MBHC_EN_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_FIR_B1_CFG			(0x0C1)
+#define MSM8X10_WCD_A_CDC_MBHC_FIR_B1_CFG__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_FIR_B2_CFG			(0x0C2)
+#define MSM8X10_WCD_A_CDC_MBHC_FIR_B2_CFG__POR				(0x06)
+#define MSM8X10_WCD_A_CDC_MBHC_TIMER_B1_CTL			(0x0C3)
+#define MSM8X10_WCD_A_CDC_MBHC_TIMER_B1_CTL__POR			(0x03)
+#define MSM8X10_WCD_A_CDC_MBHC_TIMER_B2_CTL			(0x0C4)
+#define MSM8X10_WCD_A_CDC_MBHC_TIMER_B2_CTL__POR			(0x09)
+#define MSM8X10_WCD_A_CDC_MBHC_TIMER_B3_CTL			(0x0C5)
+#define MSM8X10_WCD_A_CDC_MBHC_TIMER_B3_CTL__POR			(0x1E)
+#define MSM8X10_WCD_A_CDC_MBHC_TIMER_B4_CTL			(0x0C6)
+#define MSM8X10_WCD_A_CDC_MBHC_TIMER_B4_CTL__POR			(0x45)
+#define MSM8X10_WCD_A_CDC_MBHC_TIMER_B5_CTL			(0x0C7)
+#define MSM8X10_WCD_A_CDC_MBHC_TIMER_B5_CTL__POR			(0x04)
+#define MSM8X10_WCD_A_CDC_MBHC_TIMER_B6_CTL			(0x0C8)
+#define MSM8X10_WCD_A_CDC_MBHC_TIMER_B6_CTL__POR			(0x78)
+#define MSM8X10_WCD_A_CDC_MBHC_B1_STATUS			(0x0C9)
+#define MSM8X10_WCD_A_CDC_MBHC_B1_STATUS__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_B2_STATUS			(0x0CA)
+#define MSM8X10_WCD_A_CDC_MBHC_B2_STATUS__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_B3_STATUS			(0x0CB)
+#define MSM8X10_WCD_A_CDC_MBHC_B3_STATUS__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_B4_STATUS			(0x0CC)
+#define MSM8X10_WCD_A_CDC_MBHC_B4_STATUS__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_B5_STATUS			(0x0CD)
+#define MSM8X10_WCD_A_CDC_MBHC_B5_STATUS__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_B1_CTL			(0x0CE)
+#define MSM8X10_WCD_A_CDC_MBHC_B1_CTL__POR				(0xC0)
+#define MSM8X10_WCD_A_CDC_MBHC_B2_CTL			(0x0CF)
+#define MSM8X10_WCD_A_CDC_MBHC_B2_CTL__POR				(0x5D)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B1_CTL			(0x0D0)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B2_CTL			(0x0D1)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B3_CTL			(0x0D2)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B3_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B4_CTL			(0x0D3)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B4_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B5_CTL			(0x0D4)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B5_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B6_CTL			(0x0D5)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B6_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B7_CTL			(0x0D6)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B7_CTL__POR				(0xFF)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B8_CTL			(0x0D7)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B8_CTL__POR				(0x07)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B9_CTL			(0x0D8)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B9_CTL__POR				(0xFF)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B10_CTL			(0x0D9)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B10_CTL__POR			(0x7F)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B11_CTL			(0x0DA)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B11_CTL__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B12_CTL			(0x0DB)
+#define MSM8X10_WCD_A_CDC_MBHC_VOLT_B12_CTL__POR			(0x80)
+#define MSM8X10_WCD_A_CDC_MBHC_CLK_CTL			(0x0DC)
+#define MSM8X10_WCD_A_CDC_MBHC_CLK_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_INT_CTL			(0x0DD)
+#define MSM8X10_WCD_A_CDC_MBHC_INT_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_DEBUG_CTL			(0x0DE)
+#define MSM8X10_WCD_A_CDC_MBHC_DEBUG_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_MBHC_SPARE			(0x0DF)
+#define MSM8X10_WCD_A_CDC_MBHC_SPARE__POR				(0x00)
+#define MSM8X10_WCD_A_BIAS_REF_CTL			(0x100)
+#define MSM8X10_WCD_A_BIAS_REF_CTL__POR				(0x1C)
+#define MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL			(0x101)
+#define MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL__POR				(0x50)
+#define MSM8X10_WCD_A_BIAS_PRECHRG_CTL			(0x102)
+#define MSM8X10_WCD_A_BIAS_PRECHRG_CTL__POR				(0x07)
+#define MSM8X10_WCD_A_BIAS_CURR_CTL_1			(0x103)
+#define MSM8X10_WCD_A_BIAS_CURR_CTL_1__POR				(0x52)
+#define MSM8X10_WCD_A_BIAS_CURR_CTL_2			(0x104)
+#define MSM8X10_WCD_A_BIAS_CURR_CTL_2__POR				(0x00)
+#define MSM8X10_WCD_A_BIAS_OSC_BG_CTL			(0x105)
+#define MSM8X10_WCD_A_BIAS_OSC_BG_CTL__POR				(0x16)
+#define MSM8X10_WCD_A_MICB_CFILT_1_CTL			(0x128)
+#define MSM8X10_WCD_A_MICB_CFILT_1_CTL__POR				(0x40)
+#define MSM8X10_WCD_A_MICB_CFILT_1_VAL			(0x129)
+#define MSM8X10_WCD_A_MICB_CFILT_1_VAL__POR				(0x80)
+#define MSM8X10_WCD_A_MICB_CFILT_1_PRECHRG			(0x12A)
+#define MSM8X10_WCD_A_MICB_CFILT_1_PRECHRG__POR				(0x00)
+#define MSM8X10_WCD_A_MICB_1_CTL			(0x12B)
+#define MSM8X10_WCD_A_MICB_1_CTL__POR				(0x02)
+#define MSM8X10_WCD_A_MICB_1_INT_RBIAS			(0x12C)
+#define MSM8X10_WCD_A_MICB_1_INT_RBIAS__POR				(0x00)
+#define MSM8X10_WCD_A_MICB_1_MBHC			(0x12D)
+#define MSM8X10_WCD_A_MICB_1_MBHC__POR				(0x00)
+#define MSM8X10_WCD_A_MBHC_INSERT_DETECT			(0x14A)
+#define MSM8X10_WCD_A_MBHC_INSERT_DETECT__POR				(0x00)
+#define MSM8X10_WCD_A_MBHC_INSERT_DET_STATUS			(0x14B)
+#define MSM8X10_WCD_A_MBHC_INSERT_DET_STATUS__POR			(0x00)
+#define MSM8X10_WCD_A_TX_COM_BIAS			(0x14C)
+#define MSM8X10_WCD_A_TX_COM_BIAS__POR				(0xF0)
+#define MSM8X10_WCD_A_MBHC_SCALING_MUX_1			(0x14E)
+#define MSM8X10_WCD_A_MBHC_SCALING_MUX_1__POR				(0x00)
+#define MSM8X10_WCD_A_MBHC_SCALING_MUX_2			(0x14F)
+#define MSM8X10_WCD_A_MBHC_SCALING_MUX_2__POR				(0x80)
+#define MSM8X10_WCD_A_RESERVED_MAD_ANA_CTRL			(0x150)
+#define MSM8X10_WCD_A_RESERVED_MAD_ANA_CTRL__POR			(0xF1)
+#define MSM8X10_WCD_A_TX_SUP_SWITCH_CTRL_1			(0x151)
+#define MSM8X10_WCD_A_TX_SUP_SWITCH_CTRL_1__POR				(0x00)
+#define MSM8X10_WCD_A_TX_SUP_SWITCH_CTRL_2			(0x152)
+#define MSM8X10_WCD_A_TX_SUP_SWITCH_CTRL_2__POR				(0x80)
+#define MSM8X10_WCD_A_TX_1_EN			(0x153)
+#define MSM8X10_WCD_A_TX_1_EN__POR				(0x02)
+#define MSM8X10_WCD_A_TX_2_EN			(0x154)
+#define MSM8X10_WCD_A_TX_2_EN__POR				(0x02)
+#define MSM8X10_WCD_A_TX_1_2_ADC_CH1			(0x155)
+#define MSM8X10_WCD_A_TX_1_2_ADC_CH1__POR				(0x44)
+#define MSM8X10_WCD_A_TX_1_2_ADC_CH2			(0x156)
+#define MSM8X10_WCD_A_TX_1_2_ADC_CH2__POR				(0x44)
+#define MSM8X10_WCD_A_TX_1_2_ATEST_REFCTRL			(0x157)
+#define MSM8X10_WCD_A_TX_1_2_ATEST_REFCTRL__POR				(0x00)
+#define MSM8X10_WCD_A_TX_1_2_TEST_CTL			(0x158)
+#define MSM8X10_WCD_A_TX_1_2_TEST_CTL__POR				(0x38)
+#define MSM8X10_WCD_A_TX_1_2_TEST_BLOCK_EN			(0x159)
+#define MSM8X10_WCD_A_TX_1_2_TEST_BLOCK_EN__POR				(0xFC)
+#define MSM8X10_WCD_A_TX_1_2_TXFE_CLKDIV			(0x15A)
+#define MSM8X10_WCD_A_TX_1_2_TXFE_CLKDIV__POR				(0x55)
+#define MSM8X10_WCD_A_TX_1_2_SAR_ERR_CH1			(0x15B)
+#define MSM8X10_WCD_A_TX_1_2_SAR_ERR_CH1__POR				(0x00)
+#define MSM8X10_WCD_A_TX_1_2_SAR_ERR_CH2			(0x15C)
+#define MSM8X10_WCD_A_TX_1_2_SAR_ERR_CH2__POR				(0x00)
+#define MSM8X10_WCD_A_TX_3_EN			(0x15D)
+#define MSM8X10_WCD_A_TX_3_EN__POR				(0x00)
+#define MSM8X10_WCD_A_TX_1_2_TEST_EN			(0x15E)
+#define MSM8X10_WCD_A_TX_1_2_TEST_EN__POR				(0xCC)
+#define MSM8X10_WCD_A_TX_7_MBHC_EN_ATEST_CTRL			(0x171)
+#define MSM8X10_WCD_A_TX_7_MBHC_EN_ATEST_CTRL__POR			(0x10)
+#define MSM8X10_WCD_A_TX_7_MBHC_SAR_ERR			(0x175)
+#define MSM8X10_WCD_A_TX_7_MBHC_SAR_ERR__POR				(0x00)
+#define MSM8X10_WCD_A_CP_EN			(0x192)
+#define MSM8X10_WCD_A_CP_EN__POR				(0xE6)
+#define MSM8X10_WCD_A_CP_CLK			(0x193)
+#define MSM8X10_WCD_A_CP_CLK__POR				(0x29)
+#define MSM8X10_WCD_A_CP_STATIC			(0x194)
+#define MSM8X10_WCD_A_CP_STATIC__POR				(0x10)
+#define MSM8X10_WCD_A_CP_DCC1			(0x195)
+#define MSM8X10_WCD_A_CP_DCC1__POR				(0x52)
+#define MSM8X10_WCD_A_CP_DCC3			(0x196)
+#define MSM8X10_WCD_A_CP_DCC3__POR				(0x01)
+#define MSM8X10_WCD_A_CP_ATEST			(0x197)
+#define MSM8X10_WCD_A_CP_ATEST__POR				(0x00)
+#define MSM8X10_WCD_A_CP_DTEST			(0x198)
+#define MSM8X10_WCD_A_CP_DTEST__POR				(0x00)
+#define MSM8X10_WCD_A_RX_AUX_SW_CTL			(0x19B)
+#define MSM8X10_WCD_A_RX_AUX_SW_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_RX_PA_AUX_IN_CONN			(0x19C)
+#define MSM8X10_WCD_A_RX_PA_AUX_IN_CONN__POR				(0x00)
+#define MSM8X10_WCD_A_RX_COM_TIMER_DIV			(0x19E)
+#define MSM8X10_WCD_A_RX_COM_TIMER_DIV__POR				(0xE8)
+#define MSM8X10_WCD_A_RX_COM_OCP_CTL			(0x19F)
+#define MSM8X10_WCD_A_RX_COM_OCP_CTL__POR				(0x1F)
+#define MSM8X10_WCD_A_RX_COM_OCP_COUNT			(0x1A0)
+#define MSM8X10_WCD_A_RX_COM_OCP_COUNT__POR				(0x77)
+#define MSM8X10_WCD_A_RX_COM_DAC_CTL			(0x1A1)
+#define MSM8X10_WCD_A_RX_COM_DAC_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_RX_COM_BIAS			(0x1A2)
+#define MSM8X10_WCD_A_RX_COM_BIAS__POR				(0x00)
+#define MSM8X10_WCD_A_RX_HPH_AUTO_CHOP			(0x1A4)
+#define MSM8X10_WCD_A_RX_HPH_AUTO_CHOP__POR				(0x38)
+#define MSM8X10_WCD_A_RX_HPH_CHOP_CTL			(0x1A5)
+#define MSM8X10_WCD_A_RX_HPH_CHOP_CTL__POR				(0x34)
+#define MSM8X10_WCD_A_RX_HPH_BIAS_PA			(0x1A6)
+#define MSM8X10_WCD_A_RX_HPH_BIAS_PA__POR				(0x5A)
+#define MSM8X10_WCD_A_RX_HPH_BIAS_LDO			(0x1A7)
+#define MSM8X10_WCD_A_RX_HPH_BIAS_LDO__POR				(0x87)
+#define MSM8X10_WCD_A_RX_HPH_BIAS_CNP			(0x1A8)
+#define MSM8X10_WCD_A_RX_HPH_BIAS_CNP__POR				(0x8A)
+#define MSM8X10_WCD_A_RX_HPH_BIAS_WG_OCP			(0x1A9)
+#define MSM8X10_WCD_A_RX_HPH_BIAS_WG_OCP__POR				(0x2A)
+#define MSM8X10_WCD_A_RX_HPH_OCP_CTL			(0x1AA)
+#define MSM8X10_WCD_A_RX_HPH_OCP_CTL__POR				(0x69)
+#define MSM8X10_WCD_A_RX_HPH_CNP_EN			(0x1AB)
+#define MSM8X10_WCD_A_RX_HPH_CNP_EN__POR				(0x80)
+#define MSM8X10_WCD_A_RX_HPH_CNP_WG_CTL			(0x1AC)
+#define MSM8X10_WCD_A_RX_HPH_CNP_WG_CTL__POR				(0xDE)
+#define MSM8X10_WCD_A_RX_HPH_CNP_WG_TIME			(0x1AD)
+#define MSM8X10_WCD_A_RX_HPH_CNP_WG_TIME__POR				(0x15)
+#define MSM8X10_WCD_A_RX_HPH_L_GAIN			(0x1AE)
+#define MSM8X10_WCD_A_RX_HPH_L_GAIN__POR				(0x00)
+#define MSM8X10_WCD_A_RX_HPH_L_TEST			(0x1AF)
+#define MSM8X10_WCD_A_RX_HPH_L_TEST__POR				(0x00)
+#define MSM8X10_WCD_A_RX_HPH_L_PA_CTL			(0x1B0)
+#define MSM8X10_WCD_A_RX_HPH_L_PA_CTL__POR				(0x40)
+#define MSM8X10_WCD_A_RX_HPH_L_DAC_CTL			(0x1B1)
+#define MSM8X10_WCD_A_RX_HPH_L_DAC_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_RX_HPH_L_ATEST			(0x1B2)
+#define MSM8X10_WCD_A_RX_HPH_L_ATEST__POR				(0x00)
+#define MSM8X10_WCD_A_RX_HPH_L_STATUS			(0x1B3)
+#define MSM8X10_WCD_A_RX_HPH_L_STATUS__POR				(0x00)
+#define MSM8X10_WCD_A_RX_HPH_R_GAIN			(0x1B4)
+#define MSM8X10_WCD_A_RX_HPH_R_GAIN__POR				(0x00)
+#define MSM8X10_WCD_A_RX_HPH_R_TEST			(0x1B5)
+#define MSM8X10_WCD_A_RX_HPH_R_TEST__POR				(0x00)
+#define MSM8X10_WCD_A_RX_HPH_R_PA_CTL			(0x1B6)
+#define MSM8X10_WCD_A_RX_HPH_R_PA_CTL__POR				(0x40)
+#define MSM8X10_WCD_A_RX_HPH_R_DAC_CTL			(0x1B7)
+#define MSM8X10_WCD_A_RX_HPH_R_DAC_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_RX_HPH_R_ATEST			(0x1B8)
+#define MSM8X10_WCD_A_RX_HPH_R_ATEST__POR				(0x00)
+#define MSM8X10_WCD_A_RX_HPH_R_STATUS			(0x1B9)
+#define MSM8X10_WCD_A_RX_HPH_R_STATUS__POR				(0x00)
+#define MSM8X10_WCD_A_RX_EAR_BIAS_PA			(0x1BA)
+#define MSM8X10_WCD_A_RX_EAR_BIAS_PA__POR				(0x56)
+#define MSM8X10_WCD_A_RX_EAR_BIAS_CMBUFF			(0x1BB)
+#define MSM8X10_WCD_A_RX_EAR_BIAS_CMBUFF__POR				(0xA0)
+#define MSM8X10_WCD_A_RX_EAR_EN			(0x1BC)
+#define MSM8X10_WCD_A_RX_EAR_EN__POR				(0x00)
+#define MSM8X10_WCD_A_RX_EAR_GAIN			(0x1BD)
+#define MSM8X10_WCD_A_RX_EAR_GAIN__POR				(0x02)
+#define MSM8X10_WCD_A_RX_EAR_CMBUFF			(0x1BE)
+#define MSM8X10_WCD_A_RX_EAR_CMBUFF__POR				(0x05)
+#define MSM8X10_WCD_A_RX_EAR_ICTL			(0x1BF)
+#define MSM8X10_WCD_A_RX_EAR_ICTL__POR				(0x40)
+#define MSM8X10_WCD_A_RX_EAR_CCOMP			(0x1C0)
+#define MSM8X10_WCD_A_RX_EAR_CCOMP__POR				(0x08)
+#define MSM8X10_WCD_A_RX_EAR_VCM			(0x1C1)
+#define MSM8X10_WCD_A_RX_EAR_VCM__POR				(0x03)
+#define MSM8X10_WCD_A_RX_EAR_CNP			(0x1C2)
+#define MSM8X10_WCD_A_RX_EAR_CNP__POR				(0xF2)
+#define MSM8X10_WCD_A_RX_EAR_DAC_CTL_ATEST			(0x1C3)
+#define MSM8X10_WCD_A_RX_EAR_DAC_CTL_ATEST__POR				(0x00)
+#define MSM8X10_WCD_A_RX_EAR_STATUS			(0x1C5)
+#define MSM8X10_WCD_A_RX_EAR_STATUS__POR				(0x04)
+#define MSM8X10_WCD_A_RX_LINE_BIAS_PA			(0x1C6)
+#define MSM8X10_WCD_A_RX_LINE_BIAS_PA__POR				(0x58)
+#define MSM8X10_WCD_A_RX_BUCK_BIAS1			(0x1C7)
+#define MSM8X10_WCD_A_RX_BUCK_BIAS1__POR				(0x42)
+#define MSM8X10_WCD_A_RX_BUCK_BIAS2			(0x1C8)
+#define MSM8X10_WCD_A_RX_BUCK_BIAS2__POR				(0x84)
+#define MSM8X10_WCD_A_RX_LINE_COM			(0x1C9)
+#define MSM8X10_WCD_A_RX_LINE_COM__POR				(0x80)
+#define MSM8X10_WCD_A_RX_LINE_CNP_EN			(0x1CA)
+#define MSM8X10_WCD_A_RX_LINE_CNP_EN__POR				(0x00)
+#define MSM8X10_WCD_A_RX_LINE_CNP_WG_CTL			(0x1CB)
+#define MSM8X10_WCD_A_RX_LINE_CNP_WG_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_RX_LINE_CNP_WG_TIME			(0x1CC)
+#define MSM8X10_WCD_A_RX_LINE_CNP_WG_TIME__POR				(0x04)
+#define MSM8X10_WCD_A_RX_LINE_1_GAIN			(0x1CD)
+#define MSM8X10_WCD_A_RX_LINE_1_GAIN__POR				(0x00)
+#define MSM8X10_WCD_A_RX_LINE_1_TEST			(0x1CE)
+#define MSM8X10_WCD_A_RX_LINE_1_TEST__POR				(0x00)
+#define MSM8X10_WCD_A_RX_LINE_1_DAC_CTL			(0x1CF)
+#define MSM8X10_WCD_A_RX_LINE_1_DAC_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_RX_LINE_1_STATUS			(0x1D0)
+#define MSM8X10_WCD_A_RX_LINE_1_STATUS__POR				(0x00)
+#define MSM8X10_WCD_A_RX_LINE_CNP_DBG			(0x1DD)
+#define MSM8X10_WCD_A_RX_LINE_CNP_DBG__POR				(0x00)
+#define MSM8X10_WCD_A_SPKR_DRV_EN			(0x1DF)
+#define MSM8X10_WCD_A_SPKR_DRV_EN__POR				(0x6F)
+#define MSM8X10_WCD_A_SPKR_DRV_GAIN			(0x1E0)
+#define MSM8X10_WCD_A_SPKR_DRV_GAIN__POR				(0x00)
+#define MSM8X10_WCD_A_SPKR_DRV_DAC_CTL			(0x1E1)
+#define MSM8X10_WCD_A_SPKR_DRV_DAC_CTL__POR				(0x04)
+#define MSM8X10_WCD_A_SPKR_DRV_OCP_CTL			(0x1E2)
+#define MSM8X10_WCD_A_SPKR_DRV_OCP_CTL__POR				(0x98)
+#define MSM8X10_WCD_A_SPKR_DRV_CLIP_DET			(0x1E3)
+#define MSM8X10_WCD_A_SPKR_DRV_CLIP_DET__POR				(0x01)
+#define MSM8X10_WCD_A_SPKR_DRV_IEC			(0x1E4)
+#define MSM8X10_WCD_A_SPKR_DRV_IEC__POR				(0x00)
+#define MSM8X10_WCD_A_SPKR_DRV_DBG_DAC			(0x1E5)
+#define MSM8X10_WCD_A_SPKR_DRV_DBG_DAC__POR				(0x05)
+#define MSM8X10_WCD_A_SPKR_DRV_DBG_PA			(0x1E6)
+#define MSM8X10_WCD_A_SPKR_DRV_DBG_PA__POR				(0x18)
+#define MSM8X10_WCD_A_SPKR_DRV_DBG_PWRSTG			(0x1E7)
+#define MSM8X10_WCD_A_SPKR_DRV_DBG_PWRSTG__POR				(0x00)
+#define MSM8X10_WCD_A_SPKR_DRV_BIAS_LDO			(0x1E8)
+#define MSM8X10_WCD_A_SPKR_DRV_BIAS_LDO__POR				(0x45)
+#define MSM8X10_WCD_A_SPKR_DRV_BIAS_INT			(0x1E9)
+#define MSM8X10_WCD_A_SPKR_DRV_BIAS_INT__POR				(0xA5)
+#define MSM8X10_WCD_A_SPKR_DRV_BIAS_PA			(0x1EA)
+#define MSM8X10_WCD_A_SPKR_DRV_BIAS_PA__POR				(0x55)
+#define MSM8X10_WCD_A_SPKR_DRV_STATUS_OCP			(0x1EB)
+#define MSM8X10_WCD_A_SPKR_DRV_STATUS_OCP__POR				(0x00)
+#define MSM8X10_WCD_A_SPKR_DRV_STATUS_PA			(0x1EC)
+#define MSM8X10_WCD_A_SPKR_DRV_STATUS_PA__POR				(0x00)
+#define MSM8X10_WCD_A_RC_OSC_FREQ			(0x1FA)
+#define MSM8X10_WCD_A_RC_OSC_FREQ__POR				(0x46)
+#define MSM8X10_WCD_A_RC_OSC_TEST			(0x1FB)
+#define MSM8X10_WCD_A_RC_OSC_TEST__POR				(0x0A)
+#define MSM8X10_WCD_A_RC_OSC_STATUS			(0x1FC)
+#define MSM8X10_WCD_A_RC_OSC_STATUS__POR				(0x18)
+#define MSM8X10_WCD_A_RC_OSC_TUNER			(0x1FD)
+#define MSM8X10_WCD_A_RC_OSC_TUNER__POR				(0x00)
+#define MSM8X10_WCD_A_MBHC_HPH			(0x1FE)
+#define MSM8X10_WCD_A_MBHC_HPH__POR				(0x44)
+#define MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL			(0x400)
+#define MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CLK_TX_RESET_B1_CTL			(0x404)
+#define MSM8X10_WCD_A_CDC_CLK_TX_RESET_B1_CTL__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL			(0x408)
+#define MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CLK_RX_I2S_CTL			(0x40C)
+#define MSM8X10_WCD_A_CDC_CLK_RX_I2S_CTL__POR				(0x10)
+#define MSM8X10_WCD_A_CDC_CLK_TX_I2S_CTL			(0x410)
+#define MSM8X10_WCD_A_CDC_CLK_TX_I2S_CTL__POR				(0x10)
+#define MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL			(0x414)
+#define MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL			(0x418)
+#define MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_CLK_OTHR_CTL			(0x41C)
+#define MSM8X10_WCD_A_CDC_CLK_OTHR_CTL__POR				(0x04)
+#define MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL			(0x420)
+#define MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CLK_MCLK_CTL			(0x424)
+#define MSM8X10_WCD_A_CDC_CLK_MCLK_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CLK_PDM_CTL			(0x428)
+#define MSM8X10_WCD_A_CDC_CLK_PDM_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CLK_SD_CTL			(0x42C)
+#define MSM8X10_WCD_A_CDC_CLK_SD_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX1_B1_CTL			(0x440)
+#define MSM8X10_WCD_A_CDC_RX1_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX2_B1_CTL			(0x460)
+#define MSM8X10_WCD_A_CDC_RX2_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX3_B1_CTL			(0x480)
+#define MSM8X10_WCD_A_CDC_RX3_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX1_B2_CTL			(0x444)
+#define MSM8X10_WCD_A_CDC_RX1_B2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX2_B2_CTL			(0x464)
+#define MSM8X10_WCD_A_CDC_RX2_B2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX3_B2_CTL			(0x484)
+#define MSM8X10_WCD_A_CDC_RX3_B2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX1_B3_CTL			(0x448)
+#define MSM8X10_WCD_A_CDC_RX1_B3_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX2_B3_CTL			(0x468)
+#define MSM8X10_WCD_A_CDC_RX2_B3_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX3_B3_CTL			(0x488)
+#define MSM8X10_WCD_A_CDC_RX3_B3_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX1_B4_CTL			(0x44C)
+#define MSM8X10_WCD_A_CDC_RX1_B4_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX2_B4_CTL			(0x46C)
+#define MSM8X10_WCD_A_CDC_RX2_B4_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX3_B4_CTL			(0x48C)
+#define MSM8X10_WCD_A_CDC_RX3_B4_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX1_B5_CTL			(0x450)
+#define MSM8X10_WCD_A_CDC_RX1_B5_CTL__POR				(0x68)
+#define MSM8X10_WCD_A_CDC_RX2_B5_CTL			(0x470)
+#define MSM8X10_WCD_A_CDC_RX2_B5_CTL__POR				(0x68)
+#define MSM8X10_WCD_A_CDC_RX3_B5_CTL			(0x490)
+#define MSM8X10_WCD_A_CDC_RX3_B5_CTL__POR				(0x68)
+#define MSM8X10_WCD_A_CDC_RX1_B6_CTL			(0x454)
+#define MSM8X10_WCD_A_CDC_RX1_B6_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX2_B6_CTL			(0x474)
+#define MSM8X10_WCD_A_CDC_RX2_B6_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX3_B6_CTL			(0x494)
+#define MSM8X10_WCD_A_CDC_RX3_B6_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B1_CTL			(0x458)
+#define MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B1_CTL__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B1_CTL			(0x478)
+#define MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B1_CTL__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B1_CTL			(0x498)
+#define MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B1_CTL__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL			(0x45C)
+#define MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL			(0x47C)
+#define MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL			(0x49C)
+#define MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B1_CTL			(0x4A0)
+#define MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B1_CTL__POR			(0x07)
+#define MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B2_CTL			(0x4A4)
+#define MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B2_CTL__POR			(0x13)
+#define MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B3_CTL			(0x4A8)
+#define MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B3_CTL__POR			(0x1B)
+#define MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B4_CTL			(0x4AC)
+#define MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B4_CTL__POR			(0x7F)
+#define MSM8X10_WCD_A_CDC_CLSG_GAIN_THRESH_CTL			(0x4B0)
+#define MSM8X10_WCD_A_CDC_CLSG_GAIN_THRESH_CTL__POR			(0x26)
+#define MSM8X10_WCD_A_CDC_CLSG_TIMER_B1_CFG			(0x4B4)
+#define MSM8X10_WCD_A_CDC_CLSG_TIMER_B1_CFG__POR			(0x0A)
+#define MSM8X10_WCD_A_CDC_CLSG_TIMER_B2_CFG			(0x4B8)
+#define MSM8X10_WCD_A_CDC_CLSG_TIMER_B2_CFG__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_CLSG_CTL			(0x4BC)
+#define MSM8X10_WCD_A_CDC_CLSG_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_TX1_VOL_CTL_TIMER			(0x4C0)
+#define MSM8X10_WCD_A_CDC_TX1_VOL_CTL_TIMER__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_TX2_VOL_CTL_TIMER			(0x4E0)
+#define MSM8X10_WCD_A_CDC_TX2_VOL_CTL_TIMER__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN			(0x4C4)
+#define MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN			(0x4E4)
+#define MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_TX1_VOL_CTL_CFG			(0x4C8)
+#define MSM8X10_WCD_A_CDC_TX1_VOL_CTL_CFG__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_TX2_VOL_CTL_CFG			(0x4E8)
+#define MSM8X10_WCD_A_CDC_TX2_VOL_CTL_CFG__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_TX1_MUX_CTL			(0x4CC)
+#define MSM8X10_WCD_A_CDC_TX1_MUX_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_TX2_MUX_CTL			(0x4EC)
+#define MSM8X10_WCD_A_CDC_TX2_MUX_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_TX1_CLK_FS_CTL			(0x4D0)
+#define MSM8X10_WCD_A_CDC_TX1_CLK_FS_CTL__POR				(0x03)
+#define MSM8X10_WCD_A_CDC_TX2_CLK_FS_CTL			(0x4F0)
+#define MSM8X10_WCD_A_CDC_TX2_CLK_FS_CTL__POR				(0x03)
+#define MSM8X10_WCD_A_CDC_TX1_DMIC_CTL			(0x4D4)
+#define MSM8X10_WCD_A_CDC_TX1_DMIC_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_TX2_DMIC_CTL			(0x4F4)
+#define MSM8X10_WCD_A_CDC_TX2_DMIC_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B1_CTL			(0x500)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B1_CTL			(0x540)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B2_CTL			(0x504)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B2_CTL			(0x544)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B3_CTL			(0x508)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B3_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B3_CTL			(0x548)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B3_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL			(0x50C)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B4_CTL			(0x54C)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B4_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B5_CTL			(0x510)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B5_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B5_CTL			(0x550)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B5_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B6_CTL			(0x514)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B6_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B6_CTL			(0x554)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B6_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B7_CTL			(0x518)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B7_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B7_CTL			(0x558)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B7_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B8_CTL			(0x51C)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_B8_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B8_CTL			(0x55C)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_B8_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR1_CTL			(0x520)
+#define MSM8X10_WCD_A_CDC_IIR1_CTL__POR				(0x40)
+#define MSM8X10_WCD_A_CDC_IIR2_CTL			(0x560)
+#define MSM8X10_WCD_A_CDC_IIR2_CTL__POR				(0x40)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_TIMER_CTL			(0x524)
+#define MSM8X10_WCD_A_CDC_IIR1_GAIN_TIMER_CTL__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_TIMER_CTL			(0x564)
+#define MSM8X10_WCD_A_CDC_IIR2_GAIN_TIMER_CTL__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL			(0x528)
+#define MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR2_COEF_B1_CTL			(0x568)
+#define MSM8X10_WCD_A_CDC_IIR2_COEF_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL			(0x52C)
+#define MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_IIR2_COEF_B2_CTL			(0x56C)
+#define MSM8X10_WCD_A_CDC_IIR2_COEF_B2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL			(0x580)
+#define MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_RX1_B2_CTL			(0x584)
+#define MSM8X10_WCD_A_CDC_CONN_RX1_B2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_RX1_B3_CTL			(0x588)
+#define MSM8X10_WCD_A_CDC_CONN_RX1_B3_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL			(0x58C)
+#define MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_RX2_B2_CTL			(0x590)
+#define MSM8X10_WCD_A_CDC_CONN_RX2_B2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_RX2_B3_CTL			(0x594)
+#define MSM8X10_WCD_A_CDC_CONN_RX2_B3_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL			(0x598)
+#define MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_RX3_B2_CTL			(0x59C)
+#define MSM8X10_WCD_A_CDC_CONN_RX3_B2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL			(0x5A4)
+#define MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_EQ1_B1_CTL			(0x5A8)
+#define MSM8X10_WCD_A_CDC_CONN_EQ1_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_EQ1_B2_CTL			(0x5AC)
+#define MSM8X10_WCD_A_CDC_CONN_EQ1_B2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_EQ1_B3_CTL			(0x5B0)
+#define MSM8X10_WCD_A_CDC_CONN_EQ1_B3_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_EQ1_B4_CTL			(0x5B4)
+#define MSM8X10_WCD_A_CDC_CONN_EQ1_B4_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_EQ2_B1_CTL			(0x5B8)
+#define MSM8X10_WCD_A_CDC_CONN_EQ2_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_EQ2_B2_CTL			(0x5BC)
+#define MSM8X10_WCD_A_CDC_CONN_EQ2_B2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_EQ2_B3_CTL			(0x5C0)
+#define MSM8X10_WCD_A_CDC_CONN_EQ2_B3_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_EQ2_B4_CTL			(0x5C4)
+#define MSM8X10_WCD_A_CDC_CONN_EQ2_B4_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_CONN_TX_I2S_SD1_CTL			(0x5C8)
+#define MSM8X10_WCD_A_CDC_CONN_TX_I2S_SD1_CTL__POR			(0x00)
+#define MSM8X10_WCD_A_CDC_TOP_GAIN_UPDATE			(0x5D0)
+#define MSM8X10_WCD_A_CDC_TOP_GAIN_UPDATE__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_TOP_CTL			(0x5D8)
+#define MSM8X10_WCD_A_CDC_TOP_CTL__POR				(0x01)
+#define MSM8X10_WCD_A_CDC_DEBUG_DESER1_CTL			(0x5E0)
+#define MSM8X10_WCD_A_CDC_DEBUG_DESER1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_DEBUG_DESER2_CTL			(0x5E4)
+#define MSM8X10_WCD_A_CDC_DEBUG_DESER2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_DEBUG_B1_CTL			(0x5E8)
+#define MSM8X10_WCD_A_CDC_DEBUG_B1_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_DEBUG_B2_CTL			(0x5EC)
+#define MSM8X10_WCD_A_CDC_DEBUG_B2_CTL__POR				(0x00)
+#define MSM8X10_WCD_A_CDC_DEBUG_B3_CTL			(0x5F0)
+#define MSM8X10_WCD_A_CDC_DEBUG_B3_CTL__POR				(0x00)
+#endif
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 28be822..f48dbf1 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -36,6 +36,7 @@
 #include <linux/gpio.h>
 #include "wcd9320.h"
 #include "wcd9xxx-resmgr.h"
+#include "wcd9xxx-common.h"
 
 static atomic_t kp_taiko_priv;
 static int spkr_drv_wrnd_param_set(const char *val,
@@ -69,6 +70,12 @@
 #define TAIKO_SLIM_IRQ_PORT_CLOSED (1 << 2)
 #define TAIKO_MCLK_CLK_12P288MHZ 12288000
 #define TAIKO_MCLK_CLK_9P6HZ 9600000
+
+#define TAIKO_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FORMAT_S24_LE)
+
+#define TAIKO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
 enum {
 	AIF1_PB = 0,
 	AIF1_CAP,
@@ -233,6 +240,10 @@
 	struct wcd9xxx_resmgr resmgr;
 	/* mbhc module */
 	struct wcd9xxx_mbhc mbhc;
+
+	/* class h specific data */
+	struct wcd9xxx_clsh_cdc_data clsh_d;
+
 };
 
 static const u32 comp_shift[] = {
@@ -354,73 +365,6 @@
 	return 0;
 }
 
-static int taiko_codec_enable_class_h_clk(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-
-	pr_debug("%s %s  %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, TAIKO_A_CDC_CLSH_B1_CTL, 0x01, 0x01);
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x80, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_CDC_CLSH_B1_CTL, 0x01, 0x00);
-		break;
-	}
-	return 0;
-}
-
-static int taiko_codec_enable_class_h(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-
-	pr_debug("%s %s  %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x02);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_4, 0xFF, 0xFF);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x04, 0x04);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x04, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x80, 0x80);
-		usleep_range(1000, 1000);
-		break;
-	}
-	return 0;
-}
-
-static int taiko_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-
-	pr_debug("%s %s %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, w->reg, 0x01, 0x01);
-		snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
-		break;
-
-	case SND_SOC_DAPM_POST_PMU:
-		usleep_range(1000, 1000);
-		break;
-
-	case SND_SOC_DAPM_PRE_PMD:
-	    snd_soc_update_bits(codec, w->reg, 0x01, 0x00);
-		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
-		break;
-	}
-	return 0;
-}
-
-
 static int taiko_get_anc_slot(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
@@ -905,6 +849,17 @@
 static const struct soc_enum cf_rxmix7_enum =
 	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
 
+static const char * const class_h_dsm_text[] = {
+	"ZERO", "DSM_HPHL_RX1", "DSM_SPKR_RX7"
+};
+
+static const struct soc_enum class_h_dsm_enum =
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_CLSH_CTL, 4, 3, class_h_dsm_text);
+
+static const struct snd_kcontrol_new class_h_dsm_mux =
+	SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
+
+
 static const struct snd_kcontrol_new taiko_snd_controls[] = {
 
 	SOC_ENUM_EXT("EAR PA Gain", taiko_ear_pa_gain_enum[0],
@@ -1842,11 +1797,12 @@
 
 	if (enable) {
 		taiko->adc_count++;
-		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
+						0x2, 0x2);
 	} else {
 		taiko->adc_count--;
 		if (!taiko->adc_count)
-			snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_CTL,
+			snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
 					    0x2, 0x0);
 	}
 }
@@ -1934,6 +1890,7 @@
 		struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
 	u16 lineout_gain_reg;
 
 	pr_debug("%s %d %s\n", __func__, event, w->name);
@@ -1962,11 +1919,19 @@
 		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-		pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
+		wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+						 WCD9XXX_CLSH_STATE_LO,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
+		pr_debug("%s: sleeping 3 ms after %s PA turn on\n",
 				__func__, w->name);
-		usleep_range(16000, 16000);
+		usleep_range(3000, 3000);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+						 WCD9XXX_CLSH_STATE_LO,
+						 WCD9XXX_CLSH_REQ_DISABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
 		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
 		break;
 	}
@@ -2169,45 +2134,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 +2190,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 +2207,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);
 
@@ -2496,18 +2480,52 @@
 	}
 	return 0;
 }
-static int taiko_hphr_dac_event(struct snd_soc_dapm_widget *w,
+
+static int taiko_hphl_dac_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
 
 	pr_debug("%s %s %d\n", __func__, w->name, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+							0x02, 0x02);
+		wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+						 WCD9XXX_CLSH_STATE_HPHL,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_PRE_DAC);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+							0x02, 0x00);
+	}
+	return 0;
+}
+
+static int taiko_hphr_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+							0x04, 0x04);
+		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+		wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+						 WCD9XXX_CLSH_STATE_HPHR,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_PRE_DAC);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+							0x04, 0x00);
 		snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
 		break;
 	}
@@ -2520,14 +2538,17 @@
 	struct snd_soc_codec *codec = w->codec;
 	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
 	enum wcd9xxx_notify_event e_pre_on, e_post_off;
+	u8 req_clsh_state;
 
 	pr_debug("%s: %s event = %d\n", __func__, w->name, event);
 	if (w->shift == 5) {
 		e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
 		e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
+		req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
 	} else if (w->shift == 4) {
 		e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
 		e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
+		req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
 	} else {
 		pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
 		return -EINVAL;
@@ -2540,29 +2561,27 @@
 		break;
 
 	case SND_SOC_DAPM_POST_PMU:
-		usleep_range(10000, 10000);
+		wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+						 req_clsh_state,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
 
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x20, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x04);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
 
-		usleep_range(10, 10);
+		usleep_range(5000, 5000);
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
 		/* Let MBHC module know PA turned off */
 		wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_off);
 
-		/*
-		 * schedule work is required because at the time HPH PA DAPM
-		 * event callback is called by DAPM framework, CODEC dapm mutex
-		 * would have been locked while snd_soc_jack_report also
-		 * attempts to acquire same lock.
-		 */
+		wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+						 req_clsh_state,
+						 WCD9XXX_CLSH_REQ_DISABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
+
 		pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
 			 w->name);
-		usleep_range(10000, 10000);
+		usleep_range(5000, 5000);
 		break;
 	}
 	return 0;
@@ -2579,11 +2598,16 @@
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
 
 	pr_debug("%s %s %d\n", __func__, w->name, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+						 WCD9XXX_CLSH_STATE_LO,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_PRE_DAC);
 		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
 		break;
 
@@ -2738,15 +2762,11 @@
 	{"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
 	{"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
 
-	/* Change Pump */
-	{"CP", NULL, "CLASS_H_CLK"},
-
 	/* Earpiece (RX MIX1) */
 	{"EAR", NULL, "EAR PA"},
 	{"EAR PA", NULL, "EAR_PA_MIXER"},
 	{"EAR_PA_MIXER", NULL, "DAC1"},
-	{"DAC1", NULL, "CLASS_H_EAR"},
-	{"CLASS_H_EAR", NULL, "CP"},
+	{"DAC1", NULL, "RX_BIAS"},
 
 	{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
 	{"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
@@ -2758,15 +2778,11 @@
 
 	{"HPHL", NULL, "HPHL_PA_MIXER"},
 	{"HPHL_PA_MIXER", NULL, "HPHL DAC"},
+	{"HPHL DAC", NULL, "RX_BIAS"},
 
 	{"HPHR", NULL, "HPHR_PA_MIXER"},
 	{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
-
-	{"HPHL DAC", NULL, "CLASS_H_HPH_L"},
-	{"CLASS_H_HPH_L", NULL, "CP"},
-
-	{"HPHR DAC", NULL, "CLASS_H_HPH_R"},
-	{"CLASS_H_HPH_R", NULL, "CP"},
+	{"HPHR DAC", NULL, "RX_BIAS"},
 
 	{"ANC", NULL, "ANC1 MUX"},
 	{"ANC", NULL, "ANC2 MUX"},
@@ -2781,8 +2797,8 @@
 
 	{"ANC", NULL, "CDC_CONN"},
 
-	{"DAC1", "Switch", "RX1 CHAIN"},
-	{"HPHL DAC", "Switch", "RX1 CHAIN"},
+	{"DAC1", "Switch", "CLASS_H_DSM MUX"},
+	{"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
 	{"HPHR DAC", NULL, "RX2 CHAIN"},
 
 	{"LINEOUT1", NULL, "LINEOUT1 PA"},
@@ -2791,30 +2807,20 @@
 	{"LINEOUT4", NULL, "LINEOUT4 PA"},
 	{"SPK_OUT", NULL, "SPK PA"},
 
-	{"LINEOUT1 PA", NULL, "CP"},
 	{"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
 	{"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
 
-	{"LINEOUT2 PA", NULL, "CP"},
 	{"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
 	{"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
 
-	{"LINEOUT3 PA", NULL, "CP"},
 	{"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
 	{"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
 
-	{"LINEOUT4 PA", NULL, "CP"},
 	{"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
 	{"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
 
-	{"CP", NULL, "CLASS_H_LINEOUTS_PA"},
-	{"CLASS_H_LINEOUTS_PA", NULL, "CLASS_H_CLK"},
-
-
-
 	{"LINEOUT1 DAC", NULL, "RX3 MIX1"},
 
-
 	{"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
 	{"RDAC5 MUX", "DEM4", "RX4 MIX1"},
 
@@ -2831,12 +2837,13 @@
 	{"SPK DAC", NULL, "RX7 MIX2"},
 	{"SPK DAC", NULL, "VDD_SPKDRV"},
 
+	{"CLASS_H_DSM MUX", "DSM_HPHL_RX1", "RX1 CHAIN"},
+
 	{"RX1 CHAIN", NULL, "RX1 MIX2"},
 	{"RX2 CHAIN", NULL, "RX2 MIX2"},
 	{"RX1 CHAIN", NULL, "ANC"},
 	{"RX2 CHAIN", NULL, "ANC"},
 
-	{"CLASS_H_CLK", NULL, "RX_BIAS"},
 	{"LINEOUT1 DAC", NULL, "RX_BIAS"},
 	{"LINEOUT2 DAC", NULL, "RX_BIAS"},
 	{"LINEOUT3 DAC", NULL, "RX_BIAS"},
@@ -3194,7 +3201,6 @@
 	return 0;
 }
 
-#define TAIKO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
 static int taiko_write(struct snd_soc_codec *codec, unsigned int reg,
 	unsigned int value)
 {
@@ -3671,6 +3677,29 @@
 			snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_I2S_CTL,
 					    0x03, (rx_fs_rate >> 0x05));
 		} else {
+			switch (params_format(params)) {
+			case SNDRV_PCM_FORMAT_S16_LE:
+				snd_soc_update_bits(codec,
+					TAIKO_A_CDC_CONN_RX_SB_B1_CTL,
+					0xFF, 0xAA);
+				snd_soc_update_bits(codec,
+					TAIKO_A_CDC_CONN_RX_SB_B2_CTL,
+					0xFF, 0x2A);
+				taiko->dai[dai->id].bit_width = 16;
+				break;
+			case SNDRV_PCM_FORMAT_S24_LE:
+				snd_soc_update_bits(codec,
+					TAIKO_A_CDC_CONN_RX_SB_B1_CTL,
+					0xFF, 0x00);
+				snd_soc_update_bits(codec,
+					TAIKO_A_CDC_CONN_RX_SB_B2_CTL,
+					0xFF, 0x00);
+				taiko->dai[dai->id].bit_width = 24;
+				break;
+			default:
+				dev_err(codec->dev, "Invalid format\n");
+				break;
+			}
 			taiko->dai[dai->id].rate   = params_rate(params);
 		}
 		break;
@@ -3700,7 +3729,7 @@
 		.playback = {
 			.stream_name = "AIF1 Playback",
 			.rates = WCD9320_RATES,
-			.formats = TAIKO_FORMATS,
+			.formats = TAIKO_FORMATS_S16_S24_LE,
 			.rate_max = 192000,
 			.rate_min = 8000,
 			.channels_min = 1,
@@ -3728,7 +3757,7 @@
 		.playback = {
 			.stream_name = "AIF2 Playback",
 			.rates = WCD9320_RATES,
-			.formats = TAIKO_FORMATS,
+			.formats = TAIKO_FORMATS_S16_S24_LE,
 			.rate_min = 8000,
 			.rate_max = 192000,
 			.channels_min = 1,
@@ -3770,7 +3799,7 @@
 		.playback = {
 			.stream_name = "AIF3 Playback",
 			.rates = WCD9320_RATES,
-			.formats = TAIKO_FORMATS,
+			.formats = TAIKO_FORMATS_S16_S24_LE,
 			.rate_min = 8000,
 			.rate_max = 192000,
 			.channels_min = 1,
@@ -3967,24 +3996,81 @@
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
 
 	pr_debug("%s %s %d\n", __func__, w->name, event);
 
 	switch (event) {
-		break;
 	case SND_SOC_DAPM_POST_PMU:
-
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x20, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x04);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
+		wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+						 WCD9XXX_CLSH_STATE_EAR,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
 
 		usleep_range(5000, 5000);
 		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+						 WCD9XXX_CLSH_STATE_EAR,
+						 WCD9XXX_CLSH_REQ_DISABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
+		usleep_range(5000, 5000);
+	}
+	return 0;
+}
+
+static int taiko_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+						 WCD9XXX_CLSH_STATE_EAR,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_PRE_DAC);
+		break;
+	}
+
+	return 0;
+}
+
+static int taiko_codec_dsm_mux_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u8 reg_val, zoh_mux_val = 0x00;
+
+	pr_debug("%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		reg_val = snd_soc_read(codec, TAIKO_A_CDC_CONN_CLSH_CTL);
+
+		if ((reg_val & 0x30) == 0x10)
+			zoh_mux_val = 0x04;
+		else if ((reg_val & 0x30) == 0x20)
+			zoh_mux_val = 0x08;
+
+		if (zoh_mux_val != 0x00)
+			snd_soc_update_bits(codec,
+					TAIKO_A_CDC_CONN_CLSH_CTL,
+					0x0C, zoh_mux_val);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, TAIKO_A_CDC_CONN_CLSH_CTL,
+							0x0C, 0x00);
+		break;
 	}
 	return 0;
 }
 
+
 /* Todo: Have seperate dapm widgets for I2S and Slimbus.
  * Might Need to have callbacks registered only for slimbus
  */
@@ -3993,10 +4079,12 @@
 	SND_SOC_DAPM_OUTPUT("EAR"),
 
 	SND_SOC_DAPM_PGA_E("EAR PA", TAIKO_A_RX_EAR_EN, 4, 0, NULL, 0,
-			taiko_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU),
+			taiko_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
+			SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_MIXER("DAC1", TAIKO_A_RX_EAR_EN, 6, 0, dac1_switch,
-		ARRAY_SIZE(dac1_switch)),
+	SND_SOC_DAPM_MIXER_E("DAC1", TAIKO_A_RX_EAR_EN, 6, 0, dac1_switch,
+		ARRAY_SIZE(dac1_switch), taiko_codec_ear_dac_event,
+		SND_SOC_DAPM_PRE_PMU),
 
 	SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
 				AIF1_PB, 0, taiko_codec_enable_slimrx,
@@ -4036,8 +4124,9 @@
 	SND_SOC_DAPM_PGA_E("HPHL", TAIKO_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
 		taiko_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MIXER("HPHL DAC", TAIKO_A_RX_HPH_L_DAC_CTL, 7, 0,
-		hphl_switch, ARRAY_SIZE(hphl_switch)),
+	SND_SOC_DAPM_MIXER_E("HPHL DAC", TAIKO_A_RX_HPH_L_DAC_CTL, 7, 0,
+		hphl_switch, ARRAY_SIZE(hphl_switch), taiko_hphl_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_PGA_E("HPHR", TAIKO_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
 		taiko_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
@@ -4173,36 +4262,20 @@
 	SND_SOC_DAPM_MUX("RDAC7 MUX", SND_SOC_NOPM, 0, 0,
 		&rx_dac7_mux),
 
-	SND_SOC_DAPM_SUPPLY("CLASS_H_CLK", TAIKO_A_CDC_CLK_OTHR_CTL, 0, 0,
-		taiko_codec_enable_class_h_clk, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_PRE_PMD),
-
-	SND_SOC_DAPM_SUPPLY("CLASS_H_EAR", TAIKO_A_CDC_CLSH_B1_CTL, 4, 0,
-		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_L", TAIKO_A_CDC_CLSH_B1_CTL, 3, 0,
-		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_R", TAIKO_A_CDC_CLSH_B1_CTL, 2, 0,
-		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_SUPPLY("CLASS_H_LINEOUTS_PA", SND_SOC_NOPM, 0, 0,
-		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_SUPPLY("CP", TAIKO_A_NCP_EN, 0, 0,
-		taiko_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MUX_E("CLASS_H_DSM MUX", SND_SOC_NOPM, 0, 0,
+		&class_h_dsm_mux, taiko_codec_dsm_mux_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
 		taiko_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_SUPPLY("CDC_I2S_RX_CONN", TAIKO_A_CDC_CLK_OTHR_CTL, 5, 0,
+	SND_SOC_DAPM_SUPPLY("CDC_I2S_RX_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 5, 0,
 			    NULL, 0),
 
 	/* TX */
 
-	SND_SOC_DAPM_SUPPLY("CDC_CONN", TAIKO_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
+	SND_SOC_DAPM_SUPPLY("CDC_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
 		0),
 
 	SND_SOC_DAPM_SUPPLY("LDO_H", TAIKO_A_LDO_H_MODE_1, 7, 0,
@@ -4220,15 +4293,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 +4387,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 |
@@ -4511,84 +4594,6 @@
 	return IRQ_HANDLED;
 }
 
-static const struct taiko_reg_mask_val taiko_1_0_class_h_ear[] = {
-
-	/* CLASS-H EAR  IDLE_THRESHOLD Table */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_IDLE_EAR_THSD, 0x26),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_FCLKONLY_EAR_THSD, 0x2C),
-
-	/* CLASS-H EAR I_PA_FACT Table. */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_L,	0xA9),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_U, 0x07),
-
-	/* CLASS-H EAR Voltage Headroom , Voltage Min. */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_HD_EAR, 0x0D),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_MIN_EAR, 0x3A),
-
-	/* CLASS-H EAR K values --chnages from load. */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_ADDR, 0x08),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x1B),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x2D),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x36),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x37),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-	/** end of Ear PA load 32 */
-};
-
-static const struct taiko_reg_mask_val taiko_1_0_class_h_hph[] = {
-
-	/* CLASS-H HPH  IDLE_THRESHOLD Table */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_IDLE_HPH_THSD, 0x13),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0x19),
-
-	/* CLASS-H HPH I_PA_FACT Table */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_L,	0x9A),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_U, 0x06),
-
-	/* CLASS-H HPH Voltage Headroom , Voltage Min */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_HD_HPH, 0x0D),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_MIN_HPH, 0x1D),
-
-	/* CLASS-H HPH K values --chnages from load .*/
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_ADDR, 0x00),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0xAE),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x01),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x1C),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x25),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x27),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-};
-
-static int taiko_config_ear_class_h(struct snd_soc_codec *codec, u32 ear_load)
-{
-	u32 i;
-
-	if (ear_load  != 32)
-		return -EINVAL;
-
-	for (i = 0; i < ARRAY_SIZE(taiko_1_0_class_h_ear); i++)
-		snd_soc_write(codec, taiko_1_0_class_h_ear[i].reg,
-				taiko_1_0_class_h_ear[i].val);
-	return 0;
-}
-
-static int taiko_config_hph_class_h(struct snd_soc_codec *codec, u32 hph_load)
-{
-	u32 i;
-	if (hph_load  != 16)
-		return -EINVAL;
-
-	for (i = 0; i < ARRAY_SIZE(taiko_1_0_class_h_hph); i++)
-		snd_soc_write(codec, taiko_1_0_class_h_hph[i].reg,
-				taiko_1_0_class_h_hph[i].val);
-	return 0;
-}
-
 static int taiko_handle_pdata(struct taiko_priv *taiko)
 {
 	struct snd_soc_codec *codec = taiko->codec;
@@ -4727,14 +4732,11 @@
 		 0x00 : 0x16);
 	snd_soc_update_bits(codec, TAIKO_A_MICB_4_CTL, 0x1E, value);
 
-	taiko_config_ear_class_h(codec, 32);
-	taiko_config_hph_class_h(codec, 16);
-
 done:
 	return rc;
 }
 
-static const struct taiko_reg_mask_val taiko_reg_defaults[] = {
+static const struct wcd9xxx_reg_mask_val taiko_reg_defaults[] = {
 
 	/* set MCLk to 9.6 */
 	TAIKO_REG_VAL(TAIKO_A_CHIP_CTL, 0x02),
@@ -4743,24 +4745,6 @@
 	/* EAR PA deafults  */
 	TAIKO_REG_VAL(TAIKO_A_RX_EAR_CMBUFF, 0x05),
 
-	/* BUCK and NCP defaults for EAR and HS */
-	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_1, 0x5B),
-
-	/* CLASS-H defaults for EAR and HS */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_BUCK_NCP_VARS, 0x04),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B2_CTL, 0x01),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B2_CTL, 0x05),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B2_CTL, 0x35),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B3_CTL, 0x30),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B3_CTL, 0x3B),
-
-	/*
-	 * For CLASS-H, Enable ANC delay buffer,
-	 * set HPHL and EAR PA ref gain to 0 DB.
-	 */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B1_CTL, 0x26),
-
 	/* RX deafults */
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX1_B5_CTL, 0x78),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX2_B5_CTL, 0x78),
@@ -4782,25 +4766,31 @@
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
 };
 
-static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
+static const struct wcd9xxx_reg_mask_val taiko_1_0_reg_defaults[] = {
 	/*
 	 * The following only need to be written for Taiko 1.0 parts.
 	 * Taiko 2.0 will have appropriate defaults for these registers.
 	 */
 
 	/* BUCK default */
-	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_4, 0x50),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x50),
+
+	/* Required defaults for class H operation */
+	TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xF4),
+	TAIKO_REG_VAL(TAIKO_A_BIAS_CURR_CTL_2, 0x08),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_3, 0x60),
 
 	/* Choose max non-overlap time for NCP */
 	TAIKO_REG_VAL(TAIKO_A_NCP_CLK, 0xFC),
 	/* Use 25mV/50mV for deltap/m to reduce ripple */
-	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_VCL_1, 0x08),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x08),
 	/*
 	 * Set DISABLE_MODE_SEL<1:0> to 0b10 (disable PWM in auto mode).
 	 * Note that the other bits of this register will be changed during
 	 * Rx PA bring up.
 	 */
-	TAIKO_REG_VAL(TAIKO_A_BUCK_MODE_3, 0xCE),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
 	/* Reduce HPH DAC bias to 70% */
 	TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
 	/*Reduce EAR DAC bias to 70% */
@@ -4829,7 +4819,7 @@
  * Don't update TAIKO_A_CHIP_CTL, TAIKO_A_BUCK_CTRL_CCL_1 and
  * TAIKO_A_RX_EAR_CMBUFF as those are updated in taiko_reg_defaults
  */
-static const struct taiko_reg_mask_val taiko_2_0_reg_defaults[] = {
+static const struct wcd9xxx_reg_mask_val taiko_2_0_reg_defaults[] = {
 	TAIKO_REG_VAL(TAIKO_A_CDC_TX_1_GAIN, 0x2),
 	TAIKO_REG_VAL(TAIKO_A_CDC_TX_2_GAIN, 0x2),
 	TAIKO_REG_VAL(TAIKO_A_CDC_TX_1_2_ADC_IB, 0x44),
@@ -4839,9 +4829,9 @@
 	TAIKO_REG_VAL(TAIKO_A_CDC_TX_5_GAIN, 0x2),
 	TAIKO_REG_VAL(TAIKO_A_CDC_TX_6_GAIN, 0x2),
 	TAIKO_REG_VAL(TAIKO_A_CDC_TX_5_6_ADC_IB, 0x44),
-	TAIKO_REG_VAL(TAIKO_A_BUCK_MODE_3, 0xCE),
-	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_VCL_1, 0x8),
-	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_4, 0x51),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x8),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x51),
 	TAIKO_REG_VAL(TAIKO_A_NCP_DTEST, 0x10),
 	TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xA4),
 	TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
@@ -4902,7 +4892,7 @@
 	}
 }
 
-static const struct taiko_reg_mask_val taiko_codec_reg_init_val[] = {
+static const struct wcd9xxx_reg_mask_val taiko_codec_reg_init_val[] = {
 	/* Initialize current threshold to 350MA
 	 * number of wait and run cycles to 4096
 	 */
@@ -4920,9 +4910,6 @@
 	{TAIKO_A_RX_LINE_4_GAIN, 0x20, 0x20},
 	{TAIKO_A_SPKR_DRV_GAIN, 0x04, 0x04},
 
-	/* CLASS H config */
-	{TAIKO_A_CDC_CONN_CLSH_CTL, 0x3C, 0x14},
-
 	/* Use 16 bit sample size for TX1 to TX6 */
 	{TAIKO_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
 	{TAIKO_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
@@ -4937,10 +4924,6 @@
 	{TAIKO_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
 	{TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
 
-	/* Use 16 bit sample size for RX */
-	{TAIKO_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
-	{TAIKO_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0x2A},
-
 	/*enable HPF filter for TX paths */
 	{TAIKO_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
 	{TAIKO_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
@@ -5072,6 +5055,24 @@
 	return 0;
 }
 
+static int taiko_codec_get_buck_mv(struct snd_soc_codec *codec)
+{
+	int buck_volt = WCD9XXX_CDC_BUCK_UNSUPPORTED;
+	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx_pdata *pdata = taiko->resmgr.pdata;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		if (!strncmp(pdata->regulator[i].name,
+					 WCD9XXX_SUPPLY_BUCK_NAME,
+					 sizeof(WCD9XXX_SUPPLY_BUCK_NAME))) {
+			buck_volt = pdata->regulator[i].min_uV;
+			break;
+		}
+	}
+	return buck_volt;
+}
+
 static int taiko_codec_probe(struct snd_soc_codec *codec)
 {
 	struct wcd9xxx *control;
@@ -5103,8 +5104,10 @@
 			tx_hpf_corner_freq_callback);
 	}
 
+
 	snd_soc_codec_set_drvdata(codec, taiko);
 
+
 	/* codec resmgr module init */
 	wcd9xxx = codec->control_data;
 	pdata = dev_get_platdata(codec->dev->parent);
@@ -5115,6 +5118,9 @@
 		return ret;
 	}
 
+	taiko->clsh_d.buck_mv = taiko_codec_get_buck_mv(codec);
+	wcd9xxx_clsh_init(&taiko->clsh_d);
+
 	/* init and start mbhc */
 	ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec);
 	if (ret) {
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index aea31db..89a0b9f 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -41,12 +41,6 @@
 	TAIKO_PID_MIC_20_UA,
 };
 
-struct taiko_reg_mask_val {
-	u16	reg;
-	u8	mask;
-	u8	val;
-};
-
 enum taiko_mbhc_analog_pwr_cfg {
 	TAIKO_ANALOG_PWR_COLLAPSED = 0,
 	TAIKO_ANALOG_PWR_ON,
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
new file mode 100644
index 0000000..dbf2e39
--- /dev/null
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -0,0 +1,591 @@
+/* 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/module.h>
+#include <sound/soc.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include "wcd9xxx-common.h"
+
+#define CLSH_COMPUTE_EAR 0x01
+#define CLSH_COMPUTE_HPH_L 0x02
+#define CLSH_COMPUTE_HPH_R 0x03
+
+#define BUCK_VREF_2V 0xFF
+#define BUCK_VREF_1P8V 0xE6
+
+#define NCP_FCLK_LEVEL_8 0x08
+#define NCP_FCLK_LEVEL_5 0x05
+
+#define BUCK_SETTLE_TIME_US 50
+#define NCP_SETTLE_TIME_US 50
+
+static inline void wcd9xxx_enable_clsh_block(
+	struct snd_soc_codec *codec,
+	bool on)
+{
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
+		0x01, on ? 0x01 : 0x00);
+}
+
+static inline void wcd9xxx_enable_anc_delay(
+	struct snd_soc_codec *codec,
+	bool on)
+{
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
+		0x02, on ? 0x02 : 0x00);
+}
+
+static inline void wcd9xxx_enable_ncp(
+	struct snd_soc_codec *codec,
+	bool on)
+{
+	snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
+		0x01, on ? 0x01 : 0x00);
+}
+
+static inline void wcd9xxx_enable_buck(
+	struct snd_soc_codec *codec,
+	bool on)
+{
+	snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
+		0x80, on ? 0x80 : 0x00);
+}
+
+static int cdc_lo_count;
+
+static void (*clsh_state_fp[NUM_CLSH_STATES])
+			(struct snd_soc_codec *,
+			 struct wcd9xxx_clsh_cdc_data *,
+			 u8 req_state, bool req_type);
+
+static const char *state_to_str(u8 state)
+{
+	if (state == WCD9XXX_CLSH_STATE_IDLE)
+		return "STATE_IDLE";
+	else if (state == WCD9XXX_CLSH_STATE_EAR)
+		return "STATE_EAR";
+	else if (state == WCD9XXX_CLSH_STATE_HPHL)
+		return "STATE_HPH_L";
+	else if (state == WCD9XXX_CLSH_STATE_HPHR)
+		return "STATE_HPH_R";
+	else if (state == (WCD9XXX_CLSH_STATE_HPHL
+				| WCD9XXX_CLSH_STATE_HPHR))
+		return "STATE_HPH_L_R";
+	else if (state == WCD9XXX_CLSH_STATE_LO)
+		return "STATE_LO";
+
+	return "UNKNOWN_STATE";
+}
+
+static void wcd9xxx_cfg_clsh_buck(
+		struct snd_soc_codec *codec)
+{
+	int i;
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_BUCK_CTRL_CCL_4, 0x0B, 0x00},
+		{WCD9XXX_A_BUCK_CTRL_CCL_1, 0xF0, 0x50},
+		{WCD9XXX_A_BUCK_CTRL_CCL_3, 0x03, 0x00},
+		{WCD9XXX_A_BUCK_CTRL_CCL_3, 0x0B, 0x00},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
+						    reg_set[i].val);
+
+	dev_dbg(codec->dev, "%s: Programmed buck parameters", __func__);
+}
+
+static void wcd9xxx_cfg_clsh_param_common(
+		struct snd_soc_codec *codec)
+{
+	int i;
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 0, 0},
+		{WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 2, 1 << 2},
+		{WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, (0x1 << 4), 0},
+		{WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 0), 0x01},
+		{WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 2), (0x01 << 2)},
+		{WCD9XXX_A_CDC_CLSH_B2_CTL, (0xf << 4), (0x03 << 4)},
+		{WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 4), (0x03 << 4)},
+		{WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 0), (0x0B)},
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 5), (0x01 << 5)},
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 1), (0x01 << 1)},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
+						    reg_set[i].val);
+
+	dev_dbg(codec->dev, "%s: Programmed class H controller common parameters",
+			 __func__);
+}
+
+static void wcd9xxx_chargepump_request(
+	struct snd_soc_codec *codec, bool on)
+{
+	static int cp_count;
+
+	if (on && (++cp_count == 1)) {
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
+							0x01, 0x01);
+		dev_info(codec->dev, "%s: Charge Pump enabled, count = %d\n",
+				__func__, cp_count);
+	}
+
+	else if (!on) {
+		if (--cp_count < 0) {
+			dev_dbg(codec->dev, "%s: Unbalanced disable for charge pump\n",
+					__func__);
+			if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL)
+					& 0x01) {
+				dev_info(codec->dev, "%s: Actual chargepump is ON\n",
+						__func__);
+			}
+			cp_count = 0;
+			WARN_ON(1);
+		}
+
+		if (cp_count == 0) {
+			snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
+							0x01, 0x00);
+			dev_dbg(codec->dev, "%s: Charge pump disabled, count = %d\n",
+					__func__, cp_count);
+		}
+	}
+}
+
+static inline void wcd9xxx_clsh_computation_request(
+	struct snd_soc_codec *codec, int compute_pa, bool on)
+{
+	u8 reg_val, reg_mask;
+
+	switch (compute_pa) {
+	case CLSH_COMPUTE_EAR:
+		reg_mask = 0x10;
+		reg_val = (on ? 0x10 : 0x00);
+		break;
+	case CLSH_COMPUTE_HPH_L:
+		reg_mask = 0x08;
+		reg_val = (on ? 0x08 : 0x00);
+		break;
+	case CLSH_COMPUTE_HPH_R:
+		reg_mask = 0x04;
+		reg_val = (on ? 0x04 : 0x00);
+		break;
+	default:
+		dev_dbg(codec->dev, "%s: class h computation PA request incorrect\n",
+			   __func__);
+		return;
+	}
+
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
+						reg_mask, reg_val);
+
+}
+
+static void wcd9xxx_enable_buck_mode(struct snd_soc_codec *codec,
+		u8 buck_vref)
+{
+	int i;
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_BUCK_MODE_5, 0x02, 0x03},
+		{WCD9XXX_A_BUCK_MODE_4, 0xFF, buck_vref},
+		{WCD9XXX_A_BUCK_MODE_1, 0x04, 0x04},
+		{WCD9XXX_A_BUCK_MODE_1, 0x08, 0x00},
+		{WCD9XXX_A_BUCK_MODE_3, 0x04, 0x00},
+		{WCD9XXX_A_BUCK_MODE_3, 0x08, 0x00},
+		{WCD9XXX_A_BUCK_MODE_1, 0x80, 0x80},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg,
+					reg_set[i].mask, reg_set[i].val);
+
+	dev_dbg(codec->dev, "%s: Done\n", __func__);
+	usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US);
+}
+
+static void wcd9xxx_clsh_enable_post_pa(struct snd_soc_codec *codec)
+{
+	int i;
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_BUCK_MODE_5, 0x02, 0x00},
+		{WCD9XXX_A_NCP_STATIC, 0x20, 0x00},
+		{WCD9XXX_A_BUCK_MODE_3, 0x04, 0x04},
+		{WCD9XXX_A_BUCK_MODE_3, 0x08, 0x08},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg,
+					reg_set[i].mask, reg_set[i].val);
+
+	dev_dbg(codec->dev, "%s: completed clsh mode settings after PA enable\n",
+		   __func__);
+
+}
+
+static void wcd9xxx_set_fclk_enable_ncp(struct snd_soc_codec *codec,
+		u8 fclk_level)
+{
+	int i;
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_NCP_STATIC, 0x20, 0x20},
+		{WCD9XXX_A_NCP_EN, 0x01, 0x01},
+	};
+	snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+						0x010, 0x00);
+	snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+						0x0F, fclk_level);
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg,
+					reg_set[i].mask, reg_set[i].val);
+
+	usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US);
+
+	dev_dbg(codec->dev, "%s: set ncp done\n", __func__);
+}
+
+static void wcd9xxx_cfg_clsh_param_ear(struct snd_soc_codec *codec)
+{
+	int i;
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 7), 0},
+		{WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR, (0x3f << 0), 0x0D},
+		{WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR, (0x3f << 0), 0x3A},
+
+		/* Under assumption that EAR load is 10.7ohm */
+		{WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD, (0x3f << 0), 0x26},
+		{WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD, (0x3f << 0), 0x2C},
+		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L, 0xff, 0xA9},
+		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U, 0xff, 0x07},
+		{WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
+		{WCD9XXX_A_CDC_CLSH_K_ADDR, (0xf << 0), 0x08},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1b},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2d},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x36},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x37},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg,
+					reg_set[i].mask, reg_set[i].val);
+
+	dev_dbg(codec->dev, "%s: Programmed Class H controller EAR specific params\n",
+			 __func__);
+}
+
+static void wcd9xxx_cfg_clsh_param_hph(struct snd_soc_codec *codec)
+{
+	int i;
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 6), 0},
+		{WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH, 0x3f, 0x0D},
+		{WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH, 0x3f, 0x1D},
+
+		/* Under assumption that HPH load is 16ohm per channel */
+		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0x3f, 0x13},
+		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0x1f, 0x19},
+		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x97},
+		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
+		{WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
+		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0x0f, 0},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
+							reg_set[i].val);
+	dev_dbg(codec->dev, "%s: Programmed Class H controller HPH specific params\n",
+			 __func__);
+}
+
+static void wcd9xxx_clsh_turnoff_postpa
+	(struct snd_soc_codec *codec)
+{
+
+	int i;
+
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_NCP_EN, 0x01, 0x00},
+		{WCD9XXX_A_BUCK_MODE_1, 0x80, 0x00},
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, 0x10, 0x00},
+	};
+
+	wcd9xxx_chargepump_request(codec, false);
+
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg,
+				reg_set[i].mask, reg_set[i].val);
+
+	wcd9xxx_enable_clsh_block(codec, false);
+
+	dev_dbg(codec->dev, "%s: Done\n", __func__);
+}
+
+static void wcd9xxx_clsh_state_idle(struct snd_soc_codec *codec,
+			struct wcd9xxx_clsh_cdc_data *clsh_d,
+			u8 req_state, bool is_enable)
+{
+	if (is_enable) {
+		dev_dbg(codec->dev, "%s: wrong transition, cannot enable IDLE state\n",
+			   __func__);
+	} else {
+		if (req_state == WCD9XXX_CLSH_STATE_EAR) {
+			wcd9xxx_clsh_turnoff_postpa(codec);
+		} else if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
+			wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_L, false);
+			wcd9xxx_clsh_turnoff_postpa(codec);
+		} else if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
+			wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_R, false);
+			wcd9xxx_clsh_turnoff_postpa(codec);
+		} else if (req_state == WCD9XXX_CLSH_STATE_LO) {
+			wcd9xxx_enable_ncp(codec, false);
+			wcd9xxx_enable_buck(codec, false);
+		}
+	}
+}
+
+static void wcd9xxx_clsh_state_ear(struct snd_soc_codec *codec,
+			struct wcd9xxx_clsh_cdc_data *clsh_d,
+			u8 req_state, bool is_enable)
+{
+	if (is_enable) {
+		wcd9xxx_cfg_clsh_buck(codec);
+		wcd9xxx_cfg_clsh_param_common(codec);
+		wcd9xxx_cfg_clsh_param_ear(codec);
+		wcd9xxx_enable_clsh_block(codec, true);
+		wcd9xxx_chargepump_request(codec, true);
+		wcd9xxx_enable_anc_delay(codec, true);
+		wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_EAR, true);
+		wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
+		wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+
+		dev_dbg(codec->dev, "%s: Enabled ear mode class h\n", __func__);
+	} else {
+		dev_dbg(codec->dev, "%s: stub fallback to ear\n", __func__);
+	}
+}
+
+static void wcd9xxx_clsh_state_hph_l(struct snd_soc_codec *codec,
+		struct wcd9xxx_clsh_cdc_data *clsh_d,
+		u8 req_state, bool is_enable)
+{
+	if (is_enable) {
+		wcd9xxx_cfg_clsh_buck(codec);
+		wcd9xxx_cfg_clsh_param_common(codec);
+		wcd9xxx_cfg_clsh_param_hph(codec);
+		wcd9xxx_enable_clsh_block(codec, true);
+		wcd9xxx_chargepump_request(codec, true);
+		wcd9xxx_enable_anc_delay(codec, true);
+		wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_L, true);
+		wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
+		wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+
+		dev_dbg(codec->dev, "%s: Done\n", __func__);
+	} else {
+		if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
+			wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_R, false);
+		} else {
+			dev_dbg(codec->dev, "%s: stub fallback to hph_l\n",
+					__func__);
+		}
+	}
+}
+
+static void wcd9xxx_clsh_state_hph_r(struct snd_soc_codec *codec,
+		struct wcd9xxx_clsh_cdc_data *clsh_d,
+		u8 req_state, bool is_enable)
+{
+	if (is_enable) {
+
+		wcd9xxx_cfg_clsh_buck(codec);
+		wcd9xxx_cfg_clsh_param_common(codec);
+		wcd9xxx_cfg_clsh_param_hph(codec);
+		wcd9xxx_enable_clsh_block(codec, true);
+		wcd9xxx_chargepump_request(codec, true);
+		wcd9xxx_enable_anc_delay(codec, true);
+		wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_R, true);
+		wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
+		wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+
+		dev_dbg(codec->dev, "%s: Done\n", __func__);
+	} else {
+		if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
+			wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_L, false);
+		} else {
+			dev_dbg(codec->dev, "%s: stub fallback to hph_r\n",
+					__func__);
+		}
+	}
+}
+
+static void wcd9xxx_clsh_state_hph_st(struct snd_soc_codec *codec,
+		struct wcd9xxx_clsh_cdc_data *clsh_d,
+		u8 req_state, bool is_enable)
+{
+	if (is_enable) {
+		wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_L, true);
+		wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_R, true);
+	} else {
+		dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
+	}
+}
+
+static void wcd9xxx_clsh_state_lo(struct snd_soc_codec *codec,
+		struct wcd9xxx_clsh_cdc_data *clsh_d,
+		u8 req_state, bool is_enable)
+{
+	if (is_enable) {
+		if (++cdc_lo_count > 1)
+			return;
+
+		wcd9xxx_enable_buck_mode(codec, BUCK_VREF_1P8V);
+		wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_5);
+
+		if (clsh_d->buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
+			wcd9xxx_enable_buck(codec, false);
+			snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+							0x20, 0x01);
+			wcd9xxx_enable_ncp(codec, true);
+			msleep(NCP_SETTLE_TIME_US);
+
+		} else {
+			snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
+							0x40, 0x00);
+			wcd9xxx_enable_ncp(codec, true);
+			msleep(NCP_SETTLE_TIME_US);
+			snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
+							0x01, 0x01);
+			snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
+							0xFB, (0x02 << 2));
+		}
+		snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
+							0x04, 0x00);
+	} else {
+		dev_dbg(codec->dev, "%s: stub fallback to lineout\n", __func__);
+	}
+}
+
+static void wcd9xxx_clsh_state_err(struct snd_soc_codec *codec,
+		struct wcd9xxx_clsh_cdc_data *clsh_d,
+		u8 req_state, bool is_enable)
+{
+	dev_dbg(codec->dev, "%s Wrong request for class H state machine requested to %s %s"
+			, __func__, is_enable ? "enable" : "disable",
+			state_to_str(req_state));
+	WARN_ON(1);
+}
+
+void wcd9xxx_clsh_fsm(struct snd_soc_codec *codec,
+		struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
+		u8 req_state, bool req_type, u8 clsh_event)
+{
+	u8 old_state, new_state;
+
+	switch (clsh_event) {
+
+	case WCD9XXX_CLSH_EVENT_PRE_DAC:
+
+		/* PRE_DAC event should be used only for Enable */
+		BUG_ON(req_type != WCD9XXX_CLSH_REQ_ENABLE);
+
+		old_state = cdc_clsh_d->state;
+		new_state = old_state | req_state;
+
+		(*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
+							req_state, req_type);
+		cdc_clsh_d->state = new_state;
+		dev_info(codec->dev, "%s: ClassH state transition from %s to %s\n",
+			__func__, state_to_str(old_state),
+			state_to_str(cdc_clsh_d->state));
+
+		break;
+
+	case WCD9XXX_CLSH_EVENT_POST_PA:
+
+		if (req_type == WCD9XXX_CLSH_REQ_DISABLE) {
+			if (req_state == WCD9XXX_CLSH_STATE_LO
+					&& --cdc_lo_count > 0)
+				break;
+
+			old_state = cdc_clsh_d->state;
+			new_state = old_state & (~req_state);
+
+			if (new_state < NUM_CLSH_STATES) {
+				(*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
+							req_state, req_type);
+				cdc_clsh_d->state = new_state;
+				dev_info(codec->dev, "%s: ClassH state transition from %s to %s\n",
+					__func__, state_to_str(old_state),
+					state_to_str(cdc_clsh_d->state));
+
+			} else {
+				dev_dbg(codec->dev, "%s: wrong new state = %x\n",
+						__func__, new_state);
+			}
+
+
+		} else if (req_state != WCD9XXX_CLSH_STATE_LO) {
+			wcd9xxx_clsh_enable_post_pa(codec);
+		}
+
+		break;
+	}
+
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_clsh_fsm);
+
+void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh)
+{
+	int i;
+	clsh->state = WCD9XXX_CLSH_STATE_IDLE;
+
+	for (i = 0; i < NUM_CLSH_STATES; i++)
+		clsh_state_fp[i] = wcd9xxx_clsh_state_err;
+
+	clsh_state_fp[WCD9XXX_CLSH_STATE_IDLE] = wcd9xxx_clsh_state_idle;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_EAR] = wcd9xxx_clsh_state_ear;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL] =
+						wcd9xxx_clsh_state_hph_l;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR] =
+						wcd9xxx_clsh_state_hph_r;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST] =
+						wcd9xxx_clsh_state_hph_st;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_LO] = wcd9xxx_clsh_state_lo;
+
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_clsh_init);
+
+MODULE_DESCRIPTION("WCD9XXX Common");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
new file mode 100644
index 0000000..743ab0c
--- /dev/null
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -0,0 +1,68 @@
+/* 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 WCD9XXX_CODEC_COMMON
+
+#define WCD9XXX_CODEC_COMMON
+
+#define WCD9XXX_CLSH_REQ_ENABLE true
+#define WCD9XXX_CLSH_REQ_DISABLE false
+
+#define WCD9XXX_CLSH_EVENT_PRE_DAC 0x01
+#define WCD9XXX_CLSH_EVENT_POST_PA 0x02
+
+/* Basic states for Class H state machine.
+ * represented as a bit mask within a u8 data type
+ * bit 0: EAR mode
+ * bit 1: HPH Left mode
+ * bit 2: HPH Right mode
+ * bit 3: Lineout mode
+ * bit 4: Ultrasound mode
+ */
+#define	WCD9XXX_CLSH_STATE_IDLE 0x00
+#define	WCD9XXX_CLSH_STATE_EAR (0x01 << 0)
+#define	WCD9XXX_CLSH_STATE_HPHL (0x01 << 1)
+#define	WCD9XXX_CLSH_STATE_HPHR (0x01 << 2)
+#define	WCD9XXX_CLSH_STATE_LO (0x01 << 3)
+#define NUM_CLSH_STATES ((0x01 << 4) - 1)
+
+/* Derived State: Bits 1 and 2 should be set for Headphone stereo */
+#define WCD9XXX_CLSH_STATE_HPH_ST (WCD9XXX_CLSH_STATE_HPHL | \
+						WCD9XXX_CLSH_STATE_HPHR)
+
+
+struct wcd9xxx_reg_mask_val {
+	u16	reg;
+	u8	mask;
+	u8	val;
+};
+
+/* Class H data that the codec driver will maintain */
+struct wcd9xxx_clsh_cdc_data {
+	u8 state;
+	int buck_mv;
+};
+
+
+enum wcd9xxx_buck_volt {
+	WCD9XXX_CDC_BUCK_UNSUPPORTED = 0,
+	WCD9XXX_CDC_BUCK_MV_1P8 = 1800000,
+	WCD9XXX_CDC_BUCK_MV_2P15 = 2150000,
+};
+
+extern void wcd9xxx_clsh_fsm(struct snd_soc_codec *codec,
+		struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
+		u8 req_state, bool req_type, u8 clsh_event);
+
+extern void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh);
+
+#endif
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-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 3f0c1d7..96709be 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-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
@@ -24,7 +24,8 @@
 
 /* Conventional and unconventional sample rate supported */
 static unsigned int supported_sample_rates[] = {
-	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
+	96000
 };
 
 static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
@@ -52,13 +53,14 @@
 		.playback = {
 			.stream_name = "Multimedia1 Playback",
 			.aif_name = "MM_DL1",
-			.rates = (SNDRV_PCM_RATE_8000_48000|
+			.rates = (SNDRV_PCM_RATE_8000_96000|
 					SNDRV_PCM_RATE_KNOT),
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+						SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min =     8000,
-			.rate_max =	48000,
+			.rate_max =	96000,
 		},
 		.capture = {
 			.stream_name = "Multimedia1 Capture",
@@ -78,13 +80,14 @@
 		.playback = {
 			.stream_name = "Multimedia2 Playback",
 			.aif_name = "MM_DL2",
-			.rates = (SNDRV_PCM_RATE_8000_48000|
+			.rates = (SNDRV_PCM_RATE_8000_96000|
 					SNDRV_PCM_RATE_KNOT),
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+						SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min =     8000,
-			.rate_max =	48000,
+			.rate_max =	96000,
 		},
 		.capture = {
 			.stream_name = "Multimedia2 Capture",
@@ -154,13 +157,14 @@
 		.playback = {
 			.stream_name = "MultiMedia3 Playback",
 			.aif_name = "MM_DL3",
-			.rates = (SNDRV_PCM_RATE_8000_48000 |
+			.rates = (SNDRV_PCM_RATE_8000_96000 |
 					SNDRV_PCM_RATE_KNOT),
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+						SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
 			.channels_max = 6,
 			.rate_min =	8000,
-			.rate_max = 48000,
+			.rate_max = 96000,
 		},
 		.ops = &msm_fe_Multimedia_dai_ops,
 		.name = "MultiMedia3",
@@ -169,13 +173,14 @@
 		.playback = {
 			.stream_name = "MultiMedia4 Playback",
 			.aif_name = "MM_DL4",
-			.rates = (SNDRV_PCM_RATE_8000_48000 |
+			.rates = (SNDRV_PCM_RATE_8000_96000 |
 					SNDRV_PCM_RATE_KNOT),
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+						SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min =	8000,
-			.rate_max = 48000,
+			.rate_max = 96000,
 		},
 		.capture = {
 			.stream_name = "MultiMedia4 Capture",
@@ -195,13 +200,14 @@
 		.playback = {
 			.stream_name = "MultiMedia5 Playback",
 			.aif_name = "MM_DL5",
-			.rates = (SNDRV_PCM_RATE_8000_48000 |
+			.rates = (SNDRV_PCM_RATE_8000_96000 |
 					SNDRV_PCM_RATE_KNOT),
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+						SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min =	8000,
-			.rate_max = 48000,
+			.rate_max = 96000,
 		},
 		.capture = {
 			.stream_name = "MultiMedia5 Capture",
@@ -221,13 +227,14 @@
 		.playback = {
 			.stream_name = "MultiMedia6 Playback",
 			.aif_name = "MM_DL6",
-			.rates = (SNDRV_PCM_RATE_8000_48000 |
+			.rates = (SNDRV_PCM_RATE_8000_96000 |
 					SNDRV_PCM_RATE_KNOT),
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+						SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min =	8000,
-			.rate_max = 48000,
+			.rate_max = 96000,
 		},
 		.ops = &msm_fe_Multimedia_dai_ops,
 		.name = "MultiMedia6",
@@ -236,13 +243,14 @@
 		.playback = {
 			.stream_name = "MultiMedia7 Playback",
 			.aif_name = "MM_DL7",
-			.rates = (SNDRV_PCM_RATE_8000_48000 |
+			.rates = (SNDRV_PCM_RATE_8000_96000 |
 					SNDRV_PCM_RATE_KNOT),
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+						SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min =	8000,
-			.rate_max = 48000,
+			.rate_max = 96000,
 		},
 		.ops = &msm_fe_Multimedia_dai_ops,
 		.name = "MultiMedia7",
@@ -251,13 +259,14 @@
 		.playback = {
 			.stream_name = "MultiMedia8 Playback",
 			.aif_name = "MM_DL8",
-			.rates = (SNDRV_PCM_RATE_8000_48000 |
+			.rates = (SNDRV_PCM_RATE_8000_96000 |
 					SNDRV_PCM_RATE_KNOT),
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+						SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min =	8000,
-			.rate_max = 48000,
+			.rate_max = 96000,
 		},
 		.ops = &msm_fe_Multimedia_dai_ops,
 		.name = "MultiMedia8",
@@ -267,8 +276,9 @@
 		.playback = {
 			.stream_name = "SLIMBUS0 Hostless Playback",
 			.aif_name = "SLIM0_DL_HL",
-			.rates = SNDRV_PCM_RATE_8000_48000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rates = SNDRV_PCM_RATE_8000_96000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+						SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min =     8000,
@@ -277,7 +287,7 @@
 		.capture = {
 			.stream_name = "SLIMBUS0 Hostless Capture",
 			.aif_name = "SLIM0_UL_HL",
-			.rates = SNDRV_PCM_RATE_8000_48000,
+			.rates = SNDRV_PCM_RATE_8000_96000,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
 			.channels_max = 8,
@@ -291,12 +301,13 @@
 		.playback = {
 			.stream_name = "SLIMBUS1 Hostless Playback",
 			.aif_name = "SLIM1_DL_HL",
-			.rates = SNDRV_PCM_RATE_8000_48000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rates = SNDRV_PCM_RATE_8000_96000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+						SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
 			.channels_max = 2,
 			.rate_min =     8000,
-			.rate_max =     48000,
+			.rate_max =     96000,
 		},
 		.capture = {
 			.stream_name = "SLIMBUS1 Hostless Capture",
@@ -316,7 +327,8 @@
 			.stream_name = "SLIMBUS3 Hostless Playback",
 			.aif_name = "SLIM3_DL_HL",
 			.rates = SNDRV_PCM_RATE_8000_48000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+						SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
 			.channels_max = 2,
 			.rate_min =     8000,
@@ -339,8 +351,9 @@
 		.playback = {
 			.stream_name = "SLIMBUS4 Hostless Playback",
 			.aif_name = "SLIM4_DL_HL",
-			.rates = SNDRV_PCM_RATE_8000_48000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rates = SNDRV_PCM_RATE_8000_96000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+						SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
 			.channels_max = 2,
 			.rate_min =     8000,
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..91e5e67 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -26,6 +26,7 @@
 #include <sound/jack.h>
 #include <asm/mach-types.h>
 #include <mach/socinfo.h>
+#include <sound/pcm_params.h>
 #include <qdsp6v2/msm-pcm-routing-v2.h>
 #include "../codecs/wcd9320.h"
 #include <linux/io.h>
@@ -41,6 +42,11 @@
 #define BTSCO_RATE_8KHZ 8000
 #define BTSCO_RATE_16KHZ 16000
 
+static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+
+#define SAMPLING_RATE_48KHZ 48000
+#define SAMPLING_RATE_96KHZ 96000
+
 static int msm8974_auxpcm_rate = 8000;
 #define LO_1_SPK_AMP	0x1
 #define LO_3_SPK_AMP	0x2
@@ -68,6 +74,29 @@
 
 #define NUM_OF_AUXPCM_GPIOS 4
 
+static inline int param_is_mask(int p)
+{
+	return ((p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+			(p <= SNDRV_PCM_HW_PARAM_LAST_MASK));
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
+{
+	return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
+{
+	if (bit >= SNDRV_MASK_MAX)
+		return;
+	if (param_is_mask(n)) {
+		struct snd_mask *m = param_to_mask(p, n);
+		m->bits[0] = 0;
+		m->bits[1] = 0;
+		m->bits[bit >> 5] |= (1 << (bit & 31));
+	}
+}
+
 static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
 static const struct soc_enum msm8974_auxpcm_enum[] = {
 		SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
@@ -150,6 +179,7 @@
 static int msm_btsco_rate = BTSCO_RATE_8KHZ;
 static int msm_btsco_ch = 1;
 static int msm_hdmi_rx_ch = 2;
+static int slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
 
 static struct mutex cdc_mclk_mutex;
 static struct q_clkdiv *codec_clk;
@@ -543,6 +573,8 @@
 static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
 static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five",
 					"Six", "Seven", "Eight"};
+static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE"};
+static char const *slim0_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96"};
 
 static const struct soc_enum msm_enum[] = {
 	SOC_ENUM_SINGLE_EXT(2, spk_function),
@@ -555,6 +587,87 @@
 	SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
 };
 
+static int slim0_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	int sample_rate_val = 0;
+
+	switch (slim0_rx_sample_rate) {
+	case SAMPLING_RATE_96KHZ:
+		sample_rate_val = 1;
+		break;
+
+	case SAMPLING_RATE_48KHZ:
+	default:
+		sample_rate_val = 0;
+		break;
+	}
+
+	ucontrol->value.integer.value[0] = sample_rate_val;
+	pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+				slim0_rx_sample_rate);
+
+	return 0;
+}
+
+static int slim0_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: ucontrol value = %ld\n", __func__,
+			ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 1:
+		slim0_rx_sample_rate = SAMPLING_RATE_96KHZ;
+		break;
+	case 0:
+	default:
+		slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
+	}
+
+	pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+			slim0_rx_sample_rate);
+
+	return 0;
+}
+
+static int slim0_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+
+	switch (slim0_rx_bit_format) {
+	case SNDRV_PCM_FORMAT_S24_LE:
+		ucontrol->value.integer.value[0] = 1;
+		break;
+
+	case SNDRV_PCM_FORMAT_S16_LE:
+	default:
+		ucontrol->value.integer.value[0] = 0;
+		break;
+	}
+
+	pr_debug("%s: slim0_rx_bit_format = %d, ucontrol value = %ld\n",
+			 __func__, slim0_rx_bit_format,
+			ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int slim0_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 1:
+		slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+		break;
+	case 0:
+	default:
+		slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+		break;
+	}
+	return 0;
+}
+
 static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
@@ -861,9 +974,15 @@
 	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
 
 	pr_debug("%s()\n", __func__);
-	rate->min = rate->max = 48000;
+	param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+				   slim0_rx_bit_format);
+	rate->min = rate->max = slim0_rx_sample_rate;
 	channels->min = channels->max = msm_slim_0_rx_ch;
 
+	 pr_debug("%s: format = %d, rate = %d, channels = %d\n",
+			  __func__, params_format(params), params_rate(params),
+			  msm_slim_0_rx_ch);
+
 	return 0;
 }
 
@@ -900,6 +1019,8 @@
 	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
 	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
 	SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(2, rx_bit_format_text),
+	SOC_ENUM_SINGLE_EXT(2, slim0_rx_sample_rate_text),
 };
 
 static const struct snd_kcontrol_new msm_snd_controls[] = {
@@ -913,6 +1034,10 @@
 			msm8974_auxpcm_rate_get, msm8974_auxpcm_rate_put),
 	SOC_ENUM_EXT("HDMI_RX Channels", msm_snd_enum[3],
 			msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
+	SOC_ENUM_EXT("SLIM_0_RX Format", msm_snd_enum[4],
+			slim0_rx_bit_format_get, slim0_rx_bit_format_put),
+	SOC_ENUM_EXT("SLIM_0_RX SampleRate", msm_snd_enum[5],
+			slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
 };
 
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
@@ -1041,18 +1166,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;
@@ -1213,7 +1338,7 @@
 		.name = "MSM8974 Media1",
 		.stream_name = "MultiMedia1",
 		.cpu_dai_name	= "MultiMedia1",
-		.platform_name  = "msm-pcm-dsp",
+		.platform_name  = "msm-pcm-dsp.0",
 		.dynamic = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -1228,7 +1353,7 @@
 		.name = "MSM8974 Media2",
 		.stream_name = "MultiMedia2",
 		.cpu_dai_name   = "MultiMedia2",
-		.platform_name  = "msm-pcm-dsp",
+		.platform_name  = "msm-pcm-dsp.0",
 		.dynamic = 1,
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
@@ -1423,6 +1548,21 @@
 		.codec_name = "snd-soc-dummy",
 		.be_id = MSM_FRONTEND_DAI_VOLTE,
 	},
+	{
+		.name = "MSM8974 LowLatency",
+		.stream_name = "MultiMedia5",
+		.cpu_dai_name   = "MultiMedia5",
+		.platform_name  = "msm-pcm-dsp.1",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+	},
 	/* Backend BT/FM DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 58fdc1b..b71132e 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -66,6 +66,12 @@
 	/* VocProc dev cfg cal*/
 	struct acdb_atomic_cal_block	vocproc_dev_cal;
 
+	/* Custom topology */
+	struct acdb_atomic_cal_block	adm_custom_topology;
+	struct acdb_atomic_cal_block	asm_custom_topology;
+	atomic_t			valid_adm_custom_top;
+	atomic_t			valid_asm_custom_top;
+
 	/* AFE cal */
 	struct acdb_atomic_cal_block	afe_cal[MAX_AUDPROC_TYPES];
 
@@ -134,6 +140,106 @@
 	atomic_set(&acdb_data.asm_topology, topology);
 }
 
+void reset_custom_topology_flags(void)
+{
+	atomic_set(&acdb_data.valid_adm_custom_top, 1);
+	atomic_set(&acdb_data.valid_asm_custom_top, 1);
+}
+
+void get_adm_custom_topology(struct acdb_cal_block *cal_block)
+{
+	pr_debug("%s\n", __func__);
+
+	if (cal_block == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+
+	if (atomic_read(&acdb_data.valid_adm_custom_top) == 0) {
+		cal_block->cal_size = 0;
+		goto done;
+	}
+	atomic_set(&acdb_data.valid_adm_custom_top, 0);
+
+	cal_block->cal_size =
+		atomic_read(&acdb_data.adm_custom_topology.cal_size);
+	cal_block->cal_paddr =
+		atomic_read(&acdb_data.adm_custom_topology.cal_paddr);
+	cal_block->cal_kvaddr =
+		atomic_read(&acdb_data.adm_custom_topology.cal_kvaddr);
+done:
+	return;
+}
+
+void store_adm_custom_topology(struct cal_block *cal_block)
+{
+	pr_debug("%s,\n", __func__);
+
+	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+		pr_err("%s: offset %d is > mem_len %ld\n",
+			__func__, cal_block->cal_offset,
+			(long)atomic64_read(&acdb_data.mem_len));
+		goto done;
+	}
+
+	atomic_set(&acdb_data.adm_custom_topology.cal_size,
+		cal_block->cal_size);
+	atomic_set(&acdb_data.adm_custom_topology.cal_paddr,
+		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+	atomic_set(&acdb_data.adm_custom_topology.cal_kvaddr,
+		cal_block->cal_offset +
+		atomic64_read(&acdb_data.kvaddr));
+done:
+	return;
+}
+
+void get_asm_custom_topology(struct acdb_cal_block *cal_block)
+{
+	pr_debug("%s\n", __func__);
+
+	if (cal_block == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+
+	if (atomic_read(&acdb_data.valid_asm_custom_top) == 0) {
+		cal_block->cal_size = 0;
+		goto done;
+	}
+	atomic_set(&acdb_data.valid_asm_custom_top, 0);
+
+	cal_block->cal_size =
+		atomic_read(&acdb_data.asm_custom_topology.cal_size);
+	cal_block->cal_paddr =
+		atomic_read(&acdb_data.asm_custom_topology.cal_paddr);
+	cal_block->cal_kvaddr =
+		atomic_read(&acdb_data.asm_custom_topology.cal_kvaddr);
+done:
+	return;
+}
+
+void store_asm_custom_topology(struct cal_block *cal_block)
+{
+	pr_debug("%s,\n", __func__);
+
+	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+		pr_err("%s: offset %d is > mem_len %ld\n",
+			__func__, cal_block->cal_offset,
+			(long)atomic64_read(&acdb_data.mem_len));
+		goto done;
+	}
+
+	atomic_set(&acdb_data.asm_custom_topology.cal_size,
+		cal_block->cal_size);
+	atomic_set(&acdb_data.asm_custom_topology.cal_paddr,
+		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+	atomic_set(&acdb_data.asm_custom_topology.cal_kvaddr,
+		cal_block->cal_offset +
+		atomic64_read(&acdb_data.kvaddr));
+done:
+	return;
+}
+
 void get_voice_cal_allocation(struct acdb_cal_block *cal_block)
 {
 	cal_block->cal_size = ACDB_TOTAL_VOICE_ALLOCATION;
@@ -672,6 +778,8 @@
 			__func__);
 	}
 
+	atomic_set(&acdb_data.valid_adm_custom_top, 1);
+	atomic_set(&acdb_data.valid_asm_custom_top, 1);
 	atomic_inc(&usage_count);
 	return result;
 }
@@ -925,6 +1033,12 @@
 	case AUDIO_SET_LSM_CAL:
 		store_lsm_cal((struct cal_block *)data);
 		goto done;
+	case AUDIO_SET_ADM_CUSTOM_TOPOLOGY:
+		store_adm_custom_topology((struct cal_block *)data);
+		goto done;
+	case AUDIO_SET_ASM_CUSTOM_TOPOLOGY:
+		store_asm_custom_topology((struct cal_block *)data);
+		goto done;
 	default:
 		pr_err("ACDB=> ACDB ioctl not found!\n");
 	}
@@ -998,6 +1112,8 @@
 	memset(&acdb_data, 0, sizeof(acdb_data));
 	mutex_init(&acdb_data.acdb_mutex);
 	atomic_set(&usage_count, 0);
+	atomic_set(&acdb_data.valid_adm_custom_top, 1);
+	atomic_set(&acdb_data.valid_asm_custom_top, 1);
 
 	return misc_register(&acdb_misc);
 }
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index 8528e3c..0b6110d 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -46,6 +46,9 @@
 uint32_t get_adm_rx_topology(void);
 uint32_t get_adm_tx_topology(void);
 uint32_t get_asm_topology(void);
+void reset_custom_topology_flags(void);
+void get_adm_custom_topology(struct acdb_cal_block *cal_block);
+void get_asm_custom_topology(struct acdb_cal_block *cal_block);
 void get_voice_cal_allocation(struct acdb_cal_block *cal_block);
 void get_lsm_cal(struct acdb_cal_block *cal_block);
 void get_anc_cal(struct acdb_cal_block *cal_block);
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-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 6df2fb93..33b72e8 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -81,7 +81,7 @@
 				SNDRV_PCM_INFO_MMAP_VALID |
 				SNDRV_PCM_INFO_INTERLEAVED |
 				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
-	.formats =	      SNDRV_PCM_FMTBIT_S16_LE,
+	.formats =	      SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
 	.rates =		SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
 	.rate_min =	     8000,
 	.rate_max =	     48000,
@@ -527,6 +527,7 @@
 		return -ENOMEM;
 	}
 
+	prtd->audio_client->perf_mode = false;
 	pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
 
 	prtd->session_id = prtd->audio_client->session;
@@ -696,6 +697,8 @@
 	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
 	struct audio_buffer *buf;
 	int dir, ret;
+	uint16_t bits_per_sample = 16;
+
 	struct asm_softpause_params softpause = {
 		.enable = SOFT_PAUSE_ENABLE,
 		.period = SOFT_PAUSE_PERIOD,
@@ -713,9 +716,13 @@
 		dir = IN;
 	else
 		dir = OUT;
+
+	if (runtime->format == SNDRV_PCM_FORMAT_S24_LE)
+		bits_per_sample = 24;
+
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		ret = q6asm_open_write(prtd->audio_client,
-				compr->codec);
+		ret = q6asm_open_write_v2(prtd->audio_client,
+				compr->codec, bits_per_sample);
 		if (ret < 0) {
 			pr_err("%s: Session out open failed\n",
 				__func__);
@@ -723,6 +730,7 @@
 		}
 		msm_pcm_routing_reg_phy_stream(
 			soc_prtd->dai_link->be_id,
+			prtd->audio_client->perf_mode,
 			prtd->session_id,
 			substream->stream);
 
@@ -754,6 +762,7 @@
 			pr_debug("msm_pcm_routing_reg_phy_stream\n");
 			msm_pcm_routing_reg_phy_stream(
 					soc_prtd->dai_link->be_id,
+					prtd->audio_client->perf_mode,
 					prtd->session_id, substream->stream);
 			break;
 		default:
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 4efdb24..a6dce77 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -482,6 +482,18 @@
 		return -EINVAL;
 		break;
 	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		dai_data->port_config.i2s.bit_width = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		dai_data->port_config.i2s.bit_width = 24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	dai_data->rate = params_rate(params);
 	dai_data->port_config.i2s.sample_rate = dai_data->rate;
 	dai_data->port_config.i2s.i2s_cfg_minor_version =
@@ -490,8 +502,6 @@
 	dev_dbg(dai->dev, " channel %d sample rate %d entered\n",
 	dai_data->channels, dai_data->rate);
 
-	/* Q6 only supports 16 as now */
-	dai_data->port_config.i2s.bit_width = 16;
 	dai_data->port_config.i2s.channel_mode = 1;
 	return 0;
 }
@@ -548,10 +558,19 @@
 	dai_data->channels = params_channels(params);
 	dai_data->rate = params_rate(params);
 
-	/* Q6 only supports 16 as now */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		dai_data->port_config.slim_sch.bit_width = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		dai_data->port_config.slim_sch.bit_width = 24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	dai_data->port_config.slim_sch.sb_cfg_minor_version =
 				AFE_API_VERSION_SLIMBUS_CONFIG;
-	dai_data->port_config.slim_sch.bit_width = 16;
 	dai_data->port_config.slim_sch.data_format = 0;
 	dai_data->port_config.slim_sch.num_channels = dai_data->channels;
 	dai_data->port_config.slim_sch.sample_rate = dai_data->rate;
@@ -889,7 +908,7 @@
 	.playback = {
 		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
 		SNDRV_PCM_RATE_16000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
 		.channels_min = 1,
 		.channels_max = 2,
 		.rate_min =     8000,
@@ -918,12 +937,12 @@
 static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
 	.playback = {
 		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-		SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
 		.channels_min = 1,
 		.channels_max = 2,
 		.rate_min = 8000,
-		.rate_max = 48000,
+		.rate_max = 96000,
 	},
 	.ops = &msm_dai_q6_ops,
 	.probe = msm_dai_q6_dai_probe,
@@ -1247,7 +1266,7 @@
 		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
 		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
 		SNDRV_PCM_RATE_192000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
 		.channels_min = 1,
 		.channels_max = 8,
 		.rate_min = 8000,
diff --git a/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
index 827aaa3..d0d573c 100644
--- a/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
@@ -76,10 +76,11 @@
 				SNDRV_PCM_INFO_MMAP_VALID |
 				SNDRV_PCM_INFO_INTERLEAVED |
 				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
-	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
-	.rates =                SNDRV_PCM_RATE_8000_48000,
+	.formats =              (SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S24_LE),
+	.rates =                SNDRV_PCM_RATE_8000_96000,
 	.rate_min =             8000,
-	.rate_max =             48000,
+	.rate_max =             96000,
 	.channels_min =         1,
 	.channels_max =         6,
 	.buffer_bytes_max =     PLAYBACK_NUM_PERIODS * PLAYBACK_PERIOD_SIZE,
@@ -92,7 +93,8 @@
 
 /* Conventional and unconventional sample rate supported */
 static unsigned int supported_sample_rates[] = {
-	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
+	96000
 };
 
 static uint32_t in_frame_info[CAPTURE_NUM_PERIODS][2];
@@ -172,8 +174,7 @@
 				break;
 			}
 			if (prtd->mmap_flag) {
-				pr_debug("%s:writing %d bytes"
-					" of buffer to dsp\n",
+				pr_debug("%s:writing %d bytes of buffer to dsp\n",
 					__func__,
 					prtd->pcm_count);
 				q6asm_write_nolock(prtd->audio_client,
@@ -181,8 +182,7 @@
 					0, 0, NO_TIMESTAMP);
 			} else {
 				while (atomic_read(&prtd->out_needed)) {
-					pr_debug("%s:writing %d bytes"
-						 " of buffer to dsp\n",
+					pr_debug("%s:writing %d bytes of buffer to dsp\n",
 						__func__,
 						prtd->pcm_count);
 					q6asm_write_nolock(prtd->audio_client,
@@ -210,6 +210,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct msm_audio *prtd = runtime->private_data;
 	int ret;
+	uint16_t bits_per_sample = 16;
 
 	pr_debug("%s\n", __func__);
 	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
@@ -221,8 +222,19 @@
 	if (prtd->enabled)
 		return 0;
 
-	ret = q6asm_media_format_block_pcm(prtd->audio_client,
-			runtime->rate, runtime->channels);
+	switch (runtime->format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		bits_per_sample = 16;
+		break;
+
+	case SNDRV_PCM_FORMAT_S24_LE:
+		bits_per_sample = 24;
+		break;
+	}
+
+	ret = q6asm_media_format_block_pcm_format_support(
+			prtd->audio_client, runtime->rate,
+			runtime->channels, bits_per_sample);
 	if (ret < 0)
 		pr_info("%s: CMD Format block failed\n", __func__);
 
@@ -336,6 +348,7 @@
 		kfree(prtd);
 		return -ENOMEM;
 	}
+	prtd->audio_client->perf_mode = false;
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		runtime->hw = msm_pcm_hardware_playback;
 		ret = q6asm_open_write(prtd->audio_client,
@@ -363,6 +376,7 @@
 
 	prtd->session_id = prtd->audio_client->session;
 	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+			prtd->audio_client->perf_mode,
 			prtd->session_id, substream->stream);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -412,8 +426,8 @@
 		rc = q6asm_set_volume(multi_ch_pcm_audio.prtd->audio_client,
 								volume);
 		if (rc < 0) {
-			pr_err("%s: Send Volume command failed"
-				" rc=%d\n", __func__, rc);
+			pr_err("%s: Send Volume command failed rc=%d\n",
+							__func__, rc);
 		}
 	}
 	multi_ch_pcm_audio.volume = volume;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index b9fafb1..74a3af9 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -42,7 +42,8 @@
 				SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				SNDRV_PCM_INFO_MMAP_VALID |
 				SNDRV_PCM_INFO_INTERLEAVED),
-	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S24_LE,
 	.rates =                (SNDRV_PCM_RATE_8000 |
 				SNDRV_PCM_RATE_16000 |
 				SNDRV_PCM_RATE_48000),
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index 4d88246..2fca464 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -52,7 +52,8 @@
 				SNDRV_PCM_INFO_MMAP_VALID |
 				SNDRV_PCM_INFO_INTERLEAVED |
 				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
-	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE |
+					SNDRV_PCM_FMTBIT_S24_LE,
 	.rates =                SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
 	.rate_min =             8000,
 	.rate_max =             48000,
@@ -196,6 +197,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct msm_audio *prtd = runtime->private_data;
 	int ret;
+	uint16_t bits_per_sample = 16;
 
 	pr_debug("%s\n", __func__);
 	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
@@ -208,8 +210,19 @@
 	if (prtd->enabled)
 		return 0;
 
-	ret = q6asm_media_format_block_pcm(prtd->audio_client, runtime->rate,
-				runtime->channels);
+	switch (runtime->format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		bits_per_sample = 16;
+		break;
+
+	case SNDRV_PCM_FORMAT_S24_LE:
+		bits_per_sample = 24;
+		break;
+	}
+
+	ret = q6asm_media_format_block_pcm_format_support(
+				prtd->audio_client, runtime->rate,
+				runtime->channels, bits_per_sample);
 	if (ret < 0)
 		pr_debug("%s: CMD Format block failed\n", __func__);
 
@@ -293,6 +306,7 @@
 		kfree(prtd);
 		return -ENOMEM;
 	}
+	prtd->audio_client->perf_mode = false;
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
 		if (ret < 0) {
@@ -315,6 +329,7 @@
 	pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
 	prtd->session_id = prtd->audio_client->session;
 	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+		prtd->audio_client->perf_mode,
 		prtd->session_id, substream->stream);
 
 	ret = snd_pcm_hw_constraint_list(runtime, 0,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 34b38a6..e05e58d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -29,6 +29,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/android_pmem.h>
 #include <linux/of_device.h>
+#include <sound/pcm_params.h>
 
 #include "msm-pcm-q6-v2.h"
 #include "msm-pcm-routing-v2.h"
@@ -48,7 +49,7 @@
 
 #define PLAYBACK_NUM_PERIODS	8
 #define PLAYBACK_MAX_PERIOD_SIZE    12288
-#define PLAYBACK_MIN_PERIOD_SIZE    2048
+#define PLAYBACK_MIN_PERIOD_SIZE    1024
 #define CAPTURE_NUM_PERIODS	16
 #define CAPTURE_MAX_PERIOD_SIZE 4096
 #define CAPTURE_MIN_PERIOD_SIZE 512
@@ -79,10 +80,11 @@
 				SNDRV_PCM_INFO_MMAP_VALID |
 				SNDRV_PCM_INFO_INTERLEAVED |
 				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
-	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
-	.rates =                SNDRV_PCM_RATE_8000_48000,
+	.formats =              (SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S24_LE),
+	.rates =                SNDRV_PCM_RATE_8000_96000,
 	.rate_min =             8000,
-	.rate_max =             48000,
+	.rate_max =             96000,
 	.channels_min =         1,
 	.channels_max =         8,
 	.buffer_bytes_max =     PLAYBACK_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
@@ -95,7 +97,8 @@
 
 /* Conventional and unconventional sample rate supported */
 static unsigned int supported_sample_rates[] = {
-	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
+	96000
 };
 
 static uint32_t in_frame_info[CAPTURE_NUM_PERIODS][2];
@@ -209,6 +212,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct msm_audio *prtd = runtime->private_data;
 	int ret;
+	uint16_t bits_per_sample = 16;
 
 	pr_debug("%s\n", __func__);
 	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
@@ -220,11 +224,19 @@
 	if (prtd->enabled)
 		return 0;
 
-	ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
-							runtime->rate,
-							runtime->channels,
-							!prtd->set_channel_map,
-							prtd->channel_map);
+	switch (runtime->format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		bits_per_sample = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		bits_per_sample = 24;
+		break;
+	}
+
+	ret = q6asm_media_format_block_multi_ch_pcm_v2(
+			prtd->audio_client, runtime->rate,
+			runtime->channels, !prtd->set_channel_map,
+			prtd->channel_map, bits_per_sample);
 	if (ret < 0)
 		pr_info("%s: CMD Format block failed\n", __func__);
 
@@ -309,11 +321,9 @@
 static int msm_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct msm_audio *prtd;
 	int ret = 0;
 
-	pr_debug("%s\n", __func__);
 	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
 	if (prtd == NULL) {
 		pr_err("Failed to allocate memory for msm_audio\n");
@@ -327,24 +337,10 @@
 		kfree(prtd);
 		return -ENOMEM;
 	}
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		runtime->hw = msm_pcm_hardware_playback;
-		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
-		if (ret < 0) {
-			pr_err("%s: pcm out open failed\n", __func__);
-			q6asm_audio_client_free(prtd->audio_client);
-			kfree(prtd);
-			return -ENOMEM;
-		}
 
-		pr_debug("%s: session ID %d\n", __func__,
-			prtd->audio_client->session);
-		prtd->session_id = prtd->audio_client->session;
-		msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
-			prtd->session_id, substream->stream);
-		prtd->cmd_ack = 1;
-
-	}
 	/* Capture path */
 	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 		runtime->hw = msm_pcm_hardware_capture;
@@ -655,11 +651,49 @@
 	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct audio_buffer *buf;
 	int dir, ret;
+	struct msm_plat_data *pdata;
+	uint16_t bits_per_sample = 16;
+
+	pdata = (struct msm_plat_data *)
+				dev_get_drvdata(soc_prtd->platform->dev);
+	if (!pdata) {
+		pr_err("%s: platform data not populated\n", __func__);
+		return -EINVAL;
+	}
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		dir = IN;
-	else {
+	else
 		dir = OUT;
+
+	prtd->audio_client->perf_mode = pdata->perf_mode;
+	pr_debug("%s: perf: %x\n", __func__, pdata->perf_mode);
+	/* Playback Path */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (params_format(params) == SNDRV_PCM_FORMAT_S24_LE)
+			bits_per_sample = 24;
+
+		ret = q6asm_open_write_v2(prtd->audio_client,
+				FORMAT_LINEAR_PCM, bits_per_sample);
+		if (ret < 0) {
+			pr_err("%s: q6asm_open_write_v2 failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+
+		pr_debug("%s: session ID %d\n", __func__,
+			prtd->audio_client->session);
+		prtd->session_id = prtd->audio_client->session;
+		msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+				prtd->audio_client->perf_mode,
+				prtd->session_id, substream->stream);
+		prtd->cmd_ack = 1;
+	}
+
+	/* Capture Path */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+
 		pr_debug("%s Opening %d-ch PCM read stream\n",
 			__func__, params_channels(params));
 		ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
@@ -669,14 +703,15 @@
 			prtd->audio_client = NULL;
 			return -ENOMEM;
 		}
+
+		pr_debug("%s: session ID %d\n",
+				__func__, prtd->audio_client->session);
+		prtd->session_id = prtd->audio_client->session;
+		msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+				prtd->audio_client->perf_mode,
+				prtd->session_id, substream->stream);
 	}
 
-	pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
-	prtd->session_id = prtd->audio_client->session;
-	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
-			prtd->session_id, substream->stream);
-
-
 	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
 			prtd->audio_client,
 			(params_buffer_bytes(params) / params_periods(params)),
@@ -769,16 +804,46 @@
 
 static __devinit int msm_pcm_probe(struct platform_device *pdev)
 {
-	if (pdev->dev.of_node)
-		dev_set_name(&pdev->dev, "%s", "msm-pcm-dsp");
+	int rc;
+	int id;
+	struct msm_plat_data *pdata;
 
-	pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	rc = of_property_read_u32(pdev->dev.of_node,
+				"qcom,msm-pcm-dsp-id", &id);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: qcom,msm-pcm-dsp-id missing in DT node\n",
+					__func__);
+		return rc;
+	}
+
+	pdata = kzalloc(sizeof(struct msm_plat_data), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
+		return -ENOMEM;
+	}
+
+	if (of_property_read_bool(pdev->dev.of_node,
+				"qcom,msm-pcm-low-latency"))
+		pdata->perf_mode = 1;
+	else
+		pdata->perf_mode = 0;
+
+	dev_set_drvdata(&pdev->dev, pdata);
+
+	dev_set_name(&pdev->dev, "%s.%d", "msm-pcm-dsp", id);
+
+	dev_dbg(&pdev->dev, "%s: dev name %s\n",
+				__func__, dev_name(&pdev->dev));
 	return snd_soc_register_platform(&pdev->dev,
 				   &msm_soc_platform);
 }
 
 static int msm_pcm_remove(struct platform_device *pdev)
 {
+	struct msm_plat_data *pdata;
+
+	pdata = dev_get_drvdata(&pdev->dev);
+	kfree(pdata);
 	snd_soc_unregister_platform(&pdev->dev);
 	return 0;
 }
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
index 01ed41f..4b3cfe7 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -95,4 +95,8 @@
 	uint32_t reserved[12];
 };
 
+struct msm_plat_data {
+	int perf_mode;
+};
+
 #endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 8a5abc9..c48132e 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -29,6 +29,8 @@
 #include <sound/q6asm-v2.h>
 #include <sound/q6afe-v2.h>
 #include <sound/tlv.h>
+#include <sound/asound.h>
+#include <sound/pcm_params.h>
 
 #include "msm-pcm-routing-v2.h"
 #include "q6voice.h"
@@ -40,6 +42,8 @@
 	unsigned long port_sessions; /* track Tx BE ports -> Rx BE */
 	unsigned int  sample_rate;
 	unsigned int  channel;
+	unsigned int  format;
+	bool perf_mode;
 };
 
 #define INVALID_SESSION -1
@@ -71,6 +75,9 @@
 static const DECLARE_TLV_DB_LINEAR(compressed_rx_vol_gain, 0,
 			INT_RX_VOL_MAX_STEPS);
 
+static int msm_route_multimedia5_vol_control;
+static const DECLARE_TLV_DB_LINEAR(multimedia5_rx_vol_gain, 0,
+			INT_RX_VOL_MAX_STEPS);
 
 
 /* Equal to Frontend after last of the MULTIMEDIA SESSIONS */
@@ -208,6 +215,8 @@
 	{INVALID_SESSION, INVALID_SESSION},
 	/* MULTIMEDIA4 */
 	{INVALID_SESSION, INVALID_SESSION},
+	/* MULTIMEDIA5 */
+	{INVALID_SESSION, INVALID_SESSION},
 };
 
 static uint8_t is_be_dai_extproc(int be_dai)
@@ -283,11 +292,13 @@
 	mutex_unlock(&routing_lock);
 }
 
-void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id, int stream_type)
+void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode,
+					int dspst_id, int stream_type)
 {
 	int i, session_type, path_type, port_type;
 	struct route_payload payload;
 	u32 channels;
+	uint16_t bits_per_sample = 16;
 
 	if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
 		/* bad ID assigned in machine driver */
@@ -313,6 +324,8 @@
 	if (eq_data[fedai_id].enable)
 		msm_send_eq_values(fedai_id);
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+		if (test_bit(fedai_id, &msm_bedais[i].fe_sessions))
+			msm_bedais[i].perf_mode = perf_mode;
 		if (!is_be_dai_extproc(i) &&
 		   (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
 		   (msm_bedais[i].active) &&
@@ -320,19 +333,27 @@
 
 			channels = msm_bedais[i].channel;
 
+			if (msm_bedais[i].format == SNDRV_PCM_FORMAT_S16_LE)
+				bits_per_sample = 16;
+			else if (msm_bedais[i].format ==
+						SNDRV_PCM_FORMAT_S24_LE)
+				bits_per_sample = 24;
+
 			if ((stream_type == SNDRV_PCM_STREAM_PLAYBACK) &&
-				(channels > 2))
+				(channels > 0))
 				adm_multi_ch_copp_open(msm_bedais[i].port_id,
 				path_type,
 				msm_bedais[i].sample_rate,
 				msm_bedais[i].channel,
-				DEFAULT_COPP_TOPOLOGY);
+				DEFAULT_COPP_TOPOLOGY, msm_bedais[i].perf_mode,
+				bits_per_sample);
 			else
 				adm_open(msm_bedais[i].port_id,
 				path_type,
 				msm_bedais[i].sample_rate,
 				msm_bedais[i].channel,
-				DEFAULT_COPP_TOPOLOGY);
+				DEFAULT_COPP_TOPOLOGY, false,
+				bits_per_sample);
 
 			payload.copp_ids[payload.num_copps++] =
 				msm_bedais[i].port_id;
@@ -401,6 +422,7 @@
 {
 	int session_type, path_type;
 	u32 channels;
+	uint16_t bits_per_sample = 16;
 
 	pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
 
@@ -430,18 +452,23 @@
 			INVALID_SESSION) {
 
 			channels = msm_bedais[reg].channel;
+			if (msm_bedais[reg].format == SNDRV_PCM_FORMAT_S24_LE)
+				bits_per_sample = 24;
 
-			if ((session_type == SESSION_TYPE_RX) && (channels > 2))
+			if ((session_type == SESSION_TYPE_RX) &&
+				(channels > 0)) {
 				adm_multi_ch_copp_open(msm_bedais[reg].port_id,
 				path_type,
 				msm_bedais[reg].sample_rate,
 				channels,
-				DEFAULT_COPP_TOPOLOGY);
-			else
+				DEFAULT_COPP_TOPOLOGY,
+				msm_bedais[reg].perf_mode,
+				bits_per_sample);
+			} else
 				adm_open(msm_bedais[reg].port_id,
 				path_type,
 				msm_bedais[reg].sample_rate, channels,
-				DEFAULT_COPP_TOPOLOGY);
+				DEFAULT_COPP_TOPOLOGY, false, bits_per_sample);
 
 			msm_pcm_routing_build_matrix(val,
 				fe_dai_map[val][session_type], path_type);
@@ -787,6 +814,25 @@
 	return 0;
 }
 
+static int msm_routing_get_multimedia5_vol_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+
+	ucontrol->value.integer.value[0] = msm_route_multimedia5_vol_control;
+	return 0;
+}
+
+static int msm_routing_set_multimedia5_vol_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+
+	if (!multi_ch_pcm_set_volume(ucontrol->value.integer.value[0]))
+		msm_route_multimedia5_vol_control =
+			ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
 static int msm_routing_set_multimedia2_vol_mixer(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -1082,6 +1128,9 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_I2S_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_I2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = {
@@ -1097,6 +1146,9 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_I2S_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_I2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
@@ -1112,6 +1164,9 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SLIMBUS_0_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = {
@@ -1127,6 +1182,9 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_MI2S_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = {
@@ -1187,6 +1245,9 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_HDMI_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_HDMI_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 	/* incall music delivery mixer */
 static const struct snd_kcontrol_new incall_music_delivery_mixer_controls[] = {
@@ -1220,6 +1281,9 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_BT_SCO_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -1235,6 +1299,9 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_FM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_FM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
@@ -1250,6 +1317,9 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AFE_PCM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -1265,6 +1335,9 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
@@ -1318,6 +1391,27 @@
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new mmul5_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_TX", MSM_BACKEND_DAI_AUXPCM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
 	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
 	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -1658,6 +1752,12 @@
 	msm_routing_set_multimedia2_vol_mixer, multimedia2_rx_vol_gain),
 };
 
+static const struct snd_kcontrol_new multimedia5_vol_mixer_controls[] = {
+	SOC_SINGLE_EXT_TLV("HIFI3 RX Volume", SND_SOC_NOPM, 0,
+	INT_RX_VOL_GAIN, 0, msm_routing_get_multimedia5_vol_mixer,
+	msm_routing_set_multimedia5_vol_mixer, multimedia5_rx_vol_gain),
+};
+
 static const struct snd_kcontrol_new compressed_vol_mixer_controls[] = {
 	SOC_SINGLE_EXT_TLV("COMPRESSED RX Volume", SND_SOC_NOPM, 0,
 	INT_RX_VOL_GAIN, 0, msm_routing_get_compressed_vol_mixer,
@@ -1913,9 +2013,11 @@
 	SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
@@ -2048,6 +2150,8 @@
 	mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
 	/* incall */
@@ -2152,24 +2256,28 @@
 	{"PRI_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"PRI_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"PRI_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"PRI_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"PRI_I2S_RX", NULL, "PRI_RX Audio Mixer"},
 
 	{"SEC_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"SEC_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"SEC_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"SEC_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"SEC_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"SEC_I2S_RX", NULL, "SEC_RX Audio Mixer"},
 
 	{"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"SLIMBUS_0_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"SLIMBUS_0_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"SLIMBUS_0_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"SLIMBUS_0_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Audio Mixer"},
 
 	{"HDMI Mixer", "MultiMedia1", "MM_DL1"},
 	{"HDMI Mixer", "MultiMedia2", "MM_DL2"},
 	{"HDMI Mixer", "MultiMedia3", "MM_DL3"},
 	{"HDMI Mixer", "MultiMedia4", "MM_DL4"},
+	{"HDMI Mixer", "MultiMedia5", "MM_DL5"},
 	{"HDMI", NULL, "HDMI Mixer"},
 
 		/* incall */
@@ -2183,10 +2291,12 @@
 	{"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
 	{"MultiMedia1 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
 	{"MultiMedia1 Mixer", "SLIM_4_TX", "SLIMBUS_4_TX"},
+	{"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
 
 	{"QUAT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2214,6 +2324,7 @@
 	{"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
 	{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+	{"MultiMedia5 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"},
 	{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
 
@@ -2221,32 +2332,40 @@
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
 
 	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"INT_FM_RX", NULL, "INTERNAL_FM_RX Audio Mixer"},
 
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"AFE_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 
 	{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
+	{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"MM_UL1", NULL, "MultiMedia1 Mixer"},
 	{"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"MM_UL2", NULL, "MultiMedia2 Mixer"},
+	{"MM_UL5", NULL, "MultiMedia5 Mixer"},
 
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
 
 	{"MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -2452,6 +2571,7 @@
 	mutex_lock(&routing_lock);
 	msm_bedais[be_id].sample_rate = params_rate(params);
 	msm_bedais[be_id].channel = params_channels(params);
+	msm_bedais[be_id].format = params_format(params);
 	mutex_unlock(&routing_lock);
 	return 0;
 }
@@ -2483,6 +2603,7 @@
 	bedai->active = 0;
 	bedai->sample_rate = 0;
 	bedai->channel = 0;
+	bedai->perf_mode = false;
 	mutex_unlock(&routing_lock);
 
 	return 0;
@@ -2495,6 +2616,8 @@
 	int i, path_type, session_type;
 	struct msm_pcm_routing_bdai_data *bedai;
 	u32 channels;
+	bool playback, capture;
+	uint16_t bits_per_sample = 16;
 
 	if (be_id >= MSM_BACKEND_DAI_MAX) {
 		pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -2522,24 +2645,31 @@
 	 * is started.
 	 */
 	bedai->active = 1;
+	playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	capture = substream->stream == SNDRV_PCM_STREAM_CAPTURE;
+
 	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
 		if (fe_dai_map[i][session_type] != INVALID_SESSION) {
 
 			channels = bedai->channel;
-			if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
-				substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-				&& (channels > 2))
+			if (bedai->format == SNDRV_PCM_FORMAT_S24_LE)
+				bits_per_sample = 24;
+
+			if ((playback) && (channels > 0)) {
 				adm_multi_ch_copp_open(bedai->port_id,
-				path_type,
-				bedai->sample_rate,
-				channels,
-				DEFAULT_COPP_TOPOLOGY);
-			else
+					path_type,
+					bedai->sample_rate,
+					channels,
+					DEFAULT_COPP_TOPOLOGY, bedai->perf_mode,
+					bits_per_sample);
+			} else if (capture) {
 				adm_open(bedai->port_id,
 				path_type,
 				bedai->sample_rate,
 				channels,
-				DEFAULT_COPP_TOPOLOGY);
+				DEFAULT_COPP_TOPOLOGY, false,
+				bits_per_sample);
+			}
 
 			msm_pcm_routing_build_matrix(i,
 				fe_dai_map[i][session_type], path_type);
@@ -2610,6 +2740,10 @@
 			ARRAY_SIZE(multimedia2_vol_mixer_controls));
 
 	snd_soc_add_platform_controls(platform,
+				multimedia5_vol_mixer_controls,
+			ARRAY_SIZE(multimedia5_vol_mixer_controls));
+
+	snd_soc_add_platform_controls(platform,
 				compressed_vol_mixer_controls,
 			ARRAY_SIZE(compressed_vol_mixer_controls));
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index cf24f9a..7ecdff3 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -63,6 +63,7 @@
 	MSM_FRONTEND_DAI_MULTIMEDIA2,
 	MSM_FRONTEND_DAI_MULTIMEDIA3,
 	MSM_FRONTEND_DAI_MULTIMEDIA4,
+	MSM_FRONTEND_DAI_MULTIMEDIA5,
 	MSM_FRONTEND_DAI_CS_VOICE,
 	MSM_FRONTEND_DAI_VOIP,
 	MSM_FRONTEND_DAI_AFE_RX,
@@ -73,8 +74,8 @@
 	MSM_FRONTEND_DAI_MAX,
 };
 
-#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA4 + 1)
-#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA4
+#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA5 + 1)
+#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA5
 
 enum {
 	MSM_BACKEND_DAI_PRI_I2S_RX = 0,
@@ -121,7 +122,7 @@
  * dspst_id:  DSP audio stream ID
  * stream_type: playback or capture
  */
-void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id,
+void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode, int dspst_id,
 	int stream_type);
 void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
 		int stream_type);
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;
 }
 
 
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index bc11304..093070c 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -46,8 +46,11 @@
 
 /* 0 - (MAX_AUDPROC_TYPES -1):				audproc handles */
 /* (MAX_AUDPROC_TYPES -1) - (2 * MAX_AUDPROC_TYPES -1):	audvol handles */
-	atomic_t mem_map_cal_handles[(2 * MAX_AUDPROC_TYPES)];
+/* + 1 for custom ADM topology */
+	atomic_t mem_map_cal_handles[(2 * MAX_AUDPROC_TYPES) + 1];
 	atomic_t mem_map_cal_index;
+
+	int set_custom_topology;
 };
 
 static struct adm_ctl			this_adm;
@@ -309,6 +312,8 @@
 				atomic_set(&this_adm.copp_stat[i], 0);
 			}
 			this_adm.apr = NULL;
+			reset_custom_topology_flags();
+			this_adm.set_custom_topology = 1;
 		}
 		pr_debug("Resetting calibration blocks");
 		for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
@@ -350,6 +355,7 @@
 			case ADM_CMD_DEVICE_CLOSE_V5:
 			case ADM_CMD_SHARED_MEM_UNMAP_REGIONS:
 			case ADM_CMD_MATRIX_MAP_ROUTINGS_V5:
+			case ADM_CMD_ADD_TOPOLOGIES:
 				pr_debug("%s: Basic callback received, wake up.\n",
 					__func__);
 				atomic_set(&this_adm.copp_stat[index], 1);
@@ -435,6 +441,87 @@
 	return 0;
 }
 
+void send_adm_custom_topology(int port_id)
+{
+	struct acdb_cal_block		cal_block;
+	struct cmd_set_topologies	adm_top;
+	int				index;
+	int				result;
+	int				size = 4096;
+
+	get_adm_custom_topology(&cal_block);
+	if (cal_block.cal_size == 0) {
+		pr_debug("%s: no cal to send addr= 0x%x\n",
+				__func__, cal_block.cal_paddr);
+		goto done;
+	}
+
+	index = afe_get_port_index(port_id);
+	if (index < 0 || index >= AFE_MAX_PORTS) {
+		pr_err("%s: invalid port idx %d portid %#x\n",
+				__func__, index, port_id);
+		goto done;
+	}
+
+	if (this_adm.set_custom_topology) {
+		/* specific index 4 for adm topology memory */
+		atomic_set(&this_adm.mem_map_cal_index, 4);
+
+		/* Only call this once */
+		this_adm.set_custom_topology = 0;
+
+		result = adm_memory_map_regions(port_id, &cal_block.cal_paddr,
+					0, &size, 1);
+		if (result < 0) {
+			pr_err("%s: mmap did not work! addr = 0x%x, size = %d\n",
+				__func__, cal_block.cal_paddr,
+			       cal_block.cal_size);
+			goto done;
+		}
+	}
+
+
+	adm_top.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(20), APR_PKT_VER);
+	adm_top.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		sizeof(adm_top));
+	adm_top.hdr.src_svc = APR_SVC_ADM;
+	adm_top.hdr.src_domain = APR_DOMAIN_APPS;
+	adm_top.hdr.src_port = port_id;
+	adm_top.hdr.dest_svc = APR_SVC_ADM;
+	adm_top.hdr.dest_domain = APR_DOMAIN_ADSP;
+	adm_top.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+	adm_top.hdr.token = port_id;
+	adm_top.hdr.opcode = ADM_CMD_ADD_TOPOLOGIES;
+	adm_top.payload_addr_lsw = cal_block.cal_paddr;
+	adm_top.payload_addr_msw = 0;
+	adm_top.mem_map_handle = atomic_read(&this_adm.mem_map_cal_handles[4]);
+	adm_top.payload_size = cal_block.cal_size;
+
+	atomic_set(&this_adm.copp_stat[index], 0);
+	pr_debug("%s: Sending ADM_CMD_ADD_TOPOLOGIES payload = 0x%x, size = %d\n",
+		__func__, adm_top.payload_addr_lsw,
+		adm_top.payload_size);
+	result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_top);
+	if (result < 0) {
+		pr_err("%s: Set topologies failed port = 0x%x payload = 0x%x\n",
+			__func__, port_id, cal_block.cal_paddr);
+		goto done;
+	}
+	/* Wait for the callback */
+	result = wait_event_timeout(this_adm.wait[index],
+		atomic_read(&this_adm.copp_stat[index]),
+		msecs_to_jiffies(TIMEOUT_MS));
+	if (!result) {
+		pr_err("%s: Set topologies timed out port = 0x%x, payload = 0x%x\n",
+			__func__, port_id, cal_block.cal_paddr);
+		goto done;
+	}
+
+done:
+	return;
+}
+
 static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
 {
 	s32				result = 0;
@@ -653,7 +740,8 @@
 	return ret;
 }
 
-int adm_open(int port_id, int path, int rate, int channel_mode, int topology)
+int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
+			bool perf_mode, uint16_t bits_per_sample)
 {
 	struct adm_cmd_device_open_v5	open;
 	int ret = 0;
@@ -684,6 +772,7 @@
 		rtac_set_adm_handle(this_adm.apr);
 	}
 
+	send_adm_custom_topology(port_id);
 
 	/* Create a COPP if port id are not enabled */
 	if (atomic_read(&this_adm.copp_cnt[index]) == 0) {
@@ -699,10 +788,16 @@
 		open.hdr.dest_port = tmp_port;
 		open.hdr.token = port_id;
 		open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
+		open.flags = 0x00;
+		if (perf_mode) {
+			open.flags |= ADM_LOW_LATENCY_DEVICE_SESSION <<
+				ADM_BIT_SHIFT_DEVICE_PERF_MODE_FLAG;
+		} else {
+			open.flags |= ADM_LEGACY_DEVICE_SESSION <<
+				ADM_BIT_SHIFT_DEVICE_PERF_MODE_FLAG;
+		}
 
 		open.mode_of_operation = path;
-		/* Reserved for future use, need to set this to 0 */
-		open.flags = 0x00;
 		open.endpoint_id_1 = tmp_port;
 		open.endpoint_id_2 = 0xFFFF;
 
@@ -722,7 +817,7 @@
 			open.topology_id = topology;
 
 		open.dev_num_channel = channel_mode & 0x00FF;
-		open.bit_width = 16;
+		open.bit_width = bits_per_sample;
 		open.sample_rate  = rate;
 		memset(open.dev_channel_mapping, 0, 8);
 
@@ -791,8 +886,8 @@
 			atomic_read(&this_adm.copp_stat[index]),
 			msecs_to_jiffies(TIMEOUT_MS));
 		if (!ret) {
-			pr_err("%s ADM open failed for port %#x"
-			"for [%d]\n", __func__, tmp_port, port_id);
+			pr_err("%s ADM open failed for port %#x for [%d]\n",
+						__func__, tmp_port, port_id);
 			ret = -EINVAL;
 			goto fail_cmd;
 		}
@@ -805,13 +900,13 @@
 	return ret;
 }
 
-
 int adm_multi_ch_copp_open(int port_id, int path, int rate, int channel_mode,
-				int topology)
+			int topology, bool perf_mode, uint16_t bits_per_sample)
 {
 	int ret = 0;
 
-	ret = adm_open(port_id, path, rate, channel_mode, topology);
+	ret = adm_open(port_id, path, rate, channel_mode,
+				   topology, perf_mode, bits_per_sample);
 
 	return ret;
 }
@@ -1154,6 +1249,7 @@
 {
 	int i = 0;
 	this_adm.apr = NULL;
+	this_adm.set_custom_topology = 1;
 
 	for (i = 0; i < AFE_MAX_PORTS; i++) {
 		atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 3d8d5eb..87990a9 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -106,6 +106,9 @@
 static int out_cold_index;
 static char *out_buffer;
 static char *in_buffer;
+static int set_custom_topology;
+static int topology_map_handle;
+
 static int audio_output_latency_dbgfs_open(struct inode *inode,
 							struct file *file)
 {
@@ -338,6 +341,91 @@
 	session[ac->session] = 0;
 	mutex_unlock(&session_lock);
 	ac->session = 0;
+	ac->perf_mode = 0;
+	return;
+}
+
+void send_asm_custom_topology(struct audio_client *ac)
+{
+	struct acdb_cal_block		cal_block;
+	struct cmd_set_topologies	asm_top;
+	struct audio_buffer		*buf;
+	struct asm_buffer_node		*buf_node = NULL;
+	struct list_head		*ptr, *next;
+	int				result;
+	int				size = 4096;
+
+	get_asm_custom_topology(&cal_block);
+	if (cal_block.cal_size == 0) {
+		pr_debug("%s: no cal to send addr= 0x%x\n",
+				__func__, cal_block.cal_paddr);
+		goto done;
+	}
+
+	if (set_custom_topology) {
+		/* Only call this once */
+		set_custom_topology = 0;
+
+		/* Use first asm buf to map memory */
+		buf = kzalloc(sizeof(struct audio_buffer), GFP_KERNEL);
+		if (!buf) {
+			pr_debug("%s: could not allocate temp memory\n",
+				__func__);
+			goto done;
+		}
+		buf[0].phys = cal_block.cal_paddr;
+		ac->port[0].buf = buf;
+
+		result = q6asm_memory_map_regions(ac, 0, size, 1, 1);
+		if (result < 0) {
+			pr_err("%s: mmap did not work! addr = 0x%x, size = %d\n",
+				__func__, cal_block.cal_paddr,
+				cal_block.cal_size);
+			goto done;
+		}
+
+		list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
+			buf_node = list_entry(ptr, struct asm_buffer_node,
+						list);
+			if (buf_node->buf_addr_lsw == cal_block.cal_paddr) {
+				topology_map_handle =  buf_node->mmap_hdl;
+				break;
+			}
+		}
+
+		kfree(buf);
+	}
+
+	q6asm_add_hdr(ac, &asm_top.hdr, APR_PKT_SIZE(APR_HDR_SIZE,
+						sizeof(asm_top)), TRUE);
+
+	asm_top.hdr.opcode = ASM_CMD_ADD_TOPOLOGIES;
+	asm_top.payload_addr_lsw = cal_block.cal_paddr;
+	asm_top.payload_addr_msw = 0;
+	asm_top.mem_map_handle = topology_map_handle;
+	asm_top.payload_size = cal_block.cal_size;
+
+	 pr_debug("%s: Sending ASM_CMD_ADD_TOPOLOGIES payload = 0x%x, size = %d, map handle = 0x%x\n",
+		__func__, asm_top.payload_addr_lsw,
+		asm_top.payload_size, asm_top.mem_map_handle);
+
+	result = apr_send_pkt(ac->apr, (uint32_t *) &asm_top);
+	if (result < 0) {
+		pr_err("%s: Set topologies failed payload = 0x%x\n",
+			__func__, cal_block.cal_paddr);
+		goto done;
+	}
+
+	result = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (result < 0) {
+		pr_err("%s: Set topologies failed payload = 0x%x\n",
+			__func__, cal_block.cal_paddr);
+		goto done;
+	}
+
+
+done:
 	return;
 }
 
@@ -535,6 +623,7 @@
 	ac->cb = cb;
 	ac->priv = priv;
 	ac->io_mode = SYNC_IO_MODE;
+	ac->perf_mode = false;
 	ac->apr = apr_register("ADSP", "ASM", \
 				(apr_fn)q6asm_callback,\
 				((ac->session) << 8 | 0x0001),\
@@ -552,6 +641,8 @@
 		goto fail;
 
 	init_waitqueue_head(&ac->cmd_wait);
+	init_waitqueue_head(&ac->time_wait);
+	atomic_set(&ac->time_flag, 1);
 	INIT_LIST_HEAD(&ac->port[0].mem_map_handle);
 	INIT_LIST_HEAD(&ac->port[1].mem_map_handle);
 	pr_debug("%s: mem_map_handle list init'ed\n", __func__);
@@ -563,6 +654,8 @@
 	atomic_set(&ac->cmd_state, 0);
 	atomic_set(&ac->nowait_cmd_cnt, 0);
 
+	send_asm_custom_topology(ac);
+
 	pr_debug("%s: session[%d]\n", __func__, ac->session);
 
 	return ac;
@@ -822,6 +915,8 @@
 		apr_reset(this_mmap.apr);
 		atomic_set(&this_mmap.ref_cnt, 0);
 		this_mmap.apr = NULL;
+		reset_custom_topology_flags();
+		set_custom_topology = 1;
 		return 0;
 	}
 	sid = (data->token >> 8) & 0x0F;
@@ -956,6 +1051,8 @@
 					(uint32_t *)data->payload, ac->priv);
 		apr_reset(ac->apr);
 		ac->apr = NULL;
+		reset_custom_topology_flags();
+		set_custom_topology = 1;
 		return 0;
 	}
 
@@ -992,11 +1089,12 @@
 					__func__, token, ac->session);
 			return -EINVAL;
 		}
-		case ASM_STREAM_CMD_OPEN_READ_V2:
-		case ASM_STREAM_CMD_OPEN_WRITE_V2:
+		case ASM_STREAM_CMD_OPEN_READ_V3:
+		case ASM_STREAM_CMD_OPEN_WRITE_V3:
 		case ASM_STREAM_CMD_OPEN_READWRITE_V2:
 		case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+		case ASM_CMD_ADD_TOPOLOGIES:
 		pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
 				__func__, payload[0], payload[1]);
 			if (atomic_read(&ac->cmd_state) && wakeup_flag) {
@@ -1128,10 +1226,8 @@
 				 payload[0], payload[1], payload[2]);
 		ac->time_stamp = (uint64_t)(((uint64_t)payload[2] << 32) |
 				payload[1]);
-		if (atomic_read(&ac->cmd_state)) {
-			atomic_set(&ac->cmd_state, 0);
-			wake_up(&ac->cmd_wait);
-		}
+		if (atomic_cmpxchg(&ac->time_flag, 1, 0))
+			wake_up(&ac->time_wait);
 		break;
 	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
 	case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
@@ -1339,7 +1435,7 @@
 		uint32_t format)
 {
 	int rc = 0x00;
-	struct asm_stream_cmd_open_read_v2 open;
+	struct asm_stream_cmd_open_read_v3 open;
 
 	uint16_t bits_per_sample = 16;
 
@@ -1353,7 +1449,7 @@
 	pr_debug("%s:session[%d]", __func__, ac->session);
 
 	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
-	open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V2;
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
 	/* Stream prio : High, provide meta info with encoded frames */
 	open.src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
 
@@ -1361,30 +1457,39 @@
 	if (open.preprocopo_id == 0)
 		open.preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
 	open.bits_per_sample = bits_per_sample;
+	open.mode_flags = 0x0;
+
+	if (ac->perf_mode) {
+		open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION <<
+				ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
+	} else {
+		open.mode_flags |= ASM_LEGACY_STREAM_SESSION <<
+				ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
+	}
 
 	switch (format) {
 	case FORMAT_LINEAR_PCM:
-		open.mode_flags = 0x00;
+		open.mode_flags |= 0x00;
 		open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
 		break;
 	case FORMAT_MPEG4_AAC:
-		open.mode_flags = BUFFER_META_ENABLE;
+		open.mode_flags |= BUFFER_META_ENABLE;
 		open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
 		break;
 	case FORMAT_V13K:
-		open.mode_flags = BUFFER_META_ENABLE;
+		open.mode_flags |= BUFFER_META_ENABLE;
 		open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
 		break;
 	case FORMAT_EVRC:
-		open.mode_flags = BUFFER_META_ENABLE;
+		open.mode_flags |= BUFFER_META_ENABLE;
 		open.enc_cfg_id = ASM_MEDIA_FMT_EVRC_FS;
 		break;
 	case FORMAT_AMRNB:
-		open.mode_flags = BUFFER_META_ENABLE ;
+		open.mode_flags |= BUFFER_META_ENABLE ;
 		open.enc_cfg_id = ASM_MEDIA_FMT_AMRNB_FS;
 		break;
 	case FORMAT_AMRWB:
-		open.mode_flags = BUFFER_META_ENABLE ;
+		open.mode_flags |= BUFFER_META_ENABLE ;
 		open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS;
 		break;
 	default:
@@ -1408,10 +1513,12 @@
 fail_cmd:
 	return -EINVAL;
 }
-int q6asm_open_write(struct audio_client *ac, uint32_t format)
+
+static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
+		uint16_t bits_per_sample)
 {
 	int rc = 0x00;
-	struct asm_stream_cmd_open_write_v2 open;
+	struct asm_stream_cmd_open_write_v3 open;
 
 	if ((ac == NULL) || (ac->apr == NULL)) {
 		pr_err("%s: APR handle NULL\n", __func__);
@@ -1422,11 +1529,18 @@
 
 	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
 
-	open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V2;
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
 	open.mode_flags = 0x00;
+	if (ac->perf_mode)
+		open.mode_flags |= (ASM_LOW_LATENCY_STREAM_SESSION <<
+				ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_WRITE);
+	else
+		open.mode_flags |= (ASM_LEGACY_STREAM_SESSION <<
+				ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_WRITE);
+
 	/* source endpoint : matrix */
 	open.sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
-	open.bits_per_sample = 16;
+	open.bits_per_sample = bits_per_sample;
 
 	open.postprocopo_id = get_asm_topology();
 	if (open.postprocopo_id == 0)
@@ -1473,6 +1587,17 @@
 	return -EINVAL;
 }
 
+int q6asm_open_write(struct audio_client *ac, uint32_t format)
+{
+	return __q6asm_open_write(ac, format, 16);
+}
+
+int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
+		uint16_t bits_per_sample)
+{
+	return __q6asm_open_write(ac, format, bits_per_sample);
+}
+
 int q6asm_open_read_write(struct audio_client *ac,
 			uint32_t rd_format,
 			uint32_t wr_format)
@@ -2130,8 +2255,9 @@
 	return q6asm_media_format_block_multi_aac(ac, cfg);
 }
 
-int q6asm_media_format_block_pcm(struct audio_client *ac,
-				uint32_t rate, uint32_t channels)
+static int __q6asm_media_format_block_pcm(struct audio_client *ac,
+				uint32_t rate, uint32_t channels,
+				uint16_t bits_per_sample)
 {
 	struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
 	u8 *channel_mapping;
@@ -2146,7 +2272,7 @@
 	fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
 					sizeof(fmt.fmt_blk);
 	fmt.num_channels = channels;
-	fmt.bits_per_sample = 16;
+	fmt.bits_per_sample = bits_per_sample;
 	fmt.sample_rate = rate;
 	fmt.is_signed = 1;
 
@@ -2173,9 +2299,25 @@
 	return -EINVAL;
 }
 
-int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+int q6asm_media_format_block_pcm(struct audio_client *ac,
+				uint32_t rate, uint32_t channels)
+{
+	return __q6asm_media_format_block_pcm(ac, rate,
+				channels, 16);
+}
+
+int q6asm_media_format_block_pcm_format_support(struct audio_client *ac,
 				uint32_t rate, uint32_t channels,
-				bool use_default_chmap, char *channel_map)
+				uint16_t bits_per_sample)
+{
+	return __q6asm_media_format_block_pcm(ac, rate,
+				channels, bits_per_sample);
+}
+
+static int __q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+				uint32_t rate, uint32_t channels,
+				bool use_default_chmap, char *channel_map,
+				uint16_t bits_per_sample)
 {
 	struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
 	u8 *channel_mapping;
@@ -2223,6 +2365,26 @@
 fail_cmd:
 	return -EINVAL;
 }
+
+int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+		uint32_t rate, uint32_t channels,
+		bool use_default_chmap, char *channel_map)
+{
+	return __q6asm_media_format_block_multi_ch_pcm(ac, rate,
+			channels, use_default_chmap, channel_map, 16);
+}
+
+int q6asm_media_format_block_multi_ch_pcm_v2(
+		struct audio_client *ac,
+		uint32_t rate, uint32_t channels,
+		bool use_default_chmap, char *channel_map,
+		uint16_t bits_per_sample)
+{
+	return __q6asm_media_format_block_multi_ch_pcm(ac, rate,
+			channels, use_default_chmap, channel_map,
+			bits_per_sample);
+}
+
 int q6asm_media_format_block_multi_aac(struct audio_client *ac,
 				struct asm_aac_cfg *cfg)
 {
@@ -3342,7 +3504,7 @@
 	}
 	q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
 	hdr.opcode = ASM_SESSION_CMD_GET_SESSIONTIME_V3;
-	atomic_set(&ac->cmd_state, 1);
+	atomic_set(&ac->time_flag, 1);
 
 	pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
 						ac->session,
@@ -3352,8 +3514,8 @@
 		pr_err("Commmand 0x%x failed\n", hdr.opcode);
 		goto fail_cmd;
 	}
-	rc = wait_event_timeout(ac->cmd_wait,
-			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	rc = wait_event_timeout(ac->time_wait,
+			(atomic_read(&ac->time_flag) == 0), 5*HZ);
 	if (!rc) {
 		pr_err("%s: timeout in getting session time from DSP\n",
 			__func__);
@@ -3564,6 +3726,7 @@
 {
 	pr_debug("%s\n", __func__);
 	memset(session, 0, sizeof(session));
+	set_custom_topology = 1;
 
 	config_debug_fs_init();