Merge "msm: Kconfig: Update SUBSYSTEM_RESTART config" into msm-3.4
diff --git a/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
new file mode 100644
index 0000000..d82284d
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
@@ -0,0 +1,14 @@
+Qualcomm BAM Data Multiplexer Driver
+
+Required properties:
+- compatible : should be "qcom,bam_dmux"
+- reg : the location and size of the BAM hardware
+- interrupts : the BAM hardware to apps processor interrupt line
+
+Example:
+
+	qcom,bam_dmux@fc834000 {
+		compatible = "qcom,bam_dmux";
+		reg = <0xfc834000 0x7000>;
+		interrupts = <0 29 1>;
+	};
diff --git a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
index c674a13..5f7651a 100644
--- a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
+++ b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
@@ -5,8 +5,12 @@
 
 Required properties:
   - compatible : should be "qcom,msm-sdcc"
-  - reg : should contain SDCC, BAM register map.
+  - reg : should contain SDCC, SDCC-DML and BAM register map.
+  - reg-names : indicates various resources passed to driver (via reg proptery) by name.
+  "reg-names" examples are "core_mem", "dml_mem" and "bam_mem"
   - interrupts : should contain SDCC core interrupt.
+  - interrupt-names : indicates interrupts passed to driver (via interrupts property) by name.
+  "interrupt-names" examples are "core_irq", "bam_irq" and "status_irq"
   - qcom,sdcc-clk-rates : specifies supported SDCC clock frequencies, Units - Hz.
   - qcom,sdcc-sup-voltages: specifies supported voltage ranges for card. Should always be
 			specified in pairs (min, max), Units - mV.
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 62258ca..43e87a8 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -95,6 +95,10 @@
 - qcom,descriptor-fifo-offset: descriptor fifo offset address
 - qcom,descriptor-fifo-size: descriptor fifo size
 
+Optional properties :
+- qcom,ignore-core-reset-ack: If present then BAM ignores ACK from USB core
+	    while performing PIPE RESET
+
 Example USB BAM controller device node:
 
 	qcom,usbbam@f9304000 {
@@ -109,6 +113,7 @@
 		qcom,usb-total-bam-num = <2>;
 		qcom,usb-bam-num-pipes = <16>;
 		qcom,usb-base-address = <0xf9200000>;
+		qcom,ignore-core-reset-ack;
 
 		qcom,pipe1 {
 			label = "usb-to-peri-qdss-dwc3";
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index a2b7dfc..bff3732 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -3,6 +3,8 @@
 Required properties :
 - compatible : should be "qcom,dwc-usb3-msm"
 - reg : offset and length of the register set in the memory map
+	offset and length of the TCSR register for routing USB
+	signals to either picoPHY0 or picoPHY1.
 - interrupts: IRQ lines used by this controller
 - interrupt-names : Required interrupt resource entries are:
 	"irq" : Interrupt for DWC3 core
@@ -18,7 +20,8 @@
 Example MSM USB3.0 controller device node :
 	usb@f9200000 {
 		compatible = "qcom,dwc-usb3-msm";
-		reg = <0xF9200000 0xFA000>;
+		reg = <0xF9200000 0xFA000>,
+		      <0xFD4AB000 0x4>;
 		interrupts = <0 131 0 0 179 0>;
 		interrupt-names = "irq", "otg_irq";
 		SSUSB_VDDCX-supply = <&pm8841_s2>;
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
new file mode 100644
index 0000000..1f7e488
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -0,0 +1,119 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_dsi {
+
+	qcom,mdss_dsi_toshiba_720p_video {
+		compatible = "qcom,mdss-dsi-panel";
+		label = "toshiba 720p video mode dsi panel";
+		status = "disable";
+		qcom,enable-gpio = <&msmgpio 58 0>;
+		qcom,rst-gpio = <&pm8941_gpios 19 0>;
+		qcom,mdss-pan-res = <720 1280>;
+		qcom,mdss-pan-bpp = <24>;
+		qcom,mdss-pan-porch-values = <32 12 144 3 4 9>;
+		qcom,mdss-pan-underflow-clr = <0xff>;
+		qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+		qcom,mdss-pan-bl-levels = <1 255>;
+		qcom,mdss-pan-dsi-mode = <0>;
+		qcom,mdss-pan-dsi-h-pulse-mode = <0>;
+		qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+		qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+		qcom,mdss-pan-dsi-traffic-mode = <1>;
+		qcom,mdss-pan-dsi-dst-format = <3>;
+		qcom,mdss-pan-dsi-vc = <0>;
+		qcom,mdss-pan-dsi-rgb-swap = <0>;
+		qcom,mdss-pan-dsi-data-lanes = <1 1 1 1>;
+		qcom,mdss-pan-dsi-t-clk = <0x1b 0x04>;
+		qcom,mdss-pan-dsi-stream = <0>;
+		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 */
+						    20 00 01 00];
+		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-bistCtrl = [00 00 01 ff           /* BIST Ctrl settings */
+					   00 00];
+		qcom,panel-phy-laneConfig = [05 c2 00 00 00 00 00 01 75 /* lane0 config */
+					     05 c2 00 00 00 00 00 01 75 /* lane1 config */
+					     05 c2 00 00 00 00 00 01 75 /* lane2 config */
+					     05 c2 00 00 00 00 00 01 75 /* lane3 config */
+					     00 c2 00 00 00 00 00 01 97]; /* Clk ln config */
+
+		qcom,panel-on-cmds = [23 01 00 00 0a 02 b0 00
+					23 01 00 00 0a 02 b2 00
+					23 01 00 00 0a 02 b3 0c
+					23 01 00 00 0a 02 b4 02
+					29 01 00 00 00 06
+						c0 40 02 7f c8 08
+					29 01 00 00 00 10
+						c1 00 a8 00 00 00
+						00 00 9d 08 27 00
+						00 00 00 00
+					29 01 00 00 00 06
+						c2 00 00 09 00 00
+					23 01 00 00 0a 02 c3 04
+					29 01 00 00 00 04
+						c4 4d 83 00
+					29 01 00 00 00 0b
+						c6 12 00 08 71 00
+						00 00 80 00 04
+					23 01 00 00 0a 02 c7 22
+					29 01 00 00 00 05
+						c8 4c 0c 0c 0c
+					29 01 00 00 00 0e
+						c9 00 40 00 16 32
+						2e 3a 43 3e 3c 45
+						79 3f
+					29 01 00 00 00 0e
+						ca 00 46 1a 23 21
+						1c 25 31 2d 49 5f
+						7f 3f
+					29 01 00 00 00 0e
+						cb 00 4c 20 3a 42
+						40 47 4b 42 3e 46
+						7e 3f
+					29 01 00 00 00 0e
+						cc 00 41 19 21 1d
+						14 18 1f 1d 25 3f
+						73 3f
+					29 01 00 00 00 0e
+						cd 23 79 5a 5f 57
+						4c 51 51 45 3f 4b
+						7f 3f
+					29 01 00 00 00 0e
+						ce 00 40 14 20 1a
+						0e 0e 13 08 00 05
+						46 1c
+					29 01 00 00 00 04
+						d0 6a 64 01
+					29 01 00 00 00 03 d1 77 d4
+					23 01 00 00 0a 02 d3 33
+					29 01 00 00 00 03 d5 0f 0f
+					29 01 00 00 00 07
+						d8 34 64 23 25 62
+						32
+					29 01 00 00 00 0c
+						de 10 7b 11 0a 00
+						00 00 00 00 00 00
+					29 01 00 00 00 09
+						fd 04 55 53 00 70
+						ff 10 73
+					23 01 00 00 0a 02 e2 00
+					05 01 00 00 78 02 11 00
+					05 01 00 00 32 02 29 00];
+		qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+					05 01 00 00 78 02 10 00];
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 0375e93..cf4f098 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -19,6 +19,7 @@
 		reg = <0xfd8C0000 0x10000>;
 		reg-names = "server";
 	};
+
 	qcom,csiphy@fda0ac00 {
 		cell-index = <0>;
 		compatible = "qcom,csiphy";
@@ -27,6 +28,7 @@
 		interrupts = <0 78 0>;
 		interrupt-names = "csiphy";
 	};
+
 	qcom,csiphy@fda0b000 {
 		cell-index = <1>;
 		compatible = "qcom,csiphy";
@@ -35,6 +37,7 @@
 		interrupts = <0 79 0>;
 		interrupt-names = "csiphy";
 	};
+
 	qcom,csiphy@fda0b400 {
 		cell-index = <2>;
 		compatible = "qcom,csiphy";
@@ -43,6 +46,7 @@
 		interrupts = <0 80 0>;
 		interrupt-names = "csiphy";
 	};
+
 	qcom,csid@fda08000  {
 		cell-index = <0>;
 		compatible = "qcom,csid";
@@ -50,7 +54,9 @@
 		reg-names = "csid";
 		interrupts = <0 51 0>;
 		interrupt-names = "csid";
+                mipi_csi_vdd-supply = <&pm8941_l12>;
 	};
+
 	qcom,csid@fda08400 {
 		cell-index = <1>;
 		compatible = "qcom,csid";
@@ -58,7 +64,9 @@
 		reg-names = "csid";
 		interrupts = <0 52 0>;
 		interrupt-names = "csid";
+                mipi_csi_vdd-supply = <&pm8941_l12>;
 	};
+
 	qcom,csid@fda08800 {
 		cell-index = <2>;
 		compatible = "qcom,csid";
@@ -66,7 +74,9 @@
 		reg-names = "csid";
 		interrupts = <0 53 0>;
 		interrupt-names = "csid";
+                mipi_csi_vdd-supply = <&pm8941_l12>;
 	};
+
 	qcom,csid@fda08C00 {
 		cell-index = <3>;
 		compatible = "qcom,csid";
@@ -74,7 +84,9 @@
 		reg-names = "csid";
 		interrupts = <0 54 0>;
 		interrupt-names = "csid";
+                mipi_csi_vdd-supply = <&pm8941_l12>;
 	};
+
 	qcom,ispif@fda0A000 {
 		cell-index = <0>;
 		compatible = "qcom,ispif";
@@ -83,32 +95,29 @@
 		interrupts = <0 55 0>;
 		interrupt-names = "ispif";
 	};
-	qcom,cci@fda0C000 {
-		cell-index = <0>;
-		compatible = "qcom,cci";
-		reg = <0xfda0C000 0x1000>;
-		reg-names = "cci";
-		interrupts = <0 50 0>;
-		interrupt-names = "cci";
-	};
+
 	qcom,vfe@fda10000 {
 		cell-index = <0>;
 		compatible = "qcom,vfe40";
-		reg = <0xfda10000 0x1000>;
-		reg-names = "vfe";
+		reg = <0xfda10000 0x1000>,
+                      <0xfda40000 0x200>;
+		reg-names = "vfe", "vfe_vbif";
 		interrupts = <0 57 0>;
 		interrupt-names = "vfe";
 		vdd-supply = <&gdsc_vfe>;
 	};
+
 	qcom,vfe@fda14000 {
 		cell-index = <1>;
 		compatible = "qcom,vfe40";
-		reg = <0xfda14000 0x1000>;
-		reg-names = "vfe";
+		reg = <0xfda14000 0x1000>,
+                      <0xfda40000 0x200>;
+		reg-names = "vfe", "vfe_vbif";
 		interrupts = <0 58 0>;
 		interrupt-names = "vfe";
 		vdd-supply = <&gdsc_vfe>;
 	};
+
 	qcom,jpeg@fda1c000 {
 		cell-index = <0>;
 		compatible = "qcom,jpeg";
@@ -117,6 +126,7 @@
 		interrupts = <0 59 0>;
 		interrupt-names = "jpeg";
 	};
+
 	qcom,jpeg@fda20000 {
 		cell-index = <1>;
 		compatible = "qcom,jpeg";
@@ -125,6 +135,7 @@
 		interrupts = <0 60 0>;
 		interrupt-names = "jpeg";
 	};
+
 	qcom,jpeg@fda24000 {
 		cell-index = <2>;
 		compatible = "qcom,jpeg";
@@ -133,12 +144,14 @@
 		interrupts = <0 61 0>;
 		interrupt-names = "jpeg";
 	};
+
 	qcom,irqrouter@fda00000 {
 		cell-index = <0>;
 		compatible = "qcom,irqrouter";
 		reg = <0xfda00000 0x100>;
 		reg-names = "irqrouter";
 	};
+
 	qcom,cpp@fda04000 {
 		cell-index = <0>;
 		compatible = "qcom,cpp";
@@ -148,4 +161,98 @@
 		interrupt-names = "cpp";
 		vdd-supply = <&gdsc_vfe>;
 	};
+
+	qcom,cci@fda0C000 {
+		cell-index = <0>;
+		compatible = "qcom,cci";
+		reg = <0xfda0C000 0x1000>;
+                #address-cells = <1>;
+                #size-cells = <1>;
+                ranges;
+		reg-names = "cci";
+		interrupts = <0 50 0>;
+		interrupt-names = "cci";
+
+		qcom,camera@6e {
+			compatible = "qcom,s5k3l1yx";
+			reg = <0x6e 0x0>;
+			qcom,csi-if = <1>;
+			qcom,csid-core = <0>;
+			qcom,is-vpe = <1>;
+			qcom,flash-type = <0>;
+			qcom,mount-angle = <90>;
+			qcom,sensor-name = "s5k3l1yx";
+			cam_vdig-supply = <&pm8941_l3>;
+			cam_vana-supply = <&pm8941_l17>;
+			cam_vio-supply = <&pm8941_lvs3>;
+			cam_vaf-supply = <&pm8941_l23>;
+			qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio",
+					     "cam_vaf";
+			qcom,cam-vreg-type = <0 0 1 0>;
+			qcom,cam-vreg-min-voltage = <1225000 2850000 0 3000000>;
+			qcom,cam-vreg-max-voltage = <1225000 2850000 0 3000000>;
+			qcom,cam-vreg-op-mode = <105000 80000 0 100000>;
+			qcom,gpio-no-mux = <0>;
+			gpios = <&msmgpio 15 0>,
+				<&msmgpio 19 0>,
+				<&msmgpio 20 0>,
+				<&msmgpio 90 0>;
+			qcom,gpio-common-tbl-num = <0 1 2>;
+			qcom,gpio-common-tbl-flags = <1 1 1>;
+			qcom,gpio-common-tbl-label = "CAMIF_MCLK",
+						     "CAMIF_I2C_DATA",
+						     "CAMIF_I2C_CLK";
+			qcom,gpio-req-tbl-num = <3>;
+			qcom,gpio-req-tbl-flags = <0>;
+			qcom,gpio-req-tbl-label = "CAM_RESET1";
+			qcom,gpio-set-tbl-num = <3 3>;
+			qcom,gpio-set-tbl-flags = <0 2>;
+			qcom,gpio-set-tbl-delay = <1000 30000>;
+			qcom,csi-lane-assign = <0x4320>;
+			qcom,csi-lane-mask = <0x1F>;
+			qcom,csi-phy-sel = <0>;
+			qcom,camera-type = <0>;
+			qcom,sensor-type = <0>;
+		};
+
+		qcom,camera@6c {
+			compatible = "qcom,ov2720";
+			reg = <0x6c 0x0>;
+			qcom,csi-if = <1>;
+			qcom,csid-core = <1>;
+			qcom,is-vpe = <1>;
+			qcom,flash-type = <0>;
+			qcom,mount-angle = <0>;
+			qcom,sensor-name = "ov2720";
+			cam_vdig-supply = <&pm8941_l3>;
+			cam_vana-supply = <&pm8941_l17>;
+			cam_vio-supply = <&pm8941_lvs3>;
+			qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+			qcom,cam-vreg-type = <0 0 1>;
+			qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+			qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+			qcom,cam-vreg-op-mode = <105000 80000 0>;
+			qcom,gpio-no-mux = <0>;
+			gpios = <&msmgpio 16 0>,
+				<&msmgpio 19 0>,
+				<&msmgpio 20 0>,
+				<&msmgpio 92 0>;
+			qcom,gpio-common-tbl-num = <0 1 2>;
+			qcom,gpio-common-tbl-flags = <1 1 1>;
+			qcom,gpio-common-tbl-label = "CAMIF_MCLK",
+						     "CAMIF_I2C_DATA",
+						     "CAMIF_I2C_CLK";
+			qcom,gpio-req-tbl-num = <3>;
+			qcom,gpio-req-tbl-flags = <0>;
+			qcom,gpio-req-tbl-label = "CAM_RESET1";
+			qcom,gpio-set-tbl-num = <3 3>;
+			qcom,gpio-set-tbl-flags = <0 2>;
+			qcom,gpio-set-tbl-delay = <1000 4000>;
+			qcom,csi-lane-assign = <0x4320>;
+			qcom,csi-lane-mask = <0x7>;
+			qcom,csi-phy-sel = <1>;
+			qcom,camera-type = <0>;
+			qcom,sensor-type = <0>;
+		};
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974-cdp.dts b/arch/arm/boot/dts/msm8974-cdp.dts
index 8ae9583..e764e01 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-cdp.dts
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 /include/ "msm8974.dtsi"
+/include/ "dsi-panel-toshiba-720p-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8974 CDP";
@@ -22,16 +23,23 @@
 	serial@f991e000 {
 		status = "ok";
 	};
+
+	qcom,mdss_dsi@fd922800 {
+		qcom,mdss_dsi_toshiba_720p_video {
+			status = "ok";
+		};
+	};
 };
 
 &sdcc2 {
 	#address-cells = <0>;
 	interrupt-parent = <&sdcc2>;
-	interrupts = <0 1>;
+	interrupts = <0 1 2>;
 	#interrupt-cells = <1>;
 	interrupt-map-mask = <0xffffffff>;
 	interrupt-map = <0 &intc 0 125 0
-			1 &msmgpio 62 0x3>;
-	interrupt-names = "core_irq", "status_irq";
+			1 &intc 0 220 0
+			2 &msmgpio 62 0x3>;
+	interrupt-names = "core_irq", "bam_irq", "status_irq";
 	cd-gpios = <&msmgpio 62 0x1>;
 };
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index de9173c7..dbaa492 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -22,8 +22,11 @@
 
 	mdss_dsi: qcom,mdss_dsi@fd922800 {
 		compatible = "qcom,msm-mdss-dsi";
-		reg = <0xfd922800 0x5ac>,
+		reg = <0xfd922800 0x600>,
 			<0xfd8c2000 0x01000>;
+		vdd-supply = <&pm8941_l22>;
+		vdd_io-supply = <&pm8941_l12>;
+		vreg-supply = <&pm8941_l2>;
 	};
 
 	qcom,mdss_wb_panel {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 1be0af9..b4ac3d6 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -101,10 +101,12 @@
 	sdcc1: qcom,sdcc@f9824000 {
 		cell-index = <1>; /* SDC1 eMMC slot */
 		compatible = "qcom,msm-sdcc";
-		reg = <0xf9824000 0x1000>;
-		reg-names = "core_mem";
-		interrupts = <0 123 0>;
-		interrupt-names = "core_irq";
+		reg = <0xf9824000 0x800>,
+			<0xf9824800 0x100>,
+			<0xf9804000 0x7000>;
+		reg-names = "core_mem", "dml_mem", "bam_mem";
+		interrupts = <0 123 0>, <0 137 0>;
+		interrupt-names = "core_irq", "bam_irq";
 		vdd-supply = <&pm8941_l20>;
 		vdd-io-supply = <&pm8941_s3>;
 
@@ -130,10 +132,12 @@
 	sdcc2: qcom,sdcc@f98a4000 {
 		cell-index = <2>; /* SDC2 SD card slot */
 		compatible = "qcom,msm-sdcc";
-		reg = <0xf98a4000 0x1000>;
-		reg-names = "core_mem";
-		interrupts = <0 125 0>;
-		interrupt-names = "core_irq";
+		reg = <0xf98a4000 0x800>,
+			<0xf98a4800 0x100>,
+			<0xf9884000 0x7000>;
+		reg-names = "core_mem", "dml_mem", "bam_mem";
+		interrupts = <0 125 0>, <0 220 0>;
+		interrupt-names = "core_irq", "bam_irq";
 		vdd-supply = <&pm8941_l21>;
 		vdd-io-supply = <&pm8941_l13>;
 
@@ -161,10 +165,12 @@
 	sdcc3: qcom,sdcc@f9864000 {
 		cell-index = <3>; /* SDC3 SDIO slot */
 		compatible = "qcom,msm-sdcc";
-		reg = <0xf9864000 0x1000>;
-		reg-names = "core_mem";
-		interrupts = <0 127 0>;
-		interrupt-names = "core_irq";
+		reg = <0xf9864000 0x800>,
+			<0xf9864800 0x100>,
+			<0xf9844000 0x7000>;
+		reg-names = "core_mem", "dml_mem", "bam_mem";
+		interrupts = <0 127 0>, <0 223 0>;
+		interrupt-names = "core_irq", "bam_irq";
 
 		gpios = <&msmgpio 40 0>, /* CLK */
 			<&msmgpio 39 0>, /* CMD */
@@ -184,10 +190,12 @@
 	sdcc4: qcom,sdcc@f98e4000 {
 		cell-index = <4>; /* SDC4 SDIO slot */
 		compatible = "qcom,msm-sdcc";
-		reg = <0xf98e4000 0x1000>;
-		reg-names = "core_mem";
-		interrupts = <0 129 0>;
-		interrupt-names = "core_irq";
+		reg = <0xf98e4000 0x800>,
+			<0xf98e4800 0x100>,
+			<0xf98c4000 0x7000>;
+		reg-names = "core_mem", "dml_mem", "bam_mem";
+		interrupts = <0 129 0>, <0 226 0>;
+		interrupt-names = "core_irq", "bam_irq";
 
 		gpios = <&msmgpio 93 0>, /* CLK */
 			<&msmgpio 91 0>, /* CMD */
@@ -421,12 +429,12 @@
 					 <0x1e70008c>; /* LPG_CHAN12 */
 	};
 
-	i2c@f9966000 {
+	i2c@f9967000 {
 		cell-index = <0>;
 		compatible = "qcom,i2c-qup";
-		reg = <0Xf9966000 0x1000>;
+		reg = <0Xf9967000 0x1000>;
 		reg-names = "qup_phys_addr";
-		interrupts = <0 104 0>;
+		interrupts = <0 105 0>;
 		interrupt-names = "qup_err_intr";
 		qcom,i2c-bus-freq = <100000>;
 		qcom,i2c-src-freq = <24000000>;
@@ -551,7 +559,8 @@
 
 	qcom,ssusb@f9200000 {
 		compatible = "qcom,dwc-usb3-msm";
-		reg = <0xf9200000 0xfc000>;
+		reg = <0xf9200000 0xfc000>,
+			  <0xfd4ab000 0x4>;
 		interrupts = <0 131 0 0 179 0>;
 		interrupt-names = "irq", "otg_irq";
 		SSUSB_VDDCX-supply = <&pm8841_s2>;
@@ -828,6 +837,7 @@
 		qcom,usb-total-bam-num = <2>;
 		qcom,usb-bam-num-pipes = <16>;
 		qcom,usb-base-address = <0xf9200000>;
+		qcom,ignore-core-reset-ack;
 
 		qcom,pipe1 {
 			label = "usb-to-peri-qdss-dwc3";
diff --git a/arch/arm/boot/dts/msm8974_pm.dtsi b/arch/arm/boot/dts/msm8974_pm.dtsi
index 476f2b5..82d317d 100644
--- a/arch/arm/boot/dts/msm8974_pm.dtsi
+++ b/arch/arm/boot/dts/msm8974_pm.dtsi
@@ -20,7 +20,7 @@
 		reg = <0xf9089000 0x1000>;
 		qcom,core-id = <0>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-cfg = <0x01>;
 		qcom,saw2-avs-ctl = <0>;
 		qcom,saw2-avs-hysteresis = <0>;
 		qcom,saw2-avs-limit = <0>;
@@ -28,11 +28,10 @@
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
-				a0 b0 03 68 70 3b 92 a0 b0
-				82 2b 50 10 30 02 22 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
-				a0 b0 82 10 30 02 22 30 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,spm@f9099000 {
@@ -42,7 +41,7 @@
 		reg = <0xf9099000 0x1000>;
 		qcom,core-id = <1>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-cfg = <0x01>;
 		qcom,saw2-avs-ctl = <0>;
 		qcom,saw2-avs-hysteresis = <0>;
 		qcom,saw2-avs-limit = <0>;
@@ -50,11 +49,10 @@
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
-				a0 b0 03 68 70 3b 92 a0 b0
-				82 2b 50 10 30 02 22 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
-				a0 b0 82 10 30 02 22 30 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,spm@f90a9000 {
@@ -64,7 +62,7 @@
 		reg = <0xf90a9000 0x1000>;
 		qcom,core-id = <2>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-cfg = <0x01>;
 		qcom,saw2-avs-ctl = <0>;
 		qcom,saw2-avs-hysteresis = <0>;
 		qcom,saw2-avs-limit = <0>;
@@ -72,11 +70,10 @@
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
-				a0 b0 03 68 70 3b 92 a0 b0
-				82 2b 50 10 30 02 22 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
-				a0 b0 82 10 30 02 22 30 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,spm@f90b9000 {
@@ -86,7 +83,7 @@
 		reg = <0xf90b9000 0x1000>;
 		qcom,core-id = <3>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-cfg = <0x01>;
 		qcom,saw2-avs-ctl = <0>;
 		qcom,saw2-avs-hysteresis = <0>;
 		qcom,saw2-avs-limit = <0>;
@@ -94,11 +91,10 @@
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
-				a0 b0 03 68 70 3b 92 a0 b0
-				82 2b 50 10 30 02 22 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
-				a0 b0 82 10 30 02 22 30 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,spm@f9012000 {
@@ -108,28 +104,26 @@
 		reg = <0xf9012000 0x1000>;
 		qcom,core-id = <0xffff>; /* L2/APCS SAW */
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x1a>;
+		qcom,saw2-cfg = <0x14>;
 		qcom,saw2-avs-ctl = <0>;
 		qcom,saw2-avs-hysteresis = <0>;
 		qcom,saw2-avs-limit = <0>;
 		qcom,saw2-avs-dly= <0>;
 		qcom,saw2-spm-dly= <0x20000400>;
-		qcom,saw2-spm-ctl = <0x0>; /* TODO: Enable L2 SPM */
+		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-pmic-dly = <0x02020204>;
 		qcom,saw2-pmic-data0 = <0x0400009c>;
 		qcom,saw2-pmic-data1 = <0x00000060>;
 		qcom,saw2-pmic-data2 = <0x0000001c>;
 		qcom,saw2-pmic-data3 = <0x04000000>;
 		qcom,vctl-timeout-us = <50>;
-		qcom,vctl-port = <0x0>; /* TODO: */
-		qcom,phase-port = <0x1>; /* TODO: */
+		qcom,vctl-port = <0x0>;
+		qcom,phase-port = <0x1>;
 		qcom,saw2-spm-cmd-ret = [0b 00 20 03 22 00 0f];
-		qcom,saw2-spm-cmd-gdhs =  [00 20 32 60 70 80 0b 42 07
-				      78 80 44 22 50 3b 60 02 32
-				      50 0f];
-		qcom,saw2-spm-cmd-pc = [00 10 32 60 70 80 b0 11 0b
-				42 07 01 b0 78 80 12 44 a0 50
-				3b 60 02 32 a0 50 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 20 32 0b 42 07 44 22 50 02 32 50
+				0f];
+		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 0b 42 07 01 b0 12 44 a0
+				50 02 32 a0 50 0f];
 	};
 
 	qcom,lpm-resources {
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 719933f..aea920b 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -148,6 +148,7 @@
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
+CONFIG_MSM_BUS_SCALING=y
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=m
@@ -168,12 +169,22 @@
 CONFIG_REGULATOR_STUB=y
 CONFIG_REGULATOR_QPNP=y
 CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
-# CONFIG_RC_CORE is not set
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_VIDEOBUF2_MSM_MEM=y
-# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
-# CONFIG_RADIO_ADAPTERS is not set
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
+CONFIG_MSM_CAM_IRQ_ROUTER=n
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_CSI2_REGISTER=y
+CONFIG_MSM_ISPIF=y
+CONFIG_S5K3L1YX=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
@@ -218,6 +229,7 @@
 # CONFIG_MMC_BLOCK_BOUNCE is not set
 CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
 CONFIG_SWITCH=y
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_DRV_MSM is not set
@@ -231,6 +243,7 @@
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_MSM_SSBI=y
 CONFIG_SPS=y
+CONFIG_USB_BAM=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_QPNP_POWER_ON=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index db94f13..b8417fe 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -147,6 +147,10 @@
 CONFIG_IP6_NF_TARGET_REJECT_SKERR=y
 CONFIG_IP6_NF_MANGLE=y
 CONFIG_IP6_NF_RAW=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
 CONFIG_MTD=y
 CONFIG_MTD_TESTS=m
 CONFIG_MTD_CMDLINE_PARTS=y
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index f27889b..da3d3c4 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -276,9 +276,9 @@
 obj-$(CONFIG_MACH_MSM8960_CDP) += board-8960-all.o board-8960-regulator.o
 obj-$(CONFIG_MACH_MSM8960_MTP) += board-8960-all.o board-8960-regulator.o
 obj-$(CONFIG_MACH_MSM8960_FLUID) += board-8960-all.o board-8960-regulator.o
-obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8930-regulator.o
-obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8930-regulator.o
-obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator.o
+obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
+obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
+obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
 obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o
 obj-$(CONFIG_MACH_APQ8064_CDP) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_MACH_APQ8064_MTP) += board-8064-all.o board-8064-regulator.o
diff --git a/arch/arm/mach-msm/acpuclock-8930.c b/arch/arm/mach-msm/acpuclock-8930.c
index 5647d14..782ee60 100644
--- a/arch/arm/mach-msm/acpuclock-8930.c
+++ b/arch/arm/mach-msm/acpuclock-8930.c
@@ -45,6 +45,39 @@
 	.vdd[HFPLL_VDD_HIGH] = LVL_HIGH,
 };
 
+static struct scalable scalable_pm8917[] __initdata = {
+	[CPU0] = {
+		.hfpll_phys_base = 0x00903200,
+		.aux_clk_sel_phys = 0x02088014,
+		.aux_clk_sel = 3,
+		.l2cpmr_iaddr = 0x4501,
+		.vreg[VREG_CORE] = { "krait0", 1300000 },
+		.vreg[VREG_MEM]  = { "krait0_mem", 1150000 },
+		.vreg[VREG_DIG]  = { "krait0_dig", 1150000 },
+		.vreg[VREG_HFPLL_A] = { "krait0_s8", 2050000 },
+		.vreg[VREG_HFPLL_B] = { "krait0_l23", 1800000 },
+	},
+	[CPU1] = {
+		.hfpll_phys_base = 0x00903300,
+		.aux_clk_sel_phys = 0x02098014,
+		.aux_clk_sel = 3,
+		.l2cpmr_iaddr = 0x5501,
+		.vreg[VREG_CORE] = { "krait1", 1300000 },
+		.vreg[VREG_MEM]  = { "krait1_mem", 1150000 },
+		.vreg[VREG_DIG]  = { "krait1_dig", 1150000 },
+		.vreg[VREG_HFPLL_A] = { "krait1_s8", 2050000 },
+		.vreg[VREG_HFPLL_B] = { "krait1_l23", 1800000 },
+	},
+	[L2] = {
+		.hfpll_phys_base = 0x00903400,
+		.aux_clk_sel_phys = 0x02011028,
+		.aux_clk_sel = 3,
+		.l2cpmr_iaddr = 0x0500,
+		.vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
+		.vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
+	},
+};
+
 static struct scalable scalable[] __initdata = {
 	[CPU0] = {
 		.hfpll_phys_base = 0x00903200,
@@ -193,6 +226,10 @@
 
 static int __init acpuclk_8930_probe(struct platform_device *pdev)
 {
+	struct acpuclk_platform_data *pdata = pdev->dev.platform_data;
+	if (pdata && pdata->uses_pm8917)
+		acpuclk_8930_params.scalable = scalable_pm8917;
+
 	return acpuclk_krait_init(&pdev->dev, &acpuclk_8930_params);
 }
 
diff --git a/arch/arm/mach-msm/acpuclock-8960ab.c b/arch/arm/mach-msm/acpuclock-8960ab.c
index 1097907..3c42090 100644
--- a/arch/arm/mach-msm/acpuclock-8960ab.c
+++ b/arch/arm/mach-msm/acpuclock-8960ab.c
@@ -124,6 +124,10 @@
 	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(9),  1237500 },
 	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(9),  1237500 },
 	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(9),  1250000 },
+	{ 1, {  1566000, HFPLL, 1, 0, 0x3A }, L2(9),  1250000 },
+	{ 1, {  1620000, HFPLL, 1, 0, 0x3C }, L2(9),  1250000 },
+	{ 1, {  1674000, HFPLL, 1, 0, 0x3E }, L2(9),  1250000 },
+	{ 1, {  1728000, HFPLL, 1, 0, 0x40 }, L2(9),  1250000 },
 	{ 0, { 0 } }
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index 5a95e76..1b891b1 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -253,9 +253,16 @@
 };
 
 /**
+ * struct acpuclk_platform_data - PMIC configuration data.
+ * @uses_pm8917: Boolean indicates presence of pm8917.
+ */
+struct acpuclk_platform_data {
+	bool uses_pm8917;
+};
+
+/**
  * acpuclk_krait_init - Initialize the Krait CPU clock driver give SoC params.
  */
 extern int acpuclk_krait_init(struct device *dev,
 			      const struct acpuclk_krait_params *params);
-
 #endif
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 125094d..fbc3e25 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -27,6 +27,7 @@
 #include <linux/clk.h>
 #include <linux/wakelock.h>
 #include <linux/kfifo.h>
+#include <linux/of.h>
 
 #include <mach/sps.h>
 #include <mach/bam_dmux.h>
@@ -175,6 +176,14 @@
 #define A2_PHYS_SIZE		0x2000
 #define BUFFER_SIZE		2048
 #define NUM_BUFFERS		32
+
+#ifndef A2_BAM_IRQ
+#define A2_BAM_IRQ -1
+#endif
+
+static void *a2_phys_base;
+static uint32_t a2_phys_size;
+static int a2_bam_irq;
 static struct sps_bam_props a2_props;
 static u32 a2_device_handle;
 static struct sps_pipe *bam_tx_pipe;
@@ -2028,16 +2037,17 @@
 
 	vote_dfab();
 	/* init BAM */
-	a2_virt_addr = ioremap_nocache(A2_PHYS_BASE, A2_PHYS_SIZE);
+	a2_virt_addr = ioremap_nocache((unsigned long)(a2_phys_base),
+							a2_phys_size);
 	if (!a2_virt_addr) {
 		pr_err("%s: ioremap failed\n", __func__);
 		ret = -ENOMEM;
 		goto ioremap_failed;
 	}
-	a2_props.phys_addr = A2_PHYS_BASE;
+	a2_props.phys_addr = (u32)(a2_phys_base);
 	a2_props.virt_addr = a2_virt_addr;
-	a2_props.virt_size = A2_PHYS_SIZE;
-	a2_props.irq = A2_BAM_IRQ;
+	a2_props.virt_size = a2_phys_size;
+	a2_props.irq = a2_bam_irq;
 	a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP;
 	a2_props.num_pipes = A2_NUM_PIPES;
 	a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
@@ -2199,16 +2209,17 @@
 	void *a2_virt_addr;
 
 	/* init BAM */
-	a2_virt_addr = ioremap_nocache(A2_PHYS_BASE, A2_PHYS_SIZE);
+	a2_virt_addr = ioremap_nocache((unsigned long)(a2_phys_base),
+							a2_phys_size);
 	if (!a2_virt_addr) {
 		pr_err("%s: ioremap failed\n", __func__);
 		ret = -ENOMEM;
 		goto ioremap_failed;
 	}
-	a2_props.phys_addr = A2_PHYS_BASE;
+	a2_props.phys_addr = (u32)(a2_phys_base);
 	a2_props.virt_addr = a2_virt_addr;
-	a2_props.virt_size = A2_PHYS_SIZE;
-	a2_props.irq = A2_BAM_IRQ;
+	a2_props.virt_size = a2_phys_size;
+	a2_props.irq = a2_bam_irq;
 	a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP;
 	a2_props.num_pipes = A2_NUM_PIPES;
 	a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
@@ -2321,11 +2332,35 @@
 static int bam_dmux_probe(struct platform_device *pdev)
 {
 	int rc;
+	struct resource *r;
 
 	DBG("%s probe called\n", __func__);
 	if (bam_mux_initialized)
 		return 0;
 
+	if (pdev->dev.of_node) {
+		r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (!r) {
+			pr_err("%s: reg field missing\n", __func__);
+			return -ENODEV;
+		}
+		a2_phys_base = (void *)(r->start);
+		a2_phys_size = (uint32_t)(resource_size(r));
+		a2_bam_irq = platform_get_irq(pdev, 0);
+		if (a2_bam_irq == -ENXIO) {
+			pr_err("%s: irq field missing\n", __func__);
+			return -ENODEV;
+		}
+		DBG("%s: base:%p size:%x irq:%d\n", __func__,
+							a2_phys_base,
+							a2_phys_size,
+							a2_bam_irq);
+	} else { /* fallback to default init data */
+		a2_phys_base = (void *)(A2_PHYS_BASE);
+		a2_phys_size = A2_PHYS_SIZE;
+		a2_bam_irq = A2_BAM_IRQ;
+	}
+
 	xo_clk = clk_get(&pdev->dev, "xo");
 	if (IS_ERR(xo_clk)) {
 		bam_dmux_log("%s: did not get xo clock\n", __func__);
@@ -2409,11 +2444,17 @@
 	return 0;
 }
 
+static struct of_device_id msm_match_table[] = {
+	{.compatible = "qcom,bam_dmux"},
+	{},
+};
+
 static struct platform_driver bam_dmux_driver = {
 	.probe		= bam_dmux_probe,
 	.driver		= {
 		.name	= "BAM_RMNT",
 		.owner	= THIS_MODULE,
+		.of_match_table = msm_match_table,
 	},
 };
 
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 4c7ea58..e050073 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -428,6 +428,20 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
+static struct gpiomux_setting hdmi_active_3_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+	.dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting hdmi_active_4_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+	.dir = GPIOMUX_OUT_HIGH,
+};
+
 static struct gpiomux_setting gsbi5_suspended_cfg = {
 	.func = GPIOMUX_FUNC_2,
 	.drv = GPIOMUX_DRV_12MA,
@@ -617,6 +631,23 @@
 	},
 };
 
+static struct msm_gpiomux_config apq8064_mhl_configs[] __initdata = {
+	{
+		.gpio = 30,
+		.settings = {
+		[GPIOMUX_ACTIVE]    = &hdmi_active_3_cfg,
+		[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 35,
+		.settings = {
+		[GPIOMUX_ACTIVE]    = &hdmi_active_4_cfg,
+		[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+};
+
 static struct msm_gpiomux_config apq8064_gsbi_configs[] __initdata = {
 	{
 		.gpio      = 8,			/* GSBI3 I2C QUP SDA */
@@ -1357,6 +1388,10 @@
 	msm_gpiomux_install(apq8064_hdmi_configs,
 			ARRAY_SIZE(apq8064_hdmi_configs));
 
+	if (apq8064_mhl_display_enabled())
+		msm_gpiomux_install(apq8064_mhl_configs,
+				ARRAY_SIZE(apq8064_mhl_configs));
+
 	 if (machine_is_mpq8064_cdp())
 		msm_gpiomux_install(mpq8064_ir_configs,
 				ARRAY_SIZE(mpq8064_ir_configs));
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 86bc6ba..04326aa 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -126,7 +126,7 @@
 	PM8921_GPIO_INPUT(35, PM_GPIO_PULL_UP_30),
 	PM8921_GPIO_INPUT(38, PM_GPIO_PULL_UP_30),
 	/* TABLA CODEC RESET */
-	PM8921_GPIO_OUTPUT(34, 1, MED),
+	PM8921_GPIO_OUTPUT(34, 0, MED),
 	PM8921_GPIO_OUTPUT(13, 0, HIGH),               /* PCIE_CLK_PWR_EN */
 	PM8921_GPIO_INPUT(12, PM_GPIO_PULL_UP_30),     /* PCIE_WAKE_N */
 };
@@ -494,5 +494,7 @@
 		apq8064_pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
 	} else if (machine_is_apq8064_liquid()) {
 		apq8064_pm8921_bms_pdata.battery_type = BATT_DESAY;
+	} else if (machine_is_apq8064_cdp()) {
+		apq8064_pm8921_chg_pdata.has_dc_supply = true;
 	}
 }
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 7070b42..276d753 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -85,6 +85,9 @@
 #include "devices-msm8x60.h"
 #include "smd_private.h"
 
+#define MHL_GPIO_INT           30
+#define MHL_GPIO_RESET         35
+
 #define MSM_PMEM_ADSP_SIZE         0x7800000
 #define MSM_PMEM_AUDIO_SIZE        0x4CF000
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
@@ -1805,6 +1808,26 @@
 						(void *)MSM_QGIC_CPU_BASE);
 }
 
+static struct msm_mhl_platform_data mhl_platform_data = {
+	.irq = MSM_GPIO_TO_INT(MHL_GPIO_INT),
+	.gpio_mhl_int = MHL_GPIO_INT,
+	.gpio_mhl_reset = MHL_GPIO_RESET,
+	.gpio_mhl_power = 0,
+	.gpio_hdmi_mhl_mux = 0,
+};
+
+static struct i2c_board_info sii_device_info[] __initdata = {
+	{
+		/*
+		 * keeps SI 8334 as the default
+		 * MHL TX
+		 */
+		I2C_BOARD_INFO("sii8334", 0x39),
+		.platform_data = &mhl_platform_data,
+		.flags = I2C_CLIENT_WAKE,
+	},
+};
+
 static struct platform_device msm8064_device_saw_regulator_core0 = {
 	.name	= "saw-regulator",
 	.id	= 0,
@@ -2833,6 +2856,12 @@
 		cs8427_device_info,
 		ARRAY_SIZE(cs8427_device_info),
 	},
+	{
+		I2C_SURF | I2C_FFA | I2C_LIQUID,
+		APQ_8064_GSBI1_QUP_I2C_BUS_ID,
+		sii_device_info,
+		ARRAY_SIZE(sii_device_info),
+	}
 };
 
 #define SX150X_EXP1_INT_N	PM8921_MPP_IRQ(PM8921_IRQ_BASE, 9)
@@ -3023,6 +3052,9 @@
 	if (machine_is_apq8064_liquid())
 		msm_otg_pdata.mhl_enable = true;
 
+	if (apq8064_mhl_display_enabled())
+		mhl_platform_data.mhl_enabled = true;
+
 	android_usb_pdata.swfi_latency =
 		msm_rpmrs_levels[0].latency_us;
 
@@ -3195,4 +3227,3 @@
 	.init_very_early = apq8064_early_reserve,
 	.restart = msm_restart,
 MACHINE_END
-
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index 2a8e918..4b4a51a 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -135,6 +135,8 @@
 static int mipi_dsi_cdp_panel_power(int on)
 {
 	static struct regulator *reg_l8, *reg_l23, *reg_l2;
+	/* Control backlight GPIO (24) directly when using PM8917 */
+	int gpio24 = PM8917_GPIO_PM_TO_SYS(24);
 	int rc;
 
 	pr_debug("%s: state : %d\n", __func__, on);
@@ -190,13 +192,21 @@
 				 rc);
 			gpio_free(DISP_3D_2D_MODE);
 			return -ENODEV;
-			}
+		}
 		rc = gpio_direction_output(DISP_3D_2D_MODE, 0);
 		if (rc) {
 			pr_err("gpio_direction_output failed for %d gpio rc=%d\n",
 			DISP_3D_2D_MODE, rc);
 			return -ENODEV;
+		}
+		if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917) {
+			rc = gpio_request(gpio24, "disp_bl");
+			if (rc) {
+				pr_err("request for gpio 24 failed, rc=%d\n",
+					rc);
+				return -ENODEV;
 			}
+		}
 		dsi_power_on = true;
 	}
 	if (on) {
@@ -238,6 +248,8 @@
 		gpio_set_value(DISP_RST_GPIO, 1);
 		gpio_set_value(DISP_3D_2D_MODE, 1);
 		usleep(20);
+		if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+			gpio_set_value_cansleep(gpio24, 1);
 	} else {
 
 		gpio_set_value(DISP_RST_GPIO, 0);
@@ -274,6 +286,8 @@
 		}
 		gpio_set_value(DISP_3D_2D_MODE, 0);
 		usleep(20);
+		if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+			gpio_set_value_cansleep(gpio24, 0);
 	}
 	return 0;
 }
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index 74dfca1..2331b0b 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -280,6 +280,13 @@
 
 #endif
 
+static struct gpiomux_setting sitar_reset = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
 #if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
 static struct msm_gpiomux_config msm8960_ethernet_configs[] = {
 	{
@@ -710,6 +717,15 @@
 	},
 };
 
+static struct msm_gpiomux_config msm_sitar_config[] __initdata = {
+	{
+		.gpio   = 42,           /* SYS_RST_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &sitar_reset,
+		},
+	}
+};
+
 int __init msm8930_init_gpiomux(void)
 {
 	int rc = msm_gpiomux_init(NR_GPIO_IRQS);
@@ -784,5 +800,7 @@
 		msm_gpiomux_install(msm8930_gyro_int_config,
 			ARRAY_SIZE(msm8930_gyro_int_config));
 
+	msm_gpiomux_install(msm_sitar_config, ARRAY_SIZE(msm_sitar_config));
+
 	return 0;
 }
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index e3479eb..b6e20fd 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -18,6 +18,7 @@
 #include <asm/mach-types.h>
 #include <mach/msm_bus_board.h>
 #include <mach/restart.h>
+#include <mach/socinfo.h>
 #include "devices.h"
 #include "board-8930.h"
 
@@ -31,7 +32,7 @@
 	struct pm8xxx_mpp_config_data	config;
 };
 
-#define PM8XXX_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+#define PM8038_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
 			_func, _inv, _disable) \
 { \
 	.gpio	= PM8038_GPIO_PM_TO_SYS(_gpio), \
@@ -48,7 +49,7 @@
 	} \
 }
 
-#define PM8XXX_MPP_INIT(_mpp, _type, _level, _control) \
+#define PM8038_MPP_INIT(_mpp, _type, _level, _control) \
 { \
 	.mpp	= PM8038_MPP_PM_TO_SYS(_mpp), \
 	.config	= { \
@@ -58,49 +59,128 @@
 	} \
 }
 
-#define PM8XXX_GPIO_DISABLE(_gpio) \
-	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM8038_GPIO_VIN_L11, \
+#define PM8038_GPIO_DISABLE(_gpio) \
+	PM8038_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM8038_GPIO_VIN_L11, \
 			 0, 0, 0, 1)
 
-#define PM8XXX_GPIO_OUTPUT(_gpio, _val) \
-	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+#define PM8038_GPIO_OUTPUT(_gpio, _val) \
+	PM8038_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
 			PM_GPIO_PULL_NO, PM8038_GPIO_VIN_L11, \
 			PM_GPIO_STRENGTH_HIGH, \
 			PM_GPIO_FUNC_NORMAL, 0, 0)
 
-#define PM8XXX_GPIO_INPUT(_gpio, _pull) \
-	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+#define PM8038_GPIO_INPUT(_gpio, _pull) \
+	PM8038_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
 			_pull, PM8038_GPIO_VIN_L11, \
 			PM_GPIO_STRENGTH_NO, \
 			PM_GPIO_FUNC_NORMAL, 0, 0)
 
-#define PM8XXX_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
-	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+#define PM8038_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+	PM8038_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
 			PM_GPIO_PULL_NO, PM8038_GPIO_VIN_L11, \
 			PM_GPIO_STRENGTH_HIGH, \
 			_func, 0, 0)
 
-#define PM8XXX_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
-	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+#define PM8038_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+	PM8038_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
 			PM_GPIO_PULL_NO, _vin, \
 			PM_GPIO_STRENGTH_HIGH, \
 			PM_GPIO_FUNC_NORMAL, 0, 0)
 
-/* Initial pm8038 GPIO configurations */
+#define PM8917_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+			_func, _inv, _disable) \
+{ \
+	.gpio	= PM8917_GPIO_PM_TO_SYS(_gpio), \
+	.config	= { \
+		.direction	= _dir, \
+		.output_buffer	= _buf, \
+		.output_value	= _val, \
+		.pull		= _pull, \
+		.vin_sel	= _vin, \
+		.out_strength	= _out_strength, \
+		.function	= _func, \
+		.inv_int_pol	= _inv, \
+		.disable_pin	= _disable, \
+	} \
+}
+
+#define PM8917_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+	.mpp	= PM8917_MPP_PM_TO_SYS(_mpp), \
+	.config	= { \
+		.type		= PM8XXX_MPP_TYPE_##_type, \
+		.level		= _level, \
+		.control	= PM8XXX_MPP_##_control, \
+	} \
+}
+
+#define PM8917_GPIO_DISABLE(_gpio) \
+	PM8917_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM_GPIO_VIN_S4, \
+			 0, 0, 0, 1)
+
+#define PM8917_GPIO_OUTPUT(_gpio, _val) \
+	PM8917_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_HIGH, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8917_GPIO_INPUT(_gpio, _pull) \
+	PM8917_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+			_pull, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_NO, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8917_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+	PM8917_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_HIGH, \
+			_func, 0, 0)
+
+#define PM8917_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+	PM8917_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, _vin, \
+			PM_GPIO_STRENGTH_HIGH, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+/* GPIO and MPP configurations for MSM8930 + PM8038 targets */
+
+/* Initial PM8038 GPIO configurations */
 static struct pm8xxx_gpio_init pm8038_gpios[] __initdata = {
 	/* keys GPIOs */
-	PM8XXX_GPIO_INPUT(3, PM_GPIO_PULL_UP_30),
-	PM8XXX_GPIO_INPUT(8, PM_GPIO_PULL_UP_30),
-	PM8XXX_GPIO_INPUT(10, PM_GPIO_PULL_UP_30),
-	PM8XXX_GPIO_INPUT(11, PM_GPIO_PULL_UP_30),
+	PM8038_GPIO_INPUT(3, PM_GPIO_PULL_UP_30),
+	PM8038_GPIO_INPUT(8, PM_GPIO_PULL_UP_30),
+	PM8038_GPIO_INPUT(10, PM_GPIO_PULL_UP_30),
+	PM8038_GPIO_INPUT(11, PM_GPIO_PULL_UP_30),
 	/* haptics gpio */
-	PM8XXX_GPIO_OUTPUT_FUNC(7, 0, PM_GPIO_FUNC_1),
+	PM8038_GPIO_OUTPUT_FUNC(7, 0, PM_GPIO_FUNC_1),
 	/* MHL PWR EN */
-	PM8XXX_GPIO_OUTPUT_VIN(5, 1, PM_GPIO_VIN_VPH),
+	PM8038_GPIO_OUTPUT_VIN(5, 1, PM8038_GPIO_VIN_VPH),
 };
 
-/* Initial pm8038 MPP configurations */
-static struct pm8xxx_mpp_init pm8038_mpps[] __initdata = {};
+/* Initial PM8038 MPP configurations */
+static struct pm8xxx_mpp_init pm8038_mpps[] __initdata = {
+};
+
+/* GPIO and MPP configurations for MSM8930 + PM8917 targets */
+
+/* Initial PM8917 GPIO configurations */
+static struct pm8xxx_gpio_init pm8917_gpios[] __initdata = {
+	/* Backlight enable control */
+	PM8917_GPIO_OUTPUT(24, 1),
+	/* keys GPIOs */
+	PM8917_GPIO_INPUT(27, PM_GPIO_PULL_UP_30),
+	PM8917_GPIO_INPUT(28, PM_GPIO_PULL_UP_30),
+	PM8917_GPIO_INPUT(36, PM_GPIO_PULL_UP_30),
+	PM8917_GPIO_INPUT(37, PM_GPIO_PULL_UP_30),
+	/* haptics gpio */
+	PM8917_GPIO_OUTPUT_FUNC(38, 0, PM_GPIO_FUNC_2),
+	/* MHL PWR EN */
+	PM8917_GPIO_OUTPUT_VIN(25, 1, PM_GPIO_VIN_VPH),
+};
+
+/* Initial PM8917 MPP configurations */
+static struct pm8xxx_mpp_init pm8917_mpps[] __initdata = {
+};
 
 void __init msm8930_pm8038_gpio_mpp_init(void)
 {
@@ -126,7 +206,31 @@
 	}
 }
 
-static struct pm8xxx_adc_amux pm8xxx_adc_channels_data[] = {
+void __init msm8930_pm8917_gpio_mpp_init(void)
+{
+	int i, rc;
+
+	for (i = 0; i < ARRAY_SIZE(pm8917_gpios); i++) {
+		rc = pm8xxx_gpio_config(pm8917_gpios[i].gpio,
+					&pm8917_gpios[i].config);
+		if (rc) {
+			pr_err("%s: pm8xxx_gpio_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+
+	/* Initial MPP configuration. */
+	for (i = 0; i < ARRAY_SIZE(pm8917_mpps); i++) {
+		rc = pm8xxx_mpp_config(pm8917_mpps[i].mpp,
+					&pm8917_mpps[i].config);
+		if (rc) {
+			pr_err("%s: pm8xxx_mpp_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+}
+
+static struct pm8xxx_adc_amux pm8038_adc_channels_data[] = {
 	{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
 		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
 	{"vbat", CHANNEL_VBAT, CHAN_PATH_SCALING2, AMUX_RSV1,
@@ -161,16 +265,16 @@
 		ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
 };
 
-static struct pm8xxx_adc_properties pm8xxx_adc_data = {
+static struct pm8xxx_adc_properties pm8038_adc_data = {
 	.adc_vdd_reference	= 1800, /* milli-voltage for this adc */
 	.bitresolution		= 15,
 	.bipolar                = 0,
 };
 
-static struct pm8xxx_adc_platform_data pm8xxx_adc_pdata = {
-	.adc_channel            = pm8xxx_adc_channels_data,
-	.adc_num_board_channel  = ARRAY_SIZE(pm8xxx_adc_channels_data),
-	.adc_prop               = &pm8xxx_adc_data,
+static struct pm8xxx_adc_platform_data pm8038_adc_pdata = {
+	.adc_channel            = pm8038_adc_channels_data,
+	.adc_num_board_channel  = ARRAY_SIZE(pm8038_adc_channels_data),
+	.adc_prop               = &pm8038_adc_data,
 	.adc_mpp_base		= PM8038_MPP_PM_TO_SYS(1),
 };
 
@@ -227,6 +331,7 @@
 	.thermal_mitigation	= pm8921_therm_mitigation,
 	.thermal_levels		= ARRAY_SIZE(pm8921_therm_mitigation),
 	.led_src_config		= LED_SRC_VPH_PWR,
+	.rconn_mohm		= 18,
 };
 
 #define PM8038_WLED_MAX_CURRENT		25
@@ -348,6 +453,7 @@
 	.shutdown_soc_valid_limit	= 20,
 	.adjust_soc_low_threshold	= 25,
 	.chg_term_ua			= CHG_TERM_MA * 1000,
+	.rconn_mohm			= 18,
 };
 
 static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
@@ -360,7 +466,7 @@
 	.regulator_pdatas	= msm8930_pm8038_regulator_pdata,
 	.charger_pdata		= &pm8921_chg_pdata,
 	.bms_pdata		= &pm8921_bms_pdata,
-	.adc_pdata		= &pm8xxx_adc_pdata,
+	.adc_pdata		= &pm8038_adc_pdata,
 	.leds_pdata		= &pm8xxx_leds_pdata,
 	.ccadc_pdata		= &pm8xxx_ccadc_pdata,
 	.spk_pdata		= &pm8xxx_spk_pdata,
@@ -374,15 +480,99 @@
 	},
 };
 
+/* PM8917 platform data */
+
+static struct pm8xxx_adc_amux pm8917_adc_channels_data[] = {
+	{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"vbat", CHANNEL_VBAT, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"dcin", CHANNEL_DCIN, CHAN_PATH_SCALING4, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"ichg", CHANNEL_ICHG, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"vph_pwr", CHANNEL_VPH_PWR, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"ibat", CHANNEL_IBAT, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"batt_therm", CHANNEL_BATT_THERM, CHAN_PATH_SCALING1, AMUX_RSV2,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_BATT_THERM},
+	{"batt_id", CHANNEL_BATT_ID, CHAN_PATH_SCALING1, AMUX_RSV2,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"usbin", CHANNEL_USBIN, CHAN_PATH_SCALING3, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"pmic_therm", CHANNEL_DIE_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_PMIC_THERM},
+	{"625mv", CHANNEL_625MV, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"125v", CHANNEL_125V, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"chg_temp", CHANNEL_CHG_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"xo_therm", CHANNEL_MUXOFF, CHAN_PATH_SCALING1, AMUX_RSV0,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_XOTHERM},
+	{"pa_therm0", ADC_MPP_1_AMUX3, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
+};
+
+static struct pm8xxx_adc_properties pm8917_adc_data = {
+	.adc_vdd_reference	= 1800, /* milli-voltage for this adc */
+	.bitresolution		= 15,
+	.bipolar                = 0,
+};
+
+static struct pm8xxx_adc_platform_data pm8917_adc_pdata = {
+	.adc_channel            = pm8917_adc_channels_data,
+	.adc_num_board_channel  = ARRAY_SIZE(pm8917_adc_channels_data),
+	.adc_prop               = &pm8917_adc_data,
+	.adc_mpp_base		= PM8917_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8921_platform_data pm8917_platform_data __devinitdata = {
+	.irq_pdata		= &pm8xxx_irq_pdata,
+	.gpio_pdata		= &pm8xxx_gpio_pdata,
+	.mpp_pdata		= &pm8xxx_mpp_pdata,
+	.rtc_pdata              = &pm8xxx_rtc_pdata,
+	.pwrkey_pdata		= &pm8xxx_pwrkey_pdata,
+	.misc_pdata		= &pm8xxx_misc_pdata,
+	.regulator_pdatas	= msm8930_pm8917_regulator_pdata,
+	.charger_pdata		= &pm8921_chg_pdata,
+	.bms_pdata		= &pm8921_bms_pdata,
+	.adc_pdata		= &pm8917_adc_pdata,
+	.ccadc_pdata		= &pm8xxx_ccadc_pdata,
+};
+
+static struct msm_ssbi_platform_data msm8930_ssbi_pm8917_pdata __devinitdata = {
+	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+	.slave	= {
+		.name			= "pm8921-core",
+		.platform_data		= &pm8917_platform_data,
+	},
+};
+
 void __init msm8930_init_pmic(void)
 {
-	pmic_reset_irq = PM8038_IRQ_BASE + PM8038_RESOUT_IRQ;
-	msm8960_device_ssbi_pmic.dev.platform_data =
-				&msm8930_ssbi_pm8038_pdata;
-	pm8038_platform_data.num_regulators
-		= msm8930_pm8038_regulator_pdata_len;
-	if (machine_is_apq8064_mtp())
-		pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
-	else if (machine_is_apq8064_liquid())
-		pm8921_bms_pdata.battery_type = BATT_DESAY;
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
+		/* PM8038 configuration */
+		pmic_reset_irq = PM8038_IRQ_BASE + PM8038_RESOUT_IRQ;
+		msm8960_device_ssbi_pmic.dev.platform_data =
+					&msm8930_ssbi_pm8038_pdata;
+		pm8038_platform_data.num_regulators
+			= msm8930_pm8038_regulator_pdata_len;
+		if (machine_is_msm8930_mtp())
+			pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+		else if (machine_is_msm8930_cdp())
+			pm8921_chg_pdata.has_dc_supply = true;
+	} else {
+		/* PM8917 configuration */
+		pmic_reset_irq = PM8917_IRQ_BASE + PM8921_RESOUT_IRQ;
+		msm8960_device_ssbi_pmic.dev.platform_data =
+					&msm8930_ssbi_pm8917_pdata;
+		pm8917_platform_data.num_regulators
+			= msm8930_pm8917_regulator_pdata_len;
+		if (machine_is_msm8930_mtp())
+			pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+		else if (machine_is_msm8930_cdp())
+			pm8921_chg_pdata.has_dc_supply = true;
+	}
 }
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
similarity index 97%
rename from arch/arm/mach-msm/board-8930-regulator.c
rename to arch/arm/mach-msm/board-8930-regulator-pm8038.c
index d4bd18f..ed9d802 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
@@ -11,6 +11,11 @@
  * GNU General Public License for more details.
  */
 
+/*
+ * This file contains regulator configuration and mappings for targets
+ * consisting of MSM8930 and PM8038.
+ */
+
 #include <linux/regulator/pm8xxx-regulator.h>
 
 #include "board-8930.h"
@@ -449,17 +454,17 @@
 
 /* GPIO regulator constraints */
 struct gpio_regulator_platform_data
-msm8930_gpio_regulator_pdata[] __devinitdata = {
+msm8930_pm8038_gpio_regulator_pdata[] __devinitdata = {
 	/*        ID          vreg_name     gpio_label     gpio  supply */
 	GPIO_VREG(EXT_5V,     "ext_5v",     "ext_5v_en",     63, NULL),
 	GPIO_VREG(EXT_OTG_SW, "ext_otg_sw", "ext_otg_sw_en", 97, "ext_5v"),
 };
 
 /* SAW regulator constraints */
-struct regulator_init_data msm8930_saw_regulator_core0_pdata =
+struct regulator_init_data msm8930_pm8038_saw_regulator_core0_pdata =
 	/*	      ID  vreg_name	       min_uV   max_uV */
 	SAW_VREG_INIT(S5, "8038_s5",	       850000, 1300000);
-struct regulator_init_data msm8930_saw_regulator_core1_pdata =
+struct regulator_init_data msm8930_pm8038_saw_regulator_core1_pdata =
 	SAW_VREG_INIT(S6, "8038_s6",	       850000, 1300000);
 
 /* PM8038 regulator constraints */
@@ -558,7 +563,8 @@
 	RPM_REG_MAP(VDD_DIG_CORNER, 0, 2, "krait1_dig",   "acpuclk-8930aa"),
 };
 
-struct rpm_regulator_platform_data msm8930_rpm_regulator_pdata __devinitdata = {
+struct rpm_regulator_platform_data
+msm8930_pm8038_rpm_regulator_pdata __devinitdata = {
 	.init_data		= msm8930_rpm_regulator_init_data,
 	.num_regulators		= ARRAY_SIZE(msm8930_rpm_regulator_init_data),
 	.version		= RPM_VREG_VERSION_8930,
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
similarity index 72%
copy from arch/arm/mach-msm/board-8930-regulator.c
copy to arch/arm/mach-msm/board-8930-regulator-pm8917.c
index d4bd18f..db40e5d 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,6 +11,11 @@
  * GNU General Public License for more details.
  */
 
+/*
+ * This file contains regulator configuration and mappings for targets
+ * consisting of MSM8930 and PM8917.
+ */
+
 #include <linux/regulator/pm8xxx-regulator.h>
 
 #include "board-8930.h"
@@ -23,11 +28,10 @@
  *			 regulator name		consumer dev_name
  */
 VREG_CONSUMERS(L1) = {
-	REGULATOR_SUPPLY("8038_l1",		NULL),
-	REGULATOR_SUPPLY("iris_vddrfa",		"wcnss_wlan.0"),
+	REGULATOR_SUPPLY("8917_l1",		NULL),
 };
 VREG_CONSUMERS(L2) = {
-	REGULATOR_SUPPLY("8038_l2",		NULL),
+	REGULATOR_SUPPLY("8917_l2",		NULL),
 	REGULATOR_SUPPLY("iris_vdddig",		"wcnss_wlan.0"),
 	REGULATOR_SUPPLY("dsi_vdda",		"mipi_dsi.1"),
 	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.0"),
@@ -35,53 +39,152 @@
 	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.2"),
 };
 VREG_CONSUMERS(L3) = {
-	REGULATOR_SUPPLY("8038_l3",		NULL),
+	REGULATOR_SUPPLY("8917_l3",		NULL),
 	REGULATOR_SUPPLY("HSUSB_3p3",		"msm_otg"),
 };
 VREG_CONSUMERS(L4) = {
-	REGULATOR_SUPPLY("8038_l4",		NULL),
+	REGULATOR_SUPPLY("8917_l4",		NULL),
 	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_otg"),
 	REGULATOR_SUPPLY("iris_vddxo",		"wcnss_wlan.0"),
 };
 VREG_CONSUMERS(L5) = {
-	REGULATOR_SUPPLY("8038_l5",		NULL),
+	REGULATOR_SUPPLY("8917_l5",		NULL),
 	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.1"),
 };
 VREG_CONSUMERS(L6) = {
-	REGULATOR_SUPPLY("8038_l6",		NULL),
+	REGULATOR_SUPPLY("8917_l6",		NULL),
 	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.3"),
 };
 VREG_CONSUMERS(L7) = {
-	REGULATOR_SUPPLY("8038_l7",		NULL),
+	REGULATOR_SUPPLY("8917_l7",		NULL),
+	REGULATOR_SUPPLY("sdc_vdd_io",		"msm_sdcc.3"),
 };
 VREG_CONSUMERS(L8) = {
-	REGULATOR_SUPPLY("8038_l8",		NULL),
+	REGULATOR_SUPPLY("8917_l8",		NULL),
 	REGULATOR_SUPPLY("dsi_vdc",		"mipi_dsi.1"),
 };
 VREG_CONSUMERS(L9) = {
-	REGULATOR_SUPPLY("8038_l9",		NULL),
+	REGULATOR_SUPPLY("8917_l9",		NULL),
 	REGULATOR_SUPPLY("vdd_ana",		"3-004a"),
 	REGULATOR_SUPPLY("vdd",			"3-0024"),
-	REGULATOR_SUPPLY("cam_vana",		"4-001a"),
-	REGULATOR_SUPPLY("cam_vana",		"4-006c"),
-	REGULATOR_SUPPLY("cam_vana",		"4-0048"),
-	REGULATOR_SUPPLY("cam_vaf",		"4-001a"),
-	REGULATOR_SUPPLY("cam_vaf",		"4-006c"),
-	REGULATOR_SUPPLY("cam_vaf",		"4-0048"),
-	REGULATOR_SUPPLY("cam_vana",            "4-0020"),
-	REGULATOR_SUPPLY("cam_vaf",             "4-0020"),
 	REGULATOR_SUPPLY("vdd",			"12-0018"),
 	REGULATOR_SUPPLY("vdd",			"12-0068"),
 };
 VREG_CONSUMERS(L10) = {
-	REGULATOR_SUPPLY("8038_l10",		NULL),
+	REGULATOR_SUPPLY("8917_l10",		NULL),
 	REGULATOR_SUPPLY("iris_vddpa",		"wcnss_wlan.0"),
 };
 VREG_CONSUMERS(L11) = {
-	REGULATOR_SUPPLY("8038_l11",		NULL),
+	REGULATOR_SUPPLY("8917_l11",		NULL),
+	REGULATOR_SUPPLY("cam_vana",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vana",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vana",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vana",            "4-0020"),
+};
+VREG_CONSUMERS(L12) = {
+	REGULATOR_SUPPLY("8917_l12",		NULL),
+	REGULATOR_SUPPLY("cam_vdig",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vdig",            "4-0020"),
+};
+VREG_CONSUMERS(L14) = {
+	REGULATOR_SUPPLY("8917_l14",		NULL),
+	REGULATOR_SUPPLY("pa_therm",		"pm8xxx-adc"),
+};
+VREG_CONSUMERS(L15) = {
+	REGULATOR_SUPPLY("8917_l15",		NULL),
+};
+VREG_CONSUMERS(L16) = {
+	REGULATOR_SUPPLY("8917_l16",		NULL),
+	REGULATOR_SUPPLY("cam_vaf",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vaf",             "4-0020"),
+};
+VREG_CONSUMERS(L17) = {
+	REGULATOR_SUPPLY("8917_l17",		NULL),
+};
+VREG_CONSUMERS(L18) = {
+	REGULATOR_SUPPLY("8917_l18",		NULL),
+};
+VREG_CONSUMERS(L21) = {
+	REGULATOR_SUPPLY("8917_l21",		NULL),
+};
+VREG_CONSUMERS(L22) = {
+	REGULATOR_SUPPLY("8917_l22",		NULL),
+};
+VREG_CONSUMERS(L23) = {
+	REGULATOR_SUPPLY("8917_l23",		NULL),
+	REGULATOR_SUPPLY("dsi_vddio",		"mipi_dsi.1"),
+	REGULATOR_SUPPLY("hdmi_avdd",		"hdmi_msm.0"),
+	REGULATOR_SUPPLY("hdmi_vcc",		"hdmi_msm.0"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_riva"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.1"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.2"),
+};
+VREG_CONSUMERS(L24) = {
+	REGULATOR_SUPPLY("8917_l24",		NULL),
+	REGULATOR_SUPPLY("riva_vddmx",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(L25) = {
+	REGULATOR_SUPPLY("8917_l25",		NULL),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"sitar-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"sitar-slim"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"sitar1p1-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"sitar1p1-slim"),
+	REGULATOR_SUPPLY("mhl_avcc12",		"0-0039"),
+};
+VREG_CONSUMERS(L26) = {
+	REGULATOR_SUPPLY("8921_l26",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.0"),
+};
+VREG_CONSUMERS(L27) = {
+	REGULATOR_SUPPLY("8921_l27",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.2"),
+};
+VREG_CONSUMERS(L28) = {
+	REGULATOR_SUPPLY("8921_l28",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.1"),
+};
+VREG_CONSUMERS(L29) = {
+	REGULATOR_SUPPLY("8921_l29",		NULL),
+};
+VREG_CONSUMERS(L30) = {
+	REGULATOR_SUPPLY("8917_l30",		NULL),
+};
+VREG_CONSUMERS(L31) = {
+	REGULATOR_SUPPLY("8917_l31",		NULL),
+};
+VREG_CONSUMERS(L32) = {
+	REGULATOR_SUPPLY("8917_l32",		NULL),
+};
+VREG_CONSUMERS(L33) = {
+	REGULATOR_SUPPLY("8917_l33",		NULL),
+};
+VREG_CONSUMERS(L34) = {
+	REGULATOR_SUPPLY("8917_l34",		NULL),
+};
+VREG_CONSUMERS(L35) = {
+	REGULATOR_SUPPLY("8917_l35",		NULL),
+};
+VREG_CONSUMERS(L36) = {
+	REGULATOR_SUPPLY("8917_l36",		NULL),
+};
+VREG_CONSUMERS(S1) = {
+	REGULATOR_SUPPLY("8917_s1",		NULL),
+};
+VREG_CONSUMERS(S2) = {
+	REGULATOR_SUPPLY("8917_s2",		NULL),
+	REGULATOR_SUPPLY("iris_vddrfa",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(S3) = {
+	REGULATOR_SUPPLY("8917_s3",		NULL),
+	REGULATOR_SUPPLY("riva_vddcx",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(S4) = {
+	REGULATOR_SUPPLY("8917_s4",		NULL),
 	REGULATOR_SUPPLY("vdd_dig",		"3-004a"),
-	REGULATOR_SUPPLY("iris_vddio",		"wcnss_wlan.0"),
-	REGULATOR_SUPPLY("riva_vddpx",		"wcnss_wlan.0"),
 	REGULATOR_SUPPLY("sdc_vdd_io",		"msm_sdcc.1"),
 	REGULATOR_SUPPLY("VDDIO_CDC",		"sitar-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_TX",		"sitar-slim"),
@@ -91,132 +194,71 @@
 	REGULATOR_SUPPLY("CDC_VDDA_RX",		"sitar1p1-slim"),
 	REGULATOR_SUPPLY("vddp",		"0-0048"),
 	REGULATOR_SUPPLY("mhl_iovcc18",		"0-0039"),
-};
-VREG_CONSUMERS(L12) = {
-	REGULATOR_SUPPLY("8038_l12",		NULL),
-	REGULATOR_SUPPLY("cam_vdig",		"4-001a"),
-	REGULATOR_SUPPLY("cam_vdig",		"4-006c"),
-	REGULATOR_SUPPLY("cam_vdig",		"4-0048"),
-	REGULATOR_SUPPLY("cam_vdig",            "4-0020"),
-};
-VREG_CONSUMERS(L13) = {
-	REGULATOR_SUPPLY("8038_l13",		NULL),
-};
-VREG_CONSUMERS(L14) = {
-	REGULATOR_SUPPLY("8038_l14",		NULL),
-	REGULATOR_SUPPLY("pa_therm",		"pm8xxx-adc"),
-};
-VREG_CONSUMERS(L15) = {
-	REGULATOR_SUPPLY("8038_l15",		NULL),
-};
-VREG_CONSUMERS(L16) = {
-	REGULATOR_SUPPLY("8038_l16",		NULL),
-	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.2"),
-};
-VREG_CONSUMERS(L17) = {
-	REGULATOR_SUPPLY("8038_l17",		NULL),
-};
-VREG_CONSUMERS(L18) = {
-	REGULATOR_SUPPLY("8038_l18",		NULL),
-};
-VREG_CONSUMERS(L19) = {
-	REGULATOR_SUPPLY("8038_l19",		NULL),
-	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.1"),
-};
-VREG_CONSUMERS(L20) = {
-	REGULATOR_SUPPLY("8038_l20",		NULL),
-	REGULATOR_SUPPLY("VDDD_CDC_D",		"sitar-slim"),
-	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"sitar-slim"),
-	REGULATOR_SUPPLY("VDDD_CDC_D",		"sitar1p1-slim"),
-	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"sitar1p1-slim"),
-	REGULATOR_SUPPLY("mhl_avcc12",		"0-0039"),
-};
-VREG_CONSUMERS(L21) = {
-	REGULATOR_SUPPLY("8038_l21",		NULL),
-};
-VREG_CONSUMERS(L22) = {
-	REGULATOR_SUPPLY("8038_l22",		NULL),
-	REGULATOR_SUPPLY("sdc_vdd_io",		"msm_sdcc.3"),
-};
-VREG_CONSUMERS(L23) = {
-	REGULATOR_SUPPLY("8038_l23",		NULL),
-	REGULATOR_SUPPLY("dsi_vddio",		"mipi_dsi.1"),
-	REGULATOR_SUPPLY("hdmi_avdd",		"hdmi_msm.0"),
-	REGULATOR_SUPPLY("hdmi_vcc",		"hdmi_msm.0"),
-	REGULATOR_SUPPLY("pll_vdd",		"pil_riva"),
-	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.1"),
-	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.2"),
-};
-VREG_CONSUMERS(L24) = {
-	REGULATOR_SUPPLY("8038_l24",		NULL),
-	REGULATOR_SUPPLY("riva_vddmx",		"wcnss_wlan.0"),
-};
-VREG_CONSUMERS(L25) = {
-	REGULATOR_SUPPLY("8038_l25",		NULL),
-};
-VREG_CONSUMERS(L26) = {
-	REGULATOR_SUPPLY("8038_l26",		NULL),
-};
-VREG_CONSUMERS(L27) = {
-	REGULATOR_SUPPLY("8038_l27",		NULL),
-	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.0"),
-};
-VREG_CONSUMERS(S1) = {
-	REGULATOR_SUPPLY("8038_s1",		NULL),
-	REGULATOR_SUPPLY("riva_vddcx",		"wcnss_wlan.0"),
-};
-VREG_CONSUMERS(S2) = {
-	REGULATOR_SUPPLY("8038_s2",		NULL),
-};
-VREG_CONSUMERS(S3) = {
-	REGULATOR_SUPPLY("8038_s3",		NULL),
-};
-VREG_CONSUMERS(S4) = {
-	REGULATOR_SUPPLY("8038_s4",		NULL),
 	REGULATOR_SUPPLY("CDC_VDD_CP",		"sitar-slim"),
 	REGULATOR_SUPPLY("CDC_VDD_CP",		"sitar1p1-slim"),
 };
 VREG_CONSUMERS(S5) = {
-	REGULATOR_SUPPLY("8038_s5",		NULL),
+	REGULATOR_SUPPLY("8917_s5",		NULL),
 	REGULATOR_SUPPLY("krait0",		"acpuclk-8627"),
 	REGULATOR_SUPPLY("krait0",		"acpuclk-8930"),
 	REGULATOR_SUPPLY("krait0",		"acpuclk-8930aa"),
 };
 VREG_CONSUMERS(S6) = {
-	REGULATOR_SUPPLY("8038_s6",		NULL),
+	REGULATOR_SUPPLY("8917_s6",		NULL),
 	REGULATOR_SUPPLY("krait1",		"acpuclk-8627"),
 	REGULATOR_SUPPLY("krait1",		"acpuclk-8930"),
 	REGULATOR_SUPPLY("krait1",		"acpuclk-8930aa"),
 };
-VREG_CONSUMERS(LVS1) = {
-	REGULATOR_SUPPLY("8038_lvs1",		NULL),
-	REGULATOR_SUPPLY("cam_vio",		"4-001a"),
-	REGULATOR_SUPPLY("cam_vio",		"4-006c"),
-	REGULATOR_SUPPLY("cam_vio",		"4-0048"),
-	REGULATOR_SUPPLY("cam_vio",             "4-0020"),
+VREG_CONSUMERS(S7) = {
+	REGULATOR_SUPPLY("8917_s7",		NULL),
 };
-VREG_CONSUMERS(LVS2) = {
-	REGULATOR_SUPPLY("8038_lvs2",		NULL),
+VREG_CONSUMERS(S8) = {
+	REGULATOR_SUPPLY("8917_s8",		NULL),
+};
+VREG_CONSUMERS(LVS1) = {
+	REGULATOR_SUPPLY("8917_lvs1",		NULL),
+	REGULATOR_SUPPLY("iris_vddio",		"wcnss_wlan.0"),
+	REGULATOR_SUPPLY("riva_vddpx",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(LVS3) = {
+	REGULATOR_SUPPLY("8917_lvs3",		NULL),
+};
+VREG_CONSUMERS(LVS4) = {
+	REGULATOR_SUPPLY("8917_lvs4",		NULL),
 	REGULATOR_SUPPLY("vcc_i2c",		"3-004a"),
 	REGULATOR_SUPPLY("vcc_i2c",		"3-0024"),
 	REGULATOR_SUPPLY("vcc_i2c",		"0-0048"),
 	REGULATOR_SUPPLY("vddio",		"12-0018"),
 	REGULATOR_SUPPLY("vlogic",		"12-0068"),
 };
-VREG_CONSUMERS(EXT_5V) = {
-	REGULATOR_SUPPLY("ext_5v",		NULL),
+VREG_CONSUMERS(LVS5) = {
+	REGULATOR_SUPPLY("8917_lvs5",		NULL),
+	REGULATOR_SUPPLY("cam_vio",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vio",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vio",             "4-0020"),
+};
+VREG_CONSUMERS(LVS6) = {
+	REGULATOR_SUPPLY("8917_lvs6",		NULL),
+};
+VREG_CONSUMERS(LVS7) = {
+	REGULATOR_SUPPLY("8917_lvs7",		NULL),
+};
+VREG_CONSUMERS(USB_OTG) = {
+	REGULATOR_SUPPLY("8921_usb_otg",	NULL),
+	REGULATOR_SUPPLY("vbus_otg",		"msm_otg"),
+};
+VREG_CONSUMERS(BOOST) = {
+	REGULATOR_SUPPLY("8917_boost",		NULL),
 	REGULATOR_SUPPLY("hdmi_mvs",		"hdmi_msm.0"),
 	REGULATOR_SUPPLY("mhl_usb_hs_switch",	"msm_otg"),
 };
-VREG_CONSUMERS(EXT_OTG_SW) = {
-	REGULATOR_SUPPLY("ext_otg_sw",		NULL),
-	REGULATOR_SUPPLY("vbus_otg",		"msm_otg"),
-};
 VREG_CONSUMERS(VDD_DIG_CORNER) = {
 	REGULATOR_SUPPLY("vdd_dig_corner",	NULL),
 	REGULATOR_SUPPLY("hsusb_vdd_dig",	"msm_otg"),
 };
 
+
 #define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
 			 _apply_uV, _pull_down, _always_on, _supply_regulator, \
 			 _system_uA, _enable_time, _reg_id) \
@@ -286,7 +328,7 @@
 		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
 		_reg_id)
 
-#define PM8XXX_NCP(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
+#define PM8XXX_BOOST(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
 		_supply_regulator, _reg_id) \
 	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
 		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
@@ -332,7 +374,7 @@
 			.consumer_supplies	= vreg_consumers_##_id, \
 			.supply_regulator	= _supply_regulator, \
 		}, \
-		.id			= RPM_VREG_ID_PM8038_##_id, \
+		.id			= RPM_VREG_ID_PM8917_##_id, \
 		.default_uV		= _default_uV, \
 		.peak_uA		= _peak_uA, \
 		.avg_uA			= _avg_uA, \
@@ -414,7 +456,7 @@
 			.consumer_supplies	= vreg_consumers_##_id##_PC, \
 			.supply_regulator	= _supply_regulator, \
 		}, \
-		.id	  = RPM_VREG_ID_PM8038_##_id##_PC, \
+		.id	  = RPM_VREG_ID_PM8917_##_id##_PC, \
 		.pin_fn	  = RPM_VREG_PIN_FN_8930_##_pin_fn, \
 		.pin_ctrl = _pin_ctrl, \
 	}
@@ -449,93 +491,122 @@
 
 /* GPIO regulator constraints */
 struct gpio_regulator_platform_data
-msm8930_gpio_regulator_pdata[] __devinitdata = {
+msm8930_pm8917_gpio_regulator_pdata[] __devinitdata = {
 	/*        ID          vreg_name     gpio_label     gpio  supply */
-	GPIO_VREG(EXT_5V,     "ext_5v",     "ext_5v_en",     63, NULL),
-	GPIO_VREG(EXT_OTG_SW, "ext_otg_sw", "ext_otg_sw_en", 97, "ext_5v"),
 };
 
 /* SAW regulator constraints */
-struct regulator_init_data msm8930_saw_regulator_core0_pdata =
+struct regulator_init_data msm8930_pm8917_saw_regulator_core0_pdata =
 	/*	      ID  vreg_name	       min_uV   max_uV */
-	SAW_VREG_INIT(S5, "8038_s5",	       850000, 1300000);
-struct regulator_init_data msm8930_saw_regulator_core1_pdata =
-	SAW_VREG_INIT(S6, "8038_s6",	       850000, 1300000);
+	SAW_VREG_INIT(S5, "8917_s5",	       850000, 1300000);
+struct regulator_init_data msm8930_pm8917_saw_regulator_core1_pdata =
+	SAW_VREG_INIT(S6, "8917_s6",	       850000, 1300000);
 
-/* PM8038 regulator constraints */
+/* PM8917 regulator constraints */
 struct pm8xxx_regulator_platform_data
-msm8930_pm8038_regulator_pdata[] __devinitdata = {
+msm8930_pm8917_regulator_pdata[] __devinitdata = {
 	/*
-	 *	    ID  name always_on pd min_uV   max_uV   en_t supply
+	 *               ID  name always_on pd min_uV   max_uV   en_t supply
 	 *	system_uA reg_ID
 	 */
-	PM8XXX_NLDO1200(L16, "8038_l16", 0, 1, 375000, 1050000, 200, "8038_s3",
+	PM8XXX_NLDO1200(L26, "8921_l26", 0, 1,  375000, 1050000, 200, "8917_s7",
 		0, 0),
-	PM8XXX_NLDO1200(L19, "8038_l19", 0, 1, 375000, 1050000, 200, "8038_s3",
+	PM8XXX_NLDO1200(L27, "8921_l27", 0, 1,  375000, 1050000, 200, "8917_s7",
 		0, 1),
-	PM8XXX_NLDO1200(L27, "8038_l27", 0, 1, 375000, 1050000, 200, "8038_s3",
+	PM8XXX_NLDO1200(L28, "8921_l28", 0, 1,  375000, 1050000, 200, "8917_s7",
 		0, 2),
+	PM8XXX_LDO(L29,      "8921_l29", 0, 1, 1800000, 1800000, 200, "8917_s8",
+		0, 3),
+	PM8XXX_LDO(L30,      "8917_l30", 0, 1, 1800000, 1800000, 200, NULL,
+		0, 4),
+	PM8XXX_LDO(L31,      "8917_l31", 0, 1, 1800000, 1800000, 200, NULL,
+		0, 5),
+	PM8XXX_LDO(L32,      "8917_l32", 0, 1, 2800000, 2800000, 200, NULL,
+		0, 6),
+	PM8XXX_LDO(L33,      "8917_l33", 0, 1, 2800000, 2800000, 200, NULL,
+		0, 7),
+	PM8XXX_LDO(L34,      "8917_l34", 0, 1, 1800000, 1800000, 200, NULL,
+		0, 8),
+	PM8XXX_LDO(L35,      "8917_l35", 0, 1, 3000000, 3000000, 200, NULL,
+		0, 9),
+	PM8XXX_LDO(L36,      "8917_l36", 0, 1, 1800000, 1800000, 200, NULL,
+		0, 10),
+	/*
+	 *           ID     name  always_on   min_uV   max_uV en_t supply reg_ID
+	 */
+	PM8XXX_BOOST(BOOST, "8917_boost", 0,  5000000, 5000000, 500, NULL, 11),
+
+	/*	     ID        name      always_on pd en_t supply    reg_ID */
+	PM8XXX_VS300(USB_OTG,  "8921_usb_otg",  0, 1, 0,   "8917_boost", 12),
 };
 
 static struct rpm_regulator_init_data
 msm8930_rpm_regulator_init_data[] __devinitdata = {
 	/*	ID a_on pd ss min_uV   max_uV  supply sys_uA  freq  fm  ss_fm */
-	RPM_SMPS(S1, 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80, AUTO, LPM),
-	RPM_SMPS(S2, 1, 1, 1, 1400000, 1400000, NULL, 100000, 1p60, AUTO, LPM),
-	RPM_SMPS(S3, 0, 1, 1, 1150000, 1150000, NULL, 100000, 3p20, AUTO, LPM),
-	RPM_SMPS(S4, 1, 1, 1, 1950000, 2200000, NULL, 100000, 1p60, AUTO, LPM),
+	RPM_SMPS(S1, 1, 1, 0, 1300000, 1300000, NULL, 100000, 3p20, NONE, NONE),
+	RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL,      0, 1p60, NONE, NONE),
+	RPM_SMPS(S3, 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80, AUTO, LPM),
+	RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60, AUTO, LPM),
+	RPM_SMPS(S7, 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20, NONE, NONE),
+	RPM_SMPS(S8, 1, 1, 1, 2050000, 2050000, NULL, 100000, 1p60, NONE, NONE),
 
 	/*	ID     a_on pd ss min_uV   max_uV  supply  sys_uA init_ip */
-	RPM_LDO(L1,	 0, 1, 0, 1300000, 1300000, "8038_s2", 0, 0),
-	RPM_LDO(L2,	 0, 1, 0, 1200000, 1200000, "8038_s2", 0, 0),
+	RPM_LDO(L1,	 1, 1, 0, 1050000, 1050000, "8917_s4", 0, 10000),
+	RPM_LDO(L2,	 0, 1, 0, 1200000, 1200000, "8917_s4", 0, 0),
 	RPM_LDO(L3,	 0, 1, 0, 3075000, 3075000, NULL,      0, 0),
 	RPM_LDO(L4,	 1, 1, 0, 1800000, 1800000, NULL,      10000, 10000),
 	RPM_LDO(L5,	 0, 1, 0, 2950000, 2950000, NULL,      0, 0),
 	RPM_LDO(L6,	 0, 1, 0, 2950000, 2950000, NULL,      0, 0),
-	RPM_LDO(L7,	 0, 1, 0, 2050000, 2050000, "8038_s4", 0, 0),
+	RPM_LDO(L7,	 1, 1, 0, 1850000, 2950000, NULL,      10000, 10000),
 	RPM_LDO(L8,	 0, 1, 0, 2800000, 2800000, NULL,      0, 0),
 	RPM_LDO(L9,	 0, 1, 0, 2850000, 2850000, NULL,      0, 0),
 	RPM_LDO(L10,	 0, 1, 0, 2900000, 2900000, NULL,      0, 0),
-	RPM_LDO(L11,	 1, 1, 0, 1800000, 1800000, "8038_s4", 10000, 10000),
-	RPM_LDO(L12,	 0, 1, 0, 1200000, 1200000, "8038_s2", 0, 0),
-	RPM_LDO(L13,	 0, 0, 0, 2220000, 2220000, NULL,      0, 0),
+	RPM_LDO(L11,	 0, 1, 0, 2850000, 2850000, NULL,      0, 0),
+	RPM_LDO(L12,	 0, 1, 0, 1200000, 1200000, "8917_s4", 0, 0),
 	RPM_LDO(L14,	 0, 1, 0, 1800000, 1800000, NULL,      0, 0),
 	RPM_LDO(L15,	 0, 1, 0, 1800000, 2950000, NULL,      0, 0),
+	RPM_LDO(L16,	 0, 1, 0, 2850000, 2850000, NULL,      0, 0),
 	RPM_LDO(L17,	 0, 1, 0, 1800000, 2950000, NULL,      0, 0),
-	RPM_LDO(L18,	 0, 1, 0, 1800000, 1800000, NULL,      0, 0),
-	RPM_LDO(L20,	 1, 1, 0, 1250000, 1250000, "8038_s2", 10000, 10000),
-	RPM_LDO(L21,	 0, 1, 0, 1900000, 1900000, "8038_s4", 0, 0),
-	RPM_LDO(L22,	 1, 1, 0, 1850000, 2950000, NULL,      10000, 10000),
-	RPM_LDO(L23,	 1, 1, 1, 1800000, 1800000, "8038_s4", 0, 0),
-	RPM_LDO(L24,	 0, 1, 1,  500000, 1150000, "8038_s2", 10000, 10000),
-	RPM_LDO(L25,	 0, 0, 0, 1740000, 1740000, "8038_l13", 0, 0),
-	RPM_LDO(L26,     1, 1, 0, 1050000, 1050000, "8038_s2", 10000, 10000),
+	RPM_LDO(L18,	 0, 1, 0, 1200000, 1200000, "8917_s4", 0, 0),
+	RPM_LDO(L21,	 0, 1, 0, 1900000, 1900000, "8917_s8", 0, 0),
+	RPM_LDO(L22,	 0, 1, 0, 2750000, 2750000, NULL,      0, 0),
+	RPM_LDO(L23,	 1, 1, 1, 1800000, 1800000, "8917_s8", 10000, 10000),
+	RPM_LDO(L24,	 0, 1, 1,  500000, 1150000, "8917_s1", 10000, 10000),
+	RPM_LDO(L25,	 1, 1, 0, 1250000, 1250000, "8917_s1", 10000, 10000),
 
 	/*	ID     a_on pd ss		    supply */
-	RPM_VS(LVS1,	 0, 1, 0,		    "8038_l11"),
-	RPM_VS(LVS2,	 0, 1, 0,		    "8038_l11"),
+	RPM_VS(LVS1,	 0, 1, 0,		    "8917_s4"),
+	RPM_VS(LVS3,	 0, 1, 0,		    "8917_s4"),
+	RPM_VS(LVS4,	 0, 1, 0,		    "8917_s4"),
+	RPM_VS(LVS5,	 0, 1, 0,		    "8917_s4"),
+	RPM_VS(LVS6,	 0, 1, 0,		    "8917_s4"),
+	RPM_VS(LVS7,	 0, 1, 0,		    "8917_s4"),
 
 	/*	   ID            a_on ss min_corner  max_corner  supply */
 	RPM_CORNER(VDD_DIG_CORNER, 0, 1, RPM_VREG_CORNER_NONE,
 		RPM_VREG_CORNER_HIGH, NULL),
 };
 
-int msm8930_pm8038_regulator_pdata_len __devinitdata =
-	ARRAY_SIZE(msm8930_pm8038_regulator_pdata);
+int msm8930_pm8917_regulator_pdata_len __devinitdata =
+	ARRAY_SIZE(msm8930_pm8917_regulator_pdata);
 
 #define RPM_REG_MAP(_id, _sleep_also, _voter, _supply, _dev_name) \
 	{ \
-		.vreg_id = RPM_VREG_ID_PM8038_##_id, \
+		.vreg_id = RPM_VREG_ID_PM8917_##_id, \
 		.sleep_also = _sleep_also, \
 		.voter = _voter, \
 		.supply = _supply, \
 		.dev_name = _dev_name, \
 	}
+
 static struct rpm_regulator_consumer_mapping
 	      msm_rpm_regulator_consumer_mapping[] __devinitdata = {
-	RPM_REG_MAP(L23,            0, 1, "krait0_hfpll", "acpuclk-8930"),
-	RPM_REG_MAP(L23,            0, 2, "krait1_hfpll", "acpuclk-8930"),
-	RPM_REG_MAP(L23,            0, 6, "l2_hfpll",     "acpuclk-8930"),
+	RPM_REG_MAP(L23,            0, 1, "krait0_l23",   "acpuclk-8930"),
+	RPM_REG_MAP(S8,             0, 1, "krait0_s8",    "acpuclk-8930"),
+	RPM_REG_MAP(L23,            0, 2, "krait1_l23",   "acpuclk-8930"),
+	RPM_REG_MAP(S8,             0, 2, "krait1_s8",    "acpuclk-8930"),
+	RPM_REG_MAP(L23,            0, 6, "l2_l23",       "acpuclk-8930"),
+	RPM_REG_MAP(S8,             0, 6, "l2_s8",        "acpuclk-8930"),
 	RPM_REG_MAP(L24,            0, 1, "krait0_mem",   "acpuclk-8930"),
 	RPM_REG_MAP(L24,            0, 2, "krait1_mem",   "acpuclk-8930"),
 	RPM_REG_MAP(VDD_DIG_CORNER, 0, 1, "krait0_dig",   "acpuclk-8930"),
@@ -558,12 +629,13 @@
 	RPM_REG_MAP(VDD_DIG_CORNER, 0, 2, "krait1_dig",   "acpuclk-8930aa"),
 };
 
-struct rpm_regulator_platform_data msm8930_rpm_regulator_pdata __devinitdata = {
+struct rpm_regulator_platform_data
+msm8930_pm8917_rpm_regulator_pdata __devinitdata = {
 	.init_data		= msm8930_rpm_regulator_init_data,
 	.num_regulators		= ARRAY_SIZE(msm8930_rpm_regulator_init_data),
-	.version		= RPM_VREG_VERSION_8930,
-	.vreg_id_vdd_mem	= RPM_VREG_ID_PM8038_L24,
-	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8038_VDD_DIG_CORNER,
+	.version		= RPM_VREG_VERSION_8930_PM8917,
+	.vreg_id_vdd_mem	= RPM_VREG_ID_PM8917_L24,
+	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8917_VDD_DIG_CORNER,
 	.consumer_map		= msm_rpm_regulator_consumer_mapping,
 	.consumer_map_len = ARRAY_SIZE(msm_rpm_regulator_consumer_mapping),
 };
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index a7147b5..2b1c665 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -100,6 +100,7 @@
 #include "pm-boot.h"
 #include "msm_watchdog.h"
 #include "board-8930.h"
+#include "acpuclock-krait.h"
 
 static struct platform_device msm_fm_platform_init = {
 	.name = "iris_fm",
@@ -791,7 +792,7 @@
 	.regulator = {
 	{
 		.name = "CDC_VDD_CP",
-		.min_uV = 1950000,
+		.min_uV = 1800000,
 		.max_uV = 2200000,
 		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
 	},
@@ -857,7 +858,7 @@
 	.regulator = {
 	{
 		.name = "CDC_VDD_CP",
-		.min_uV = 1950000,
+		.min_uV = 1800000,
 		.max_uV = 2200000,
 		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
 	},
@@ -1656,18 +1657,26 @@
 
 #define ISA1200_HAP_EN_GPIO	77
 #define ISA1200_HAP_LEN_GPIO	78
-#define ISA1200_HAP_CLK		PM8038_GPIO_PM_TO_SYS(7)
+#define ISA1200_HAP_CLK_PM8038	PM8038_GPIO_PM_TO_SYS(7)
+#define ISA1200_HAP_CLK_PM8917	PM8917_GPIO_PM_TO_SYS(38)
 
 static int isa1200_power(int on)
 {
+	unsigned int gpio = ISA1200_HAP_CLK_PM8038;
+	enum pm8xxx_aux_clk_id clk_id = CLK_MP3_1;
 	int rc = 0;
 
-	gpio_set_value_cansleep(ISA1200_HAP_CLK, !!on);
+	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917) {
+		gpio = ISA1200_HAP_CLK_PM8917;
+		clk_id = CLK_MP3_2;
+	}
+
+	gpio_set_value_cansleep(gpio, !!on);
 
 	if (on)
-		rc = pm8xxx_aux_clk_control(CLK_MP3_1, XO_DIV_1, true);
+		rc = pm8xxx_aux_clk_control(clk_id, XO_DIV_1, true);
 	else
-		rc = pm8xxx_aux_clk_control(CLK_MP3_1, XO_DIV_NONE, true);
+		rc = pm8xxx_aux_clk_control(clk_id, XO_DIV_NONE, true);
 
 	if (rc) {
 		pr_err("%s: unable to write aux clock register(%d)\n",
@@ -1679,29 +1688,33 @@
 
 static int isa1200_dev_setup(bool enable)
 {
+	unsigned int gpio = ISA1200_HAP_CLK_PM8038;
 	int rc = 0;
 
+	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+		gpio = ISA1200_HAP_CLK_PM8917;
+
 	if (!enable)
 		goto fail_gpio_dir;
 
-	rc = gpio_request(ISA1200_HAP_CLK, "haptics_clk");
+	rc = gpio_request(gpio, "haptics_clk");
 	if (rc) {
 		pr_err("%s: gpio_request for %d gpio failed rc(%d)\n",
-					__func__, ISA1200_HAP_CLK, rc);
+					__func__, gpio, rc);
 		goto fail_gpio_req;
 	}
 
-	rc = gpio_direction_output(ISA1200_HAP_CLK, 0);
+	rc = gpio_direction_output(gpio, 0);
 	if (rc) {
 		pr_err("%s: gpio_direction_output failed for %d gpio rc(%d)\n",
-						__func__, ISA1200_HAP_CLK, rc);
+						__func__, gpio, rc);
 		goto fail_gpio_dir;
 	}
 
 	return 0;
 
 fail_gpio_dir:
-	gpio_free(ISA1200_HAP_CLK);
+	gpio_free(gpio);
 fail_gpio_req:
 	return rc;
 
@@ -1938,12 +1951,13 @@
 	},
 };
 
-#define MHL_POWER_GPIO       PM8038_GPIO_PM_TO_SYS(MHL_GPIO_PWR_EN)
+#define MHL_POWER_GPIO_PM8038	PM8038_GPIO_PM_TO_SYS(MHL_GPIO_PWR_EN)
+#define MHL_POWER_GPIO_PM8917	PM8917_GPIO_PM_TO_SYS(25)
 static struct msm_mhl_platform_data mhl_platform_data = {
 	.irq = MSM_GPIO_TO_INT(MHL_GPIO_INT),
 	.gpio_mhl_int = MHL_GPIO_INT,
 	.gpio_mhl_reset = MHL_GPIO_RESET,
-	.gpio_mhl_power = MHL_POWER_GPIO,
+	.gpio_mhl_power = MHL_POWER_GPIO_PM8038,
 	.gpio_hdmi_mhl_mux = HDMI_MHL_MUX_GPIO,
 };
 
@@ -1962,17 +1976,22 @@
 
 #ifdef MSM8930_PHASE_2
 
-#define GPIO_VOLUME_UP		PM8038_GPIO_PM_TO_SYS(3)
-#define GPIO_VOLUME_DOWN	PM8038_GPIO_PM_TO_SYS(8)
-#define GPIO_CAMERA_SNAPSHOT	PM8038_GPIO_PM_TO_SYS(10)
-#define GPIO_CAMERA_FOCUS	PM8038_GPIO_PM_TO_SYS(11)
+#define GPIO_VOLUME_UP_PM8038		PM8038_GPIO_PM_TO_SYS(3)
+#define GPIO_VOLUME_DOWN_PM8038		PM8038_GPIO_PM_TO_SYS(8)
+#define GPIO_CAMERA_SNAPSHOT_PM8038	PM8038_GPIO_PM_TO_SYS(10)
+#define GPIO_CAMERA_FOCUS_PM8038	PM8038_GPIO_PM_TO_SYS(11)
 
-static struct gpio_keys_button keys_8930[] = {
+#define GPIO_VOLUME_UP_PM8917		PM8917_GPIO_PM_TO_SYS(27)
+#define GPIO_VOLUME_DOWN_PM8917		PM8917_GPIO_PM_TO_SYS(28)
+#define GPIO_CAMERA_SNAPSHOT_PM8917	PM8917_GPIO_PM_TO_SYS(36)
+#define GPIO_CAMERA_FOCUS_PM8917	PM8917_GPIO_PM_TO_SYS(37)
+
+static struct gpio_keys_button keys_8930_pm8038[] = {
 	{
 		.code = KEY_VOLUMEUP,
 		.type = EV_KEY,
 		.desc = "volume_up",
-		.gpio = GPIO_VOLUME_UP,
+		.gpio = GPIO_VOLUME_UP_PM8038,
 		.wakeup = 1,
 		.active_low = 1,
 		.debounce_interval = 15,
@@ -1981,7 +2000,7 @@
 		.code = KEY_VOLUMEDOWN,
 		.type = EV_KEY,
 		.desc = "volume_down",
-		.gpio = GPIO_VOLUME_DOWN,
+		.gpio = GPIO_VOLUME_DOWN_PM8038,
 		.wakeup = 1,
 		.active_low = 1,
 		.debounce_interval = 15,
@@ -1990,7 +2009,7 @@
 		.code = KEY_CAMERA_FOCUS,
 		.type = EV_KEY,
 		.desc = "camera_focus",
-		.gpio = GPIO_CAMERA_FOCUS,
+		.gpio = GPIO_CAMERA_FOCUS_PM8038,
 		.wakeup = 1,
 		.active_low = 1,
 		.debounce_interval = 15,
@@ -1999,7 +2018,46 @@
 		.code = KEY_CAMERA_SNAPSHOT,
 		.type = EV_KEY,
 		.desc = "camera_snapshot",
-		.gpio = GPIO_CAMERA_SNAPSHOT,
+		.gpio = GPIO_CAMERA_SNAPSHOT_PM8038,
+		.wakeup = 1,
+		.active_low = 1,
+		.debounce_interval = 15,
+	},
+};
+
+static struct gpio_keys_button keys_8930_pm8917[] = {
+	{
+		.code = KEY_VOLUMEUP,
+		.type = EV_KEY,
+		.desc = "volume_up",
+		.gpio = GPIO_VOLUME_UP_PM8917,
+		.wakeup = 1,
+		.active_low = 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code = KEY_VOLUMEDOWN,
+		.type = EV_KEY,
+		.desc = "volume_down",
+		.gpio = GPIO_VOLUME_DOWN_PM8917,
+		.wakeup = 1,
+		.active_low = 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code = KEY_CAMERA_FOCUS,
+		.type = EV_KEY,
+		.desc = "camera_focus",
+		.gpio = GPIO_CAMERA_FOCUS_PM8917,
+		.wakeup = 1,
+		.active_low = 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code = KEY_CAMERA_SNAPSHOT,
+		.type = EV_KEY,
+		.desc = "camera_snapshot",
+		.gpio = GPIO_CAMERA_SNAPSHOT_PM8917,
 		.wakeup = 1,
 		.active_low = 1,
 		.debounce_interval = 15,
@@ -2008,8 +2066,8 @@
 
 /* Add GPIO keys for 8930 */
 static struct gpio_keys_platform_data gpio_keys_8930_pdata = {
-	.buttons = keys_8930,
-	.nbuttons = 4,
+	.buttons = keys_8930_pm8038,
+	.nbuttons = ARRAY_SIZE(keys_8930_pm8038),
 };
 
 static struct platform_device gpio_keys_8930 = {
@@ -2075,7 +2133,7 @@
 	.name	= "saw-regulator",
 	.id	= 0,
 	.dev	= {
-		.platform_data = &msm8930_saw_regulator_core0_pdata,
+		.platform_data = &msm8930_pm8038_saw_regulator_core0_pdata,
 	},
 };
 
@@ -2083,7 +2141,7 @@
 	.name	= "saw-regulator",
 	.id	= 1,
 	.dev	= {
-		.platform_data = &msm8930_saw_regulator_core1_pdata,
+		.platform_data = &msm8930_pm8038_saw_regulator_core1_pdata,
 	},
 };
 
@@ -2140,8 +2198,8 @@
 	.name	= GPIO_REGULATOR_DEV_NAME,
 	.id	= 63,
 	.dev	= {
-		.platform_data =
-		     &msm8930_gpio_regulator_pdata[MSM8930_GPIO_VREG_ID_EXT_5V],
+		.platform_data = &msm8930_pm8038_gpio_regulator_pdata[
+					MSM8930_GPIO_VREG_ID_EXT_5V],
 	},
 };
 
@@ -2149,8 +2207,8 @@
 	.name	= GPIO_REGULATOR_DEV_NAME,
 	.id	= 97,
 	.dev	= {
-		.platform_data =
-		 &msm8930_gpio_regulator_pdata[MSM8930_GPIO_VREG_ID_EXT_OTG_SW],
+		.platform_data = &msm8930_pm8038_gpio_regulator_pdata[
+					MSM8930_GPIO_VREG_ID_EXT_OTG_SW],
 	},
 };
 
@@ -2163,18 +2221,22 @@
 #ifndef MSM8930_PHASE_2
 		.platform_data = &msm_rpm_regulator_pdata,
 #else
-		.platform_data = &msm8930_rpm_regulator_pdata,
+		.platform_data = &msm8930_pm8038_rpm_regulator_pdata,
 #endif
 	},
 };
 
-static struct platform_device *common_devices[] __initdata = {
+static struct platform_device *early_common_devices[] __initdata = {
 	&msm8960_device_dmov,
 	&msm_device_smd,
 	&msm8960_device_uart_gsbi5,
 	&msm_device_uart_dm6,
 	&msm_device_saw_core0,
 	&msm_device_saw_core1,
+};
+
+/* ext_5v and ext_otg_sw are present when using PM8038 */
+static struct platform_device *pmic_pm8038_devices[] __initdata = {
 	&msm8930_device_ext_5v_vreg,
 #ifndef MSM8930_PHASE_2
 	&msm8930_device_ext_l2_vreg,
@@ -2183,6 +2245,14 @@
 #ifdef MSM8930_PHASE_2
 	&msm8930_device_ext_otg_sw_vreg,
 #endif
+};
+
+/* ext_5v and ext_otg_sw are not present when using PM8917 */
+static struct platform_device *pmic_pm8917_devices[] __initdata = {
+	&msm8960_device_ssbi_pmic,
+};
+
+static struct platform_device *common_devices[] __initdata = {
 	&msm_8960_q6_lpass,
 	&msm_8960_q6_mss_fw,
 	&msm_8960_q6_mss_sw,
@@ -2404,6 +2474,33 @@
 	},
 };
 
+static struct msm_rpmrs_platform_data msm_rpmrs_data_pm8917 __initdata = {
+	.levels = &msm_rpmrs_levels[0],
+	.num_levels = ARRAY_SIZE(msm_rpmrs_levels),
+	.vdd_mem_levels  = {
+		[MSM_RPMRS_VDD_MEM_RET_LOW]	= 750000,
+		[MSM_RPMRS_VDD_MEM_RET_HIGH]	= 750000,
+		[MSM_RPMRS_VDD_MEM_ACTIVE]	= 1050000,
+		[MSM_RPMRS_VDD_MEM_MAX]		= 1150000,
+	},
+	.vdd_dig_levels = {
+		[MSM_RPMRS_VDD_DIG_RET_LOW]	= 0,
+		[MSM_RPMRS_VDD_DIG_RET_HIGH]	= 0,
+		[MSM_RPMRS_VDD_DIG_ACTIVE]	= 1,
+		[MSM_RPMRS_VDD_DIG_MAX]		= 3,
+	},
+	.vdd_mask = 0x7FFFFF,
+	.rpmrs_target_id = {
+		[MSM_RPMRS_ID_PXO_CLK]		= MSM_RPM_ID_PXO_CLK,
+		[MSM_RPMRS_ID_L2_CACHE_CTL]	= MSM_RPM_ID_LAST,
+		[MSM_RPMRS_ID_VDD_DIG_0]	= MSM_RPM_ID_VOLTAGE_CORNER,
+		[MSM_RPMRS_ID_VDD_DIG_1]	= MSM_RPM_ID_LAST,
+		[MSM_RPMRS_ID_VDD_MEM_0]	= MSM_RPM_ID_PM8917_L24_0,
+		[MSM_RPMRS_ID_VDD_MEM_1]	= MSM_RPM_ID_PM8917_L24_1,
+		[MSM_RPMRS_ID_RPM_CTL]		= MSM_RPM_ID_RPM_CTL,
+	},
+};
+
 static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
 	.mode = MSM_PM_BOOT_CONFIG_TZ,
 };
@@ -2570,22 +2667,54 @@
 #endif
 }
 
+/* Modify platform data values to match requirements for PM8917. */
+static void __init msm8930_pm8917_pdata_fixup(void)
+{
+	struct acpuclk_platform_data *pdata;
+
+	mhl_platform_data.gpio_mhl_power = MHL_POWER_GPIO_PM8917;
+
+	gpio_keys_8930_pdata.buttons = keys_8930_pm8917;
+	gpio_keys_8930_pdata.nbuttons = ARRAY_SIZE(keys_8930_pm8917);
+
+	msm_device_saw_core0.dev.platform_data
+		= &msm8930_pm8038_saw_regulator_core0_pdata;
+	msm_device_saw_core1.dev.platform_data
+		= &msm8930_pm8038_saw_regulator_core1_pdata;
+
+	msm8930_device_rpm_regulator.dev.platform_data
+		= &msm8930_pm8917_rpm_regulator_pdata;
+
+	pdata = msm8930_device_acpuclk.dev.platform_data;
+	pdata->uses_pm8917 = true;
+}
+
 static void __init msm8930_cdp_init(void)
 {
+	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+		msm8930_pm8917_pdata_fixup();
 	if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
 		pr_err("meminfo_init() failed!\n");
 
 	platform_device_register(&msm_gpio_device);
 	msm_tsens_early_init(&msm_tsens_pdata);
 	msm_thermal_init(&msm_thermal_pdata);
-	BUG_ON(msm_rpm_init(&msm8930_rpm_data));
-	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
+		BUG_ON(msm_rpm_init(&msm8930_rpm_data));
+		BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
+	} else {
+		BUG_ON(msm_rpm_init(&msm8930_rpm_data_pm8917));
+		BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data_pm8917));
+	}
 
 	regulator_suppress_info_printing();
 	if (msm_xo_init())
 		pr_err("Failed to initialize XO votes\n");
 	platform_device_register(&msm8930_device_rpm_regulator);
-	msm_clock_init(&msm8930_clock_init_data);
+	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+		msm_clock_init(&msm8930_pm8917_clock_init_data);
+	else
+		msm_clock_init(&msm8930_clock_init_data);
 	msm_otg_pdata.phy_init_seq = hsusb_phy_init_seq;
 	msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
 	android_usb_pdata.swfi_latency =
@@ -2622,6 +2751,14 @@
 		platform_device_register(&msm8930_device_acpuclk);
 	else if (cpu_is_msm8930aa())
 		platform_device_register(&msm8930aa_device_acpuclk);
+	platform_add_devices(early_common_devices,
+				ARRAY_SIZE(early_common_devices));
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+		platform_add_devices(pmic_pm8038_devices,
+					ARRAY_SIZE(pmic_pm8038_devices));
+	else
+		platform_add_devices(pmic_pm8917_devices,
+					ARRAY_SIZE(pmic_pm8917_devices));
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
 	msm8930_add_vidc_device();
 	/*
@@ -2632,7 +2769,10 @@
 #ifndef MSM8930_PHASE_2
 	msm8960_pm8921_gpio_mpp_init();
 #else
-	msm8930_pm8038_gpio_mpp_init();
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+		msm8930_pm8038_gpio_mpp_init();
+	else
+		msm8930_pm8917_gpio_mpp_init();
 #endif
 	platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
 #ifdef CONFIG_MSM_CAMERA
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
index 9f6276c..7c1ad5b 100644
--- a/arch/arm/mach-msm/board-8930.h
+++ b/arch/arm/mach-msm/board-8930.h
@@ -17,6 +17,7 @@
 
 #include <linux/regulator/msm-gpio-regulator.h>
 #include <linux/mfd/pm8xxx/pm8038.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/i2c.h>
 #include <linux/i2c/sx150x.h>
 #include <mach/irqs.h>
@@ -37,12 +38,23 @@
 #endif
 
 /* Macros assume PMIC GPIOs and MPPs start at 1 */
+/*
+ * PM8917 has more GPIOs and MPPs than PM8038; therefore, use PM8038 sizes at
+ * all times so that PM8038 vs PM8917 can be chosen at runtime.  This results in
+ * the Linux GPIO address space being contiguous for PM8917 and discontiguous
+ * for PM8038.
+ */
 #define PM8038_GPIO_BASE		NR_GPIO_IRQS
 #define PM8038_GPIO_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8038_GPIO_BASE)
-#define PM8038_MPP_BASE			(PM8038_GPIO_BASE + PM8038_NR_GPIOS)
+#define PM8038_MPP_BASE			(PM8038_GPIO_BASE + PM8917_NR_GPIOS)
 #define PM8038_MPP_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8038_MPP_BASE)
 #define PM8038_IRQ_BASE			(NR_MSM_IRQS + NR_GPIO_IRQS)
 
+/* These PM8917 alias macros are used to provide context in board files. */
+#define PM8917_GPIO_PM_TO_SYS(pm_gpio)	PM8038_GPIO_PM_TO_SYS(pm_gpio)
+#define PM8917_MPP_PM_TO_SYS(pm_gpio)	PM8038_MPP_PM_TO_SYS(pm_gpio)
+#define PM8917_IRQ_BASE			PM8038_IRQ_BASE
+
 /*
  * TODO: When physical 8930/PM8038 hardware becomes
  * available, replace this block with 8930/pm8038 regulator
@@ -64,27 +76,36 @@
 #define GPIO_VREG_ID_EXT_3P3V		2
 #endif
 
-extern struct regulator_init_data msm8930_saw_regulator_core0_pdata;
-extern struct regulator_init_data msm8930_saw_regulator_core1_pdata;
+extern struct regulator_init_data msm8930_pm8038_saw_regulator_core0_pdata;
+extern struct regulator_init_data msm8930_pm8038_saw_regulator_core1_pdata;
+extern struct regulator_init_data msm8930_pm8917_saw_regulator_core0_pdata;
+extern struct regulator_init_data msm8930_pm8917_saw_regulator_core1_pdata;
 
 extern struct pm8xxx_regulator_platform_data
 	msm8930_pm8038_regulator_pdata[] __devinitdata;
-
 extern int msm8930_pm8038_regulator_pdata_len __devinitdata;
 
+extern struct pm8xxx_regulator_platform_data
+	msm8930_pm8917_regulator_pdata[] __devinitdata;
+extern int msm8930_pm8917_regulator_pdata_len __devinitdata;
+
 #define MSM8930_GPIO_VREG_ID_EXT_5V		0
 #define MSM8930_GPIO_VREG_ID_EXT_OTG_SW		1
 
 extern struct gpio_regulator_platform_data
-	msm8930_gpio_regulator_pdata[] __devinitdata;
+	msm8930_pm8038_gpio_regulator_pdata[] __devinitdata;
+extern struct gpio_regulator_platform_data
+	msm8930_pm8917_gpio_regulator_pdata[] __devinitdata;
 
 extern struct rpm_regulator_platform_data
-	msm8930_rpm_regulator_pdata __devinitdata;
+	msm8930_pm8038_rpm_regulator_pdata __devinitdata;
+extern struct rpm_regulator_platform_data
+	msm8930_pm8917_rpm_regulator_pdata __devinitdata;
 
 #if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
 enum {
 	GPIO_EXPANDER_IRQ_BASE = (PM8038_IRQ_BASE + PM8038_NR_IRQS),
-	GPIO_EXPANDER_GPIO_BASE = (PM8038_MPP_BASE + PM8038_NR_MPPS),
+	GPIO_EXPANDER_GPIO_BASE = (PM8038_MPP_BASE + PM8917_NR_MPPS),
 	/* CAM Expander */
 	GPIO_CAM_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE,
 	GPIO_CAM_GP_STROBE_READY = GPIO_CAM_EXPANDER_BASE,
@@ -126,6 +147,7 @@
 int msm8930_init_gpiomux(void);
 void msm8930_allocate_fb_region(void);
 void msm8930_pm8038_gpio_mpp_init(void);
+void msm8930_pm8917_gpio_mpp_init(void);
 void msm8930_mdp_writeback(struct memtype_reserve *reserve_table);
 void __init msm8930_init_gpu(void);
 
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 8d75ee9..244125c 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -109,7 +109,7 @@
 	PM8XXX_GPIO_OUTPUT(43, 1),                       /* DISP_RESET_N */
 	PM8XXX_GPIO_OUTPUT(42, 0),                      /* USB 5V reg enable */
 	/* TABLA CODEC RESET */
-	PM8XXX_GPIO_OUTPUT_STRENGTH(34, 1, PM_GPIO_STRENGTH_MED)
+	PM8XXX_GPIO_OUTPUT_STRENGTH(34, 0, PM_GPIO_STRENGTH_MED)
 };
 
 /* Initial PM8921 MPP configurations */
@@ -603,6 +603,8 @@
 		pm8921_platform_data.bms_pdata->battery_type = BATT_DESAY;
 	} else if (machine_is_msm8960_mtp()) {
 		pm8921_platform_data.bms_pdata->battery_type = BATT_PALLADIUM;
+	} else if (machine_is_msm8960_cdp()) {
+		pm8921_chg_pdata.has_dc_supply = true;
 	}
 
 	if (machine_is_msm8960_fluid())
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 4263cd6..77f94f4 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -2324,6 +2324,7 @@
 static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi4_pdata = {
 	.clk_freq = 100000,
 	.src_clk_rate = 24000000,
+	.keep_ahb_clk_on = 1,
 };
 
 static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi3_pdata = {
@@ -2550,43 +2551,42 @@
 {
 	int rc;
 
+	pr_debug("%s on= %d\n", __func__, on);
+
 	if (on) {
-		rc = gpio_direction_output(gpio_bt_sys_rest_en, 1);
+		rc = gpio_request(gpio_bt_sys_rest_en, "bt sys_rst_n");
+		if (rc) {
+			pr_err("%s: unable to request gpio %d (%d)\n",
+				__func__, gpio_bt_sys_rest_en, rc);
+			goto out;
+		}
+		rc = gpio_direction_output(gpio_bt_sys_rest_en, 0);
+		if (rc) {
+			pr_err("%s: Unable to set gpio %d direction\n",
+				__func__, gpio_bt_sys_rest_en);
+			goto free_gpio;
+		}
 		msleep(100);
+		gpio_set_value(gpio_bt_sys_rest_en, 1);
+		msleep(100);
+		goto out;
 	} else {
 		gpio_set_value(gpio_bt_sys_rest_en, 0);
 		rc = gpio_direction_input(gpio_bt_sys_rest_en);
 		msleep(100);
 	}
-	pr_err("%s on= %d rc = %d\n", __func__, on, rc);
-	return 0;
+
+free_gpio:
+	gpio_free(gpio_bt_sys_rest_en);
+out:
+	return rc;
 }
 
 static void __init bt_power_init(void)
 {
-	int rc;
-
+	pr_debug("%s enter\n", __func__);
 	msm_bt_power_device.dev.platform_data = &bluetooth_power;
-	pr_err("%s enter\n", __func__);
 
-	rc = gpio_request(gpio_bt_sys_rest_en, "bt sys_rst_n");
-	if (rc) {
-		pr_err("%s: unable to request gpio %d (%d)\n",
-			__func__, gpio_bt_sys_rest_en, rc);
-		return;
-	}
-
-	/* When booting up, de-assert BT reset pin */
-	rc = gpio_direction_output(gpio_bt_sys_rest_en, 0);
-	if (rc) {
-		pr_err("%s: Unable to set direction\n", __func__);
-		goto free_gpio;
-	}
-	pr_err("%s done\n", __func__);
-	return;
-
-free_gpio:
-	gpio_free(gpio_bt_sys_rest_en);
 	return;
 }
 #else
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index a2087e4..74c503d 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -102,6 +102,13 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
+static struct gpiomux_setting taiko_reset = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
 static struct msm_gpiomux_config msm_touch_configs[] __initdata = {
 	{
 		.gpio      = 60,		/* TOUCH RESET */
@@ -355,6 +362,15 @@
 	},
 };
 
+static struct msm_gpiomux_config msm_taiko_config[] __initdata = {
+	{
+		.gpio	= 63,		/* SYS_RST_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &taiko_reset,
+		},
+	}
+};
+
 void __init msm_8974_init_gpiomux(void)
 {
 	int rc;
@@ -376,4 +392,6 @@
 	msm_gpiomux_install(msm_touch_configs, ARRAY_SIZE(msm_touch_configs));
 
 	msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
+
+	msm_gpiomux_install(msm_taiko_config, ARRAY_SIZE(msm_taiko_config));
 }
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
index 47a9835..9339638 100644
--- a/arch/arm/mach-msm/board-9615-gpiomux.c
+++ b/arch/arm/mach-msm/board-9615-gpiomux.c
@@ -119,6 +119,13 @@
 	.dir = GPIOMUX_IN,
 };
 
+static struct gpiomux_setting tabla_reset = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
 static struct msm_gpiomux_config msm9615_audio_codec_configs[] __initdata = {
 	{
 		.gpio = 24,
@@ -126,6 +133,12 @@
 			[GPIOMUX_SUSPENDED] = &cdc_mclk,
 		},
 	},
+	{
+		.gpio	= 84,		/* SYS_RST_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &tabla_reset,
+		},
+	}
 };
 
 static struct msm_gpiomux_config msm9615_sdcc2_configs[] __initdata = {
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 0e2aa3b..24d54e4 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -193,7 +193,7 @@
 		PM8XXX_MPP_INIT(PMIC_MPP_6, A_OUTPUT,
 			PM8XXX_MPP_AOUT_LVL_1V25_2, AOUT_CTRL_ENABLE),
 		PM8XXX_MPP_INIT(PMIC_MPP_UIM_M_DATA, D_BI_DIR,
-			PM8058_MPP_DIG_LEVEL_L3, BI_PULLUP_30KOHM),
+			PM8058_MPP_DIG_LEVEL_S3, BI_PULLUP_1KOHM),
 		PM8XXX_MPP_INIT(PMIC_MPP_UIM_DATA, D_BI_DIR,
 			PM8058_MPP_DIG_LEVEL_L3, BI_PULLUP_30KOHM),
 	};
@@ -261,7 +261,7 @@
 			REGULATOR_CHANGE_STATUS, 0, 0, 1)
 
 static struct pm8058_vreg_pdata pm8058_vreg_init[] = {
-	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L3, 1800000, 1800000),
+	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L3, 3000000, 3000000),
 	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L8, 2200000, 2200000),
 	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L9, 2050000, 2050000),
 	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L14, 2850000, 2850000),
@@ -614,11 +614,11 @@
 
 static struct msm_gpio uart3_uim_config_data[] = {
 	{ GPIO_CFG(GPIO_UIM_RESET, 0, GPIO_CFG_OUTPUT,
-		GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UIM_Reset" },
+		GPIO_CFG_PULL_UP, GPIO_CFG_2MA), "UIM_Reset" },
 	{ GPIO_CFG(GPIO_UIM_DATA_IO, 2, GPIO_CFG_OUTPUT,
-		GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UIM_Data" },
+		GPIO_CFG_PULL_UP, GPIO_CFG_2MA), "UIM_Data" },
 	{ GPIO_CFG(GPIO_UIM_CLOCK, 2, GPIO_CFG_OUTPUT,
-		GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UIM_Clock" },
+		GPIO_CFG_PULL_UP, GPIO_CFG_2MA), "UIM_Clock" },
 };
 
 static void fsm9xxx_init_uart3_uim(void)
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index e00f150..cf7faf1 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -1187,6 +1187,7 @@
 			 ARRAY_SIZE(msm8625_pm_data));
 	BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
 	msm8x25_spm_device_init();
+	msm_pm_register_cpr_ops();
 }
 
 #define UART1DM_RX_GPIO		45
@@ -1265,6 +1266,7 @@
 				ARRAY_SIZE(msm8625_pm_data));
 		BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
 		msm8x25_spm_device_init();
+		msm_pm_register_cpr_ops();
 	} else {
 		msm_pm_set_platform_data(msm7x27a_pm_data,
 				ARRAY_SIZE(msm7x27a_pm_data));
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 4524f43..f16751d 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -7173,7 +7173,6 @@
 			.type	= ION_HEAP_TYPE_CARVEOUT,
 			.name	= ION_CAMERA_HEAP_NAME,
 			.memory_type = ION_EBI_TYPE,
-			.has_outer_cache = 1,
 			.extra_data = (void *)&co_ion_pdata,
 		},
 		/* PMEM_AUDIO */
@@ -7182,7 +7181,6 @@
 			.type	= ION_HEAP_TYPE_CARVEOUT,
 			.name	= ION_AUDIO_HEAP_NAME,
 			.memory_type = ION_EBI_TYPE,
-			.has_outer_cache = 1,
 			.extra_data = (void *)&co_ion_pdata,
 		},
 		/* PMEM_MDP = SF */
@@ -7191,7 +7189,6 @@
 			.type	= ION_HEAP_TYPE_CARVEOUT,
 			.name	= ION_SF_HEAP_NAME,
 			.memory_type = ION_EBI_TYPE,
-			.has_outer_cache = 1,
 			.extra_data = (void *)&co_ion_pdata,
 		},
 #endif
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 1da9ede..fc476fb 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -1115,6 +1115,7 @@
 				ARRAY_SIZE(msm8625_pm_data));
 		BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
 		msm8x25_spm_device_init();
+		msm_pm_register_cpr_ops();
 	}
 }
 
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index cde6437..e6229d5 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -393,6 +393,7 @@
 
 static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig_8960);
 
+static int rpm_vreg_dig_8930 = RPM_VREG_ID_PM8038_VDD_DIG_CORNER;
 static int set_vdd_dig_8930(struct clk_vdd_class *vdd_class, int level)
 {
 	static const int vdd_corner[] = {
@@ -401,7 +402,7 @@
 		[VDD_DIG_NOMINAL] = RPM_VREG_CORNER_NOMINAL,
 		[VDD_DIG_HIGH]    = RPM_VREG_CORNER_HIGH,
 	};
-	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_VDD_DIG_CORNER,
+	return rpm_vreg_set_voltage(rpm_vreg_dig_8930,
 					RPM_VREG_VOTER3,
 					vdd_corner[level],
 					RPM_VREG_CORNER_HIGH, 1);
@@ -467,6 +468,36 @@
 				    sr2_lreg_uv[level], sr2_lreg_uv[level], 1);
 }
 
+static int set_vdd_sr2_hdmi_pll_8930_pm8917(struct clk_vdd_class *vdd_class,
+	int level)
+{
+	int rc = 0;
+
+	if (level == VDD_SR2_HDMI_PLL_OFF) {
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_L23,
+				RPM_VREG_VOTER3, 0, 0, 1);
+		if (rc)
+			return rc;
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_S8,
+				RPM_VREG_VOTER3, 0, 0, 1);
+		if (rc)
+			rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_L23,
+				RPM_VREG_VOTER3, 1800000, 1800000, 1);
+	} else {
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_S8,
+				RPM_VREG_VOTER3, 2050000, 2100000, 1);
+		if (rc)
+			return rc;
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_L23,
+				RPM_VREG_VOTER3, 1800000, 1800000, 1);
+		if (rc)
+			rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_S8,
+					RPM_VREG_VOTER3, 0, 0, 1);
+	}
+
+	return rc;
+}
+
 static int set_vdd_sr2_hdmi_pll_8930(struct clk_vdd_class *vdd_class, int level)
 {
 	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_L23, RPM_VREG_VOTER3,
@@ -6237,7 +6268,7 @@
 		rmwreg(0x00000003, AHB_EN_REG,  0x6C000103);
 		writel_relaxed(0x000007F9, AHB_EN2_REG);
 	} else {
-		rmwreg(0x44000000, AHB_EN_REG,  0x6C000103);
+		rmwreg(0x40000000, AHB_EN_REG,  0x6C000103);
 		writel_relaxed(0x3C7097F9, AHB_EN2_REG);
 	}
 
@@ -6421,12 +6452,8 @@
 	/* Initialize clock registers. */
 	reg_init();
 
-	if (cpu_is_apq8064()) {
+	if (cpu_is_apq8064())
 		vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
-	} else if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
-		vdd_dig.set_vdd = set_vdd_dig_8930;
-		vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930;
-	}
 
 	/* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
 	if (readl_relaxed(LCC_PLL0_L_VAL_REG) == 0x12) {
@@ -6510,6 +6537,25 @@
 	clk_ops_local_pll.enable = sr_pll_clk_enable;
 }
 
+static void __init msm8930_pm8917_clock_pre_init(void)
+{
+	/* detect pmic8917 from board file, and call this init function */
+
+	vdd_dig.set_vdd = set_vdd_dig_8930;
+	rpm_vreg_dig_8930 = RPM_VREG_ID_PM8917_VDD_DIG_CORNER;
+	vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930_pm8917;
+
+	msm8960_clock_pre_init();
+}
+
+static void __init msm8930_clock_pre_init(void)
+{
+	vdd_dig.set_vdd = set_vdd_dig_8930;
+	vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930;
+
+	msm8960_clock_pre_init();
+}
+
 static void __init msm8960_clock_post_init(void)
 {
 	/* Keep PXO on whenever APPS cpu is active */
@@ -6620,7 +6666,15 @@
 struct clock_init_data msm8930_clock_init_data __initdata = {
 	.table = msm_clocks_8930,
 	.size = ARRAY_SIZE(msm_clocks_8930),
-	.pre_init = msm8960_clock_pre_init,
+	.pre_init = msm8930_clock_pre_init,
+	.post_init = msm8960_clock_post_init,
+	.late_init = msm8960_clock_late_init,
+};
+
+struct clock_init_data msm8930_pm8917_clock_init_data __initdata = {
+	.table = msm_clocks_8930,
+	.size = ARRAY_SIZE(msm_clocks_8930),
+	.pre_init = msm8930_pm8917_clock_pre_init,
 	.post_init = msm8960_clock_post_init,
 	.late_init = msm8960_clock_late_init,
 };
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index e21a645..9eb3e8b 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -497,6 +497,7 @@
 #define LPASS_Q6SS_XO_CBCR                       0x26000
 #define LPASS_Q6_AXI_CBCR			 0x11C0
 #define Q6SS_AHBM_CBCR				 0x22004
+#define AUDIO_WRAPPER_BR_CBCR			 0x24000
 #define MSS_XO_Q6_CBCR                           0x108C
 #define MSS_BUS_Q6_CBCR                          0x10A4
 #define MSS_CFG_AHB_CBCR                         0x0280
@@ -634,7 +635,8 @@
 #define MMSSNOC_AHB_ID  0x3
 
 #define BIMC_ID		0x0
-#define OCMEM_ID	0x1
+#define OXILI_ID	0x1
+#define OCMEM_ID	0x2
 
 enum {
 	D0_ID = 1,
@@ -653,6 +655,8 @@
 DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
 DEFINE_CLK_RPM_SMD(ocmemgx_clk, ocmemgx_a_clk, RPM_MEM_CLK_TYPE, OCMEM_ID,
 			NULL);
+DEFINE_CLK_RPM_SMD(gfx3d_clk_src, gfx3d_a_clk_src, RPM_MEM_CLK_TYPE, OXILI_ID,
+			NULL);
 
 DEFINE_CLK_RPM_SMD_BRANCH(cxo_clk_src, cxo_a_clk_src,
 				RPM_MISC_CLK_TYPE, CXO_ID, 19200000);
@@ -773,7 +777,7 @@
 static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(bimc_acpu_a_clk, &bimc_a_clk.c, LONG_MAX);
-static DEFINE_CLK_VOTER(ocmemgx_gfx3d_clk, &ocmemgx_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(oxili_gfx3d_clk_src, &gfx3d_clk_src.c, LONG_MAX);
 static DEFINE_CLK_VOTER(ocmemgx_msmbus_clk, &ocmemgx_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(ocmemgx_msmbus_a_clk, &ocmemgx_a_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(ocmemgx_core_clk, &ocmemgx_clk.c, LONG_MAX);
@@ -4012,7 +4016,7 @@
 
 static struct branch_clk oxili_gfx3d_clk = {
 	.cbcr_reg = OXILI_GFX3D_CBCR,
-	.parent = &ocmemgx_gfx3d_clk.c,
+	.parent = &oxili_gfx3d_clk_src.c,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "oxili_gfx3d_clk",
@@ -4494,6 +4498,17 @@
 	},
 };
 
+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 struct branch_clk mss_xo_q6_clk = {
 	.cbcr_reg = MSS_XO_Q6_CBCR,
 	.bcr_reg = MSS_Q6SS_BCR,
@@ -4702,6 +4717,7 @@
 	{&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},
 	{&mss_bus_q6_clk.c,			MSS_BASE, 0x003b},
 	{&mss_xo_q6_clk.c,			MSS_BASE, 0x0007},
 
@@ -4976,7 +4992,7 @@
 	CLK_LOOKUP("core_clk", gcc_blsp1_uart5_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_uart6_apps_clk.c, ""),
 
-	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9966000.i2c"),
+	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9967000.i2c"),
 	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f995e000.serial"),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup1_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup1_spi_apps_clk.c, ""),
@@ -4984,9 +5000,9 @@
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup2_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup3_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup3_spi_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_blsp2_qup4_i2c_apps_clk.c, "f9966000.i2c"),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup4_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup4_spi_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_blsp2_qup5_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup5_i2c_apps_clk.c, "f9967000.i2c"),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup5_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup6_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup6_spi_apps_clk.c, ""),
@@ -5236,7 +5252,7 @@
 						"msm-dai-q6.4106"),
 	CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
 						"msm-dai-q6.4106"),
-
+	CLK_LOOKUP("br_clk", audio_wrapper_br_clk.c, "fdd00000.qcom,ocmem"),
 	CLK_LOOKUP("core_clk",       mss_xo_q6_clk.c,  "pil-q6v5-mss"),
 	CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "pil-q6v5-mss"),
 	CLK_LOOKUP("iface_clk", gcc_mss_cfg_ahb_clk.c, "pil-q6v5-mss"),
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index d88466d..4e3d83b 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -169,6 +169,7 @@
 extern struct clock_init_data qds8x50_clock_init_data;
 extern struct clock_init_data msm8625_dummy_clock_init_data;
 extern struct clock_init_data msm8930_clock_init_data;
+extern struct clock_init_data msm8930_pm8917_clock_init_data;
 extern struct clock_init_data msm8974_clock_init_data;
 extern struct clock_init_data msm8974_rumi_clock_init_data;
 
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index a257a9c..867e8fc 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -32,6 +32,7 @@
 #include "rpm_stats.h"
 #include "rpm_rbcpr_stats.h"
 #include "footswitch.h"
+#include "acpuclock-krait.h"
 
 #ifdef CONFIG_MSM_MPM
 #include <mach/mpm.h>
@@ -228,13 +229,13 @@
 		MSM_RPM_STATUS_ID_MAP(8930, PM8038_CLK2_1),
 		MSM_RPM_STATUS_ID_MAP(8930, PM8038_LVS1),
 		MSM_RPM_STATUS_ID_MAP(8930, PM8038_LVS2),
-		MSM_RPM_STATUS_ID_MAP(8930, NCP_0),
-		MSM_RPM_STATUS_ID_MAP(8930, NCP_1),
-		MSM_RPM_STATUS_ID_MAP(8930, CXO_BUFFERS),
-		MSM_RPM_STATUS_ID_MAP(8930, USB_OTG_SWITCH),
-		MSM_RPM_STATUS_ID_MAP(8930, HDMI_SWITCH),
-		MSM_RPM_STATUS_ID_MAP(8930, QDSS_CLK),
-		MSM_RPM_STATUS_ID_MAP(8930, VOLTAGE_CORNER),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_NCP_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_NCP_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_CXO_BUFFERS),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_USB_OTG_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_HDMI_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_QDSS_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_VOLTAGE_CORNER),
 	},
 	.target_ctrl_id = {
 		MSM_RPM_CTRL_MAP(8930, VERSION_MAJOR),
@@ -251,6 +252,259 @@
 	.ver = {3, 0, 0},
 };
 
+struct msm_rpm_platform_data msm8930_rpm_data_pm8917 __initdata = {
+	.reg_base_addrs = {
+		[MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE,
+		[MSM_RPM_PAGE_CTRL] = MSM_RPM_BASE + 0x400,
+		[MSM_RPM_PAGE_REQ] = MSM_RPM_BASE + 0x600,
+		[MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
+	},
+	.irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ,
+	.irq_err = RPM_APCC_CPU0_GP_LOW_IRQ,
+	.irq_wakeup = RPM_APCC_CPU0_WAKE_UP_IRQ,
+	.ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008,
+	.ipc_rpm_val = 4,
+	.target_id = {
+		MSM_RPM_MAP(8930, NOTIFICATION_CONFIGURED_0, NOTIFICATION, 4),
+		MSM_RPM_MAP(8930, NOTIFICATION_REGISTERED_0, NOTIFICATION, 4),
+		MSM_RPM_MAP(8930, INVALIDATE_0, INVALIDATE, 8),
+		MSM_RPM_MAP(8960, TRIGGER_TIMED_TO, TRIGGER_TIMED, 1),
+		MSM_RPM_MAP(8960, TRIGGER_TIMED_SCLK_COUNT, TRIGGER_TIMED, 1),
+		MSM_RPM_MAP(8930, RPM_CTL, RPM_CTL, 1),
+		MSM_RPM_MAP(8930, CXO_CLK, CXO_CLK, 1),
+		MSM_RPM_MAP(8930, PXO_CLK, PXO_CLK, 1),
+		MSM_RPM_MAP(8930, APPS_FABRIC_CLK, APPS_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8930, SYSTEM_FABRIC_CLK, SYSTEM_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8930, MM_FABRIC_CLK, MM_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8930, DAYTONA_FABRIC_CLK, DAYTONA_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8930, SFPB_CLK, SFPB_CLK, 1),
+		MSM_RPM_MAP(8930, CFPB_CLK, CFPB_CLK, 1),
+		MSM_RPM_MAP(8930, MMFPB_CLK, MMFPB_CLK, 1),
+		MSM_RPM_MAP(8930, EBI1_CLK, EBI1_CLK, 1),
+		MSM_RPM_MAP(8930, APPS_FABRIC_CFG_HALT_0,
+				APPS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(8930, APPS_FABRIC_CFG_CLKMOD_0,
+				APPS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(8930, APPS_FABRIC_CFG_IOCTL,
+				APPS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(8930, APPS_FABRIC_ARB_0, APPS_FABRIC_ARB, 6),
+		MSM_RPM_MAP(8930, SYS_FABRIC_CFG_HALT_0,
+				SYS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(8930, SYS_FABRIC_CFG_CLKMOD_0,
+				SYS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(8930, SYS_FABRIC_CFG_IOCTL,
+				SYS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(8930, SYSTEM_FABRIC_ARB_0,
+				SYSTEM_FABRIC_ARB, 20),
+		MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_HALT_0,
+				MMSS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_CLKMOD_0,
+				MMSS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_IOCTL,
+				MMSS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(8930, MM_FABRIC_ARB_0, MM_FABRIC_ARB, 11),
+		MSM_RPM_MAP(8930, PM8917_S1_0, PM8917_S1, 2),
+		MSM_RPM_MAP(8930, PM8917_S2_0, PM8917_S2, 2),
+		MSM_RPM_MAP(8930, PM8917_S3_0, PM8917_S3, 2),
+		MSM_RPM_MAP(8930, PM8917_S4_0, PM8917_S4, 2),
+		MSM_RPM_MAP(8930, PM8917_S5_0, PM8917_S5, 2),
+		MSM_RPM_MAP(8930, PM8917_S6_0, PM8917_S6, 2),
+		MSM_RPM_MAP(8930, PM8917_S7_0, PM8917_S7, 2),
+		MSM_RPM_MAP(8930, PM8917_S8_0, PM8917_S8, 2),
+		MSM_RPM_MAP(8930, PM8917_L1_0, PM8917_L1, 2),
+		MSM_RPM_MAP(8930, PM8917_L2_0, PM8917_L2, 2),
+		MSM_RPM_MAP(8930, PM8917_L3_0, PM8917_L3, 2),
+		MSM_RPM_MAP(8930, PM8917_L4_0, PM8917_L4, 2),
+		MSM_RPM_MAP(8930, PM8917_L5_0, PM8917_L5, 2),
+		MSM_RPM_MAP(8930, PM8917_L6_0, PM8917_L6, 2),
+		MSM_RPM_MAP(8930, PM8917_L7_0, PM8917_L7, 2),
+		MSM_RPM_MAP(8930, PM8917_L8_0, PM8917_L8, 2),
+		MSM_RPM_MAP(8930, PM8917_L9_0, PM8917_L9, 2),
+		MSM_RPM_MAP(8930, PM8917_L10_0, PM8917_L10, 2),
+		MSM_RPM_MAP(8930, PM8917_L11_0, PM8917_L11, 2),
+		MSM_RPM_MAP(8930, PM8917_L12_0, PM8917_L12, 2),
+		MSM_RPM_MAP(8930, PM8917_L14_0, PM8917_L14, 2),
+		MSM_RPM_MAP(8930, PM8917_L15_0, PM8917_L15, 2),
+		MSM_RPM_MAP(8930, PM8917_L16_0, PM8917_L16, 2),
+		MSM_RPM_MAP(8930, PM8917_L17_0, PM8917_L17, 2),
+		MSM_RPM_MAP(8930, PM8917_L18_0, PM8917_L18, 2),
+		MSM_RPM_MAP(8930, PM8917_L21_0, PM8917_L21, 2),
+		MSM_RPM_MAP(8930, PM8917_L22_0, PM8917_L22, 2),
+		MSM_RPM_MAP(8930, PM8917_L23_0, PM8917_L23, 2),
+		MSM_RPM_MAP(8930, PM8917_L24_0, PM8917_L24, 2),
+		MSM_RPM_MAP(8930, PM8917_L25_0, PM8917_L25, 2),
+		MSM_RPM_MAP(8930, PM8917_L26_0, PM8917_L26, 2),
+		MSM_RPM_MAP(8930, PM8917_L27_0, PM8917_L27, 2),
+		MSM_RPM_MAP(8930, PM8917_L28_0, PM8917_L28, 2),
+		MSM_RPM_MAP(8930, PM8917_L29_0, PM8917_L29, 2),
+		MSM_RPM_MAP(8930, PM8917_L30_0, PM8917_L30, 2),
+		MSM_RPM_MAP(8930, PM8917_L31_0, PM8917_L31, 2),
+		MSM_RPM_MAP(8930, PM8917_L32_0, PM8917_L32, 2),
+		MSM_RPM_MAP(8930, PM8917_L33_0, PM8917_L33, 2),
+		MSM_RPM_MAP(8930, PM8917_L34_0, PM8917_L34, 2),
+		MSM_RPM_MAP(8930, PM8917_L35_0, PM8917_L35, 2),
+		MSM_RPM_MAP(8930, PM8917_L36_0, PM8917_L36, 2),
+		MSM_RPM_MAP(8930, PM8917_CLK1_0, PM8917_CLK1, 2),
+		MSM_RPM_MAP(8930, PM8917_CLK2_0, PM8917_CLK2, 2),
+		MSM_RPM_MAP(8930, PM8917_LVS1, PM8917_LVS1, 1),
+		MSM_RPM_MAP(8930, PM8917_LVS3, PM8917_LVS3, 1),
+		MSM_RPM_MAP(8930, PM8917_LVS4, PM8917_LVS4, 1),
+		MSM_RPM_MAP(8930, PM8917_LVS5, PM8917_LVS5, 1),
+		MSM_RPM_MAP(8930, PM8917_LVS6, PM8917_LVS6, 1),
+		MSM_RPM_MAP(8930, PM8917_LVS7, PM8917_LVS7, 1),
+		MSM_RPM_MAP(8930, NCP_0, NCP, 2),
+		MSM_RPM_MAP(8930, CXO_BUFFERS, CXO_BUFFERS, 1),
+		MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
+		MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
+		MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
+		MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
+	},
+	.target_status = {
+		MSM_RPM_STATUS_ID_MAP(8930, VERSION_MAJOR),
+		MSM_RPM_STATUS_ID_MAP(8930, VERSION_MINOR),
+		MSM_RPM_STATUS_ID_MAP(8930, VERSION_BUILD),
+		MSM_RPM_STATUS_ID_MAP(8930, SUPPORTED_RESOURCES_0),
+		MSM_RPM_STATUS_ID_MAP(8930, SUPPORTED_RESOURCES_1),
+		MSM_RPM_STATUS_ID_MAP(8930, SUPPORTED_RESOURCES_2),
+		MSM_RPM_STATUS_ID_MAP(8930, RESERVED_SUPPORTED_RESOURCES_0),
+		MSM_RPM_STATUS_ID_MAP(8930, SEQUENCE),
+		MSM_RPM_STATUS_ID_MAP(8930, RPM_CTL),
+		MSM_RPM_STATUS_ID_MAP(8930, CXO_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, PXO_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, SYSTEM_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, MM_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, DAYTONA_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, SFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, CFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, MMFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, EBI1_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(8930, SYS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(8930, SYS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(8930, SYS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(8930, SYSTEM_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(8930, MMSS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(8930, MMSS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(8930, MMSS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(8930, MM_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S1_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S1_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S2_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S2_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S3_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S3_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S4_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S4_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S5_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S5_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S6_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S6_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S7_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S7_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S8_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S8_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L1_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L1_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L2_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L2_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L3_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L3_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L4_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L4_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L5_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L5_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L6_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L6_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L7_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L7_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L8_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L8_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L9_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L9_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L10_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L10_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L11_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L11_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L12_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L12_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L14_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L14_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L15_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L15_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L16_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L16_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L17_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L17_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L18_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L18_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L21_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L21_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L22_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L22_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L23_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L23_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L24_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L24_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L25_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L25_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L26_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L26_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L27_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L27_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L28_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L28_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L29_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L29_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L30_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L30_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L31_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L31_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L32_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L32_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L33_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L33_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L34_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L34_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L35_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L35_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L36_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L36_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_CLK1_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_CLK1_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_CLK2_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_CLK2_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS3),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS4),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS5),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS6),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS7),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_NCP_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_NCP_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_CXO_BUFFERS),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_USB_OTG_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_HDMI_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_QDSS_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_VOLTAGE_CORNER),
+	},
+	.target_ctrl_id = {
+		MSM_RPM_CTRL_MAP(8930, VERSION_MAJOR),
+		MSM_RPM_CTRL_MAP(8930, VERSION_MINOR),
+		MSM_RPM_CTRL_MAP(8930, VERSION_BUILD),
+		MSM_RPM_CTRL_MAP(8930, REQ_CTX_0),
+		MSM_RPM_CTRL_MAP(8930, REQ_SEL_0),
+		MSM_RPM_CTRL_MAP(8930, ACK_CTX_0),
+		MSM_RPM_CTRL_MAP(8930, ACK_SEL_0),
+	},
+	.sel_invalidate = MSM_RPM_8930_SEL_INVALIDATE,
+	.sel_notification = MSM_RPM_8930_SEL_NOTIFICATION,
+	.sel_last = MSM_RPM_8930_SEL_LAST,
+	.ver = {3, 0, 0},
+};
 struct platform_device msm8930_rpm_device = {
 	.name   = "msm_rpm",
 	.id     = -1,
@@ -386,9 +640,16 @@
 	.id		= -1,
 };
 
+static struct acpuclk_platform_data acpuclk_8930_pdata = {
+	.uses_pm8917 = false,
+};
+
 struct platform_device msm8930_device_acpuclk = {
 	.name		= "acpuclk-8930",
 	.id		= -1,
+	.dev = {
+		.platform_data = &acpuclk_8930_pdata,
+	},
 };
 
 struct platform_device msm8930aa_device_acpuclk = {
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 0331919..2de0215 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -509,6 +509,19 @@
 
 }
 
+static struct msm_pm_cpr_ops msm8625_pm_cpr_ops = {
+	.cpr_suspend = msm_cpr_pm_suspend,
+	.cpr_resume = msm_cpr_pm_resume,
+};
+
+void __init msm_pm_register_cpr_ops(void)
+{
+	/* CPR presents on revision >= v2.0 chipsets */
+	if (cpu_is_msm8625() &&
+			SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2)
+		msm_pm_set_cpr_ops(&msm8625_pm_cpr_ops);
+}
+
 #define MSM_SDC1_BASE         0xA0400000
 #define MSM_SDC2_BASE         0xA0500000
 #define MSM_SDC3_BASE         0xA0600000
@@ -1592,6 +1605,47 @@
 	},
 };
 
+enum {
+	MSM8625,
+	MSM8625A,
+	MSM8625AB,
+};
+
+static int __init msm8625_cpu_id(void)
+{
+	int raw_id, cpu;
+
+	raw_id = socinfo_get_raw_id();
+	switch (raw_id) {
+	/* Part number for 1GHz part */
+	case 0x770:
+	case 0x771:
+	case 0x77C:
+	case 0x780:
+	case 0x8D0:
+		cpu = MSM8625;
+		break;
+	/* Part number for 1.2GHz part */
+	case 0x773:
+	case 0x774:
+	case 0x781:
+	case 0x8D1:
+		cpu = MSM8625A;
+		break;
+	case 0x775:
+	case 0x776:
+	case 0x77D:
+	case 0x782:
+	case 0x8D2:
+		cpu = MSM8625AB;
+		break;
+	default:
+		pr_err("Invalid Raw ID\n");
+		return -ENODEV;
+	}
+	return cpu;
+}
+
 static struct resource cpr_resources[] = {
 	{
 		.start = MSM8625_INT_CPR_IRQ0,
@@ -1608,12 +1662,12 @@
  * These are various Vdd levels supported by PMIC
  */
 static uint32_t msm_c2_pmic_mv[] __initdata = {
-	1300, 12875 / 10, 1275, 12625 / 10, 1250,
-	12375 / 10, 1225, 12125 / 10, 1200, 11875 / 10,
-	1175, 11625 / 10, 1150, 11375 / 10, 1125,
-	11125 / 10, 1100, 10875 / 10, 1075, 10625 / 10,
-	1050, 10375 / 10, 1025, 10125 / 10, 0, 0, 0, 0,
-	0, 0, 0, 1000,
+	1300000, 1287500, 1275000, 1262500, 1250000,
+	1237500, 1225000, 1212500, 1200000, 1187500,
+	1175000, 1162500, 1150000, 1137500, 1125000,
+	1112500, 1100000, 1087500, 1075000, 1062500,
+	1050000, 1037500, 1025000, 1012500, 0, 0, 0,
+	0, 0, 0, 0, 1000,
 };
 
 /**
@@ -1633,10 +1687,10 @@
 			},
 			.ring_osc = 0,
 			.step_quot = ~0,
-			.tgt_volt_offset = 1,
-			.Vmax = 1200,
-			.Vmin = 1000,
-			.calibrated_mV = 1100,
+			.tgt_volt_offset = 0,
+			.Vmax = 1200000,
+			.Vmin = 1000000,
+			.calibrated_uV = 1100000,
 	},
 	[TURBO_MODE] = {
 			.ring_osc_data = {
@@ -1651,23 +1705,47 @@
 			},
 			.ring_osc = 0,
 			.step_quot = ~0,
-			.tgt_volt_offset = 1,
-			.Vmax = 1350,
-			.Vmin = 1250,
-			.calibrated_mV = 1300,
+			.tgt_volt_offset = 0,
+			.Vmax = 1350000,
+			.Vmin = 1150000,
+			.calibrated_uV = 1300000,
 	},
 };
 
 struct msm_cpr_vp_data vp_data = {
-	.min_volt = 1000,
-	.max_volt = 1350,
-	.default_volt = 1300,
-	.step_size = (12500 / 1000),
+	.min_volt = 1000000,
+	.max_volt = 1350000,
+	.default_volt = 1300000,
+	.step_size = 12500,
 };
 
+static uint32_t
+msm_cpr_get_quot(uint32_t max_quot, uint32_t max_freq, uint32_t new_freq)
+{
+	uint32_t quot;
+
+	/* This formula is as per chip characterization data */
+	quot = max_quot - ((max_freq / 10 - new_freq / 10) * 9) + 20;
+
+	return quot;
+}
+
+static void msm_cpr_clk_enable(void)
+{
+	uint32_t reg_val;
+
+	/* Select TCXO (19.2MHz) as clock source */
+	reg_val = readl_relaxed(A11S_TEST_BUS_SEL_ADDR);
+	reg_val |= RBCPR_CLK_MUX_SEL;
+	writel_relaxed(reg_val, A11S_TEST_BUS_SEL_ADDR);
+
+	/* Get CPR out of reset */
+	writel_relaxed(0x1, RBCPR_SW_RESET_N);
+}
+
 static struct msm_cpr_config msm_cpr_pdata = {
 	.ref_clk_khz = 19200,
-	.delay_us = 10000,
+	.delay_us = 25000,
 	.irq_line = 0,
 	.cpr_mode_data = msm_cpr_mode_data,
 	.tgt_count_div_N = 1,
@@ -1678,8 +1756,12 @@
 	.dn_threshold = 2,
 	.up_margin = 0,
 	.dn_margin = 0,
-	.nom_freq_limit = 1008000,
+	.max_nom_freq = 700800,
+	.max_freq = 1401600,
+	.max_quot = 0,
 	.vp_data = &vp_data,
+	.get_quot = msm_cpr_get_quot,
+	.clk_enable = msm_cpr_clk_enable,
 };
 
 static struct platform_device msm8625_device_cpr = {
@@ -1701,7 +1783,6 @@
 {
 	struct cpr_info_type *cpr_info = NULL;
 	uint8_t ring_osc = 0;
-	uint32_t reg_val;
 
 	cpr_info = kzalloc(sizeof(struct cpr_info_type), GFP_KERNEL);
 	if (!cpr_info) {
@@ -1728,35 +1809,32 @@
 	msm_cpr_mode_data[TURBO_MODE].ring_osc_data[ring_osc].gcnt = 19;
 	msm_cpr_mode_data[NORMAL_MODE].ring_osc_data[ring_osc].gcnt = 19;
 
-	/* The multiplier and offset are as per PTE data */
-	msm_cpr_mode_data[TURBO_MODE].ring_osc_data[ring_osc].target_count =
-		cpr_info->turbo_quot * 10 + 440;
-	msm_cpr_mode_data[NORMAL_MODE].ring_osc_data[ring_osc].target_count =
-		cpr_info->turbo_quot / msm_cpr_pdata.tgt_count_div_N;
+	/**
+	 * The scaling factor and offset are as per chip characterization data
+	 * This formula is used since available fuse bits in the chip are not
+	 * enough to represent the value of maximum quot
+	 */
+	msm_cpr_pdata.max_quot = cpr_info->turbo_quot * 10 + 610;
 
 	/**
 	 * Bits 4:0 of pvs_fuse provide mapping to the safe boot up voltage.
 	 * Boot up mode is by default Turbo.
 	 */
-	msm_cpr_mode_data[TURBO_MODE].calibrated_mV =
+	msm_cpr_mode_data[TURBO_MODE].calibrated_uV =
 				msm_c2_pmic_mv[cpr_info->pvs_fuse & 0x1F];
 
-	/* TODO: Store the tgt_volt_offset values for the modes from PTE */
-
-
 	pr_debug("%s: cpr: ring_osc: 0x%x\n", __func__,
 		msm_cpr_mode_data[TURBO_MODE].ring_osc);
 	pr_debug("%s: cpr: turbo_quot: 0x%x\n", __func__, cpr_info->turbo_quot);
 	pr_debug("%s: cpr: pvs_fuse: 0x%x\n", __func__, cpr_info->pvs_fuse);
 	kfree(cpr_info);
 
-	/* Select TCXO (19.2MHz) as clock source */
-	reg_val = readl_relaxed(A11S_TEST_BUS_SEL_ADDR);
-	reg_val |= RBCPR_CLK_MUX_SEL;
-	writel_relaxed(reg_val, A11S_TEST_BUS_SEL_ADDR);
+	if (msm8625_cpu_id() == MSM8625A)
+		msm_cpr_pdata.max_freq = 1209600;
+	else if (msm8625_cpu_id() == MSM8625)
+		msm_cpr_pdata.max_freq = 1008000;
 
-	/* Get CPR out of reset */
-	writel_relaxed(0x1, RBCPR_SW_RESET_N);
+	msm_cpr_clk_enable();
 
 	platform_device_register(&msm8625_vp_device);
 	platform_device_register(&msm8625_device_cpr);
@@ -1828,47 +1906,6 @@
 	.table = msm_clock_8625_dummy,
 	.size = ARRAY_SIZE(msm_clock_8625_dummy),
 };
-enum {
-	MSM8625,
-	MSM8625A,
-	MSM8625AB,
-};
-
-static int __init msm8625_cpu_id(void)
-{
-	int raw_id, cpu;
-
-	raw_id = socinfo_get_raw_id();
-	switch (raw_id) {
-	/* Part number for 1GHz part */
-	case 0x770:
-	case 0x771:
-	case 0x77C:
-	case 0x780:
-	case 0x8D0:
-		cpu = MSM8625;
-		break;
-	/* Part number for 1.2GHz part */
-	case 0x773:
-	case 0x774:
-	case 0x779:
-	case 0x781:
-	case 0x8D1:
-		cpu = MSM8625A;
-		break;
-	case 0x775:
-	case 0x776:
-	case 0x77D:
-	case 0x782:
-	case 0x8D2:
-		cpu = MSM8625AB;
-		break;
-	default:
-		pr_err("Invalid Raw ID\n");
-		return -ENODEV;
-	}
-	return cpu;
-}
 
 int __init msm7x2x_misc_init(void)
 {
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
index 8febe26..8b59b14 100644
--- a/arch/arm/mach-msm/devices-msm7x2xa.h
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -31,6 +31,7 @@
 void __init msm8625_map_io(void);
 int  ar600x_wlan_power(bool on);
 void __init msm8x25_spm_device_init(void);
+void __init msm_pm_register_cpr_ops(void);
 void __init msm8x25_kgsl_3d0_init(void);
 void __iomem *core1_reset_base(void);
 extern void setup_mm_for_reboot(void);
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index d8f8480..aa33a0b 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -502,6 +502,7 @@
 	uint32_t gpio_mhl_power;
 	/* GPIO no. for hdmi-mhl mux */
 	uint32_t gpio_hdmi_mhl_mux;
+	bool mhl_enabled;
 };
 
 struct msm_i2c_platform_data {
@@ -515,6 +516,7 @@
 	int aux_dat;
 	int src_clk_rate;
 	int use_gsbi_shared_mode;
+	int keep_ahb_clk_on;
 	void (*msm_i2c_config_gpio)(int iface, int config_type);
 };
 
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 0867c1d..6298d94 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -700,4 +700,6 @@
 	(struct msm_camera_sensor_info *sinfo, int gpio_en);
 int msm_camera_request_gpio_table
 	(struct msm_camera_sensor_info *sinfo, int gpio_en);
+void msm_camera_bus_scale_cfg(uint32_t bus_perf_client,
+		enum msm_bus_perf_setting perf_setting);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 97c03e7..0c452f8 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -309,6 +309,24 @@
  */
 int smd_is_pkt_avail(smd_channel_t *ch);
 
+/**
+ * smd_module_init_notifier_register() - Register a smd module
+ *					 init notifier block
+ * @nb: Notifier block to be registered
+ *
+ * In order to mark the dependency on SMD Driver module initialization
+ * register a notifier using this API. Once the smd module_init is
+ * done, notification will be passed to the registered module.
+ */
+int smd_module_init_notifier_register(struct notifier_block *nb);
+
+/**
+ * smd_module_init_notifier_register() - Unregister a smd module
+ *					 init notifier block
+ * @nb: Notifier block to be registered
+ */
+int smd_module_init_notifier_unregister(struct notifier_block *nb);
+
 /*
  * SMD initialization function that registers for a SMD platform driver.
  *
@@ -438,6 +456,16 @@
 	return -ENODEV;
 }
 
+static inline int smd_module_init_notifier_register(struct notifier_block *nb)
+{
+	return -ENODEV;
+}
+
+static inline int smd_module_init_notifier_unregister(struct notifier_block *nb)
+{
+	return -ENODEV;
+}
+
 static inline int __init msm_smd_init(void)
 {
 	return 0;
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index e19f39d..133a1b3 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -133,8 +133,6 @@
 	void *data);
 int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
 	void (*notify)(void *, uint32_t, uint32_t), void *data);
-int smsm_driver_state_notifier_register(struct notifier_block *nb);
-int smsm_driver_state_notifier_unregister(struct notifier_block *nb);
 void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
 	uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
 void smsm_reset_modem(unsigned mode);
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 737db0b..47f9b10 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -10,8 +10,8 @@
  * GNU General Public License for more details.
  */
 
-#ifndef _ARCH_ARM_MACH_MSM_OCMEM_CORE_H
-#define _ARCH_ARM_MACH_MSM_OCMEM_CORE_H
+#ifndef _ARCH_ARM_MACH_MSM_OCMEM_PRIV_H
+#define _ARCH_ARM_MACH_MSM_OCMEM_PRIV_H
 
 /** All interfaces in this header should only be used by OCMEM driver
  *  Client drivers should use wrappers available in ocmem.h
@@ -36,6 +36,29 @@
 	int (*free) (struct ocmem_zone *, unsigned long, unsigned long);
 };
 
+/* OCMEM Zone specific counters */
+/* Must be in sync with zstat_names */
+enum ocmem_zstat_item {
+	NR_REQUESTS = 0x0,
+	NR_SYNC_ALLOCATIONS,
+	NR_RANGE_ALLOCATIONS,
+	NR_ASYNC_ALLOCATIONS,
+	NR_ALLOCATION_FAILS,
+	NR_GROWTHS,
+	NR_FREES,
+	NR_SHRINKS,
+	NR_MAPS,
+	NR_MAP_FAILS,
+	NR_UNMAPS,
+	NR_UNMAP_FAILS,
+	NR_TRANSFERS_TO_OCMEM,
+	NR_TRANSFERS_TO_DDR,
+	NR_TRANSFER_FAILS,
+	NR_EVICTIONS,
+	NR_RESTORES,
+	NR_OCMEM_ZSTAT_ITEMS,
+};
+
 struct ocmem_zone {
 	bool active;
 	int owner;
@@ -47,6 +70,7 @@
 	unsigned long z_head;
 	unsigned long z_tail;
 	unsigned long z_free;
+	atomic_long_t z_stat[NR_OCMEM_ZSTAT_ITEMS];
 	struct gen_pool *z_pool;
 	struct ocmem_zone_ops *z_ops;
 };
@@ -82,6 +106,7 @@
 	void __iomem *reg_base;
 	void __iomem *br_base;
 	void __iomem *dm_base;
+	struct dentry *debug_node;
 	unsigned nr_regions;
 	unsigned nr_macros;
 	unsigned nr_ports;
@@ -143,7 +168,9 @@
 struct ocmem_handle *req_to_handle(struct ocmem_req *);
 int ocmem_read(void *);
 int ocmem_write(unsigned long, void *);
-
+void inc_ocmem_stat(struct ocmem_zone *, enum ocmem_zstat_item);
+unsigned long get_ocmem_stat(struct ocmem_zone *z,
+				enum ocmem_zstat_item item);
 struct ocmem_zone *get_zone(unsigned);
 int zone_active(int);
 unsigned long offset_to_phys(unsigned long);
@@ -159,7 +186,7 @@
 int check_id(int);
 int dispatch_notification(int, enum ocmem_notif_type, struct ocmem_buf *);
 
-int ocmem_sched_init(void);
+int ocmem_sched_init(struct platform_device *);
 int ocmem_rdm_init(struct platform_device *);
 int ocmem_core_init(struct platform_device *);
 int process_allocate(int, struct ocmem_handle *, unsigned long, unsigned long,
diff --git a/arch/arm/mach-msm/include/mach/rpm-8930.h b/arch/arm/mach-msm/include/mach/rpm-8930.h
index 6fd9cf4..4ac9192 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8930.h
@@ -59,6 +59,8 @@
 	MSM_RPM_8930_SEL_MMSS_FABRIC_CFG_CLKMOD			= 27,
 	MSM_RPM_8930_SEL_MMSS_FABRIC_CFG_IOCTL			= 28,
 	MSM_RPM_8930_SEL_MM_FABRIC_ARB				= 29,
+
+	/* PMIC 8038 */
 	MSM_RPM_8930_SEL_PM8038_S1				= 30,
 	MSM_RPM_8930_SEL_PM8038_S2				= 31,
 	MSM_RPM_8930_SEL_PM8038_S3				= 32,
@@ -96,12 +98,65 @@
 	MSM_RPM_8930_SEL_PM8038_CLK2				= 64,
 	MSM_RPM_8930_SEL_PM8038_LVS1				= 65,
 	MSM_RPM_8930_SEL_PM8038_LVS2				= 66,
+
+	/* PMIC 8917 */
+	MSM_RPM_8930_SEL_PM8917_S1				= 30,
+	MSM_RPM_8930_SEL_PM8917_S2				= 31,
+	MSM_RPM_8930_SEL_PM8917_S3				= 32,
+	MSM_RPM_8930_SEL_PM8917_S4				= 33,
+	MSM_RPM_8930_SEL_PM8917_S5				= 34,
+	MSM_RPM_8930_SEL_PM8917_S6				= 35,
+	MSM_RPM_8930_SEL_PM8917_S7				= 36,
+	MSM_RPM_8930_SEL_PM8917_S8				= 37,
+	MSM_RPM_8930_SEL_PM8917_L1				= 38,
+	MSM_RPM_8930_SEL_PM8917_L2				= 39,
+	MSM_RPM_8930_SEL_PM8917_L3				= 40,
+	MSM_RPM_8930_SEL_PM8917_L4				= 41,
+	MSM_RPM_8930_SEL_PM8917_L5				= 42,
+	MSM_RPM_8930_SEL_PM8917_L6				= 43,
+	MSM_RPM_8930_SEL_PM8917_L7				= 44,
+	MSM_RPM_8930_SEL_PM8917_L8				= 45,
+	MSM_RPM_8930_SEL_PM8917_L9				= 46,
+	MSM_RPM_8930_SEL_PM8917_L10				= 47,
+	MSM_RPM_8930_SEL_PM8917_L11				= 48,
+	MSM_RPM_8930_SEL_PM8917_L12				= 49,
+	MSM_RPM_8930_SEL_PM8917_L14				= 50,
+	MSM_RPM_8930_SEL_PM8917_L15				= 51,
+	MSM_RPM_8930_SEL_PM8917_L16				= 52,
+	MSM_RPM_8930_SEL_PM8917_L17				= 53,
+	MSM_RPM_8930_SEL_PM8917_L18				= 54,
+	MSM_RPM_8930_SEL_PM8917_L21				= 55,
+	MSM_RPM_8930_SEL_PM8917_L22				= 56,
+	MSM_RPM_8930_SEL_PM8917_L23				= 57,
+	MSM_RPM_8930_SEL_PM8917_L24				= 58,
+	MSM_RPM_8930_SEL_PM8917_L25				= 59,
+	MSM_RPM_8930_SEL_PM8917_L26				= 60,
+	MSM_RPM_8930_SEL_PM8917_L27				= 61,
+	MSM_RPM_8930_SEL_PM8917_L28				= 62,
+	MSM_RPM_8930_SEL_PM8917_L29				= 63,
+	MSM_RPM_8930_SEL_PM8917_L30				= 64,
+	MSM_RPM_8930_SEL_PM8917_L31				= 65,
+	MSM_RPM_8930_SEL_PM8917_L32				= 66,
+	MSM_RPM_8930_SEL_PM8917_L33				= 67,
+	MSM_RPM_8930_SEL_PM8917_L34				= 68,
+	MSM_RPM_8930_SEL_PM8917_L35				= 69,
+	MSM_RPM_8930_SEL_PM8917_L36				= 70,
+	MSM_RPM_8930_SEL_PM8917_CLK1				= 71,
+	MSM_RPM_8930_SEL_PM8917_CLK2				= 72,
+	MSM_RPM_8930_SEL_PM8917_LVS1				= 73,
+	MSM_RPM_8930_SEL_PM8917_LVS3				= 74,
+	MSM_RPM_8930_SEL_PM8917_LVS4				= 75,
+	MSM_RPM_8930_SEL_PM8917_LVS5				= 76,
+	MSM_RPM_8930_SEL_PM8917_LVS6				= 77,
+	MSM_RPM_8930_SEL_PM8917_LVS7				= 78,
+
 	MSM_RPM_8930_SEL_NCP					= 80,
 	MSM_RPM_8930_SEL_CXO_BUFFERS				= 81,
 	MSM_RPM_8930_SEL_USB_OTG_SWITCH				= 82,
 	MSM_RPM_8930_SEL_HDMI_SWITCH				= 83,
 	MSM_RPM_8930_SEL_DDR_DMM				= 84,
 	MSM_RPM_8930_SEL_VOLTAGE_CORNER				= 87,
+
 	MSM_RPM_8930_SEL_LAST = MSM_RPM_8930_SEL_VOLTAGE_CORNER,
 };
 
@@ -163,6 +218,7 @@
 	MSM_RPM_8930_ID_MM_FABRIC_ARB_10 =
 		MSM_RPM_8930_ID_MM_FABRIC_ARB_0	+ 10,
 
+	/* PMIC 8038 */
 	MSM_RPM_8930_ID_PM8038_S1_0	= 90,
 	MSM_RPM_8930_ID_PM8038_S1_1	= 91,
 	MSM_RPM_8930_ID_PM8038_S2_0	= 92,
@@ -235,13 +291,109 @@
 	MSM_RPM_8930_ID_PM8038_CLK2_1	= 159,
 	MSM_RPM_8930_ID_PM8038_LVS1	= 160,
 	MSM_RPM_8930_ID_PM8038_LVS2	= 161,
-	MSM_RPM_8930_ID_NCP_0	= 162,
-	MSM_RPM_8930_ID_NCP_1	= 163,
-	MSM_RPM_8930_ID_CXO_BUFFERS	= 164,
-	MSM_RPM_8930_ID_USB_OTG_SWITCH	= 165,
-	MSM_RPM_8930_ID_HDMI_SWITCH	= 166,
-	MSM_RPM_8930_ID_QDSS_CLK	= 167,
-	MSM_RPM_8930_ID_VOLTAGE_CORNER	= 168,
+
+	/* PMIC 8917 */
+	MSM_RPM_8930_ID_PM8917_S1_0	= 90,
+	MSM_RPM_8930_ID_PM8917_S1_1	= 91,
+	MSM_RPM_8930_ID_PM8917_S2_0	= 92,
+	MSM_RPM_8930_ID_PM8917_S2_1	= 93,
+	MSM_RPM_8930_ID_PM8917_S3_0	= 94,
+	MSM_RPM_8930_ID_PM8917_S3_1	= 95,
+	MSM_RPM_8930_ID_PM8917_S4_0	= 96,
+	MSM_RPM_8930_ID_PM8917_S4_1	= 97,
+	MSM_RPM_8930_ID_PM8917_S5_0	= 98,
+	MSM_RPM_8930_ID_PM8917_S5_1	= 99,
+	MSM_RPM_8930_ID_PM8917_S6_0	= 100,
+	MSM_RPM_8930_ID_PM8917_S6_1	= 101,
+	MSM_RPM_8930_ID_PM8917_S7_0	= 102,
+	MSM_RPM_8930_ID_PM8917_S7_1	= 103,
+	MSM_RPM_8930_ID_PM8917_S8_0	= 104,
+	MSM_RPM_8930_ID_PM8917_S8_1	= 105,
+	MSM_RPM_8930_ID_PM8917_L1_0	= 106,
+	MSM_RPM_8930_ID_PM8917_L1_1	= 107,
+	MSM_RPM_8930_ID_PM8917_L2_0	= 108,
+	MSM_RPM_8930_ID_PM8917_L2_1	= 109,
+	MSM_RPM_8930_ID_PM8917_L3_0	= 110,
+	MSM_RPM_8930_ID_PM8917_L3_1	= 111,
+	MSM_RPM_8930_ID_PM8917_L4_0	= 112,
+	MSM_RPM_8930_ID_PM8917_L4_1	= 113,
+	MSM_RPM_8930_ID_PM8917_L5_0	= 114,
+	MSM_RPM_8930_ID_PM8917_L5_1	= 115,
+	MSM_RPM_8930_ID_PM8917_L6_0	= 116,
+	MSM_RPM_8930_ID_PM8917_L6_1	= 117,
+	MSM_RPM_8930_ID_PM8917_L7_0	= 118,
+	MSM_RPM_8930_ID_PM8917_L7_1	= 119,
+	MSM_RPM_8930_ID_PM8917_L8_0	= 120,
+	MSM_RPM_8930_ID_PM8917_L8_1	= 121,
+	MSM_RPM_8930_ID_PM8917_L9_0	= 122,
+	MSM_RPM_8930_ID_PM8917_L9_1	= 123,
+	MSM_RPM_8930_ID_PM8917_L10_0	= 124,
+	MSM_RPM_8930_ID_PM8917_L10_1	= 125,
+	MSM_RPM_8930_ID_PM8917_L11_0	= 126,
+	MSM_RPM_8930_ID_PM8917_L11_1	= 127,
+	MSM_RPM_8930_ID_PM8917_L12_0	= 128,
+	MSM_RPM_8930_ID_PM8917_L12_1	= 129,
+	MSM_RPM_8930_ID_PM8917_L14_0	= 130,
+	MSM_RPM_8930_ID_PM8917_L14_1	= 131,
+	MSM_RPM_8930_ID_PM8917_L15_0	= 132,
+	MSM_RPM_8930_ID_PM8917_L15_1	= 133,
+	MSM_RPM_8930_ID_PM8917_L16_0	= 134,
+	MSM_RPM_8930_ID_PM8917_L16_1	= 135,
+	MSM_RPM_8930_ID_PM8917_L17_0	= 136,
+	MSM_RPM_8930_ID_PM8917_L17_1	= 137,
+	MSM_RPM_8930_ID_PM8917_L18_0	= 138,
+	MSM_RPM_8930_ID_PM8917_L18_1	= 139,
+	MSM_RPM_8930_ID_PM8917_L21_0	= 140,
+	MSM_RPM_8930_ID_PM8917_L21_1	= 141,
+	MSM_RPM_8930_ID_PM8917_L22_0	= 142,
+	MSM_RPM_8930_ID_PM8917_L22_1	= 143,
+	MSM_RPM_8930_ID_PM8917_L23_0	= 144,
+	MSM_RPM_8930_ID_PM8917_L23_1	= 145,
+	MSM_RPM_8930_ID_PM8917_L24_0	= 146,
+	MSM_RPM_8930_ID_PM8917_L24_1	= 147,
+	MSM_RPM_8930_ID_PM8917_L25_0	= 148,
+	MSM_RPM_8930_ID_PM8917_L25_1	= 149,
+	MSM_RPM_8930_ID_PM8917_L26_0	= 150,
+	MSM_RPM_8930_ID_PM8917_L26_1	= 151,
+	MSM_RPM_8930_ID_PM8917_L27_0	= 152,
+	MSM_RPM_8930_ID_PM8917_L27_1	= 153,
+	MSM_RPM_8930_ID_PM8917_L28_0	= 154,
+	MSM_RPM_8930_ID_PM8917_L28_1	= 155,
+	MSM_RPM_8930_ID_PM8917_L29_0	= 156,
+	MSM_RPM_8930_ID_PM8917_L29_1	= 157,
+	MSM_RPM_8930_ID_PM8917_L30_0	= 158,
+	MSM_RPM_8930_ID_PM8917_L30_1	= 159,
+	MSM_RPM_8930_ID_PM8917_L31_0	= 160,
+	MSM_RPM_8930_ID_PM8917_L31_1	= 161,
+	MSM_RPM_8930_ID_PM8917_L32_0	= 162,
+	MSM_RPM_8930_ID_PM8917_L32_1	= 163,
+	MSM_RPM_8930_ID_PM8917_L33_0	= 164,
+	MSM_RPM_8930_ID_PM8917_L33_1	= 165,
+	MSM_RPM_8930_ID_PM8917_L34_0	= 166,
+	MSM_RPM_8930_ID_PM8917_L34_1	= 167,
+	MSM_RPM_8930_ID_PM8917_L35_0	= 168,
+	MSM_RPM_8930_ID_PM8917_L35_1	= 169,
+	MSM_RPM_8930_ID_PM8917_L36_0	= 170,
+	MSM_RPM_8930_ID_PM8917_L36_1	= 171,
+	MSM_RPM_8930_ID_PM8917_CLK1_0	= 172,
+	MSM_RPM_8930_ID_PM8917_CLK1_1	= 173,
+	MSM_RPM_8930_ID_PM8917_CLK2_0	= 174,
+	MSM_RPM_8930_ID_PM8917_CLK2_1	= 175,
+	MSM_RPM_8930_ID_PM8917_LVS1	= 176,
+	MSM_RPM_8930_ID_PM8917_LVS3	= 177,
+	MSM_RPM_8930_ID_PM8917_LVS4	= 178,
+	MSM_RPM_8930_ID_PM8917_LVS5	= 179,
+	MSM_RPM_8930_ID_PM8917_LVS6	= 180,
+	MSM_RPM_8930_ID_PM8917_LVS7	= 181,
+
+	MSM_RPM_8930_ID_NCP_0		= 182,
+	MSM_RPM_8930_ID_NCP_1		= 183,
+	MSM_RPM_8930_ID_CXO_BUFFERS	= 184,
+	MSM_RPM_8930_ID_USB_OTG_SWITCH	= 185,
+	MSM_RPM_8930_ID_HDMI_SWITCH	= 186,
+	MSM_RPM_8930_ID_QDSS_CLK	= 187,
+	MSM_RPM_8930_ID_VOLTAGE_CORNER	= 188,
+
 	MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_VOLTAGE_CORNER,
 };
 
@@ -278,6 +430,8 @@
 	MSM_RPM_8930_STATUS_ID_MMSS_FABRIC_CFG_CLKMOD		= 28,
 	MSM_RPM_8930_STATUS_ID_MMSS_FABRIC_CFG_IOCTL		= 29,
 	MSM_RPM_8930_STATUS_ID_MM_FABRIC_ARB			= 30,
+
+	/* PMIC 8038 */
 	MSM_RPM_8930_STATUS_ID_PM8038_S1_0			= 31,
 	MSM_RPM_8930_STATUS_ID_PM8038_S1_1			= 32,
 	MSM_RPM_8930_STATUS_ID_PM8038_S2_0			= 33,
@@ -346,14 +500,119 @@
 	MSM_RPM_8930_STATUS_ID_PM8038_CLK2_1			= 100,
 	MSM_RPM_8930_STATUS_ID_PM8038_LVS1			= 101,
 	MSM_RPM_8930_STATUS_ID_PM8038_LVS2			= 102,
-	MSM_RPM_8930_STATUS_ID_NCP_0				= 103,
-	MSM_RPM_8930_STATUS_ID_NCP_1				= 104,
-	MSM_RPM_8930_STATUS_ID_CXO_BUFFERS			= 105,
-	MSM_RPM_8930_STATUS_ID_USB_OTG_SWITCH			= 106,
-	MSM_RPM_8930_STATUS_ID_HDMI_SWITCH			= 107,
-	MSM_RPM_8930_STATUS_ID_QDSS_CLK				= 108,
-	MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER			= 109,
-	MSM_RPM_8930_STATUS_ID_LAST = MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER,
+	MSM_RPM_8930_STATUS_ID_PM8038_NCP_0			= 103,
+	MSM_RPM_8930_STATUS_ID_PM8038_NCP_1			= 104,
+	MSM_RPM_8930_STATUS_ID_PM8038_CXO_BUFFERS		= 105,
+	MSM_RPM_8930_STATUS_ID_PM8038_USB_OTG_SWITCH		= 106,
+	MSM_RPM_8930_STATUS_ID_PM8038_HDMI_SWITCH		= 107,
+	MSM_RPM_8930_STATUS_ID_PM8038_QDSS_CLK			= 108,
+	MSM_RPM_8930_STATUS_ID_PM8038_VOLTAGE_CORNER		= 109,
+
+	MSM_RPM_8930_STATUS_ID_PM8038_LAST
+		= MSM_RPM_8930_STATUS_ID_PM8038_VOLTAGE_CORNER,
+
+	/* PMIC 8917 */
+	MSM_RPM_8930_STATUS_ID_PM8917_S1_0			= 31,
+	MSM_RPM_8930_STATUS_ID_PM8917_S1_1			= 32,
+	MSM_RPM_8930_STATUS_ID_PM8917_S2_0			= 33,
+	MSM_RPM_8930_STATUS_ID_PM8917_S2_1			= 34,
+	MSM_RPM_8930_STATUS_ID_PM8917_S3_0			= 35,
+	MSM_RPM_8930_STATUS_ID_PM8917_S3_1			= 36,
+	MSM_RPM_8930_STATUS_ID_PM8917_S4_0			= 37,
+	MSM_RPM_8930_STATUS_ID_PM8917_S4_1			= 38,
+	MSM_RPM_8930_STATUS_ID_PM8917_S5_0			= 39,
+	MSM_RPM_8930_STATUS_ID_PM8917_S5_1			= 40,
+	MSM_RPM_8930_STATUS_ID_PM8917_S6_0			= 41,
+	MSM_RPM_8930_STATUS_ID_PM8917_S6_1			= 42,
+	MSM_RPM_8930_STATUS_ID_PM8917_S7_0			= 43,
+	MSM_RPM_8930_STATUS_ID_PM8917_S7_1			= 44,
+	MSM_RPM_8930_STATUS_ID_PM8917_S8_0			= 45,
+	MSM_RPM_8930_STATUS_ID_PM8917_S8_1			= 46,
+	MSM_RPM_8930_STATUS_ID_PM8917_L1_0			= 47,
+	MSM_RPM_8930_STATUS_ID_PM8917_L1_1			= 48,
+	MSM_RPM_8930_STATUS_ID_PM8917_L2_0			= 49,
+	MSM_RPM_8930_STATUS_ID_PM8917_L2_1			= 50,
+	MSM_RPM_8930_STATUS_ID_PM8917_L3_0			= 51,
+	MSM_RPM_8930_STATUS_ID_PM8917_L3_1			= 52,
+	MSM_RPM_8930_STATUS_ID_PM8917_L4_0			= 53,
+	MSM_RPM_8930_STATUS_ID_PM8917_L4_1			= 54,
+	MSM_RPM_8930_STATUS_ID_PM8917_L5_0			= 55,
+	MSM_RPM_8930_STATUS_ID_PM8917_L5_1			= 56,
+	MSM_RPM_8930_STATUS_ID_PM8917_L6_0			= 57,
+	MSM_RPM_8930_STATUS_ID_PM8917_L6_1			= 58,
+	MSM_RPM_8930_STATUS_ID_PM8917_L7_0			= 59,
+	MSM_RPM_8930_STATUS_ID_PM8917_L7_1			= 60,
+	MSM_RPM_8930_STATUS_ID_PM8917_L8_0			= 61,
+	MSM_RPM_8930_STATUS_ID_PM8917_L8_1			= 62,
+	MSM_RPM_8930_STATUS_ID_PM8917_L9_0			= 63,
+	MSM_RPM_8930_STATUS_ID_PM8917_L9_1			= 64,
+	MSM_RPM_8930_STATUS_ID_PM8917_L10_0			= 65,
+	MSM_RPM_8930_STATUS_ID_PM8917_L10_1			= 66,
+	MSM_RPM_8930_STATUS_ID_PM8917_L11_0			= 67,
+	MSM_RPM_8930_STATUS_ID_PM8917_L11_1			= 68,
+	MSM_RPM_8930_STATUS_ID_PM8917_L12_0			= 69,
+	MSM_RPM_8930_STATUS_ID_PM8917_L12_1			= 70,
+	MSM_RPM_8930_STATUS_ID_PM8917_L14_0			= 71,
+	MSM_RPM_8930_STATUS_ID_PM8917_L14_1			= 72,
+	MSM_RPM_8930_STATUS_ID_PM8917_L15_0			= 73,
+	MSM_RPM_8930_STATUS_ID_PM8917_L15_1			= 74,
+	MSM_RPM_8930_STATUS_ID_PM8917_L16_0			= 75,
+	MSM_RPM_8930_STATUS_ID_PM8917_L16_1			= 76,
+	MSM_RPM_8930_STATUS_ID_PM8917_L17_0			= 77,
+	MSM_RPM_8930_STATUS_ID_PM8917_L17_1			= 78,
+	MSM_RPM_8930_STATUS_ID_PM8917_L18_0			= 79,
+	MSM_RPM_8930_STATUS_ID_PM8917_L18_1			= 80,
+	MSM_RPM_8930_STATUS_ID_PM8917_L21_0			= 81,
+	MSM_RPM_8930_STATUS_ID_PM8917_L21_1			= 82,
+	MSM_RPM_8930_STATUS_ID_PM8917_L22_0			= 83,
+	MSM_RPM_8930_STATUS_ID_PM8917_L22_1			= 84,
+	MSM_RPM_8930_STATUS_ID_PM8917_L23_0			= 85,
+	MSM_RPM_8930_STATUS_ID_PM8917_L23_1			= 86,
+	MSM_RPM_8930_STATUS_ID_PM8917_L24_0			= 87,
+	MSM_RPM_8930_STATUS_ID_PM8917_L24_1			= 88,
+	MSM_RPM_8930_STATUS_ID_PM8917_L25_0			= 89,
+	MSM_RPM_8930_STATUS_ID_PM8917_L25_1			= 90,
+	MSM_RPM_8930_STATUS_ID_PM8917_L26_0			= 91,
+	MSM_RPM_8930_STATUS_ID_PM8917_L26_1			= 92,
+	MSM_RPM_8930_STATUS_ID_PM8917_L27_0			= 93,
+	MSM_RPM_8930_STATUS_ID_PM8917_L27_1			= 94,
+	MSM_RPM_8930_STATUS_ID_PM8917_L28_0			= 95,
+	MSM_RPM_8930_STATUS_ID_PM8917_L28_1			= 96,
+	MSM_RPM_8930_STATUS_ID_PM8917_L29_0			= 97,
+	MSM_RPM_8930_STATUS_ID_PM8917_L29_1			= 98,
+	MSM_RPM_8930_STATUS_ID_PM8917_L30_0			= 99,
+	MSM_RPM_8930_STATUS_ID_PM8917_L30_1			= 100,
+	MSM_RPM_8930_STATUS_ID_PM8917_L31_0			= 101,
+	MSM_RPM_8930_STATUS_ID_PM8917_L31_1			= 102,
+	MSM_RPM_8930_STATUS_ID_PM8917_L32_0			= 103,
+	MSM_RPM_8930_STATUS_ID_PM8917_L32_1			= 104,
+	MSM_RPM_8930_STATUS_ID_PM8917_L33_0			= 105,
+	MSM_RPM_8930_STATUS_ID_PM8917_L33_1			= 106,
+	MSM_RPM_8930_STATUS_ID_PM8917_L34_0			= 107,
+	MSM_RPM_8930_STATUS_ID_PM8917_L34_1			= 108,
+	MSM_RPM_8930_STATUS_ID_PM8917_L35_0			= 109,
+	MSM_RPM_8930_STATUS_ID_PM8917_L35_1			= 110,
+	MSM_RPM_8930_STATUS_ID_PM8917_L36_0			= 111,
+	MSM_RPM_8930_STATUS_ID_PM8917_L36_1			= 112,
+	MSM_RPM_8930_STATUS_ID_PM8917_CLK1_0			= 113,
+	MSM_RPM_8930_STATUS_ID_PM8917_CLK1_1			= 114,
+	MSM_RPM_8930_STATUS_ID_PM8917_CLK2_0			= 115,
+	MSM_RPM_8930_STATUS_ID_PM8917_CLK2_1			= 116,
+	MSM_RPM_8930_STATUS_ID_PM8917_LVS1			= 117,
+	MSM_RPM_8930_STATUS_ID_PM8917_LVS3			= 118,
+	MSM_RPM_8930_STATUS_ID_PM8917_LVS4			= 119,
+	MSM_RPM_8930_STATUS_ID_PM8917_LVS5			= 120,
+	MSM_RPM_8930_STATUS_ID_PM8917_LVS6			= 121,
+	MSM_RPM_8930_STATUS_ID_PM8917_LVS7			= 122,
+	MSM_RPM_8930_STATUS_ID_PM8917_NCP_0			= 123,
+	MSM_RPM_8930_STATUS_ID_PM8917_NCP_1			= 124,
+	MSM_RPM_8930_STATUS_ID_PM8917_CXO_BUFFERS		= 125,
+	MSM_RPM_8930_STATUS_ID_PM8917_USB_OTG_SWITCH		= 126,
+	MSM_RPM_8930_STATUS_ID_PM8917_HDMI_SWITCH		= 127,
+	MSM_RPM_8930_STATUS_ID_PM8917_QDSS_CLK			= 128,
+	MSM_RPM_8930_STATUS_ID_PM8917_VOLTAGE_CORNER		= 129,
+	MSM_RPM_8930_STATUS_ID_PM8917_PM8917_LAST
+			= MSM_RPM_8930_STATUS_ID_PM8917_VOLTAGE_CORNER,
 };
 
 #endif /* __ARCH_ARM_MACH_MSM_RPM_8930_H */
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h b/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
index 47056a8..f8f53f6 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
@@ -85,9 +85,10 @@
 };
 
 /**
- * enum rpm_vreg_id - RPM regulator ID numbers (both real and pin control)
+ * enum rpm_vreg_id_8930_pm8038 - RPM regulator ID numbers (both real and
+ *		pin control) used with MSM8930 + PM8038
  */
-enum rpm_vreg_id_8930 {
+enum rpm_vreg_id_8930_pm8038 {
 	RPM_VREG_ID_PM8038_L1,
 	RPM_VREG_ID_PM8038_L2,
 	RPM_VREG_ID_PM8038_L3,
@@ -155,6 +156,109 @@
 	RPM_VREG_ID_PM8038_MAX = RPM_VREG_ID_PM8038_LVS2_PC,
 };
 
+/**
+ * enum rpm_vreg_id_8930_pm8917 - RPM regulator ID numbers (both real and
+ *		pin control) used with MSM8930 + PM8917
+ */
+enum rpm_vreg_id_8930_pm8917 {
+	RPM_VREG_ID_PM8917_L1,
+	RPM_VREG_ID_PM8917_L2,
+	RPM_VREG_ID_PM8917_L3,
+	RPM_VREG_ID_PM8917_L4,
+	RPM_VREG_ID_PM8917_L5,
+	RPM_VREG_ID_PM8917_L6,
+	RPM_VREG_ID_PM8917_L7,
+	RPM_VREG_ID_PM8917_L8,
+	RPM_VREG_ID_PM8917_L9,
+	RPM_VREG_ID_PM8917_L10,
+	RPM_VREG_ID_PM8917_L11,
+	RPM_VREG_ID_PM8917_L12,
+	RPM_VREG_ID_PM8917_L14,
+	RPM_VREG_ID_PM8917_L15,
+	RPM_VREG_ID_PM8917_L16,
+	RPM_VREG_ID_PM8917_L17,
+	RPM_VREG_ID_PM8917_L18,
+	RPM_VREG_ID_PM8917_L21,
+	RPM_VREG_ID_PM8917_L22,
+	RPM_VREG_ID_PM8917_L23,
+	RPM_VREG_ID_PM8917_L24,
+	RPM_VREG_ID_PM8917_L25,
+	RPM_VREG_ID_PM8917_L26,
+	RPM_VREG_ID_PM8917_L27,
+	RPM_VREG_ID_PM8917_L28,
+	RPM_VREG_ID_PM8917_L29,
+	RPM_VREG_ID_PM8917_L30,
+	RPM_VREG_ID_PM8917_L31,
+	RPM_VREG_ID_PM8917_L32,
+	RPM_VREG_ID_PM8917_L33,
+	RPM_VREG_ID_PM8917_L34,
+	RPM_VREG_ID_PM8917_L35,
+	RPM_VREG_ID_PM8917_L36,
+	RPM_VREG_ID_PM8917_S1,
+	RPM_VREG_ID_PM8917_S2,
+	RPM_VREG_ID_PM8917_S3,
+	RPM_VREG_ID_PM8917_S4,
+	RPM_VREG_ID_PM8917_S5,
+	RPM_VREG_ID_PM8917_S6,
+	RPM_VREG_ID_PM8917_S7,
+	RPM_VREG_ID_PM8917_S8,
+	RPM_VREG_ID_PM8917_LVS1,
+	RPM_VREG_ID_PM8917_LVS3,
+	RPM_VREG_ID_PM8917_LVS4,
+	RPM_VREG_ID_PM8917_LVS5,
+	RPM_VREG_ID_PM8917_LVS6,
+	RPM_VREG_ID_PM8917_LVS7,
+	RPM_VREG_ID_PM8917_USB_OTG,
+	RPM_VREG_ID_PM8917_VDD_DIG_CORNER,
+	RPM_VREG_ID_PM8917_MAX_REAL = RPM_VREG_ID_PM8917_VDD_DIG_CORNER,
+
+	/* The following are IDs for regulator devices to enable pin control. */
+	RPM_VREG_ID_PM8917_L1_PC,
+	RPM_VREG_ID_PM8917_L2_PC,
+	RPM_VREG_ID_PM8917_L3_PC,
+	RPM_VREG_ID_PM8917_L4_PC,
+	RPM_VREG_ID_PM8917_L5_PC,
+	RPM_VREG_ID_PM8917_L6_PC,
+	RPM_VREG_ID_PM8917_L7_PC,
+	RPM_VREG_ID_PM8917_L8_PC,
+	RPM_VREG_ID_PM8917_L9_PC,
+	RPM_VREG_ID_PM8917_L10_PC,
+	RPM_VREG_ID_PM8917_L11_PC,
+	RPM_VREG_ID_PM8917_L12_PC,
+	RPM_VREG_ID_PM8917_L14_PC,
+	RPM_VREG_ID_PM8917_L15_PC,
+	RPM_VREG_ID_PM8917_L16_PC,
+	RPM_VREG_ID_PM8917_L17_PC,
+	RPM_VREG_ID_PM8917_L18_PC,
+	RPM_VREG_ID_PM8917_L21_PC,
+	RPM_VREG_ID_PM8917_L22_PC,
+	RPM_VREG_ID_PM8917_L23_PC,
+
+	RPM_VREG_ID_PM8917_L29_PC,
+	RPM_VREG_ID_PM8917_L30_PC,
+	RPM_VREG_ID_PM8917_L31_PC,
+	RPM_VREG_ID_PM8917_L32_PC,
+	RPM_VREG_ID_PM8917_L33_PC,
+	RPM_VREG_ID_PM8917_L34_PC,
+	RPM_VREG_ID_PM8917_L35_PC,
+	RPM_VREG_ID_PM8917_L36_PC,
+	RPM_VREG_ID_PM8917_S1_PC,
+	RPM_VREG_ID_PM8917_S2_PC,
+	RPM_VREG_ID_PM8917_S3_PC,
+	RPM_VREG_ID_PM8917_S4_PC,
+
+	RPM_VREG_ID_PM8917_S7_PC,
+	RPM_VREG_ID_PM8917_S8_PC,
+	RPM_VREG_ID_PM8917_LVS1_PC,
+	RPM_VREG_ID_PM8917_LVS3_PC,
+	RPM_VREG_ID_PM8917_LVS4_PC,
+	RPM_VREG_ID_PM8917_LVS5_PC,
+	RPM_VREG_ID_PM8917_LVS6_PC,
+	RPM_VREG_ID_PM8917_LVS7_PC,
+
+	RPM_VREG_ID_PM8917_MAX = RPM_VREG_ID_PM8917_LVS7_PC,
+};
+
 /* Minimum high power mode loads in uA. */
 #define RPM_VREG_8930_LDO_5_HPM_MIN_LOAD		0
 #define RPM_VREG_8930_LDO_50_HPM_MIN_LOAD		5000
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
index d2ff2fe..f6e082d 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -31,7 +31,8 @@
 	RPM_VREG_VERSION_8960,
 	RPM_VREG_VERSION_9615,
 	RPM_VREG_VERSION_8930,
-	RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8930,
+	RPM_VREG_VERSION_8930_PM8917,
+	RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8930_PM8917,
 };
 
 #define RPM_VREG_PIN_CTRL_NONE		0x00
diff --git a/arch/arm/mach-msm/include/mach/rpm.h b/arch/arm/mach-msm/include/mach/rpm.h
index f6b9a6e..4ee1997 100644
--- a/arch/arm/mach-msm/include/mach/rpm.h
+++ b/arch/arm/mach-msm/include/mach/rpm.h
@@ -451,6 +451,100 @@
 	MSM_RPM_ID_PM8038_CLK2_1,
 	MSM_RPM_ID_PM8038_LVS1,
 	MSM_RPM_ID_PM8038_LVS2,
+
+	/* PM8917 specific */
+	MSM_RPM_ID_PM8917_S1_0,
+	MSM_RPM_ID_PM8917_S1_1,
+	MSM_RPM_ID_PM8917_S2_0,
+	MSM_RPM_ID_PM8917_S2_1,
+	MSM_RPM_ID_PM8917_S3_0,
+	MSM_RPM_ID_PM8917_S3_1,
+	MSM_RPM_ID_PM8917_S4_0,
+	MSM_RPM_ID_PM8917_S4_1,
+	MSM_RPM_ID_PM8917_S5_0,
+	MSM_RPM_ID_PM8917_S5_1,
+	MSM_RPM_ID_PM8917_S6_0,
+	MSM_RPM_ID_PM8917_S6_1,
+	MSM_RPM_ID_PM8917_S7_0,
+	MSM_RPM_ID_PM8917_S7_1,
+	MSM_RPM_ID_PM8917_S8_0,
+	MSM_RPM_ID_PM8917_S8_1,
+	MSM_RPM_ID_PM8917_L1_0,
+	MSM_RPM_ID_PM8917_L1_1,
+	MSM_RPM_ID_PM8917_L2_0,
+	MSM_RPM_ID_PM8917_L2_1,
+	MSM_RPM_ID_PM8917_L3_0,
+	MSM_RPM_ID_PM8917_L3_1,
+	MSM_RPM_ID_PM8917_L4_0,
+	MSM_RPM_ID_PM8917_L4_1,
+	MSM_RPM_ID_PM8917_L5_0,
+	MSM_RPM_ID_PM8917_L5_1,
+	MSM_RPM_ID_PM8917_L6_0,
+	MSM_RPM_ID_PM8917_L6_1,
+	MSM_RPM_ID_PM8917_L7_0,
+	MSM_RPM_ID_PM8917_L7_1,
+	MSM_RPM_ID_PM8917_L8_0,
+	MSM_RPM_ID_PM8917_L8_1,
+	MSM_RPM_ID_PM8917_L9_0,
+	MSM_RPM_ID_PM8917_L9_1,
+	MSM_RPM_ID_PM8917_L10_0,
+	MSM_RPM_ID_PM8917_L10_1,
+	MSM_RPM_ID_PM8917_L11_0,
+	MSM_RPM_ID_PM8917_L11_1,
+	MSM_RPM_ID_PM8917_L12_0,
+	MSM_RPM_ID_PM8917_L12_1,
+	MSM_RPM_ID_PM8917_L14_0,
+	MSM_RPM_ID_PM8917_L14_1,
+	MSM_RPM_ID_PM8917_L15_0,
+	MSM_RPM_ID_PM8917_L15_1,
+	MSM_RPM_ID_PM8917_L16_0,
+	MSM_RPM_ID_PM8917_L16_1,
+	MSM_RPM_ID_PM8917_L17_0,
+	MSM_RPM_ID_PM8917_L17_1,
+	MSM_RPM_ID_PM8917_L18_0,
+	MSM_RPM_ID_PM8917_L18_1,
+	MSM_RPM_ID_PM8917_L21_0,
+	MSM_RPM_ID_PM8917_L21_1,
+	MSM_RPM_ID_PM8917_L22_0,
+	MSM_RPM_ID_PM8917_L22_1,
+	MSM_RPM_ID_PM8917_L23_0,
+	MSM_RPM_ID_PM8917_L23_1,
+	MSM_RPM_ID_PM8917_L24_0,
+	MSM_RPM_ID_PM8917_L24_1,
+	MSM_RPM_ID_PM8917_L25_0,
+	MSM_RPM_ID_PM8917_L25_1,
+	MSM_RPM_ID_PM8917_L26_0,
+	MSM_RPM_ID_PM8917_L26_1,
+	MSM_RPM_ID_PM8917_L27_0,
+	MSM_RPM_ID_PM8917_L27_1,
+	MSM_RPM_ID_PM8917_L28_0,
+	MSM_RPM_ID_PM8917_L28_1,
+	MSM_RPM_ID_PM8917_L29_0,
+	MSM_RPM_ID_PM8917_L29_1,
+	MSM_RPM_ID_PM8917_L30_0,
+	MSM_RPM_ID_PM8917_L30_1,
+	MSM_RPM_ID_PM8917_L31_0,
+	MSM_RPM_ID_PM8917_L31_1,
+	MSM_RPM_ID_PM8917_L32_0,
+	MSM_RPM_ID_PM8917_L32_1,
+	MSM_RPM_ID_PM8917_L33_0,
+	MSM_RPM_ID_PM8917_L33_1,
+	MSM_RPM_ID_PM8917_L34_0,
+	MSM_RPM_ID_PM8917_L34_1,
+	MSM_RPM_ID_PM8917_L35_0,
+	MSM_RPM_ID_PM8917_L35_1,
+	MSM_RPM_ID_PM8917_L36_0,
+	MSM_RPM_ID_PM8917_L36_1,
+	MSM_RPM_ID_PM8917_CLK1_0,
+	MSM_RPM_ID_PM8917_CLK1_1,
+	MSM_RPM_ID_PM8917_CLK2_0,
+	MSM_RPM_ID_PM8917_CLK2_1,
+	MSM_RPM_ID_PM8917_LVS1,
+	MSM_RPM_ID_PM8917_LVS3,
+	MSM_RPM_ID_PM8917_LVS4,
+	MSM_RPM_ID_PM8917_LVS5,
+	MSM_RPM_ID_PM8917_LVS6,
+	MSM_RPM_ID_PM8917_LVS7,
 	MSM_RPM_ID_VOLTAGE_CORNER,
 
 	/* 8064 specific */
@@ -605,6 +699,29 @@
 	MSM_RPM_STATUS_ID_EBI1_CH1_RANGE,
 	MSM_RPM_STATUS_ID_QDSS_CLK,
 
+	/* 8930 aliases to simplify device mapping */
+	MSM_RPM_STATUS_ID_PM8038_NCP_0 = MSM_RPM_STATUS_ID_NCP_0,
+	MSM_RPM_STATUS_ID_PM8038_NCP_1 = MSM_RPM_STATUS_ID_NCP_1,
+	MSM_RPM_STATUS_ID_PM8038_CXO_BUFFERS
+		= MSM_RPM_STATUS_ID_CXO_BUFFERS,
+	MSM_RPM_STATUS_ID_PM8038_USB_OTG_SWITCH
+		= MSM_RPM_STATUS_ID_USB_OTG_SWITCH,
+	MSM_RPM_STATUS_ID_PM8038_HDMI_SWITCH
+		= MSM_RPM_STATUS_ID_HDMI_SWITCH,
+	MSM_RPM_STATUS_ID_PM8038_QDSS_CLK
+		= MSM_RPM_STATUS_ID_QDSS_CLK,
+
+	MSM_RPM_STATUS_ID_PM8917_NCP_0 = MSM_RPM_STATUS_ID_NCP_0,
+		MSM_RPM_STATUS_ID_PM8917_NCP_1 = MSM_RPM_STATUS_ID_NCP_1,
+	MSM_RPM_STATUS_ID_PM8917_CXO_BUFFERS
+		= MSM_RPM_STATUS_ID_CXO_BUFFERS,
+	MSM_RPM_STATUS_ID_PM8917_USB_OTG_SWITCH
+		= MSM_RPM_STATUS_ID_USB_OTG_SWITCH,
+	MSM_RPM_STATUS_ID_PM8917_HDMI_SWITCH
+		= MSM_RPM_STATUS_ID_HDMI_SWITCH,
+	MSM_RPM_STATUS_ID_PM8917_QDSS_CLK
+		= MSM_RPM_STATUS_ID_QDSS_CLK,
+
 	/* 8660 Specific */
 	MSM_RPM_STATUS_ID_PLL_4,
 	MSM_RPM_STATUS_ID_SMI_CLK,
@@ -817,7 +934,105 @@
 	MSM_RPM_STATUS_ID_PM8038_CLK2_1,
 	MSM_RPM_STATUS_ID_PM8038_LVS1,
 	MSM_RPM_STATUS_ID_PM8038_LVS2,
+
+	/* PMIC 8917 */
+	MSM_RPM_STATUS_ID_PM8917_S1_0,
+	MSM_RPM_STATUS_ID_PM8917_S1_1,
+	MSM_RPM_STATUS_ID_PM8917_S2_0,
+	MSM_RPM_STATUS_ID_PM8917_S2_1,
+	MSM_RPM_STATUS_ID_PM8917_S3_0,
+	MSM_RPM_STATUS_ID_PM8917_S3_1,
+	MSM_RPM_STATUS_ID_PM8917_S4_0,
+	MSM_RPM_STATUS_ID_PM8917_S4_1,
+	MSM_RPM_STATUS_ID_PM8917_S5_0,
+	MSM_RPM_STATUS_ID_PM8917_S5_1,
+	MSM_RPM_STATUS_ID_PM8917_S6_0,
+	MSM_RPM_STATUS_ID_PM8917_S6_1,
+	MSM_RPM_STATUS_ID_PM8917_S7_0,
+	MSM_RPM_STATUS_ID_PM8917_S7_1,
+	MSM_RPM_STATUS_ID_PM8917_S8_0,
+	MSM_RPM_STATUS_ID_PM8917_S8_1,
+	MSM_RPM_STATUS_ID_PM8917_L1_0,
+	MSM_RPM_STATUS_ID_PM8917_L1_1,
+	MSM_RPM_STATUS_ID_PM8917_L2_0,
+	MSM_RPM_STATUS_ID_PM8917_L2_1,
+	MSM_RPM_STATUS_ID_PM8917_L3_0,
+	MSM_RPM_STATUS_ID_PM8917_L3_1,
+	MSM_RPM_STATUS_ID_PM8917_L4_0,
+	MSM_RPM_STATUS_ID_PM8917_L4_1,
+	MSM_RPM_STATUS_ID_PM8917_L5_0,
+	MSM_RPM_STATUS_ID_PM8917_L5_1,
+	MSM_RPM_STATUS_ID_PM8917_L6_0,
+	MSM_RPM_STATUS_ID_PM8917_L6_1,
+	MSM_RPM_STATUS_ID_PM8917_L7_0,
+	MSM_RPM_STATUS_ID_PM8917_L7_1,
+	MSM_RPM_STATUS_ID_PM8917_L8_0,
+	MSM_RPM_STATUS_ID_PM8917_L8_1,
+	MSM_RPM_STATUS_ID_PM8917_L9_0,
+	MSM_RPM_STATUS_ID_PM8917_L9_1,
+	MSM_RPM_STATUS_ID_PM8917_L10_0,
+	MSM_RPM_STATUS_ID_PM8917_L10_1,
+	MSM_RPM_STATUS_ID_PM8917_L11_0,
+	MSM_RPM_STATUS_ID_PM8917_L11_1,
+	MSM_RPM_STATUS_ID_PM8917_L12_0,
+	MSM_RPM_STATUS_ID_PM8917_L12_1,
+	MSM_RPM_STATUS_ID_PM8917_L14_0,
+	MSM_RPM_STATUS_ID_PM8917_L14_1,
+	MSM_RPM_STATUS_ID_PM8917_L15_0,
+	MSM_RPM_STATUS_ID_PM8917_L15_1,
+	MSM_RPM_STATUS_ID_PM8917_L16_0,
+	MSM_RPM_STATUS_ID_PM8917_L16_1,
+	MSM_RPM_STATUS_ID_PM8917_L17_0,
+	MSM_RPM_STATUS_ID_PM8917_L17_1,
+	MSM_RPM_STATUS_ID_PM8917_L18_0,
+	MSM_RPM_STATUS_ID_PM8917_L18_1,
+	MSM_RPM_STATUS_ID_PM8917_L21_0,
+	MSM_RPM_STATUS_ID_PM8917_L21_1,
+	MSM_RPM_STATUS_ID_PM8917_L22_0,
+	MSM_RPM_STATUS_ID_PM8917_L22_1,
+	MSM_RPM_STATUS_ID_PM8917_L23_0,
+	MSM_RPM_STATUS_ID_PM8917_L23_1,
+	MSM_RPM_STATUS_ID_PM8917_L24_0,
+	MSM_RPM_STATUS_ID_PM8917_L24_1,
+	MSM_RPM_STATUS_ID_PM8917_L25_0,
+	MSM_RPM_STATUS_ID_PM8917_L25_1,
+	MSM_RPM_STATUS_ID_PM8917_L26_0,
+	MSM_RPM_STATUS_ID_PM8917_L26_1,
+	MSM_RPM_STATUS_ID_PM8917_L27_0,
+	MSM_RPM_STATUS_ID_PM8917_L27_1,
+	MSM_RPM_STATUS_ID_PM8917_L28_0,
+	MSM_RPM_STATUS_ID_PM8917_L28_1,
+	MSM_RPM_STATUS_ID_PM8917_L29_0,
+	MSM_RPM_STATUS_ID_PM8917_L29_1,
+	MSM_RPM_STATUS_ID_PM8917_L30_0,
+	MSM_RPM_STATUS_ID_PM8917_L30_1,
+	MSM_RPM_STATUS_ID_PM8917_L31_0,
+	MSM_RPM_STATUS_ID_PM8917_L31_1,
+	MSM_RPM_STATUS_ID_PM8917_L32_0,
+	MSM_RPM_STATUS_ID_PM8917_L32_1,
+	MSM_RPM_STATUS_ID_PM8917_L33_0,
+	MSM_RPM_STATUS_ID_PM8917_L33_1,
+	MSM_RPM_STATUS_ID_PM8917_L34_0,
+	MSM_RPM_STATUS_ID_PM8917_L34_1,
+	MSM_RPM_STATUS_ID_PM8917_L35_0,
+	MSM_RPM_STATUS_ID_PM8917_L35_1,
+	MSM_RPM_STATUS_ID_PM8917_L36_0,
+	MSM_RPM_STATUS_ID_PM8917_L36_1,
+	MSM_RPM_STATUS_ID_PM8917_CLK1_0,
+	MSM_RPM_STATUS_ID_PM8917_CLK1_1,
+	MSM_RPM_STATUS_ID_PM8917_CLK2_0,
+	MSM_RPM_STATUS_ID_PM8917_CLK2_1,
+	MSM_RPM_STATUS_ID_PM8917_LVS1,
+	MSM_RPM_STATUS_ID_PM8917_LVS3,
+	MSM_RPM_STATUS_ID_PM8917_LVS4,
+	MSM_RPM_STATUS_ID_PM8917_LVS5,
+	MSM_RPM_STATUS_ID_PM8917_LVS6,
+	MSM_RPM_STATUS_ID_PM8917_LVS7,
 	MSM_RPM_STATUS_ID_VOLTAGE_CORNER,
+	MSM_RPM_STATUS_ID_PM8917_VOLTAGE_CORNER
+		= MSM_RPM_STATUS_ID_VOLTAGE_CORNER,
+	MSM_RPM_STATUS_ID_PM8038_VOLTAGE_CORNER
+		= MSM_RPM_STATUS_ID_VOLTAGE_CORNER,
 
 	/* 8064 specific */
 	MSM_RPM_STATUS_ID_PM8821_S1_0,
@@ -899,6 +1114,7 @@
 extern struct msm_rpm_platform_data msm8960_rpm_data;
 extern struct msm_rpm_platform_data msm9615_rpm_data;
 extern struct msm_rpm_platform_data msm8930_rpm_data;
+extern struct msm_rpm_platform_data msm8930_rpm_data_pm8917;
 extern struct msm_rpm_platform_data apq8064_rpm_data;
 
 #if defined(CONFIG_MSM_RPM)
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index 000ffe4..5333c2e 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -1249,10 +1249,15 @@
  *
  * @para - parameter used for an option (such as pipe combination)
  *
+ * @tb_sel - testbus selection
+ *
+ * @pre_level - prescreening level
+ *
  * @return 0 on success, negative value on error
  *
  */
-int sps_get_bam_debug_info(u32 dev, u32 option, u32 para);
+int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
+		u32 tb_sel, u8 pre_level);
 
 #else
 static inline int sps_register_bam_device(const struct sps_bam_props
@@ -1411,7 +1416,8 @@
 	return -EPERM;
 }
 
-static inline int sps_get_bam_debug_info(u32 dev, u32 option, u32 para)
+static inline int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
+		u32 tb_sel, u8 pre_level)
 {
 	return -EPERM;
 }
diff --git a/arch/arm/mach-msm/mpm-8625.c b/arch/arm/mach-msm/mpm-8625.c
index 3c219be..fe7ffff 100644
--- a/arch/arm/mach-msm/mpm-8625.c
+++ b/arch/arm/mach-msm/mpm-8625.c
@@ -98,6 +98,22 @@
 	[MSM8625_INT_ADSP_A11]		= SMSM_FAKE_IRQ,
 };
 
+static uint16_t msm_bypassed_apps_irqs[] = {
+	MSM8625_INT_CPR_IRQ0,
+};
+
+/* Check IRQ falls into bypassed list are not */
+static bool msm_mpm_bypass_apps_irq(unsigned int irq)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(msm_bypassed_apps_irqs); i++)
+		if (irq == msm_bypassed_apps_irqs[i])
+			return true;
+
+	return false;
+}
+
 static void msm_gic_mask_irq(struct irq_data *d)
 {
 	unsigned int index = GIC_IRQ_INDEX(d->irq);
@@ -106,6 +122,10 @@
 
 	mask = GIC_IRQ_MASK(d->irq);
 
+	/* check whether irq to be bypassed are not */
+	if (msm_mpm_bypass_apps_irq(d->irq))
+		return;
+
 	if (smsm_irq == 0) {
 		msm_gic_irq_idle_disable[index] &= ~mask;
 	} else {
@@ -122,6 +142,10 @@
 
 	mask = GIC_IRQ_MASK(d->irq);
 
+	/* check whether irq to be bypassed are not */
+	if (msm_mpm_bypass_apps_irq(d->irq))
+		return;
+
 	if (smsm_irq == 0) {
 		msm_gic_irq_idle_disable[index] |= mask;
 	} else {
@@ -140,6 +164,10 @@
 		return  -EINVAL;
 	}
 
+	/* check whether irq to be bypassed are not */
+	if (msm_mpm_bypass_apps_irq(d->irq))
+		return 0;
+
 	if (smsm_irq == SMSM_FAKE_IRQ)
 		return 0;
 
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 012bf5a..be3e06f 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -20,7 +20,6 @@
 #include <linux/clk.h>
 #include <linux/radix-tree.h>
 #include <mach/board.h>
-#include <mach/socinfo.h>
 #include "msm_bus_core.h"
 
 enum {
@@ -344,10 +343,6 @@
 	void *sel_cdata;
 	int i;
 
-	/* Temporarily stub out arbitration settings for msm8974 */
-	if (machine_is_msm8974())
-		return;
-
 	sel_cdata = fabric->cdata[ctx];
 
 	/* If it's an ahb fabric, don't calculate arb values */
diff --git a/arch/arm/mach-msm/msm_cpr.c b/arch/arm/mach-msm/msm_cpr.c
index f4272f3..b6c05f4 100644
--- a/arch/arm/mach-msm/msm_cpr.c
+++ b/arch/arm/mach-msm/msm_cpr.c
@@ -36,6 +36,14 @@
 
 #define MODULE_NAME "msm-cpr"
 
+/**
+ * Convert the Delay time to Timer Count Register
+ * e.g if frequency is 19200 kHz and delay required is
+ * 20000us, so timer count will be 19200 * 20000 / 1000
+ */
+#define TIMER_COUNT(freq, delay) ((freq * delay) / 1000)
+#define ALL_CPR_IRQ 0x3F
+
 /* Need platform device handle for suspend and resume APIs */
 static struct platform_device *cpr_pdev;
 
@@ -45,6 +53,7 @@
 	int prev_mode;
 	uint32_t floor;
 	uint32_t ceiling;
+	bool max_volt_set;
 	void __iomem *base;
 	unsigned int irq;
 	struct mutex cpr_mutex;
@@ -157,7 +166,7 @@
 static void
 cpr_2pt_kv_analysis(struct msm_cpr *cpr, struct msm_cpr_mode *chip_data)
 {
-	int32_t tgt_volt_mV = 0, level_uV, rc;
+	int32_t level_uV = 0, rc;
 	uint32_t quot1, quot2;
 
 	/**
@@ -180,15 +189,10 @@
 	 * voltage, offset is always subtracted from it.
 	 *
 	 */
-	if (chip_data->tgt_volt_offset > 0) {
-		tgt_volt_mV = chip_data->calibrated_mV -
-			(chip_data->tgt_volt_offset * cpr->vp->step_size);
-	}
-	pr_debug("tgt_volt_mV = %d, calibrated_mV = %d", tgt_volt_mV,
-			chip_data->calibrated_mV);
+	level_uV = chip_data->Vmax -
+		(chip_data->tgt_volt_offset * cpr->vp->step_size);
+	pr_debug("tgt_volt_uV = %d\n", level_uV);
 
-	/* level_uV = tgt_volt_mV * 1000; */
-	level_uV = 1350000;
 	/* Call the PMIC specific routine to set the voltage */
 	rc = regulator_set_voltage(cpr->vreg_cx, level_uV, level_uV);
 	if (rc) {
@@ -202,10 +206,7 @@
 		return;
 	}
 
-	/* Store the adjusted value of voltage */
-	chip_data->calibrated_mV = 1300;
-
-	/* Take first CPR measurement at a higher voltage to get QUOT1 */
+	/* First CPR measurement at a higher voltage to get QUOT1 */
 
 	/* Enable the Software mode of operation */
 	cpr_modify_reg(cpr, RBCPR_CTL, HW_TO_PMIC_EN_M, SW_MODE);
@@ -231,7 +232,8 @@
 	quot1 = (cpr_read_reg(cpr, RBCPR_DEBUG1) & QUOT_SLOW_M) >> 12;
 
 	/* Take second CPR measurement at a lower voltage to get QUOT2 */
-	level_uV = 1300000;
+	level_uV -= 4 * cpr->vp->step_size;
+	pr_debug("tgt_volt_uV = %d\n", level_uV);
 
 	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
 	/* Call the PMIC specific routine to set the voltage */
@@ -261,7 +263,7 @@
 	}
 	quot2 = (cpr_read_reg(cpr, RBCPR_DEBUG1) & QUOT_SLOW_M) >> 12;
 	chip_data->step_quot = (quot1 - quot2) / 4;
-	pr_debug("%s: Calculated Step Quot is %d\n",
+	pr_info("%s: Calculated Step Quot is %d\n",
 			__func__, chip_data->step_quot);
 	/* Disable the cpr */
 	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
@@ -279,7 +281,7 @@
 void cpr_irq_clr_and_ack(struct msm_cpr *cpr, uint32_t mask)
 {
 	/* Clear the interrupt */
-	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
 	/* Acknowledge the Recommendation */
 	cpr_write_reg(cpr, RBIF_CONT_ACK_CMD, 0x1);
 }
@@ -287,7 +289,7 @@
 static inline
 void cpr_irq_clr_and_nack(struct msm_cpr *cpr, uint32_t mask)
 {
-	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
 	cpr_write_reg(cpr, RBIF_CONT_NACK_CMD, 0x1);
 }
 
@@ -307,7 +309,7 @@
 static void
 cpr_up_event_handler(struct msm_cpr *cpr, uint32_t new_volt)
 {
-	int rc, set_volt_mV;
+	int rc, set_volt_uV;
 	struct msm_cpr_mode *chip_data;
 
 	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
@@ -317,26 +319,28 @@
 	 * freq switch handler and CPR interrupt handler here
 	 */
 	/* Set New PMIC voltage */
-	set_volt_mV = (new_volt < chip_data->Vmax ? new_volt
+	set_volt_uV = (new_volt < chip_data->Vmax ? new_volt
 				: chip_data->Vmax);
-	rc = regulator_set_voltage(cpr->vreg_cx, set_volt_mV * 1000,
-					set_volt_mV * 1000);
+	rc = regulator_set_voltage(cpr->vreg_cx, set_volt_uV,
+					set_volt_uV);
 	if (rc) {
-		pr_err("%s: Voltage set at %dmV failed. %d\n",
-			__func__, set_volt_mV, rc);
+		pr_err("%s: Voltage set at %duV failed. %d\n",
+			__func__, set_volt_uV, rc);
 		cpr_irq_clr_and_nack(cpr, BIT(4) | BIT(0));
 		return;
 	}
-	pr_debug("%s: Voltage set at %dmV\n", __func__, set_volt_mV);
+	pr_info("(railway_voltage: %d uV)\n", set_volt_uV);
+
+	cpr->max_volt_set = (set_volt_uV == chip_data->Vmax) ? 1 : 0;
 
 	/**
 	 * Save the new calibrated voltage to be re-used
 	 * whenever we return to same mode after a mode switch.
 	 */
-	chip_data->calibrated_mV = set_volt_mV;
+	chip_data->calibrated_uV = set_volt_uV;
 
 	/* Clear all the interrupts */
-	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
 
 	/* Disable Auto ACK for Down interrupts */
 	cpr_modify_reg(cpr, RBCPR_CTL, SW_AUTO_CONT_NACK_DN_EN_M, 0);
@@ -353,7 +357,7 @@
 static void
 cpr_dn_event_handler(struct msm_cpr *cpr, uint32_t new_volt)
 {
-	int rc, set_volt_mV;
+	int rc, set_volt_uV;
 	struct msm_cpr_mode *chip_data;
 
 	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
@@ -363,26 +367,28 @@
 	 * freq switch handler and CPR interrupt handler here
 	 */
 	/* Set New PMIC volt */
-	set_volt_mV = (new_volt > chip_data->Vmin ? new_volt
+	set_volt_uV = (new_volt > chip_data->Vmin ? new_volt
 				: chip_data->Vmin);
-	rc = regulator_set_voltage(cpr->vreg_cx, set_volt_mV * 1000,
-					set_volt_mV * 1000);
+	rc = regulator_set_voltage(cpr->vreg_cx, set_volt_uV,
+					set_volt_uV);
 	if (rc) {
-		pr_err("%s: Voltage at %dmV failed %d\n",
-			__func__, set_volt_mV, rc);
+		pr_err("%s: Voltage at %duV failed %d\n",
+			__func__, set_volt_uV, rc);
 		cpr_irq_clr_and_nack(cpr, BIT(2) | BIT(0));
 		return;
 	}
-	pr_debug("%s: Voltage set at %dmV\n", __func__, set_volt_mV);
+	pr_info("(railway_voltage: %d uV)\n", set_volt_uV);
+
+	cpr->max_volt_set = 0;
 
 	/**
 	 * Save the new calibrated voltage to be re-used
 	 * whenever we return to same mode after a mode switch.
 	 */
-	chip_data->calibrated_mV = set_volt_mV;
+	chip_data->calibrated_uV = set_volt_uV;
 
 	/* Clear all the interrupts */
-	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
 
 	if (new_volt <= chip_data->Vmin) {
 		/*
@@ -416,16 +422,22 @@
 	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
 	error_step = cpr_read_reg(cpr, RBCPR_RESULT_0) >> 2;
 	error_step &= 0xF;
-	curr_volt = chip_data->calibrated_mV;
+	curr_volt = chip_data->calibrated_uV;
 
 	if (action == UP) {
+		/* Clear IRQ, ACK and return if Vdd already at Vmax */
+		if (cpr->max_volt_set == 1) {
+			cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
+			cpr_write_reg(cpr, RBIF_CONT_NACK_CMD, 0x1);
+			return;
+		}
+
 		/**
 		 * Using up margin in the comparison helps avoid having to
 		 * change up threshold values in chip register.
 		 */
 		if (error_step < (cpr->config->up_threshold +
 					cpr->config->up_margin)) {
-			/* FIXME: Avoid repeated dn interrupts if we are here */
 			pr_debug("UP_INT error step too small to set\n");
 			cpr_irq_clr_and_nack(cpr, BIT(4) | BIT(0));
 			return;
@@ -434,6 +446,7 @@
 		/* Calculte new PMIC voltage */
 		new_volt = curr_volt + (error_step * cpr->vp->step_size);
 		pr_debug("UP_INT: new_volt: %d\n", new_volt);
+		pr_info("(UP Voltage recommended by CPR: %d uV)\n", new_volt);
 		cpr_up_event_handler(cpr, new_volt);
 
 	} else if (action == DOWN) {
@@ -443,7 +456,6 @@
 		 */
 		if (error_step < (cpr->config->dn_threshold +
 					cpr->config->dn_margin)) {
-			/* FIXME: Avoid repeated dn interrupts if we are here */
 			pr_debug("DOWN_INT error_step too small to set\n");
 			cpr_irq_clr_and_nack(cpr, BIT(2) | BIT(0));
 			return;
@@ -452,6 +464,7 @@
 		/* Calculte new PMIC voltage */
 		new_volt = curr_volt - (error_step * cpr->vp->step_size);
 		pr_debug("DOWN_INT: new_volt: %d\n", new_volt);
+		pr_info("(DN Voltage recommended by CPR: %d uV)\n", new_volt);
 		cpr_dn_event_handler(cpr, new_volt);
 	}
 }
@@ -513,6 +526,8 @@
 			cpr->config->dn_threshold << 28);
 
 	cpr->curr_osc = chip_data->ring_osc;
+	chip_data->ring_osc_data[cpr->curr_osc].quot =
+		cpr->config->max_quot;
 
 	/**
 	 * Program the gate count and target values
@@ -522,7 +537,7 @@
 		cpr_modify_reg(cpr, RBCPR_GCNT_TARGET(cnt),
 				(GCNT_M | TARGET_M),
 				(chip_data->ring_osc_data[cnt].gcnt << 12 |
-				chip_data->ring_osc_data[cnt].target_count));
+				chip_data->ring_osc_data[cnt].quot));
 		pr_debug("RBCPR_GCNT_TARGET(%d): = 0x%x\n", cnt,
 			readl_relaxed(cpr->base + RBCPR_GCNT_TARGET(cnt)));
 		cnt++;
@@ -536,14 +551,19 @@
 	 * Set with an extra step since it helps as per
 	 * characterization data.
 	 */
-	chip_data->calibrated_mV +=  cpr->vp->step_size;
-	tmp_uV = chip_data->calibrated_mV * 1000;
+	chip_data->calibrated_uV +=  cpr->vp->step_size;
+	tmp_uV = chip_data->calibrated_uV;
 	rc = regulator_set_voltage(cpr->vreg_cx, tmp_uV, tmp_uV);
 	if (rc)
 		pr_err("%s: Voltage set failed %d\n", __func__, rc);
 
-	/* Program the Timer for default delay between CPR measurements */
-	delay_count = 0xFFFF;
+	/*
+	 * Program the Timer Register for delay between CPR measurements
+	 * This is required to allow the device sufficient time for idle
+	 * power collapse.
+	 */
+	delay_count = TIMER_COUNT(cpr->config->ref_clk_khz,
+					cpr->config->delay_us);
 	cpr_write_reg(cpr, RBCPR_TIMER_INTERVAL, delay_count);
 
 	/* Enable the Timer */
@@ -554,53 +574,69 @@
 			SW_AUTO_CONT_ACK_EN);
 }
 
-static void cpr_mode_config(struct msm_cpr *cpr, enum cpr_mode mode)
-{
-	if (cpr->cpr_mode == mode)
-		return;
-
-	cpr->cpr_mode = mode;
-	pr_debug("%s: Switching to %s mode\n", __func__,
-		(mode == TURBO_MODE ? "TURBO" : "NORMAL"));
-
-	/* Configure the new mode */
-	cpr_config(cpr);
-}
-
 static int
 cpr_freq_transition(struct notifier_block *nb, unsigned long val,
 				void *data)
 {
 	struct msm_cpr *cpr = container_of(nb, struct msm_cpr, freq_transition);
 	struct cpufreq_freqs *freqs = data;
+	uint32_t quot, new_freq;
 
 	switch (val) {
 	case CPUFREQ_PRECHANGE:
-		return 0;
 		pr_debug("pre freq change notification to cpr\n");
 
-		disable_irq(cpr->irq);
+		/* Disable Measurement to stop generation of CPR IRQs */
 		cpr_disable(cpr);
+		/* Disable routing of IRQ to App */
+		cpr_irq_set(cpr, INT_MASK & ~MID_INT, 0);
+		disable_irq(cpr->irq);
+		cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
+		pr_debug("RBCPR_CTL: 0x%x\n",
+			readl_relaxed(cpr->base + RBCPR_CTL));
+		pr_debug("RBIF_IRQ_STATUS: 0x%x\n",
+			cpr_read_reg(cpr, RBIF_IRQ_STATUS));
+		pr_debug("RBIF_IRQ_EN(0): 0x%x\n",
+			cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line)));
+
 		cpr->prev_mode = cpr->cpr_mode;
 		break;
-	case CPUFREQ_POSTCHANGE:
-		return 0;
-		pr_debug("post freq change notification to cpr\n");
 
-		if (freqs->new >= cpr->config->nom_freq_limit)
-			cpr_mode_config(cpr, TURBO_MODE);
-		else
-			cpr_mode_config(cpr, NORMAL_MODE);
+	case CPUFREQ_POSTCHANGE:
+		pr_debug("post freq change notification to cpr\n");
+		/**
+		 * As per chip characterization data, use max nominal freq
+		 * to calculate quot for all lower frequencies too
+		 */
+		new_freq = (freqs->new > cpr->config->max_nom_freq)
+					? freqs->new
+					: cpr->config->max_nom_freq;
+
+		/* Configure CPR for the new frequency */
+		quot = cpr->config->get_quot(cpr->config->max_quot,
+						cpr->config->max_freq / 1000,
+						new_freq / 1000);
+		cpr_modify_reg(cpr, RBCPR_GCNT_TARGET(cpr->curr_osc), TARGET_M,
+				quot);
+		pr_debug("RBCPR_GCNT_TARGET(%d): = 0x%x\n", cpr->curr_osc,
+			readl_relaxed(cpr->base +
+					RBCPR_GCNT_TARGET(cpr->curr_osc)));
+		pr_debug("%s: new_freq: %d, set_freq: %d, quot: %d\n", __func__,
+			freqs->new, new_freq, quot);
+
+		enable_irq(cpr->irq);
 		/**
 		 * Enable all interrupts. One of them could be in a disabled
 		 * state if vdd had hit Vmax / Vmin earlier
 		 */
-		cpr_irq_set(cpr, (UP_INT | DOWN_INT), 1);
-
-		enable_irq(cpr->irq);
-
+		cpr_irq_set(cpr, INT_MASK & ~MID_INT, 1);
+		pr_debug("RBIF_IRQ_EN(0): 0x%x\n",
+			cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line)));
+		pr_debug("RBCPR_CTL: 0x%x\n",
+			readl_relaxed(cpr->base + RBCPR_CTL));
+		pr_debug("RBIF_IRQ_STATUS: 0x%x\n",
+			cpr_read_reg(cpr, RBIF_IRQ_STATUS));
 		cpr_enable(cpr);
-
 		break;
 	default:
 		break;
@@ -614,6 +650,8 @@
 	struct msm_cpr *cpr = dev_get_drvdata(dev);
 	int osc_num = cpr->config->cpr_mode_data->ring_osc;
 
+	cpr->config->clk_enable();
+
 	cpr_write_reg(cpr, RBCPR_TIMER_INTERVAL,
 		cpr_save_state.rbif_timer_interval);
 	cpr_write_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line),
@@ -628,11 +666,11 @@
 		cpr_save_state.rbcpr_step_quot);
 	cpr_write_reg(cpr, RBIF_SW_VLEVEL,
 		cpr_save_state.rbif_sw_level);
-
-	cpr_enable(cpr);
 	cpr_write_reg(cpr, RBCPR_CTL,
 		cpr_save_state.rbcpr_ctl);
+
 	enable_irq(cpr->irq);
+	cpr_enable(cpr);
 
 	return 0;
 }
@@ -643,6 +681,10 @@
 	struct msm_cpr *cpr = dev_get_drvdata(dev);
 	int osc_num = cpr->config->cpr_mode_data->ring_osc;
 
+	/* Disable CPR measurement before IRQ to avoid pending interrupts */
+	cpr_disable(cpr);
+	disable_irq(cpr->irq);
+
 	cpr_save_state.rbif_timer_interval =
 		cpr_read_reg(cpr, RBCPR_TIMER_INTERVAL);
 	cpr_save_state.rbif_int_en =
@@ -660,9 +702,6 @@
 	cpr_save_state.rbcpr_ctl =
 		cpr_read_reg(cpr, RBCPR_CTL);
 
-	disable_irq(cpr->irq);
-	cpr_disable(cpr);
-
 	return 0;
 }
 
@@ -700,6 +739,7 @@
 	const struct msm_cpr_config *pdata = pdev->dev.platform_data;
 	void __iomem *base;
 	struct resource *mem;
+	struct msm_cpr_mode *chip_data;
 
 	if (!pdata) {
 		pr_err("CPR: Platform data is not available\n");
@@ -766,6 +806,16 @@
 
 	platform_set_drvdata(pdev, cpr);
 
+	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
+	pr_info("CPR Platform Data (upside_steps: %d) (downside_steps: %d) ",
+		cpr->config->up_threshold, cpr->config->dn_threshold);
+	pr_info("(nominal_voltage: %duV) (turbo_voltage: %duV)\n",
+		cpr->config->cpr_mode_data[NORMAL_MODE].calibrated_uV,
+		cpr->config->cpr_mode_data[TURBO_MODE].calibrated_uV);
+	pr_info("(Current corner: TURBO) (gcnt_target: %d) (quot: %d)\n",
+		chip_data->ring_osc_data[chip_data->ring_osc].gcnt,
+		chip_data->ring_osc_data[chip_data->ring_osc].quot);
+
 	/* Initialze the Debugfs Entry for cpr */
 	res = msm_cpr_debug_init(cpr->base);
 	if (res) {
@@ -793,7 +843,6 @@
 	/* Enable the cpr */
 	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
 
-
 	cpr->freq_transition.notifier_call = cpr_freq_transition;
 	cpufreq_register_notifier(&cpr->freq_transition,
 					CPUFREQ_TRANSITION_NOTIFIER);
diff --git a/arch/arm/mach-msm/msm_cpr.h b/arch/arm/mach-msm/msm_cpr.h
index 2642b9c..cb665b7 100644
--- a/arch/arm/mach-msm/msm_cpr.h
+++ b/arch/arm/mach-msm/msm_cpr.h
@@ -120,10 +120,10 @@
 
 /**
  * struct msm_vp_data - structure for VP configuration
- * @min_volt_mV: minimum milivolt level for VP
- * @max_volt_mV: maximum milivolt level for VP
- * @default_volt_mV: default milivolt for VP
- * @step_size_mV: step size of voltage
+ * @min_volt: minimum microvolt level for VP
+ * @max_volt: maximum microvolt level for VP
+ * @default_volt: default microvolt for VP
+ * @step_size: step size of voltage in microvolt
  */
 struct msm_cpr_vp_data {
 	int min_volt;
@@ -135,11 +135,11 @@
 /**
  * struct msm_cpr_osc -  Data for CPR ring oscillator
  * @gcnt: gate count value for the oscillator
- * @target_count: target value for ring oscillator
+ * @quot: target value for ring oscillator
  */
 struct msm_cpr_osc {
 	int gcnt;
-	uint32_t target_count;
+	uint32_t quot;
 };
 
 /**
@@ -156,7 +156,7 @@
 	uint32_t step_quot;
 	uint32_t Vmax;
 	uint32_t Vmin;
-	uint32_t calibrated_mV;
+	uint32_t calibrated_uV;
 };
 
 /**
@@ -180,8 +180,13 @@
 	uint32_t dn_threshold;
 	uint32_t up_margin;
 	uint32_t dn_margin;
-	uint32_t nom_freq_limit;
+	uint32_t max_nom_freq;
+	uint32_t max_freq;
+	uint32_t max_quot;
 	struct msm_cpr_vp_data *vp_data;
+	uint32_t (*get_quot)(uint32_t max_quot, uint32_t max_freq,
+				uint32_t new_freq);
+	void (*clk_enable)(void);
 };
 
 /**
diff --git a/arch/arm/mach-msm/msm_watchdog_v2.c b/arch/arm/mach-msm/msm_watchdog_v2.c
index af903f8..48a57cd 100644
--- a/arch/arm/mach-msm/msm_watchdog_v2.c
+++ b/arch/arm/mach-msm/msm_watchdog_v2.c
@@ -17,6 +17,7 @@
 #include <linux/workqueue.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
+#include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
@@ -38,6 +39,7 @@
 
 #define MASK_SIZE		32
 #define SCM_SET_REGSAVE_CMD	0x2
+#define SCM_SVC_SEC_WDOG_DIS	0x7
 
 struct msm_watchdog_data {
 	unsigned int __iomem phys_base;
@@ -54,6 +56,7 @@
 	unsigned long long min_slack_ns;
 	void *scm_regsave;
 	cpumask_t alive_mask;
+	struct mutex disable_lock;
 	struct work_struct init_dogwork_struct;
 	struct delayed_work dogwork_struct;
 	bool irq_ppi;
@@ -77,19 +80,6 @@
 static long WDT_HZ = 32765;
 module_param(WDT_HZ, long, 0);
 
-/*
- * If the watchdog is enabled at bootup (enable=1),
- * the runtime_disable sysfs node at
- * /sys/module/msm_watchdog/parameters/runtime_disable
- * can be used to deactivate the watchdog.
- * This is a one-time setting. The watchdog
- * cannot be re-enabled once it is disabled.
- */
-static int runtime_disable;
-static int wdog_enable_set(const char *val, struct kernel_param *kp);
-module_param_call(runtime_disable, wdog_enable_set, param_get_int,
-			&runtime_disable, 0644);
-
 static void pet_watchdog_work(struct work_struct *work);
 static void init_watchdog_work(struct work_struct *work);
 
@@ -142,14 +132,99 @@
 	}
 	return NOTIFY_DONE;
 }
-/*
- * TODO: implement enable/disable.
- */
-static int wdog_enable_set(const char *val, struct kernel_param *kp)
+
+static void wdog_disable(struct msm_watchdog_data *wdog_dd)
 {
-	return 0;
+	__raw_writel(0, wdog_dd->base + WDT0_EN);
+	mb();
+	if (wdog_dd->irq_ppi) {
+		disable_percpu_irq(wdog_dd->bark_irq);
+		free_percpu_irq(wdog_dd->bark_irq, wdog_dd->wdog_cpu_dd);
+	} else
+		devm_free_irq(wdog_dd->dev, wdog_dd->bark_irq, wdog_dd);
+	enable = 0;
+	/*Ensure all cpus see update to enable*/
+	smp_mb();
+	atomic_notifier_chain_unregister(&panic_notifier_list,
+						&wdog_dd->panic_blk);
+	cancel_delayed_work_sync(&wdog_dd->dogwork_struct);
+	/* may be suspended after the first write above */
+	__raw_writel(0, wdog_dd->base + WDT0_EN);
+	mb();
+	pr_info("MSM Apps Watchdog deactivated.\n");
 }
 
+struct wdog_disable_work_data {
+	struct work_struct work;
+	struct completion complete;
+	struct msm_watchdog_data *wdog_dd;
+};
+
+static void wdog_disable_work(struct work_struct *work)
+{
+	struct wdog_disable_work_data *work_data =
+		container_of(work, struct wdog_disable_work_data, work);
+	wdog_disable(work_data->wdog_dd);
+	complete(&work_data->complete);
+}
+
+static ssize_t wdog_disable_get(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int ret;
+	struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev);
+
+	mutex_lock(&wdog_dd->disable_lock);
+	ret = snprintf(buf, PAGE_SIZE, "%d\n", enable == 0 ? 1 : 0);
+	mutex_unlock(&wdog_dd->disable_lock);
+	return ret;
+}
+
+static ssize_t wdog_disable_set(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int ret;
+	u8 disable;
+	struct wdog_disable_work_data work_data;
+	struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev);
+
+	ret = kstrtou8(buf, 10, &disable);
+	if (ret) {
+		dev_err(wdog_dd->dev, "invalid user input\n");
+		return ret;
+	}
+	if (disable == 1) {
+		mutex_lock(&wdog_dd->disable_lock);
+		if (enable == 0) {
+			pr_info("MSM Apps Watchdog already disabled\n");
+			mutex_unlock(&wdog_dd->disable_lock);
+			return count;
+		}
+		disable = 1;
+		ret = scm_call(SCM_SVC_BOOT, SCM_SVC_SEC_WDOG_DIS, &disable,
+						sizeof(disable), NULL, 0);
+		if (ret) {
+			dev_err(wdog_dd->dev,
+					"Failed to deactivate secure wdog\n");
+			mutex_unlock(&wdog_dd->disable_lock);
+			return -EIO;
+		}
+		work_data.wdog_dd = wdog_dd;
+		init_completion(&work_data.complete);
+		INIT_WORK_ONSTACK(&work_data.work, wdog_disable_work);
+		schedule_work_on(0, &work_data.work);
+		wait_for_completion(&work_data.complete);
+		mutex_unlock(&wdog_dd->disable_lock);
+	} else {
+		pr_err("invalid operation, only disable = 1 supported\n");
+		return -EINVAL;
+	}
+	return count;
+}
+
+static DEVICE_ATTR(disable, S_IWUSR | S_IRUSR, wdog_disable_get,
+							wdog_disable_set);
 
 static void pet_watchdog(struct msm_watchdog_data *wdog_dd)
 {
@@ -199,9 +274,13 @@
 						struct msm_watchdog_data,
 							dogwork_struct);
 	delay_time = msecs_to_jiffies(wdog_dd->pet_time);
-	if (wdog_dd->do_ipi_ping)
-		ping_other_cpus(wdog_dd);
-	pet_watchdog(wdog_dd);
+	if (enable) {
+		if (wdog_dd->do_ipi_ping)
+			ping_other_cpus(wdog_dd);
+		pet_watchdog(wdog_dd);
+	}
+	/* Check again before scheduling *
+	 * Could have been changed on other cpu */
 	if (enable)
 		schedule_delayed_work_on(0, &wdog_dd->dogwork_struct,
 							delay_time);
@@ -209,23 +288,24 @@
 
 static int msm_watchdog_remove(struct platform_device *pdev)
 {
+	struct wdog_disable_work_data work_data;
 	struct msm_watchdog_data *wdog_dd =
 			(struct msm_watchdog_data *)platform_get_drvdata(pdev);
+
+	mutex_lock(&wdog_dd->disable_lock);
 	if (enable) {
-		__raw_writel(0, wdog_dd->base + WDT0_EN);
-		mb();
-		enable = 0;
-		/*
-		 * TODO: Not sure if we need to call into TZ to disable
-		 * secure wdog.
-		 */
-		/* In case we got suspended mid-exit */
-		__raw_writel(0, wdog_dd->base + WDT0_EN);
+		work_data.wdog_dd = wdog_dd;
+		init_completion(&work_data.complete);
+		INIT_WORK_ONSTACK(&work_data.work, wdog_disable_work);
+		schedule_work_on(0, &work_data.work);
+		wait_for_completion(&work_data.complete);
 	}
+	mutex_unlock(&wdog_dd->disable_lock);
+	device_remove_file(wdog_dd->dev, &dev_attr_disable);
 	if (wdog_dd->irq_ppi)
 		free_percpu(wdog_dd->wdog_cpu_dd);
 	printk(KERN_INFO "MSM Watchdog Exit - Deactivated\n");
-	kzfree(wdog_dd);
+	kfree(wdog_dd);
 	return 0;
 }
 
@@ -299,6 +379,7 @@
 						struct msm_watchdog_data,
 							init_dogwork_struct);
 	unsigned long delay_time;
+	int error;
 	u64 timeout;
 	int ret;
 
@@ -337,14 +418,17 @@
 	wdog_dd->panic_blk.notifier_call = panic_wdog_handler;
 	atomic_notifier_chain_register(&panic_notifier_list,
 				       &wdog_dd->panic_blk);
+	mutex_init(&wdog_dd->disable_lock);
 	schedule_delayed_work_on(0, &wdog_dd->dogwork_struct, delay_time);
-
 	__raw_writel(1, wdog_dd->base + WDT0_EN);
 	__raw_writel(1, wdog_dd->base + WDT0_RST);
 	wdog_dd->last_pet = sched_clock();
-	printk(KERN_INFO "MSM Watchdog Initialized\n");
+	error = device_create_file(wdog_dd->dev, &dev_attr_disable);
+	if (error)
+		dev_err(wdog_dd->dev, "cannot create sysfs attribute\n");
 	if (wdog_dd->irq_ppi)
 		enable_percpu_irq(wdog_dd->bark_irq, 0);
+	dev_info(wdog_dd->dev, "MSM Watchdog Initialized\n");
 	return;
 }
 
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index 82fe2f8..51445aa 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -63,6 +63,27 @@
 	"other_os",
 };
 
+/* Must be in sync with enum ocmem_zstat_item */
+static const char *zstat_names[NR_OCMEM_ZSTAT_ITEMS] = {
+	"Allocation requests",
+	"Synchronous allocations",
+	"Ranged allocations",
+	"Asynchronous allocations",
+	"Allocation failures",
+	"Allocations grown",
+	"Allocations freed",
+	"Allocations shrunk",
+	"OCMEM maps",
+	"Map failures",
+	"OCMEM unmaps",
+	"Unmap failures",
+	"Transfers to OCMEM",
+	"Transfers to DDR",
+	"Transfer failures",
+	"Evictions",
+	"Restorations",
+};
+
 struct ocmem_quota_table {
 	const char *name;
 	int id;
@@ -135,6 +156,23 @@
 		return 0;
 }
 
+inline void inc_ocmem_stat(struct ocmem_zone *z,
+				enum ocmem_zstat_item item)
+{
+	if (!z)
+		return;
+	atomic_long_inc(&z->z_stat[item]);
+}
+
+inline unsigned long get_ocmem_stat(struct ocmem_zone *z,
+				enum ocmem_zstat_item item)
+{
+	if (!z)
+		return 0;
+	else
+		return atomic_long_read(&z->z_stat[item]);
+}
+
 static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
 {
 	struct ocmem_plat_data *pdata = NULL;
@@ -473,6 +511,60 @@
 	return NULL;
 }
 
+static int ocmem_zones_show(struct seq_file *f, void *dummy)
+{
+	unsigned i = 0;
+	for (i = OCMEM_GRAPHICS; i < OCMEM_CLIENT_MAX; i++) {
+		struct ocmem_zone *z = get_zone(i);
+		if (z && z->active == true)
+			seq_printf(f, "zone %s\t:0x%08lx - 0x%08lx (%4ld KB)\n",
+				get_name(z->owner), z->z_start, z->z_end - 1,
+				(z->z_end - z->z_start)/SZ_1K);
+	}
+	return 0;
+}
+
+static int ocmem_zones_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ocmem_zones_show, inode->i_private);
+}
+
+static const struct file_operations zones_show_fops = {
+	.open = ocmem_zones_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static int ocmem_stats_show(struct seq_file *f, void *dummy)
+{
+	unsigned i = 0;
+	unsigned j = 0;
+	for (i = OCMEM_GRAPHICS; i < OCMEM_CLIENT_MAX; i++) {
+		struct ocmem_zone *z = get_zone(i);
+		if (z && z->active == true) {
+			seq_printf(f, "zone %s:\n", get_name(z->owner));
+			for (j = 0 ; j < ARRAY_SIZE(zstat_names); j++) {
+				seq_printf(f, "\t %s: %lu\n", zstat_names[j],
+					get_ocmem_stat(z, j));
+			}
+		}
+	}
+	return 0;
+}
+
+static int ocmem_stats_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ocmem_stats_show, inode->i_private);
+}
+
+static const struct file_operations stats_show_fops = {
+	.open = ocmem_stats_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
 static int ocmem_zone_init(struct platform_device *pdev)
 {
 
@@ -549,6 +641,8 @@
 			z_ops->allocate = allocate_head;
 			z_ops->free = free_head;
 		}
+		/* zap the counters */
+		memset(zone->z_stat, 0 , sizeof(zone->z_stat));
 		zone->active = true;
 		active_zones++;
 
@@ -557,7 +651,19 @@
 
 		pr_info(" zone %s\t: 0x%08lx - 0x%08lx (%4ld KB)\n",
 				client_names[part->id], zone->z_start,
-				zone->z_end, part->p_size/SZ_1K);
+				zone->z_end - 1, part->p_size/SZ_1K);
+	}
+
+	if (!debugfs_create_file("zones", S_IRUGO, pdata->debug_node,
+					NULL, &zones_show_fops)) {
+		dev_err(dev, "Unable to create debugfs node for zones\n");
+		return -EBUSY;
+	}
+
+	if (!debugfs_create_file("stats", S_IRUGO, pdata->debug_node,
+					NULL, &stats_show_fops)) {
+		dev_err(dev, "Unable to create debugfs node for stats\n");
+		return -EBUSY;
 	}
 
 	dev_dbg(dev, "Total active zones = %d\n", active_zones);
@@ -587,6 +693,27 @@
 	return 0;
 }
 
+static int __devinit ocmem_debugfs_init(struct platform_device *pdev)
+{
+	struct dentry *debug_dir = NULL;
+	struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
+
+	debug_dir = debugfs_create_dir("ocmem", NULL);
+	if (!debug_dir || IS_ERR(debug_dir)) {
+		pr_err("ocmem: Unable to create debugfs root\n");
+		return PTR_ERR(debug_dir);
+	}
+
+	pdata->debug_node =  debug_dir;
+	return 0;
+}
+
+static void __devexit ocmem_debugfs_exit(struct platform_device *pdev)
+{
+	struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
+	debugfs_remove_recursive(pdata->debug_node);
+}
+
 static int __devinit msm_ocmem_probe(struct platform_device *pdev)
 {
 	struct device   *dev = &pdev->dev;
@@ -635,6 +762,9 @@
 
 	platform_set_drvdata(pdev, ocmem_pdata);
 
+	if (ocmem_debugfs_init(pdev))
+		return -EBUSY;
+
 	if (ocmem_core_init(pdev))
 		return -EBUSY;
 
@@ -644,7 +774,7 @@
 	if (ocmem_notifier_init())
 		return -EBUSY;
 
-	if (ocmem_sched_init())
+	if (ocmem_sched_init(pdev))
 		return -EBUSY;
 
 	if (ocmem_rdm_init(pdev))
@@ -661,6 +791,7 @@
 
 static int __devexit msm_ocmem_remove(struct platform_device *pdev)
 {
+	ocmem_debugfs_exit(pdev);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index d9d67a3..de9856d 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -665,6 +665,81 @@
 	return switch_power_state(id, offset, len, REGION_DEFAULT_RETENTION);
 }
 
+static int ocmem_power_show_sw_state(struct seq_file *f, void *dummy)
+{
+	unsigned i, j;
+	unsigned m_state;
+	mutex_lock(&region_ctrl_lock);
+
+	seq_printf(f, "OCMEM Aggregated Power States\n");
+	for (i = 0 ; i < num_regions; i++) {
+		struct ocmem_hw_region *region = &region_ctrl[i];
+		seq_printf(f, "Region %u mode %x\n", i, region->mode);
+		for (j = 0; j < num_banks; j++) {
+			m_state = read_macro_state(i, j);
+			if (m_state == MACRO_ON)
+				seq_printf(f, "M%u:%s\t", j, "ON");
+			else if (m_state == MACRO_SLEEP_RETENTION)
+				seq_printf(f, "M%u:%s\t", j, "RETENTION");
+			else
+				seq_printf(f, "M%u:%s\t", j, "OFF");
+		}
+		seq_printf(f, "\n");
+	}
+	mutex_unlock(&region_ctrl_lock);
+	return 0;
+}
+
+#ifdef CONFIG_MSM_OCMEM_POWER_DEBUG
+static int ocmem_power_show_hw_state(struct seq_file *f, void *dummy)
+{
+	unsigned i = 0;
+	unsigned r_state;
+
+	mutex_lock(&region_ctrl_lock);
+
+	seq_printf(f, "OCMEM Hardware Power States\n");
+	for (i = 0 ; i < num_regions; i++) {
+		struct ocmem_hw_region *region = &region_ctrl[i];
+		seq_printf(f, "Region %u mode %x ", i, region->mode);
+		r_state = read_hw_region_state(i);
+		if (r_state == REGION_DEFAULT_ON)
+			seq_printf(f, "state: %s\t", "REGION_ON");
+		else if (r_state == MACRO_SLEEP_RETENTION)
+			seq_printf(f, "state: %s\t", "REGION_RETENTION");
+		else
+			seq_printf(f, "state: %s\t", "REGION_OFF");
+		seq_printf(f, "\n");
+	}
+	mutex_unlock(&region_ctrl_lock);
+	return 0;
+}
+#else
+static int ocmem_power_show_hw_state(struct seq_file *f, void *dummy)
+{
+	return 0;
+}
+#endif
+
+static int ocmem_power_show(struct seq_file *f, void *dummy)
+{
+	ocmem_power_show_sw_state(f, dummy);
+	ocmem_power_show_hw_state(f, dummy);
+	return 0;
+}
+
+static int ocmem_power_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ocmem_power_show, inode->i_private);
+}
+
+static const struct file_operations power_show_fops = {
+	.open = ocmem_power_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
 int ocmem_core_init(struct platform_device *pdev)
 {
 	struct device   *dev = &pdev->dev;
@@ -785,8 +860,14 @@
 		return rc;
 
 	ocmem_disable_core_clock();
-	return 0;
 
+	if (!debugfs_create_file("power_state", S_IRUGO, pdata->debug_node,
+					NULL, &power_show_fops)) {
+		dev_err(dev, "Unable to create debugfs node for power state\n");
+		return -EBUSY;
+	}
+
+	return 0;
 err_no_mem:
 	pr_err("ocmem: Unable to allocate memory\n");
 region_init_error:
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 54510c9..c95728e 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -244,6 +244,15 @@
 	return ret_addr;
 }
 
+static inline struct ocmem_zone *zone_of(struct ocmem_req *req)
+{
+	int owner;
+	if (!req)
+		return NULL;
+	owner = req->owner;
+	return get_zone(owner);
+}
+
 static int insert_region(struct ocmem_region *region)
 {
 
@@ -838,7 +847,6 @@
 	if (matched_req != req)
 		goto invalid_op_error;
 
-
 	ret = zone->z_ops->free(zone,
 		matched_req->req_start, matched_req->req_sz);
 
@@ -1317,6 +1325,8 @@
 	if (rc < 0)
 		return -EINVAL;
 
+	inc_ocmem_stat(zone_of(req), NR_FREES);
+
 	ocmem_destroy_req(req);
 	handle->req = NULL;
 
@@ -1393,14 +1403,16 @@
 		goto transfer_out_error;
 	}
 
+	inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_DDR);
+
 	rc = queue_transfer(req, handle, list, TO_DDR);
 
 	if (rc < 0) {
 		pr_err("Failed to queue rdm transfer to DDR\n");
+		inc_ocmem_stat(zone_of(req), NR_TRANSFER_FAILS);
 		goto transfer_out_error;
 	}
 
-
 	return 0;
 
 transfer_out_error:
@@ -1429,10 +1441,13 @@
 		goto transfer_in_error;
 	}
 
+	inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_OCMEM);
+
 	rc = queue_transfer(req, handle, list, TO_OCMEM);
 
 	if (rc < 0) {
 		pr_err("Failed to queue rdm transfer to OCMEM\n");
+		inc_ocmem_stat(zone_of(req), NR_TRANSFER_FAILS);
 		goto transfer_in_error;
 	}
 
@@ -1469,6 +1484,8 @@
 	if (is_tcm(req->owner))
 		do_unmap(req);
 
+	inc_ocmem_stat(zone_of(req), NR_SHRINKS);
+
 	if (size == 0) {
 		pr_info("req %p being shrunk to zero\n", req);
 		rc = do_free(req);
@@ -1551,6 +1568,8 @@
 					req->edata = edata;
 					buffer.addr = req->req_start;
 					buffer.len = 0x0;
+					inc_ocmem_stat(zone_of(req),
+								NR_EVICTIONS);
 					dispatch_notification(req->owner,
 						OCMEM_ALLOC_SHRINK, &buffer);
 				}
@@ -1580,8 +1599,10 @@
 	rc = __sched_allocate(req, can_block, can_wait);
 	mutex_unlock(&sched_mutex);
 
-	if (rc == OP_FAIL)
+	if (rc == OP_FAIL) {
+		inc_ocmem_stat(zone_of(req), NR_ALLOCATION_FAILS);
 		goto err_allocate_fail;
+	}
 
 	if (rc == OP_RESCHED) {
 		buffer->addr = 0x0;
@@ -1591,6 +1612,7 @@
 	} else if (rc == OP_PARTIAL) {
 		buffer->addr = device_address(req->owner, req->req_start);
 		buffer->len = req->req_sz;
+		inc_ocmem_stat(zone_of(req), NR_RANGE_ALLOCATIONS);
 		pr_debug("ocmem: Enqueuing req %p\n", req);
 		sched_enqueue(req);
 	} else if (rc == OP_COMPLETE) {
@@ -1622,6 +1644,7 @@
 			list_del(&req->sched_list);
 			req->op = SCHED_ALLOCATE;
 			sched_enqueue(req);
+			inc_ocmem_stat(zone_of(req), NR_RESTORES);
 		}
 	}
 	kfree(edata);
@@ -1668,11 +1691,15 @@
 	req->op = SCHED_ALLOCATE;
 	req->buffer = buffer;
 
+	inc_ocmem_stat(zone_of(req), NR_REQUESTS);
+
 	rc = do_allocate(req, can_block, can_wait);
 
 	if (rc < 0)
 		goto do_allocate_error;
 
+	inc_ocmem_stat(zone_of(req), NR_SYNC_ALLOCATIONS);
+
 	handle->req = req;
 
 	if (is_tcm(id)) {
@@ -1717,10 +1744,11 @@
 
 	rc = do_allocate(req, true, false);
 
-
 	if (rc < 0)
 		goto do_allocate_error;
 
+	inc_ocmem_stat(zone_of(req), NR_ASYNC_ALLOCATIONS);
+
 	if (is_tcm(id)) {
 		rc = process_map(req, req->req_start, req->req_end);
 		if (rc < 0)
@@ -1788,10 +1816,51 @@
 	return;
 }
 
-int ocmem_sched_init(void)
+static int ocmem_allocations_show(struct seq_file *f, void *dummy)
+{
+	struct rb_node *rb_node = NULL;
+	struct ocmem_req *req = NULL;
+	unsigned j;
+	mutex_lock(&sched_mutex);
+	for (rb_node = rb_first(&sched_tree); rb_node;
+				rb_node = rb_next(rb_node)) {
+		struct ocmem_region *tmp_region = NULL;
+		tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
+		for (j = MAX_OCMEM_PRIO - 1; j > NO_PRIO; j--) {
+			req = find_req_match(j, tmp_region);
+			if (req) {
+				seq_printf(f,
+					"owner: %s 0x%lx -- 0x%lx size 0x%lx [state: %2lx]\n",
+					get_name(req->owner),
+					req->req_start, req->req_end,
+					req->req_sz, req->state);
+			}
+		}
+	}
+	mutex_unlock(&sched_mutex);
+	return 0;
+}
+
+static int ocmem_allocations_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ocmem_allocations_show, inode->i_private);
+}
+
+static const struct file_operations allocations_show_fops = {
+	.open = ocmem_allocations_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+int ocmem_sched_init(struct platform_device *pdev)
 {
 	int i = 0;
+	struct ocmem_plat_data *pdata = NULL;
+	struct device   *dev = &pdev->dev;
+
 	sched_tree = RB_ROOT;
+	pdata = platform_get_drvdata(pdev);
 	mutex_init(&sched_mutex);
 	mutex_init(&sched_queue_mutex);
 	for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++)
@@ -1805,5 +1874,11 @@
 	ocmem_eviction_wq = alloc_workqueue("ocmem_eviction_wq", 0, 0);
 	if (!ocmem_eviction_wq)
 		return -ENOMEM;
+
+	if (!debugfs_create_file("allocations", S_IRUGO, pdata->debug_node,
+					NULL, &allocations_show_fops)) {
+		dev_err(dev, "Unable to create debugfs node for scheduler\n");
+		return -EBUSY;
+	}
 	return 0;
 }
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 44d8bc6..ed072ea 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -21,6 +21,7 @@
 #include <mach/clk.h>
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
+#include "scm-pas.h"
 
 #define QDSP6SS_RST_EVB			0x010
 #define PROXY_TIMEOUT_MS		10000
@@ -122,6 +123,30 @@
 	.shutdown = pil_lpass_shutdown,
 };
 
+static int pil_lpass_init_image_trusted(struct pil_desc *pil,
+		const u8 *metadata, size_t size)
+{
+	return pas_init_image(PAS_Q6, metadata, size);
+}
+
+static int pil_lpass_reset_trusted(struct pil_desc *pil)
+{
+	return pas_auth_and_reset(PAS_Q6);
+}
+
+static int pil_lpass_shutdown_trusted(struct pil_desc *pil)
+{
+	return pas_shutdown(PAS_Q6);
+}
+
+static struct pil_reset_ops pil_lpass_ops_trusted = {
+	.init_image = pil_lpass_init_image_trusted,
+	.proxy_vote = pil_q6v5_make_proxy_votes,
+	.proxy_unvote = pil_q6v5_remove_proxy_votes,
+	.auth_and_reset = pil_lpass_reset_trusted,
+	.shutdown = pil_lpass_shutdown_trusted,
+};
+
 static int __devinit pil_lpass_driver_probe(struct platform_device *pdev)
 {
 	struct q6v5_data *drv;
@@ -155,6 +180,14 @@
 	if (IS_ERR(drv->reg_clk))
 		return PTR_ERR(drv->reg_clk);
 
+	if (pas_supported(PAS_Q6) > 0) {
+		desc->ops = &pil_lpass_ops_trusted;
+		dev_info(&pdev->dev, "using secure boot\n");
+	} else {
+		desc->ops = &pil_lpass_ops;
+		dev_info(&pdev->dev, "using non-secure boot\n");
+	}
+
 	drv->pil = msm_pil_register(desc);
 	if (IS_ERR(drv->pil))
 		return PTR_ERR(drv->pil);
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 4dd6df3..552fb16 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -80,6 +80,11 @@
 			bool notify_rpm, bool collapsed);
 };
 
+struct msm_pm_cpr_ops {
+	void (*cpr_suspend)(void);
+	void (*cpr_resume)(void);
+};
+
 void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
 int msm_pm_idle_prepare(struct cpuidle_device *dev,
 			struct cpuidle_driver *drv, int index);
@@ -125,4 +130,6 @@
 static inline void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t) {}
 #endif
 
+void msm_pm_set_cpr_ops(struct msm_pm_cpr_ops *ops);
+
 #endif  /* __ARCH_ARM_MACH_MSM_PM_H */
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 8fccda4..10c5445 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -152,6 +152,7 @@
 
 static struct msm_pm_platform_data *msm_pm_modes;
 static struct msm_pm_irq_calls *msm_pm_irq_extns;
+static struct msm_pm_cpr_ops *msm_cpr_ops;
 
 struct msm_pm_kobj_attribute {
 	unsigned int cpu;
@@ -415,6 +416,11 @@
 	msm_pm_irq_extns = irq_calls;
 }
 
+void __init msm_pm_set_cpr_ops(struct msm_pm_cpr_ops *ops)
+{
+	msm_cpr_ops = ops;
+}
+
 /******************************************************************************
  * Sleep Limitations
  *****************************************************************************/
@@ -876,6 +882,10 @@
 		WARN_ON(ret);
 	}
 
+	/* Call CPR suspend only for "idlePC" case */
+	if (msm_cpr_ops && from_idle)
+		msm_cpr_ops->cpr_suspend();
+
 	msm_pm_irq_extns->enter_sleep1(true, from_idle,
 						&msm_pm_smem_data->irq_mask);
 	msm_sirc_enter_sleep();
@@ -1113,6 +1123,10 @@
 		WARN_ON(ret);
 	}
 
+	/* Call CPR resume only for "idlePC" case */
+	if (msm_cpr_ops && from_idle)
+		msm_cpr_ops->cpr_resume();
+
 	return 0;
 
 power_collapse_early_exit:
@@ -1165,6 +1179,10 @@
 	if (collapsed)
 		smd_sleep_exit();
 
+	/* Call CPR resume only for "idlePC" case */
+	if (msm_cpr_ops && from_idle)
+		msm_cpr_ops->cpr_resume();
+
 power_collapse_bail:
 	if (cpu_is_msm8625()) {
 		ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING,
diff --git a/arch/arm/mach-msm/rpm-regulator-8930.c b/arch/arm/mach-msm/rpm-regulator-8930.c
index 3878e22..9133856 100644
--- a/arch/arm/mach-msm/rpm-regulator-8930.c
+++ b/arch/arm/mach-msm/rpm-regulator-8930.c
@@ -111,51 +111,64 @@
 };
 
 #define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load, _requires_cxo) \
-	[RPM_VREG_ID_PM8038_##_id] = { \
+	[RPM_VREG_ID_PM##_id] = { \
 		.req = { \
-			[0] = { .id = MSM_RPM_ID_PM8038_##_id##_0, }, \
-			[1] = { .id = MSM_RPM_ID_PM8038_##_id##_1, }, \
+			[0] = { .id = MSM_RPM_ID_PM##_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_PM##_id##_1, }, \
 		}, \
 		.hpm_min_load  = RPM_VREG_8930_##_hpm_min_load##_HPM_MIN_LOAD, \
 		.type		 = RPM_REGULATOR_TYPE_LDO, \
 		.set_points	 = &_ranges##_set_points, \
 		.part		 = &ldo_parts, \
-		.id		 = RPM_VREG_ID_PM8038_##_id, \
+		.id		 = RPM_VREG_ID_PM##_id, \
 		.rdesc.name	 = _name, \
 		.rdesc_pc.name	 = _name_pc, \
 		.requires_cxo	 = _requires_cxo, \
 	}
 
 #define SMPS(_id, _name, _name_pc, _ranges, _hpm_min_load) \
-	[RPM_VREG_ID_PM8038_##_id] = { \
+	[RPM_VREG_ID_PM##_id] = { \
 		.req = { \
-			[0] = { .id = MSM_RPM_ID_PM8038_##_id##_0, }, \
-			[1] = { .id = MSM_RPM_ID_PM8038_##_id##_1, }, \
+			[0] = { .id = MSM_RPM_ID_PM##_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_PM##_id##_1, }, \
 		}, \
 		.hpm_min_load  = RPM_VREG_8930_##_hpm_min_load##_HPM_MIN_LOAD, \
 		.type		 = RPM_REGULATOR_TYPE_SMPS, \
 		.set_points	 = &_ranges##_set_points, \
 		.part		 = &smps_parts, \
-		.id		 = RPM_VREG_ID_PM8038_##_id, \
+		.id		 = RPM_VREG_ID_PM##_id, \
 		.rdesc.name	 = _name, \
 		.rdesc_pc.name	 = _name_pc, \
 	}
 
 #define LVS(_id, _name, _name_pc) \
-	[RPM_VREG_ID_PM8038_##_id] = { \
+	[RPM_VREG_ID_PM##_id] = { \
 		.req = { \
-			[0] = { .id = MSM_RPM_ID_PM8038_##_id, }, \
+			[0] = { .id = MSM_RPM_ID_PM##_id, }, \
 			[1] = { .id = -1, }, \
 		}, \
 		.type		 = RPM_REGULATOR_TYPE_VS, \
 		.part		 = &switch_parts, \
-		.id		 = RPM_VREG_ID_PM8038_##_id, \
+		.id		 = RPM_VREG_ID_PM##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define MVS(_vreg_id, _name, _name_pc, _rpm_id) \
+	[RPM_VREG_ID_PM##_vreg_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
+			[1] = { .id = -1, }, \
+		}, \
+		.type		 = RPM_REGULATOR_TYPE_VS, \
+		.part		 = &switch_parts, \
+		.id		 = RPM_VREG_ID_PM##_vreg_id, \
 		.rdesc.name	 = _name, \
 		.rdesc_pc.name	 = _name_pc, \
 	}
 
 #define CORNER(_id, _rpm_id, _name, _ranges) \
-	[RPM_VREG_ID_PM8038_##_id] = { \
+	[RPM_VREG_ID_PM##_id] = { \
 		.req = { \
 			[0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
 			[1] = { .id = -1, }, \
@@ -163,50 +176,105 @@
 		.type		 = RPM_REGULATOR_TYPE_CORNER, \
 		.set_points	 = &_ranges##_set_points, \
 		.part		 = &corner_parts, \
-		.id		 = RPM_VREG_ID_PM8038_##_id, \
+		.id		 = RPM_VREG_ID_PM##_id, \
 		.rdesc.name	 = _name, \
 	}
 
-static struct vreg vregs[] = {
-	LDO(L1,   "8038_l1",   NULL,          nldo1200, LDO_1200, 1),
-	LDO(L2,   "8038_l2",   "8038_l2_pc",  nldo,     LDO_150,  1),
-	LDO(L3,   "8038_l3",   "8038_l3_pc",  pldo,     LDO_50,   0),
-	LDO(L4,   "8038_l4",   "8038_l4_pc",  pldo,     LDO_50,   0),
-	LDO(L5,   "8038_l5",   "8038_l5_pc",  pldo,     LDO_600,  0),
-	LDO(L6,   "8038_l6",   "8038_l6_pc",  pldo,     LDO_600,  0),
-	LDO(L7,   "8038_l7",   "8038_l7_pc",  pldo,     LDO_600,  0),
-	LDO(L8,   "8038_l8",   "8038_l8_pc",  pldo,     LDO_300,  0),
-	LDO(L9,   "8038_l9",   "8038_l9_pc",  pldo,     LDO_300,  0),
-	LDO(L10,  "8038_l10",  "8038_l10_pc", pldo,     LDO_600,  0),
-	LDO(L11,  "8038_l11",  "8038_l11_pc", pldo,     LDO_600,  0),
-	LDO(L12,  "8038_l12",  "8038_l12_pc", nldo,     LDO_300,  1),
-	LDO(L13,  "8038_l13",  NULL,          ln_ldo,   LDO_5,    0),
-	LDO(L14,  "8038_l14",  "8038_l14_pc", pldo,     LDO_50,   0),
-	LDO(L15,  "8038_l15",  "8038_l15_pc", pldo,     LDO_150,  0),
-	LDO(L16,  "8038_l16",  NULL,          nldo1200, LDO_1200, 1),
-	LDO(L17,  "8038_l17",  "8038_l17_pc", pldo,     LDO_150,  0),
-	LDO(L18,  "8038_l18",  "8038_l18_pc", pldo,     LDO_50,   0),
-	LDO(L19,  "8038_l19",  NULL,          nldo1200, LDO_1200, 1),
-	LDO(L20,  "8038_l20",  NULL,          nldo1200, LDO_1200, 1),
-	LDO(L21,  "8038_l21",  "8038_l21_pc", pldo,     LDO_150,  0),
-	LDO(L22,  "8038_l22",  "8038_l22_pc", pldo,     LDO_50,   0),
-	LDO(L23,  "8038_l23",  "8038_l23_pc", pldo,     LDO_50,   0),
-	LDO(L24,  "8038_l24",  NULL,          nldo1200, LDO_1200, 1),
-	LDO(L25,  "8038_l25",  NULL,          ln_ldo,   LDO_5,    0),
-	LDO(L26,  "8038_l26",  "8038_l26_pc", nldo,     LDO_150,  1),
-	LDO(L27,  "8038_l27",  NULL,          nldo1200, LDO_1200, 1),
+static struct vreg vregs_msm8930_pm8038[] = {
+	LDO(8038_L1,   "8038_l1",   NULL,          nldo1200, LDO_1200, 1),
+	LDO(8038_L2,   "8038_l2",   "8038_l2_pc",  nldo,     LDO_150,  1),
+	LDO(8038_L3,   "8038_l3",   "8038_l3_pc",  pldo,     LDO_50,   0),
+	LDO(8038_L4,   "8038_l4",   "8038_l4_pc",  pldo,     LDO_50,   0),
+	LDO(8038_L5,   "8038_l5",   "8038_l5_pc",  pldo,     LDO_600,  0),
+	LDO(8038_L6,   "8038_l6",   "8038_l6_pc",  pldo,     LDO_600,  0),
+	LDO(8038_L7,   "8038_l7",   "8038_l7_pc",  pldo,     LDO_600,  0),
+	LDO(8038_L8,   "8038_l8",   "8038_l8_pc",  pldo,     LDO_300,  0),
+	LDO(8038_L9,   "8038_l9",   "8038_l9_pc",  pldo,     LDO_300,  0),
+	LDO(8038_L10,  "8038_l10",  "8038_l10_pc", pldo,     LDO_600,  0),
+	LDO(8038_L11,  "8038_l11",  "8038_l11_pc", pldo,     LDO_600,  0),
+	LDO(8038_L12,  "8038_l12",  "8038_l12_pc", nldo,     LDO_300,  1),
+	LDO(8038_L13,  "8038_l13",  NULL,          ln_ldo,   LDO_5,    0),
+	LDO(8038_L14,  "8038_l14",  "8038_l14_pc", pldo,     LDO_50,   0),
+	LDO(8038_L15,  "8038_l15",  "8038_l15_pc", pldo,     LDO_150,  0),
+	LDO(8038_L16,  "8038_l16",  NULL,          nldo1200, LDO_1200, 1),
+	LDO(8038_L17,  "8038_l17",  "8038_l17_pc", pldo,     LDO_150,  0),
+	LDO(8038_L18,  "8038_l18",  "8038_l18_pc", pldo,     LDO_50,   0),
+	LDO(8038_L19,  "8038_l19",  NULL,          nldo1200, LDO_1200, 1),
+	LDO(8038_L20,  "8038_l20",  NULL,          nldo1200, LDO_1200, 1),
+	LDO(8038_L21,  "8038_l21",  "8038_l21_pc", pldo,     LDO_150,  0),
+	LDO(8038_L22,  "8038_l22",  "8038_l22_pc", pldo,     LDO_50,   0),
+	LDO(8038_L23,  "8038_l23",  "8038_l23_pc", pldo,     LDO_50,   0),
+	LDO(8038_L24,  "8038_l24",  NULL,          nldo1200, LDO_1200, 1),
+	LDO(8038_L25,  "8038_l25",  NULL,          ln_ldo,   LDO_5,    0),
+	LDO(8038_L26,  "8038_l26",  "8038_l26_pc", nldo,     LDO_150,  1),
+	LDO(8038_L27,  "8038_l27",  NULL,          nldo1200, LDO_1200, 1),
 
-	SMPS(S1,  "8038_s1",   "8038_s1_pc",  smps,     SMPS_1500),
-	SMPS(S2,  "8038_s2",   "8038_s2_pc",  smps,     SMPS_1500),
-	SMPS(S3,  "8038_s3",   "8038_s3_pc",  smps,     SMPS_1500),
-	SMPS(S4,  "8038_s4",   "8038_s4_pc",  smps,     SMPS_1500),
-	SMPS(S5,  "8038_s5",   NULL,          ftsmps,   SMPS_2000),
-	SMPS(S6,  "8038_s6",   NULL,          ftsmps,   SMPS_2000),
+	SMPS(8038_S1,  "8038_s1",   "8038_s1_pc",  smps,     SMPS_1500),
+	SMPS(8038_S2,  "8038_s2",   "8038_s2_pc",  smps,     SMPS_1500),
+	SMPS(8038_S3,  "8038_s3",   "8038_s3_pc",  smps,     SMPS_1500),
+	SMPS(8038_S4,  "8038_s4",   "8038_s4_pc",  smps,     SMPS_1500),
+	SMPS(8038_S5,  "8038_s5",   NULL,          ftsmps,   SMPS_2000),
+	SMPS(8038_S6,  "8038_s6",   NULL,          ftsmps,   SMPS_2000),
 
-	LVS(LVS1, "8038_lvs1", "8038_lvs1_pc"),
-	LVS(LVS2, "8038_lvs2", "8038_lvs2_pc"),
+	LVS(8038_LVS1, "8038_lvs1", "8038_lvs1_pc"),
+	LVS(8038_LVS2, "8038_lvs2", "8038_lvs2_pc"),
 
-	CORNER(VDD_DIG_CORNER, VOLTAGE_CORNER, "vdd_dig_corner", corner),
+	CORNER(8038_VDD_DIG_CORNER, VOLTAGE_CORNER, "vdd_dig_corner", corner),
+};
+
+static struct vreg vregs_msm8930_pm8917[] = {
+	LDO(8917_L1,   "8917_l1",   "8917_l1_pc",  nldo,     LDO_150,  1),
+	LDO(8917_L2,   "8917_l2",   "8917_l2_pc",  nldo,     LDO_150,  1),
+	LDO(8917_L3,   "8917_l3",   "8917_l3_pc",  pldo,     LDO_150,  0),
+	LDO(8917_L4,   "8917_l4",   "8917_l4_pc",  pldo,     LDO_50,   0),
+	LDO(8917_L5,   "8917_l5",   "8917_l5_pc",  pldo,     LDO_300,  0),
+	LDO(8917_L6,   "8917_l6",   "8917_l6_pc",  pldo,     LDO_600,  0),
+	LDO(8917_L7,   "8917_l7",   "8917_l7_pc",  pldo,     LDO_150,  0),
+	LDO(8917_L8,   "8917_l8",   "8917_l8_pc",  pldo,     LDO_300,  0),
+	LDO(8917_L9,   "8917_l9",   "8917_l9_pc",  pldo,     LDO_300,  0),
+	LDO(8917_L10,  "8917_l10",  "8917_l10_pc", pldo,     LDO_600,  0),
+	LDO(8917_L11,  "8917_l11",  "8917_l11_pc", pldo,     LDO_150,  0),
+	LDO(8917_L12,  "8917_l12",  "8917_l12_pc", nldo,     LDO_150,  1),
+	LDO(8917_L14,  "8917_l14",  "8917_l14_pc", pldo,     LDO_50,   0),
+	LDO(8917_L15,  "8917_l15",  "8917_l15_pc", pldo,     LDO_150,  0),
+	LDO(8917_L16,  "8917_l16",  "8917_l16_pc", pldo,     LDO_300,  0),
+	LDO(8917_L17,  "8917_l17",  "8917_l17_pc", pldo,     LDO_150,  0),
+	LDO(8917_L18,  "8917_l18",  "8917_l18_pc", nldo,     LDO_150,  1),
+	LDO(8917_L21,  "8917_l21",  "8917_l21_pc", pldo,     LDO_150,  0),
+	LDO(8917_L22,  "8917_l22",  "8917_l22_pc", pldo,     LDO_150,  0),
+	LDO(8917_L23,  "8917_l23",  "8917_l23_pc", pldo,     LDO_150,  0),
+	LDO(8917_L24,  "8917_l24",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(8917_L25,  "8917_l25",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(8917_L26,  "8917_l26",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(8917_L27,  "8917_l27",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(8917_L28,  "8917_l28",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(8917_L29,  "8917_l29",  "8917_l29_pc", pldo,     LDO_150,  0),
+	LDO(8917_L30,  "8917_l30",  "8917_l30_pc", pldo,     LDO_150,  0),
+	LDO(8917_L31,  "8917_l31",  "8917_l31_pc", pldo,     LDO_150,  0),
+	LDO(8917_L32,  "8917_l32",  "8917_l32_pc", pldo,     LDO_150,  0),
+	LDO(8917_L33,  "8917_l33",  "8917_l33_pc", pldo,     LDO_150,  0),
+	LDO(8917_L34,  "8917_l34",  "8917_l34_pc", pldo,     LDO_150,  0),
+	LDO(8917_L35,  "8917_l35",  "8917_l35_pc", pldo,     LDO_300,  0),
+	LDO(8917_L36,  "8917_l36",  "8917_l36_pc", pldo,     LDO_50,   0),
+
+	SMPS(8917_S1,  "8917_s1",   "8917_s1_pc",  smps,     SMPS_1500),
+	SMPS(8917_S2,  "8917_s2",   "8917_s2_pc",  smps,     SMPS_1500),
+	SMPS(8917_S3,  "8917_s3",   "8917_s3_pc",  smps,     SMPS_1500),
+	SMPS(8917_S4,  "8917_s4",   "8917_s4_pc",  smps,     SMPS_1500),
+	SMPS(8917_S5,  "8917_s5",   NULL,          ftsmps,   SMPS_2000),
+	SMPS(8917_S6,  "8917_s6",   NULL,          ftsmps,   SMPS_2000),
+	SMPS(8917_S7,  "8917_s7",   "8917_s7_pc",  smps,     SMPS_1500),
+	SMPS(8917_S8,  "8917_s8",   "8917_s8_pc",  smps,     SMPS_1500),
+
+	LVS(8917_LVS1, "8917_lvs1", "8917_lvs1_pc"),
+	LVS(8917_LVS3, "8917_lvs3", "8917_lvs3_pc"),
+	LVS(8917_LVS4, "8917_lvs4", "8917_lvs4_pc"),
+	LVS(8917_LVS5, "8917_lvs5", "8917_lvs5_pc"),
+	LVS(8917_LVS6, "8917_lvs6", "8917_lvs6_pc"),
+	LVS(8917_LVS7, "8917_lvs7", "8917_lvs7_pc"),
+	MVS(8917_USB_OTG,  "8917_usb_otg",  NULL, USB_OTG_SWITCH),
+
+	CORNER(8917_VDD_DIG_CORNER, VOLTAGE_CORNER, "vdd_dig_corner", corner),
 };
 
 static const char *pin_func_label[] = {
@@ -237,17 +305,18 @@
 	" A2",
 };
 
-static int is_real_id(int id)
+static int is_real_id_msm8930_pm8038(int id)
 {
 	return (id >= 0) && (id <= RPM_VREG_ID_PM8038_MAX_REAL);
 }
 
-static int pc_id_to_real_id(int id)
+static int pc_id_to_real_id_msm8930_pm8038(int id)
 {
 	int real_id = 0;
 
 	if (id >= RPM_VREG_ID_PM8038_L2_PC && id <= RPM_VREG_ID_PM8038_L12_PC)
-		real_id = id - RPM_VREG_ID_PM8038_L2_PC;
+		real_id = id - RPM_VREG_ID_PM8038_L2_PC
+				+ RPM_VREG_ID_PM8038_L2;
 	else if (id >= RPM_VREG_ID_PM8038_L14_PC
 			&& id <= RPM_VREG_ID_PM8038_L15_PC)
 		real_id = id - RPM_VREG_ID_PM8038_L14_PC
@@ -274,9 +343,33 @@
 	return real_id;
 }
 
-static struct vreg_config config = {
-	.vregs			= vregs,
-	.vregs_len		= ARRAY_SIZE(vregs),
+static int is_real_id_msm8930_pm8917(int id)
+{
+	return (id >= 0) && (id <= RPM_VREG_ID_PM8917_MAX_REAL);
+}
+
+static int pc_id_to_real_id_msm8930_pm8917(int id)
+{
+	int real_id = 0;
+
+	if (id >= RPM_VREG_ID_PM8917_L1_PC && id <= RPM_VREG_ID_PM8917_L23_PC)
+		real_id = id - RPM_VREG_ID_PM8917_L1_PC
+				+ RPM_VREG_ID_PM8917_L1;
+	else if (id >= RPM_VREG_ID_PM8917_L29_PC
+			&& id <= RPM_VREG_ID_PM8917_S4_PC)
+		real_id = id - RPM_VREG_ID_PM8917_L29_PC
+				+ RPM_VREG_ID_PM8917_L29;
+	else if (id >= RPM_VREG_ID_PM8917_S7_PC
+			&& id <= RPM_VREG_ID_PM8917_LVS7_PC)
+		real_id = id - RPM_VREG_ID_PM8917_S7_PC
+				+ RPM_VREG_ID_PM8917_S7;
+
+	return real_id;
+}
+
+static struct vreg_config config_msm8930_pm8038 = {
+	.vregs			= vregs_msm8930_pm8038,
+	.vregs_len		= ARRAY_SIZE(vregs_msm8930_pm8038),
 
 	.vreg_id_min		= RPM_VREG_ID_PM8038_L1,
 	.vreg_id_max		= RPM_VREG_ID_PM8038_MAX,
@@ -299,11 +392,45 @@
 	.label_power_mode	= power_mode_label,
 	.label_power_mode_len	= ARRAY_SIZE(power_mode_label),
 
-	.is_real_id		= is_real_id,
-	.pc_id_to_real_id	= pc_id_to_real_id,
+	.is_real_id		= is_real_id_msm8930_pm8038,
+	.pc_id_to_real_id	= pc_id_to_real_id_msm8930_pm8038,
+};
+
+static struct vreg_config config_msm8930_pm8917 = {
+	.vregs			= vregs_msm8930_pm8917,
+	.vregs_len		= ARRAY_SIZE(vregs_msm8930_pm8917),
+
+	.vreg_id_min		= RPM_VREG_ID_PM8917_L1,
+	.vreg_id_max		= RPM_VREG_ID_PM8917_MAX,
+
+	.pin_func_none		= RPM_VREG_PIN_FN_8930_NONE,
+	.pin_func_sleep_b	= RPM_VREG_PIN_FN_8930_SLEEP_B,
+
+	.mode_lpm		= REGULATOR_MODE_IDLE,
+	.mode_hpm		= REGULATOR_MODE_NORMAL,
+
+	.set_points		= all_set_points,
+	.set_points_len		= ARRAY_SIZE(all_set_points),
+
+	.label_pin_ctrl		= pin_control_label,
+	.label_pin_ctrl_len	= ARRAY_SIZE(pin_control_label),
+	.label_pin_func		= pin_func_label,
+	.label_pin_func_len	= ARRAY_SIZE(pin_func_label),
+	.label_force_mode	= force_mode_label,
+	.label_force_mode_len	= ARRAY_SIZE(force_mode_label),
+	.label_power_mode	= power_mode_label,
+	.label_power_mode_len	= ARRAY_SIZE(power_mode_label),
+
+	.is_real_id		= is_real_id_msm8930_pm8917,
+	.pc_id_to_real_id	= pc_id_to_real_id_msm8930_pm8917,
 };
 
 struct vreg_config *get_config_8930(void)
 {
-	return &config;
+	return &config_msm8930_pm8038;
+}
+
+struct vreg_config *get_config_8930_pm8917(void)
+{
+	return &config_msm8930_pm8917;
 }
diff --git a/arch/arm/mach-msm/rpm-regulator-private.h b/arch/arm/mach-msm/rpm-regulator-private.h
index c3ddc33..d55bd73 100644
--- a/arch/arm/mach-msm/rpm-regulator-private.h
+++ b/arch/arm/mach-msm/rpm-regulator-private.h
@@ -176,11 +176,16 @@
 
 #if defined(CONFIG_MSM_RPM_REGULATOR) && defined(CONFIG_ARCH_MSM8930)
 struct vreg_config *get_config_8930(void);
+struct vreg_config *get_config_8930_pm8917(void);
 #else
 static inline struct vreg_config *get_config_8930(void)
 {
 	return NULL;
 }
+static inline struct vreg_config *get_config_8930_pm8917(void)
+{
+	return NULL;
+}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index 68ff55b..424a4fe 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -62,6 +62,7 @@
 	[RPM_VREG_VERSION_8960] = get_config_8960,
 	[RPM_VREG_VERSION_9615] = get_config_9615,
 	[RPM_VREG_VERSION_8930] = get_config_8930,
+	[RPM_VREG_VERSION_8930_PM8917] = get_config_8930_pm8917,
 };
 
 static struct rpm_regulator_consumer_mapping *consumer_map;
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index e82e44b..eeac2b9 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -361,9 +361,15 @@
 static DEFINE_MUTEX(smsm_lock);
 static struct smsm_state_info *smsm_states;
 static int spinlocks_initialized;
-static RAW_NOTIFIER_HEAD(smsm_driver_state_notifier_list);
-static DEFINE_MUTEX(smsm_driver_state_notifier_lock);
-static void smsm_driver_state_notify(uint32_t state, void *data);
+
+/**
+ * Variables to indicate smd module initialization.
+ * Dependents to register for smd module init notifier.
+ */
+static int smd_module_inited;
+static RAW_NOTIFIER_HEAD(smd_module_init_notifier_list);
+static DEFINE_MUTEX(smd_module_init_notifier_lock);
+static void smd_module_init_notify(uint32_t state, void *data);
 
 static inline void smd_write_intr(unsigned int val,
 				const void __iomem *addr)
@@ -2465,13 +2471,6 @@
 	int i;
 	struct smsm_size_info_type *smsm_size_info;
 
-	i = remote_spin_lock_init(&remote_spinlock, SMEM_SPINLOCK_SMEM_ALLOC);
-	if (i) {
-		pr_err("%s: remote spinlock init failed %d\n", __func__, i);
-		return i;
-	}
-	spinlocks_initialized = 1;
-
 	smsm_size_info = smem_alloc(SMEM_SMSM_SIZE_INFO,
 				sizeof(struct smsm_size_info_type));
 	if (smsm_size_info) {
@@ -2530,7 +2529,6 @@
 		return i;
 
 	wmb();
-	smsm_driver_state_notify(SMSM_INIT, NULL);
 	return 0;
 }
 
@@ -3104,37 +3102,40 @@
 }
 EXPORT_SYMBOL(smsm_state_cb_deregister);
 
-int smsm_driver_state_notifier_register(struct notifier_block *nb)
+int smd_module_init_notifier_register(struct notifier_block *nb)
 {
 	int ret;
 	if (!nb)
 		return -EINVAL;
-	mutex_lock(&smsm_driver_state_notifier_lock);
-	ret = raw_notifier_chain_register(&smsm_driver_state_notifier_list, nb);
-	mutex_unlock(&smsm_driver_state_notifier_lock);
+	mutex_lock(&smd_module_init_notifier_lock);
+	ret = raw_notifier_chain_register(&smd_module_init_notifier_list, nb);
+	if (smd_module_inited)
+		nb->notifier_call(nb, 0, NULL);
+	mutex_unlock(&smd_module_init_notifier_lock);
 	return ret;
 }
-EXPORT_SYMBOL(smsm_driver_state_notifier_register);
+EXPORT_SYMBOL(smd_module_init_notifier_register);
 
-int smsm_driver_state_notifier_unregister(struct notifier_block *nb)
+int smd_module_init_notifier_unregister(struct notifier_block *nb)
 {
 	int ret;
 	if (!nb)
 		return -EINVAL;
-	mutex_lock(&smsm_driver_state_notifier_lock);
-	ret = raw_notifier_chain_unregister(&smsm_driver_state_notifier_list,
+	mutex_lock(&smd_module_init_notifier_lock);
+	ret = raw_notifier_chain_unregister(&smd_module_init_notifier_list,
 					    nb);
-	mutex_unlock(&smsm_driver_state_notifier_lock);
+	mutex_unlock(&smd_module_init_notifier_lock);
 	return ret;
 }
-EXPORT_SYMBOL(smsm_driver_state_notifier_unregister);
+EXPORT_SYMBOL(smd_module_init_notifier_unregister);
 
-static void smsm_driver_state_notify(uint32_t state, void *data)
+static void smd_module_init_notify(uint32_t state, void *data)
 {
-	mutex_lock(&smsm_driver_state_notifier_lock);
-	raw_notifier_call_chain(&smsm_driver_state_notifier_list,
+	mutex_lock(&smd_module_init_notifier_lock);
+	smd_module_inited = 1;
+	raw_notifier_call_chain(&smd_module_init_notifier_list,
 				state, data);
-	mutex_unlock(&smsm_driver_state_notifier_lock);
+	mutex_unlock(&smd_module_init_notifier_lock);
 }
 
 int smd_core_init(void)
@@ -3547,12 +3548,29 @@
 int __init msm_smd_init(void)
 {
 	static bool registered;
+	int rc;
 
 	if (registered)
 		return 0;
 
 	registered = true;
-	return platform_driver_register(&msm_smd_driver);
+	rc = remote_spin_lock_init(&remote_spinlock, SMEM_SPINLOCK_SMEM_ALLOC);
+	if (rc) {
+		pr_err("%s: remote spinlock init failed %d\n", __func__, rc);
+		return rc;
+	}
+	spinlocks_initialized = 1;
+
+	rc = platform_driver_register(&msm_smd_driver);
+	if (rc) {
+		pr_err("%s: msm_smd_driver register failed %d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	smd_module_init_notify(0, NULL);
+
+	return 0;
 }
 
 module_init(msm_smd_init);
diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c
index 2e9a97c..fd8144a 100644
--- a/arch/arm/mach-msm/smem_log.c
+++ b/arch/arm/mach-msm/smem_log.c
@@ -2008,25 +2008,23 @@
 	return ret;
 }
 
-static int smsm_driver_state_notifier(struct notifier_block *this,
-				      unsigned long code,
-				      void *_cmd)
+static int smd_module_init_notifier(struct notifier_block *this,
+				    unsigned long code,
+				    void *_cmd)
 {
 	int ret = 0;
-	if (code & SMSM_INIT) {
-		if (!smem_log_initialized)
-			ret = smem_log_initialize();
-	}
+	if (!smem_log_initialized)
+		ret = smem_log_initialize();
 	return ret;
 }
 
 static struct notifier_block nb = {
-	.notifier_call = smsm_driver_state_notifier,
+	.notifier_call = smd_module_init_notifier,
 };
 
 static int __init smem_log_init(void)
 {
-	return smsm_driver_state_notifier_register(&nb);
+	return smd_module_init_notifier_register(&nb);
 }
 
 
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 69783f4..4495eb0 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -35,6 +35,8 @@
 #define POOL_TYPE_COPY		1
 #define POOL_TYPE_HDLC		2
 #define POOL_TYPE_WRITE_STRUCT	4
+#define POOL_TYPE_HSIC		8
+#define POOL_TYPE_HSIC_WRITE	16
 #define POOL_TYPE_ALL		7
 #define MODEM_DATA 		1
 #define QDSP_DATA  		2
@@ -273,20 +275,19 @@
 	int in_busy_smux;
 	int diag_smux_enabled;
 	int smux_connected;
+	struct diag_request *write_ptr_mdm;
 	/* HSIC variables */
-	unsigned char *buf_in_hsic;
 	int hsic_ch;
 	int hsic_device_enabled;
 	int hsic_device_opened;
 	int hsic_suspend;
 	int in_busy_hsic_read_on_device;
-	int in_busy_hsic_write_on_device;
 	int in_busy_hsic_write;
-	int in_busy_hsic_read;
 	struct work_struct diag_read_hsic_work;
 	/* USB MDM channel variables */
 	int usb_mdm_connected;
 	int read_len_mdm;
+	int write_len_mdm;
 	unsigned char *usb_buf_mdm_out;
 	struct usb_diag_ch *mdm_ch;
 	struct workqueue_struct *diag_bridge_wq;
@@ -294,7 +295,16 @@
 	struct work_struct diag_disconnect_work;
 	struct work_struct diag_usb_read_complete_work;
 	struct diag_request *usb_read_mdm_ptr;
-	struct diag_request *write_ptr_mdm;
+	int count_hsic_pool;
+	int count_hsic_write_pool;
+	unsigned int poolsize_hsic;
+	unsigned int poolsize_hsic_write;
+	unsigned int itemsize_hsic;
+	unsigned int itemsize_hsic_write;
+	mempool_t *diag_hsic_pool;
+	mempool_t *diag_hsic_write_pool;
+	int num_hsic_buf_tbl_entries;
+	struct diag_write_device *hsic_buf_tbl;
 #endif
 };
 
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 30504bc..2dc1929 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -243,6 +243,17 @@
 		driver->logging_mode = USB_MODE;
 		diagfwd_connect();
 #ifdef CONFIG_DIAG_BRIDGE_CODE
+		driver->num_hsic_buf_tbl_entries = 0;
+		for (i = 0; i < driver->poolsize_hsic_write; i++) {
+			if (driver->hsic_buf_tbl[i].buf) {
+				/* Return the buffer to the pool */
+				diagmem_free(driver, (unsigned char *)
+					(driver->hsic_buf_tbl[i].buf),
+					POOL_TYPE_HSIC);
+				driver->hsic_buf_tbl[i].buf = 0;
+				driver->hsic_buf_tbl[i].length = 0;
+			}
+		}
 		diagfwd_cancel_hsic();
 		diagfwd_connect_bridge(0);
 #endif
@@ -528,6 +539,17 @@
 			driver->in_busy_sdio = 1;
 #endif
 #ifdef CONFIG_DIAG_BRIDGE_CODE
+			driver->num_hsic_buf_tbl_entries = 0;
+			for (i = 0; i < driver->poolsize_hsic_write; i++) {
+				if (driver->hsic_buf_tbl[i].buf) {
+					/* Return the buffer to the pool */
+					diagmem_free(driver, (unsigned char *)
+						(driver->hsic_buf_tbl[i].buf),
+						POOL_TYPE_HSIC);
+					driver->hsic_buf_tbl[i].buf = 0;
+					driver->hsic_buf_tbl[i].length = 0;
+				}
+			}
 			diagfwd_disconnect_bridge(0);
 #endif
 		} else if (temp == NO_LOGGING_MODE && driver->logging_mode
@@ -556,6 +578,11 @@
 					&(driver->diag_read_sdio_work));
 #endif
 #ifdef CONFIG_DIAG_BRIDGE_CODE
+			driver->num_hsic_buf_tbl_entries = 0;
+			for (i = 0; i < driver->poolsize_hsic_write; i++) {
+				driver->hsic_buf_tbl[i].buf = 0;
+				driver->hsic_buf_tbl[i].length = 0;
+			}
 			diagfwd_connect_bridge(0);
 #endif
 		}
@@ -581,6 +608,7 @@
 			driver->in_busy_qdsp_2 = 0;
 			driver->in_busy_wcnss_1 = 0;
 			driver->in_busy_wcnss_2 = 0;
+
 			/* Poll SMD channels to check for data*/
 			if (driver->ch)
 				queue_work(driver->diag_wq,
@@ -599,6 +627,11 @@
 					&(driver->diag_read_sdio_work));
 #endif
 #ifdef CONFIG_DIAG_BRIDGE_CODE
+			driver->num_hsic_buf_tbl_entries = 0;
+			for (i = 0; i < driver->poolsize_hsic_write; i++) {
+				driver->hsic_buf_tbl[i].buf = 0;
+				driver->hsic_buf_tbl[i].length = 0;
+			}
 			diagfwd_cancel_hsic();
 			diagfwd_connect_bridge(0);
 #endif
@@ -606,6 +639,17 @@
 				 driver->logging_mode == USB_MODE) {
 			diagfwd_connect();
 #ifdef CONFIG_DIAG_BRIDGE_CODE
+			driver->num_hsic_buf_tbl_entries = 0;
+			for (i = 0; i < driver->poolsize_hsic_write; i++) {
+				if (driver->hsic_buf_tbl[i].buf) {
+					/* Return the buffer to the pool */
+					diagmem_free(driver, (unsigned char *)
+						(driver->hsic_buf_tbl[i].buf),
+						POOL_TYPE_HSIC);
+					driver->hsic_buf_tbl[i].buf = 0;
+					driver->hsic_buf_tbl[i].length = 0;
+				}
+			}
 			diagfwd_cancel_hsic();
 			diagfwd_connect_bridge(0);
 #endif
@@ -767,20 +811,44 @@
 		}
 #endif
 #ifdef CONFIG_DIAG_BRIDGE_CODE
-		pr_debug("diag: Copy data to user space %d\n",
-			 driver->in_busy_hsic_write_on_device);
-		if (driver->in_busy_hsic_write_on_device == 1) {
-			num_data++;
-			/*Copy the length of data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret,
-				 (driver->write_ptr_mdm->length), 4);
-			/*Copy the actual data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret,
-					*(driver->buf_in_hsic),
-					 driver->write_ptr_mdm->length);
-			pr_debug("diag: data copied\n");
-			/* call the write complete function */
-			diagfwd_write_complete_hsic();
+
+		for (i = 0; i < driver->poolsize_hsic_write; i++) {
+			if (driver->hsic_buf_tbl[i].length > 0) {
+				pr_debug("diag: HSIC copy to user, i: %d, buf: %x, len: %d\n",
+					 i, (unsigned int)
+					(driver->hsic_buf_tbl[i].buf),
+					driver->hsic_buf_tbl[i].length);
+				num_data++;
+				/* Copy the length of data being passed */
+				if (copy_to_user(buf+ret, (void *)&(driver->
+					hsic_buf_tbl[i].length), 4)) {
+					num_data--;
+					goto drop_hsic;
+				}
+				ret += 4;
+
+				/* Copy the actual data being passed */
+				if (copy_to_user(buf+ret,
+					(void *)driver->hsic_buf_tbl[i].buf,
+					driver->hsic_buf_tbl[i].length)) {
+					ret -= 4;
+					num_data--;
+					goto drop_hsic;
+				}
+				ret += driver->hsic_buf_tbl[i].length;
+drop_hsic:
+				/* Return the buffer to the pool */
+				diagmem_free(driver, (unsigned char *)
+					(driver->hsic_buf_tbl[i].buf),
+					POOL_TYPE_HSIC);
+
+				driver->hsic_buf_tbl[i].length = 0;
+				driver->hsic_buf_tbl[i].buf = 0;
+				driver->num_hsic_buf_tbl_entries--;
+
+				/* Call the write complete function */
+				diagfwd_write_complete_hsic(NULL);
+			}
 		}
 #endif
 		/* copy number of data fields */
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 5a74e8c..0f4aefd 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -66,6 +66,9 @@
 	msg_mask_tbl_ptr += 4;						\
 	*(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST;		\
 	msg_mask_tbl_ptr += 4;						\
+	/* mimic the last entry as actual_last while creation */	\
+	*(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST;		\
+	msg_mask_tbl_ptr += 4;						\
 	/* increment by MAX_SSID_PER_RANGE cells */			\
 	msg_mask_tbl_ptr += MAX_SSID_PER_RANGE * sizeof(int);		\
 } while (0)
@@ -307,6 +310,26 @@
 					break;
 				}
 		}
+
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+		else if (proc_num == HSIC_DATA) {
+			for (i = 0; i < driver->poolsize_hsic_write; i++) {
+				if (driver->hsic_buf_tbl[i].length == 0) {
+					driver->hsic_buf_tbl[i].buf = buf;
+					driver->hsic_buf_tbl[i].length =
+							driver->write_len_mdm;
+					driver->num_hsic_buf_tbl_entries++;
+#ifdef DIAG_DEBUG
+					pr_debug("diag: ENQUEUE HSIC buf ptr and length is %x , %d\n",
+						(unsigned int)
+						(driver->hsic_buf_tbl[i].buf),
+						driver->hsic_buf_tbl[i].length);
+#endif
+					break;
+				}
+			}
+		}
+#endif
 		for (i = 0; i < driver->num_clients; i++)
 			if (driver->client_map[i].pid ==
 						 driver->logging_process_id)
@@ -343,8 +366,6 @@
 #endif
 #ifdef CONFIG_DIAG_BRIDGE_CODE
 		else if (proc_num == HSIC_DATA) {
-			driver->in_busy_hsic_read = 0;
-			driver->in_busy_hsic_write_on_device = 0;
 			if (driver->hsic_ch)
 				queue_work(driver->diag_bridge_wq,
 					&(driver->diag_read_hsic_work));
@@ -396,11 +417,33 @@
 #ifdef CONFIG_DIAG_BRIDGE_CODE
 		else if (proc_num == HSIC_DATA) {
 			if (driver->hsic_device_enabled) {
-				write_ptr->buf = buf;
-				err = usb_diag_write(driver->mdm_ch, write_ptr);
-			} else
+				struct diag_request *write_ptr_mdm;
+				write_ptr_mdm = (struct diag_request *)
+						diagmem_alloc(driver,
+						sizeof(struct diag_request),
+							POOL_TYPE_HSIC_WRITE);
+				if (write_ptr_mdm) {
+					write_ptr_mdm->buf = buf;
+					write_ptr_mdm->length =
+						driver->write_len_mdm;
+					err = usb_diag_write(driver->mdm_ch,
+								write_ptr_mdm);
+					/* Return to the pool immediately */
+					if (err) {
+						diagmem_free(driver,
+							write_ptr_mdm,
+							POOL_TYPE_HSIC_WRITE);
+					pr_err("diag: HSIC write failure\n");
+					}
+				} else {
+					pr_err("diag: allocate write fail\n");
+					err = -1;
+				}
+			} else {
 				pr_err("diag: Incorrect hsic data "
 						"while USB write\n");
+				err = -1;
+			}
 		} else if (proc_num == SMUX_DATA) {
 				write_ptr->buf = buf;
 				pr_debug("diag: writing SMUX data\n");
@@ -512,8 +555,7 @@
 {
 /* Enable this to print mask table when updated */
 #ifdef MASK_DEBUG
-	int first;
-	int last;
+	int first, last, actual_last;
 	uint8_t *ptr = driver->msg_masks;
 	int i = 0;
 	pr_info("diag: F3 message mask table\n");
@@ -522,11 +564,12 @@
 		ptr += 4;
 		last = *(uint32_t *)ptr;
 		ptr += 4;
-		printk(KERN_INFO "SSID %d - %d\n", first, last);
-		for (i = 0 ; i <= last - first ; i++)
-			printk(KERN_INFO "MASK:%x\n", *((uint32_t *)ptr + i));
+		actual_last = *(uint32_t *)ptr;
+		ptr += 4;
+		pr_info("diag: SSID %d, %d - %d\n", first, last, actual_last);
+		for (i = 0 ; i <= actual_last - first ; i++)
+			pr_info("diag: MASK:%x\n", *((uint32_t *)ptr + i));
 		ptr += MAX_SSID_PER_RANGE*4;
-
 	}
 #endif
 }
@@ -569,7 +612,7 @@
 	mutex_lock(&driver->diagchar_mutex);
 	while (*(uint32_t *)(ptr + 4)) {
 		first_ssid = *(uint32_t *)ptr;
-		ptr += 4;
+		ptr += 8; /* increment by 8 to skip 'last' */
 		last_ssid = *(uint32_t *)ptr;
 		ptr += 4;
 		parse_ptr = ptr;
@@ -585,9 +628,8 @@
 
 static void diag_update_msg_mask(int start, int end , uint8_t *buf)
 {
-	int found = 0;
-	int first;
-	int last;
+	int found = 0, first, last, actual_last;
+	uint8_t *actual_last_ptr;
 	uint8_t *ptr = driver->msg_masks;
 	uint8_t *ptr_buffer_start = &(*(driver->msg_masks));
 	uint8_t *ptr_buffer_end = &(*(driver->msg_masks)) + MSG_MASK_SIZE;
@@ -600,23 +642,23 @@
 		ptr += 4;
 		last = *(uint32_t *)ptr;
 		ptr += 4;
-		if (start >= first && start <= last) {
+		actual_last = *(uint32_t *)ptr;
+		actual_last_ptr = ptr;
+		ptr += 4;
+		if (start >= first && start <= actual_last) {
 			ptr += (start - first)*4;
-			if (end <= last)
-				if (CHK_OVERFLOW(ptr_buffer_start, ptr,
-						  ptr_buffer_end,
-						  (((end - start)+1)*4))) {
-					pr_debug("diag: update ssid start %d,"
-						 " end %d\n", start, end);
-					memcpy(ptr, buf , ((end - start)+1)*4);
-				} else
-					printk(KERN_CRIT "Not enough"
-							 " buffer space for"
-							 " MSG_MASK\n");
-			else
-				printk(KERN_INFO "Unable to copy"
-						 " mask change\n");
-
+			if (end > actual_last) {
+				pr_info("diag: ssid range mismatch\n");
+				actual_last = end;
+				*(uint32_t *)(actual_last_ptr) = end;
+			}
+			if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
+					  (((end - start)+1)*4))) {
+				pr_debug("diag: update ssid start %d, end %d\n",
+								 start, end);
+				memcpy(ptr, buf , ((end - start)+1)*4);
+			} else
+				pr_alert("diag: Not enough space MSG_MASK\n");
 			found = 1;
 			break;
 		} else {
@@ -631,16 +673,16 @@
 			ptr += 4;
 			memcpy(ptr, &(end), 4);
 			ptr += 4;
+			memcpy(ptr, &(end), 4); /* create actual_last entry */
+			ptr += 4;
 			pr_debug("diag: adding NEW ssid start %d, end %d\n",
 								 start, end);
 			memcpy(ptr, buf , ((end - start) + 1)*4);
 		} else
-			printk(KERN_CRIT " Not enough buffer"
-					 " space for MSG_MASK\n");
+			pr_alert("diag: Not enough buffer space for MSG_MASK\n");
 	}
 	mutex_unlock(&driver->diagchar_mutex);
 	diag_print_mask_table();
-
 }
 
 void diag_toggle_event_mask(int toggle)
@@ -916,7 +958,7 @@
 						int updated_ssid_last, int proc)
 {
 	void *buf = driver->buf_msg_mask_update;
-	int first, last, size = -ENOMEM, retry_count = 0, timer;
+	int first, last, actual_last, size = -ENOMEM, retry_count = 0, timer;
 	int header_size = sizeof(struct diag_ctrl_msg_mask);
 	uint8_t *ptr = driver->msg_masks;
 
@@ -926,18 +968,21 @@
 		ptr += 4;
 		last = *(uint32_t *)ptr;
 		ptr += 4;
-		if ((updated_ssid_first >= first && updated_ssid_last <= last)
-					 || (updated_ssid_first == ALL_SSID)) {
+		actual_last = *(uint32_t *)ptr;
+		ptr += 4;
+		if ((updated_ssid_first >= first && updated_ssid_last <=
+			 actual_last) || (updated_ssid_first == ALL_SSID)) {
 			/* send f3 mask update */
 			driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
-			driver->msg_mask->msg_mask_size = last - first + 1;
+			driver->msg_mask->msg_mask_size = actual_last -
+								 first + 1;
 			driver->msg_mask->data_len = 11 +
 					 4 * (driver->msg_mask->msg_mask_size);
 			driver->msg_mask->stream_id = 1; /* 2, if dual stream */
 			driver->msg_mask->status = 3; /* status valid mask */
 			driver->msg_mask->msg_mode = 0; /* Legcay mode */
 			driver->msg_mask->ssid_first = first;
-			driver->msg_mask->ssid_last = last;
+			driver->msg_mask->ssid_last = actual_last;
 			memcpy(buf, driver->msg_mask, header_size);
 			memcpy(buf+header_size, ptr,
 				 4 * (driver->msg_mask->msg_mask_size));
@@ -959,8 +1004,8 @@
 	 "fail %d, tried %d\n", proc, size,
 	 header_size + 4*(driver->msg_mask->msg_mask_size));
 				else
-					pr_debug("diag: sending mask update for"
-		"ssid first %d, last %d on PROC %d\n", first, last, proc);
+					pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
+						first, actual_last, proc);
 			} else
 				pr_err("diag: proc %d, ch invalid msg mask"
 						 "update\n", proc);
@@ -1052,7 +1097,7 @@
 			rt_mask_ptr = driver->msg_masks;
 			while (*(uint32_t *)(rt_mask_ptr + 4)) {
 				rt_first_ssid = *(uint32_t *)rt_mask_ptr;
-				rt_mask_ptr += 4;
+				rt_mask_ptr += 8; /* +8 to skip 'last' */
 				rt_last_ssid = *(uint32_t *)rt_mask_ptr;
 				rt_mask_ptr += 4;
 				if (ssid_first == rt_first_ssid && ssid_last ==
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 95abd21..52fd673 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -401,7 +401,8 @@
 		"in_busy_qdsp_2: %d\n"
 		"in_busy_wcnss_1: %d\n"
 		"in_busy_wcnss_2: %d\n"
-		"in_busy_dci: %d\n",
+		"in_busy_dci: %d\n"
+		"logging_mode: %d\n",
 		(unsigned int)driver->ch,
 		(unsigned int)driver->chqdsp,
 		(unsigned int)driver->ch_wcnss,
@@ -421,7 +422,8 @@
 		driver->in_busy_qdsp_2,
 		driver->in_busy_wcnss_1,
 		driver->in_busy_wcnss_2,
-		driver->in_busy_dci);
+		driver->in_busy_dci,
+		driver->logging_mode);
 
 #ifdef CONFIG_DIAG_OVER_USB
 	ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
@@ -541,7 +543,7 @@
 	return ret;
 }
 
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 static ssize_t diag_dbgfs_read_hsic(struct file *file, char __user *ubuf,
 				    size_t count, loff_t *ppos)
 {
@@ -555,29 +557,35 @@
 	}
 
 	ret = scnprintf(buf, DEBUG_BUF_SIZE,
-		"hsic initialized: %d\n"
 		"hsic ch: %d\n"
 		"hsic enabled: %d\n"
 		"hsic_opened: %d\n"
-		"hisc_suspend: %d\n"
-		"in_busy_hsic_read_on_mdm: %d\n"
-		"in_busy_hsic_write_on_mdm: %d\n"
+		"hsic_suspend: %d\n"
+		"in_busy_hsic_read_on_device: %d\n"
 		"in_busy_hsic_write: %d\n"
-		"in_busy_hsic_read: %d\n"
+		"count_hsic_pool: %d\n"
+		"count_hsic_write_pool: %d\n"
+		"diag_hsic_pool: %x\n"
+		"diag_hsic_write_pool: %x\n"
+		"write_len_mdm: %d\n"
+		"num_hsic_buf_tbl_entries: %d\n"
 		"usb_mdm_connected: %d\n"
 		"diag_read_mdm_work: %d\n"
 		"diag_read_hsic_work: %d\n"
 		"diag_disconnect_work: %d\n"
 		"diag_usb_read_complete_work: %d\n",
-		driver->hsic_initialized,
 		driver->hsic_ch,
 		driver->hsic_device_enabled,
 		driver->hsic_device_opened,
 		driver->hsic_suspend,
 		driver->in_busy_hsic_read_on_device,
-		driver->in_busy_hsic_write_on_device,
 		driver->in_busy_hsic_write,
-		driver->in_busy_hsic_read,
+		driver->count_hsic_pool,
+		driver->count_hsic_write_pool,
+		(unsigned int)driver->diag_hsic_pool,
+		(unsigned int)driver->diag_hsic_write_pool,
+		driver->write_len_mdm,
+		driver->num_hsic_buf_tbl_entries,
 		driver->usb_mdm_connected,
 		work_pending(&(driver->diag_read_mdm_work)),
 		work_pending(&(driver->diag_read_hsic_work)),
@@ -622,7 +630,7 @@
 	debugfs_create_file("work_pending", 0444, diag_dbgfs_dent, 0,
 		&diag_dbgfs_workpending_ops);
 
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 	debugfs_create_file("hsic", 0444, diag_dbgfs_dent, 0,
 		&diag_dbgfs_hsic_ops);
 #endif
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index 81c6afa..54a667e 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -32,48 +32,87 @@
 #include "diagfwd_hsic.h"
 #include "diagfwd_smux.h"
 
+#define N_MDM_WRITE	8
+#define N_MDM_READ	1
+
+#define READ_HSIC_BUF_SIZE 2048
+
+#define NUM_HSIC_BUF_TBL_ENTRIES N_MDM_WRITE
+
 static void diag_read_hsic_work_fn(struct work_struct *work)
 {
+	unsigned char *buf_in_hsic = NULL;
+	int num_reads_submitted = 0;
+	int err = 0;
+	int write_ptrs_available;
+
 	if (!driver->hsic_ch) {
 		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
 		return;
 	}
 
-	/* If there is no hsic data being read from the hsic and there
-	 * is no hsic data being written to the device
+	/*
+	 * Determine the current number of available buffers for writing after
+	 * reading from the HSIC has completed.
 	 */
-	if (!driver->in_busy_hsic_read &&
-			 !driver->in_busy_hsic_write_on_device) {
-		/*
-		 * Initiate the read from the hsic.  The hsic read is
-		 * asynchronous.  Once the read is complete the read
-		 * callback function will be called.
-		 */
-		int err;
-		driver->in_busy_hsic_read = 1;
-		APPEND_DEBUG('i');
-		pr_debug("diag: read from HSIC\n");
-		err = diag_bridge_read((char *)driver->buf_in_hsic,
-					IN_BUF_SIZE);
-		if (err) {
-			pr_err_ratelimited("DIAG: Error initiating HSIC read, err: %d\n",
-				err);
-			/*
-			 * If the error is recoverable, then clear
-			 * the read flag, so we will resubmit a
-			 * read on the next frame.  Otherwise, don't
-			 * resubmit a read on the next frame.
-			 */
-			if ((-ENODEV) != err)
-				driver->in_busy_hsic_read = 0;
-		}
-	}
+	if (driver->logging_mode == MEMORY_DEVICE_MODE)
+		write_ptrs_available = driver->poolsize_hsic_write -
+					driver->num_hsic_buf_tbl_entries;
+	else
+		write_ptrs_available = driver->poolsize_hsic_write -
+					driver->count_hsic_write_pool;
 
 	/*
-	 * If for some reason there was no hsic data, set up
-	 * the next read
+	 * Queue up a read on the HSIC for all available buffers in the
+	 * pool, exhausting the pool.
 	 */
-	if (!driver->in_busy_hsic_read)
+	do {
+		/*
+		 * If no more write buffers are available,
+		 * stop queuing reads
+		 */
+		if (write_ptrs_available <= 0)
+			break;
+
+		write_ptrs_available--;
+
+		buf_in_hsic = diagmem_alloc(driver, READ_HSIC_BUF_SIZE,
+							POOL_TYPE_HSIC);
+		if (buf_in_hsic) {
+			/*
+			 * Initiate the read from the hsic.  The hsic read is
+			 * asynchronous.  Once the read is complete the read
+			 * callback function will be called.
+			 */
+			int err;
+			pr_debug("diag: read from HSIC\n");
+			num_reads_submitted++;
+			err = diag_bridge_read((char *)buf_in_hsic,
+							READ_HSIC_BUF_SIZE);
+			if (err) {
+				num_reads_submitted--;
+
+				/* Return the buffer to the pool */
+				diagmem_free(driver, buf_in_hsic,
+						POOL_TYPE_HSIC);
+
+				pr_err_ratelimited("diag: Error initiating HSIC read, err: %d\n",
+					err);
+				/*
+				 * An error occurred, discontinue queuing
+				 * reads
+				 */
+				break;
+			}
+		}
+	} while (buf_in_hsic);
+
+	/*
+	 * If there are no buffers available or for some reason there
+	 * was no hsic data, and if no unrecoverable error occurred
+	 * (-ENODEV is an unrecoverable error), then set up the next read
+	 */
+	if ((num_reads_submitted == 0) && (err != -ENODEV))
 		queue_work(driver->diag_bridge_wq,
 				 &driver->diag_read_hsic_work);
 }
@@ -81,45 +120,58 @@
 static void diag_hsic_read_complete_callback(void *ctxt, char *buf,
 					int buf_size, int actual_size)
 {
-	/* The read of the data from the HSIC bridge is complete */
-	driver->in_busy_hsic_read = 0;
+	int err = -2;
 
 	if (!driver->hsic_ch) {
-		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+		/*
+		 * The hsic channel is closed. Return the buffer to
+		 * the pool.  Do not send it on.
+		 */
+		diagmem_free(driver, buf, POOL_TYPE_HSIC);
+		pr_debug("diag: In %s: driver->hsic_ch == 0, actual_size: %d\n",
+			__func__, actual_size);
 		return;
 	}
 
-	APPEND_DEBUG('j');
-	if (actual_size > 0) {
+	/* Note that zero length is valid and still needs to be sent */
+	if (actual_size >= 0) {
 		if (!buf) {
-			pr_err("Out of diagmem for HSIC\n");
+			pr_err("diag: Out of diagmem for HSIC\n");
 		} else {
-			driver->write_ptr_mdm->length = actual_size;
 			/*
-			 * Set flag to denote hsic data is currently
-			 * being written to the usb mdm channel.
-			 * driver->buf_in_hsic was given to
-			 * diag_bridge_read(), so buf here should be
-			 * driver->buf_in_hsic
+			 * Send data in buf to be written on the
+			 * appropriate device, e.g. USB MDM channel
 			 */
-			driver->in_busy_hsic_write_on_device = 1;
-			pr_debug("diag: write to device\n");
-			diag_device_write((void *)buf, HSIC_DATA,
-						driver->write_ptr_mdm);
+			driver->write_len_mdm = actual_size;
+			err = diag_device_write((void *)buf, HSIC_DATA, NULL);
+			/* If an error, return buffer to the pool */
+			if (err) {
+				diagmem_free(driver, buf, POOL_TYPE_HSIC);
+				pr_err("diag: In %s, error calling diag_device_write, err: %d\n",
+					__func__, err);
+			}
 		}
 	} else {
-		pr_debug("%s: actual_size: %d\n", __func__, actual_size);
+		/*
+		 * The buffer has an error status associated with it. Do not
+		 * pass it on. Note that -ENOENT is sent when the diag bridge
+		 * is closed.
+		 */
+		diagmem_free(driver, buf, POOL_TYPE_HSIC);
+		pr_debug("diag: In %s: error status: %d\n", __func__,
+			actual_size);
 	}
 
 	/*
 	 * If for some reason there was no hsic data to write to the
 	 * mdm channel, set up another read
 	 */
-	if (!driver->in_busy_hsic_write_on_device && ((driver->logging_mode
-			== MEMORY_DEVICE_MODE) || (driver->usb_mdm_connected &&
-						    !driver->hsic_suspend)))
+	if (err &&
+		((driver->logging_mode == MEMORY_DEVICE_MODE) ||
+		(driver->usb_mdm_connected && !driver->hsic_suspend))) {
 		queue_work(driver->diag_bridge_wq,
 				 &driver->diag_read_hsic_work);
+	}
 }
 
 static void diag_hsic_write_complete_callback(void *ctxt, char *buf,
@@ -143,6 +195,8 @@
 static int diag_hsic_suspend(void *ctxt)
 {
 	pr_debug("diag: hsic_suspend\n");
+
+	/* Don't allow suspend if a write in the HSIC is in progress */
 	if (driver->in_busy_hsic_write)
 		return -EBUSY;
 
@@ -160,8 +214,8 @@
 	pr_debug("diag: hsic_resume\n");
 	driver->hsic_suspend = 0;
 
-	if (!driver->in_busy_hsic_write_on_device && (driver->logging_mode
-			== MEMORY_DEVICE_MODE || driver->usb_mdm_connected))
+	if ((driver->logging_mode == MEMORY_DEVICE_MODE) ||
+				(driver->usb_mdm_connected))
 		queue_work(driver->diag_bridge_wq,
 			 &driver->diag_read_hsic_work);
 }
@@ -202,10 +256,10 @@
 			diag_bridge_close();
 			err = diag_bridge_open(&hsic_diag_bridge_ops);
 			if (err) {
-				pr_err("DIAG: HSIC channel open error: %d\n",
+				pr_err("diag: HSIC channel open error: %d\n",
 					err);
 			} else {
-				pr_debug("DIAG: opened HSIC channel\n");
+				pr_debug("diag: opened HSIC channel\n");
 				driver->hsic_device_opened = 1;
 				driver->hsic_ch = 1;
 			}
@@ -234,10 +288,8 @@
 	}
 
 	if (driver->hsic_device_enabled) {
-		driver->in_busy_hsic_write_on_device = 0;
 		driver->in_busy_hsic_read_on_device = 0;
 		driver->in_busy_hsic_write = 0;
-		driver->in_busy_hsic_read = 0;
 	} else if (driver->diag_smux_enabled) {
 		driver->in_busy_smux = 0;
 		diagfwd_connect_smux();
@@ -288,7 +340,7 @@
  */
 int diagfwd_disconnect_bridge(int process_cable)
 {
-	pr_debug("DIAG in %s\n", __func__);
+	pr_debug("diag: In %s, process_cable: %d\n", __func__, process_cable);
 
 	/* If the usb cable is being disconnected */
 	if (process_cable) {
@@ -298,10 +350,8 @@
 
 	if (driver->logging_mode == USB_MODE) {
 		if (driver->hsic_device_enabled) {
-			driver->in_busy_hsic_write_on_device = 1;
 			driver->in_busy_hsic_read_on_device = 1;
 			driver->in_busy_hsic_write = 1;
-			driver->in_busy_hsic_read = 1;
 			/* Turn off communication over usb mdm and hsic */
 			return diag_hsic_close();
 		} else if (driver->diag_smux_enabled) {
@@ -319,19 +369,21 @@
  * diagfwd_write_complete_hsic is called after the asynchronous
  * usb_diag_write() on mdm channel is complete
  */
-int diagfwd_write_complete_hsic(void)
+int diagfwd_write_complete_hsic(struct diag_request *diag_write_ptr)
 {
-	/*
-	 * Clear flag to denote that the write of the hsic data on the
-	 * usb mdm channel is complete
-	 */
-	driver->in_busy_hsic_write_on_device = 0;
-	if (!driver->hsic_ch) {
-		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
-		return 0;
+	unsigned char *buf = (diag_write_ptr) ? diag_write_ptr->buf : NULL;
+
+	if (buf) {
+		/* Return buffers to their pools */
+		diagmem_free(driver, (unsigned char *)buf, POOL_TYPE_HSIC);
+		diagmem_free(driver, (unsigned char *)diag_write_ptr,
+							POOL_TYPE_HSIC_WRITE);
 	}
 
-	APPEND_DEBUG('q');
+	if (!driver->hsic_ch) {
+		pr_err("diag: In %s: driver->hsic_ch == 0\n", __func__);
+		return 0;
+	}
 
 	/* Read data from the hsic */
 	queue_work(driver->diag_bridge_wq, &driver->diag_read_hsic_work);
@@ -375,7 +427,7 @@
 		err = diag_bridge_write(driver->usb_buf_mdm_out,
 					driver->read_len_mdm);
 		if (err) {
-			pr_err_ratelimited("DIAG: mdm data on hsic write err: %d\n",
+			pr_err_ratelimited("diag: mdm data on hsic write err: %d\n",
 					err);
 			/*
 			 * If the error is recoverable, then clear
@@ -415,7 +467,7 @@
 		break;
 	case USB_DIAG_WRITE_DONE:
 		if (driver->hsic_device_enabled)
-			diagfwd_write_complete_hsic();
+			diagfwd_write_complete_hsic(d_req);
 		else if (driver->diag_smux_enabled)
 			diagfwd_write_complete_smux();
 		break;
@@ -492,8 +544,7 @@
 	int err = 0;
 	pr_debug("diag: in %s\n", __func__);
 	if (!driver->hsic_device_enabled) {
-		if (driver->buf_in_hsic == NULL)
-			driver->buf_in_hsic = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+		diagmem_hsic_init(driver);
 		INIT_WORK(&(driver->diag_read_hsic_work),
 					 diag_read_hsic_work_fn);
 		driver->hsic_device_enabled = 1;
@@ -517,10 +568,9 @@
 		pr_info("diag: opened HSIC channel\n");
 		driver->hsic_device_opened = 1;
 		driver->hsic_ch = 1;
-		driver->in_busy_hsic_write_on_device = 0;
+
 		driver->in_busy_hsic_read_on_device = 0;
 		driver->in_busy_hsic_write = 0;
-		driver->in_busy_hsic_read = 0;
 
 		if (driver->usb_mdm_connected) {
 			/* Poll USB mdm channel to check for data */
@@ -538,7 +588,7 @@
 
 static int diag_hsic_remove(struct platform_device *pdev)
 {
-	pr_debug("DIAG: %s called\n", __func__);
+	pr_debug("diag: %s called\n", __func__);
 	diag_hsic_close();
 	return 0;
 }
@@ -578,11 +628,14 @@
 	driver->diag_bridge_wq = create_singlethread_workqueue(
 							"diag_bridge_wq");
 	driver->read_len_mdm = 0;
+	driver->write_len_mdm = 0;
+	driver->num_hsic_buf_tbl_entries = 0;
 	if (driver->usb_buf_mdm_out  == NULL)
 		driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF,
 							 GFP_KERNEL);
 	if (driver->usb_buf_mdm_out == NULL)
 		goto err;
+	/* Only used by smux move to smux probe function */
 	if (driver->write_ptr_mdm == NULL)
 		driver->write_ptr_mdm = kzalloc(
 		sizeof(struct diag_request), GFP_KERNEL);
@@ -594,6 +647,20 @@
 	if (driver->usb_read_mdm_ptr == NULL)
 		goto err;
 
+	if (driver->hsic_buf_tbl == NULL)
+		driver->hsic_buf_tbl = kzalloc(NUM_HSIC_BUF_TBL_ENTRIES *
+				sizeof(struct diag_write_device), GFP_KERNEL);
+	if (driver->hsic_buf_tbl == NULL)
+		goto err;
+
+	driver->count_hsic_pool = 0;
+	driver->count_hsic_write_pool = 0;
+
+	driver->itemsize_hsic = READ_HSIC_BUF_SIZE;
+	driver->poolsize_hsic = N_MDM_WRITE;
+	driver->itemsize_hsic_write = sizeof(struct diag_request);
+	driver->poolsize_hsic_write = N_MDM_WRITE;
+
 #ifdef CONFIG_DIAG_OVER_USB
 	INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
 #endif
@@ -608,10 +675,6 @@
 		goto err;
 	}
 #endif
-#ifdef CONFIG_DIAG_BRIDGE_CODE
-	INIT_WORK(&(driver->diag_disconnect_work), diag_disconnect_work_fn);
-	INIT_WORK(&(driver->diag_usb_read_complete_work),
-			diag_usb_read_complete_fn);
 	/* register HSIC device */
 	ret = platform_driver_register(&msm_hsic_ch_driver);
 	if (ret)
@@ -620,11 +683,12 @@
 	ret = platform_driver_register(&msm_diagfwd_smux_driver);
 	if (ret)
 		pr_err("diag: could not register SMUX device, ret: %d\n", ret);
-#endif
+
 	return;
 err:
 	pr_err("diag: Could not initialize for bridge forwarding\n");
 	kfree(driver->usb_buf_mdm_out);
+	kfree(driver->hsic_buf_tbl);
 	kfree(driver->write_ptr_mdm);
 	kfree(driver->usb_read_mdm_ptr);
 	if (driver->diag_bridge_wq)
@@ -639,8 +703,8 @@
 
 	if (driver->hsic_device_enabled) {
 		diag_hsic_close();
-		kfree(driver->buf_in_hsic);
 		driver->hsic_device_enabled = 0;
+		diagmem_exit(driver, POOL_TYPE_ALL);
 	}
 	if (driver->diag_smux_enabled) {
 		driver->lcid = LCID_INVALID;
@@ -656,6 +720,7 @@
 	usb_diag_close(driver->mdm_ch);
 #endif
 	kfree(driver->usb_buf_mdm_out);
+	kfree(driver->hsic_buf_tbl);
 	kfree(driver->write_ptr_mdm);
 	kfree(driver->usb_read_mdm_ptr);
 	destroy_workqueue(driver->diag_bridge_wq);
diff --git a/drivers/char/diag/diagfwd_hsic.h b/drivers/char/diag/diagfwd_hsic.h
index b189c94..b2d9c9f 100644
--- a/drivers/char/diag/diagfwd_hsic.h
+++ b/drivers/char/diag/diagfwd_hsic.h
@@ -14,12 +14,10 @@
 #define DIAGFWD_HSIC_H
 
 #include <mach/diag_bridge.h>
-#define N_MDM_WRITE	1 /* Upgrade to 2 with ping pong buffer */
-#define N_MDM_READ	1
 
 int diagfwd_connect_bridge(int);
 int diagfwd_disconnect_bridge(int);
-int diagfwd_write_complete_hsic(void);
+int diagfwd_write_complete_hsic(struct diag_request *);
 int diagfwd_cancel_hsic(void);
 void diagfwd_bridge_init(void);
 void diagfwd_bridge_exit(void);
diff --git a/drivers/char/diag/diagmem.c b/drivers/char/diag/diagmem.c
index 0b5c27a..82c47af 100644
--- a/drivers/char/diag/diagmem.c
+++ b/drivers/char/diag/diagmem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -51,6 +51,28 @@
 				driver->diag_write_struct_pool, GFP_ATOMIC);
 			}
 		}
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+	} else if (pool_type == POOL_TYPE_HSIC) {
+		if (driver->diag_hsic_pool) {
+			if (driver->count_hsic_pool < driver->poolsize_hsic) {
+				atomic_add(1,
+					(atomic_t *)&driver->count_hsic_pool);
+				buf = mempool_alloc(driver->diag_hsic_pool,
+								GFP_ATOMIC);
+			}
+		}
+	} else if (pool_type == POOL_TYPE_HSIC_WRITE) {
+		if (driver->diag_hsic_write_pool) {
+			if (driver->count_hsic_write_pool <
+				driver->poolsize_hsic_write) {
+				atomic_add(1, (atomic_t *)
+					&driver->count_hsic_write_pool);
+				buf = mempool_alloc(
+					driver->diag_hsic_write_pool,
+					GFP_ATOMIC);
+			}
+		}
+#endif
 	}
 	return buf;
 }
@@ -63,7 +85,7 @@
 			driver->diagpool = NULL;
 		} else if (driver->ref_count == 0 && pool_type == POOL_TYPE_ALL)
 			printk(KERN_ALERT "Unable to destroy COPY mempool");
-		}
+	}
 
 	if (driver->diag_hdlc_pool) {
 		if (driver->count_hdlc_pool == 0 && driver->ref_count == 0) {
@@ -71,7 +93,7 @@
 			driver->diag_hdlc_pool = NULL;
 		} else if (driver->ref_count == 0 && pool_type == POOL_TYPE_ALL)
 			printk(KERN_ALERT "Unable to destroy HDLC mempool");
-		}
+	}
 
 	if (driver->diag_write_struct_pool) {
 		/* Free up struct pool ONLY if there are no outstanding
@@ -82,7 +104,30 @@
 			driver->diag_write_struct_pool = NULL;
 		} else if (driver->ref_count == 0 && pool_type == POOL_TYPE_ALL)
 			printk(KERN_ALERT "Unable to destroy STRUCT mempool");
-		}
+	}
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+	if (driver->diag_hsic_pool && (driver->hsic_device_enabled == 0)) {
+		if (driver->count_hsic_pool == 0) {
+			mempool_destroy(driver->diag_hdlc_pool);
+			driver->diag_hdlc_pool = NULL;
+		} else if (pool_type == POOL_TYPE_ALL)
+			pr_err("Unable to destroy HDLC mempool");
+	}
+
+	if (driver->diag_hsic_write_pool &&
+		(driver->hsic_device_enabled == 0)) {
+		/*
+		 * Free up struct pool ONLY if there are no outstanding
+		 * transactions(aggregation buffer) with USB
+		 */
+		if (driver->count_hsic_write_pool == 0 &&
+			driver->count_hsic_pool == 0) {
+			mempool_destroy(driver->diag_hsic_write_pool);
+			driver->diag_hsic_write_pool = NULL;
+		} else if (pool_type == POOL_TYPE_ALL)
+			pr_err("Unable to destroy HSIC USB struct mempool");
+	}
+#endif
 }
 
 void diagmem_free(struct diagchar_dev *driver, void *buf, int pool_type)
@@ -112,6 +157,29 @@
 			pr_err("diag: Attempt to free up DIAG driver "
 			   "USB structure mempool which is already free %d ",
 				    driver->count_write_struct_pool);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+	} else if (pool_type == POOL_TYPE_HSIC) {
+		if (driver->diag_hsic_pool != NULL &&
+			driver->count_hsic_pool > 0) {
+			mempool_free(buf, driver->diag_hsic_pool);
+			atomic_add(-1, (atomic_t *)&driver->count_hsic_pool);
+		} else
+			pr_err("diag: Attempt to free up DIAG driver HSIC mempool which is already free %d ",
+				driver->count_hsic_pool);
+	} else if (pool_type == POOL_TYPE_HSIC_WRITE) {
+		if (driver->diag_hsic_write_pool != NULL &&
+			driver->count_hsic_write_pool > 0) {
+			mempool_free(buf, driver->diag_hsic_write_pool);
+			atomic_add(-1,
+				(atomic_t *)&driver->count_hsic_write_pool);
+		} else
+			pr_err("diag: Attempt to free up DIAG driver HSIC USB structure mempool which is already free %d ",
+				driver->count_write_struct_pool);
+#endif
+	} else {
+		pr_err("diag: In %s, unknown pool type: %d\n",
+			__func__, pool_type);
+
 	}
 
 	diagmem_exit(driver, pool_type);
@@ -143,3 +211,25 @@
 		printk(KERN_INFO "Cannot allocate diag USB struct mempool\n");
 }
 
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+void diagmem_hsic_init(struct diagchar_dev *driver)
+{
+	if (driver->count_hsic_pool == 0)
+		driver->diag_hsic_pool = mempool_create_kmalloc_pool(
+					driver->poolsize_hsic,
+					driver->itemsize_hsic);
+
+	if (driver->count_hsic_write_pool == 0)
+		driver->diag_hsic_write_pool = mempool_create_kmalloc_pool(
+					driver->poolsize_hsic_write,
+					driver->itemsize_hsic_write);
+
+	if (!driver->diag_hsic_pool)
+		pr_err("Cannot allocate diag HSIC mempool\n");
+
+	if (!driver->diag_hsic_write_pool)
+		pr_err("Cannot allocate diag HSIC struct mempool\n");
+
+}
+#endif
+
diff --git a/drivers/char/diag/diagmem.h b/drivers/char/diag/diagmem.h
index 43829ae..8665c75 100644
--- a/drivers/char/diag/diagmem.h
+++ b/drivers/char/diag/diagmem.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,5 +18,7 @@
 void diagmem_free(struct diagchar_dev *driver, void *buf, int pool_type);
 void diagmem_init(struct diagchar_dev *driver);
 void diagmem_exit(struct diagchar_dev *driver, int pool_type);
-
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+void diagmem_hsic_init(struct diagchar_dev *driver);
+#endif
 #endif
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 33fcbfd..1bb33b6 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -234,6 +234,7 @@
 #define A3XX_TPL1_TP_VS_TEX_OFFSET 0x2340
 #define A3XX_TPL1_TP_FS_TEX_OFFSET 0x2342
 #define A3XX_TPL1_TP_FS_BORDER_COLOR_BASE_ADDR 0x2343
+#define A3XX_VBIF_CLKON 0x3001
 #define A3XX_VBIF_FIXED_SORT_EN 0x300C
 #define A3XX_VBIF_FIXED_SORT_SEL0 0x300D
 #define A3XX_VBIF_FIXED_SORT_SEL1 0x300E
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 5ce34db..548ef3c 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2699,13 +2699,13 @@
 
 	/* Set up 16 deep read/write request queues */
 	if (adreno_dev->gpurev == ADRENO_REV_A330) {
-		adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x01010101);
-		adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x01010101);
-		adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x01010101);
-		adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x01010101);
+		adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818);
+		adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818);
+		adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818);
+		adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818);
 		adreno_regwrite(device, A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
-		adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x01010101);
-		adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x01010101);
+		adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818);
+		adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818);
 		/* Enable WR-REQ */
 		adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003F);
 
@@ -2721,6 +2721,11 @@
 		/* Enable 1K sort */
 		adreno_regwrite(device, A3XX_VBIF_ABIT_SORT, 0x1FFFF);
 		adreno_regwrite(device, A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4);
+
+		/* Diable VBIF clock gating. This is to enable AXI running
+		 * higher frequency than GPU.
+		 */
+		adreno_regwrite(device, A3XX_VBIF_CLKON, 1);
 	} else {
 		adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
 		adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index ad9007f..1a9da60 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -401,8 +401,15 @@
 
 void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
 {
-	if (rb->flags & KGSL_FLAGS_STARTED)
+	struct kgsl_device *device = rb->device;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	if (rb->flags & KGSL_FLAGS_STARTED) {
+		if (adreno_is_a200(adreno_dev))
+			adreno_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
+
 		rb->flags &= ~KGSL_FLAGS_STARTED;
+	}
 }
 
 int adreno_ringbuffer_init(struct kgsl_device *device)
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index c1617bff..085b632 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -328,12 +328,14 @@
 	dev->clk_state = state;
 	if (state != 0) {
 		clk_enable(dev->clk);
-		clk_enable(dev->pclk);
+		if (!dev->pdata->keep_ahb_clk_on)
+			clk_enable(dev->pclk);
 	} else {
 		qup_update_state(dev, QUP_RESET_STATE);
 		clk_disable(dev->clk);
 		qup_config_core_on_en(dev);
-		clk_disable(dev->pclk);
+		if (!dev->pdata->keep_ahb_clk_on)
+			clk_disable(dev->pclk);
 	}
 }
 
@@ -1325,6 +1327,12 @@
 	dev->clk_state = 0;
 	clk_prepare(dev->clk);
 	clk_prepare(dev->pclk);
+	/* If the same AHB clock is used on Modem side
+	 * switch it on here itself and don't switch it
+	 * on and off during suspend and resume.
+	 */
+	if (dev->pdata->keep_ahb_clk_on)
+		clk_enable(dev->pclk);
 	setup_timer(&dev->pwr_timer, qup_i2c_pwr_timer, (unsigned long) dev);
 
 	pm_runtime_set_active(&pdev->dev);
@@ -1396,9 +1404,11 @@
 	free_irq(dev->err_irq, dev);
 	i2c_del_adapter(&dev->adapter);
 	clk_unprepare(dev->clk);
-	clk_unprepare(dev->pclk);
+	if (!dev->pdata->keep_ahb_clk_on) {
+		clk_unprepare(dev->pclk);
+		clk_put(dev->pclk);
+	}
 	clk_put(dev->clk);
-	clk_put(dev->pclk);
 	qup_i2c_free_gpios(dev);
 	if (dev->gsbi)
 		iounmap(dev->gsbi);
@@ -1434,7 +1444,8 @@
 	if (dev->clk_state != 0)
 		qup_i2c_pwr_mgmt(dev, 0);
 	clk_unprepare(dev->clk);
-	clk_unprepare(dev->pclk);
+	if (!dev->pdata->keep_ahb_clk_on)
+		clk_unprepare(dev->pclk);
 	qup_i2c_free_gpios(dev);
 	return 0;
 }
@@ -1445,7 +1456,8 @@
 	struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
 	BUG_ON(qup_i2c_request_gpios(dev) != 0);
 	clk_prepare(dev->clk);
-	clk_prepare(dev->pclk);
+	if (!dev->pdata->keep_ahb_clk_on)
+		clk_prepare(dev->pclk);
 	dev->suspended = 0;
 	return 0;
 }
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index d3da652..04a7598 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -123,6 +123,7 @@
 	struct delayed_work input_work;
 	u32    use_poll;
 	u32    poll_interval;
+	u32    dlpf_index;
 };
 
 struct sensor_regulator {
@@ -137,6 +138,39 @@
 	{NULL, "vlogic", 1800000, 1800000},
 };
 
+struct dlpf_cfg_tb {
+	u8  cfg;	/* cfg index */
+	u32 lpf_bw;	/* low pass filter bandwidth in Hz */
+	u32 sample_rate; /* analog sample rate in Khz, 1 or 8 */
+};
+
+static struct dlpf_cfg_tb dlpf_table[] = {
+	{6,   5, 1},
+	{5,  10, 1},
+	{4,  20, 1},
+	{3,  42, 1},
+	{2,  98, 1},
+	{1, 188, 1},
+	{0, 256, 8},
+};
+
+static u8 interval_to_dlpf_cfg(u32 interval)
+{
+	u32 sample_rate = 1000 / interval;
+	u32 i;
+
+	/* the filter bandwidth needs to be greater or
+	 * equal to half of the sample rate
+	 */
+	for (i = 0; i < sizeof(dlpf_table)/sizeof(dlpf_table[0]); i++) {
+		if (dlpf_table[i].lpf_bw * 2 >= sample_rate)
+			return i;
+	}
+
+	/* return the maximum possible */
+	return --i;
+}
+
 static int mpu3050_config_regulator(struct i2c_client *client, bool on)
 {
 	int rc = 0, i;
@@ -217,6 +251,9 @@
 {
 	struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
 	unsigned long interval_ms;
+	unsigned int  dlpf_index;
+	u8  divider, reg;
+	int ret;
 
 	if (kstrtoul(buf, 10, &interval_ms))
 		return -EINVAL;
@@ -224,12 +261,27 @@
 		(interval_ms > MPU3050_MAX_POLL_INTERVAL))
 		return -EINVAL;
 
-	if (sensor)
-		sensor->poll_interval = interval_ms;
+	dlpf_index = interval_to_dlpf_cfg(interval_ms);
+	divider = interval_ms * dlpf_table[dlpf_index].sample_rate - 1;
 
-	/* Output frequency divider. The poll interval */
-	i2c_smbus_write_byte_data(sensor->client, MPU3050_SMPLRT_DIV,
-					interval_ms - 1);
+	if (sensor->dlpf_index != dlpf_index) {
+		/* Set low pass filter and full scale */
+		reg = dlpf_table[dlpf_index].cfg;
+		reg |= MPU3050_DEFAULT_FS_RANGE << 3;
+		reg |= MPU3050_EXT_SYNC_NONE << 5;
+		ret = i2c_smbus_write_byte_data(sensor->client,
+				MPU3050_DLPF_FS_SYNC, reg);
+		if (ret == 0)
+			sensor->dlpf_index = dlpf_index;
+	}
+
+	if (sensor->poll_interval != interval_ms) {
+		/* Output frequency divider. The poll interval */
+		ret = i2c_smbus_write_byte_data(sensor->client,
+				MPU3050_SMPLRT_DIV, divider);
+		if (ret == 0)
+			sensor->poll_interval = interval_ms;
+	}
 
 	return size;
 }
@@ -482,8 +534,8 @@
 		return ret;
 
 	/* Set low pass filter and full scale */
-	reg = MPU3050_DEFAULT_FS_RANGE;
-	reg |= MPU3050_DLPF_CFG_42HZ << 3;
+	reg = MPU3050_DLPF_CFG_42HZ;
+	reg |= MPU3050_DEFAULT_FS_RANGE << 3;
 	reg |= MPU3050_EXT_SYNC_NONE << 5;
 	ret = i2c_smbus_write_byte_data(client, MPU3050_DLPF_FS_SYNC, reg);
 	if (ret < 0)
diff --git a/drivers/media/dvb/mpq/Kconfig b/drivers/media/dvb/mpq/Kconfig
index 868ad8c..766312c 100644
--- a/drivers/media/dvb/mpq/Kconfig
+++ b/drivers/media/dvb/mpq/Kconfig
@@ -8,5 +8,5 @@
 	  Say Y or M if you own such a device and want to use it.
 
 source "drivers/media/dvb/mpq/demux/Kconfig"
-
+source "drivers/media/dvb/mpq/video/Kconfig"
 
diff --git a/drivers/media/dvb/mpq/Makefile b/drivers/media/dvb/mpq/Makefile
index 7ccf13e..a8d7137 100644
--- a/drivers/media/dvb/mpq/Makefile
+++ b/drivers/media/dvb/mpq/Makefile
@@ -1,5 +1,5 @@
 
 obj-$(CONFIG_DVB_MPQ)	    += adapter/
 obj-$(CONFIG_DVB_MPQ_DEMUX) += demux/
-
+obj-$(CONFIG_DVB_MPQ_VIDEO) += video/
 
diff --git a/drivers/media/dvb/mpq/video/Kconfig b/drivers/media/dvb/mpq/video/Kconfig
new file mode 100644
index 0000000..1344a67
--- /dev/null
+++ b/drivers/media/dvb/mpq/video/Kconfig
@@ -0,0 +1,16 @@
+config DVB_MPQ_VIDEO
+	tristate "DVB Video Device"
+	depends on DVB_MPQ
+
+	---help---
+	  This is a dvb/video interface with extensions for
+	  Qualcomm Chipset Video hardware. For dvb/video
+	  specification please check http://linuxtv.org/
+
+	  Say Y or M if you own such a device and want to use it.
+
+config DVB_MPQ_NUM_VIDEO_DEVICES
+	int "Number of video devices"
+	depends on DVB_MPQ_VIDEO
+	default 4
+	range 1 255
diff --git a/drivers/media/dvb/mpq/video/Makefile b/drivers/media/dvb/mpq/video/Makefile
new file mode 100644
index 0000000..38c1091
--- /dev/null
+++ b/drivers/media/dvb/mpq/video/Makefile
@@ -0,0 +1,5 @@
+
+ccflags-y += -Idrivers/media/dvb/dvb-core/
+ccflags-y += -Idrivers/media/dvb/mpq/include/
+
+obj-$(CONFIG_DVB_MPQ_VIDEO) += mpq_dvb_video.o
diff --git a/drivers/media/dvb/mpq/video/mpq_dvb_video.c b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
new file mode 100644
index 0000000..cd0f605
--- /dev/null
+++ b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
@@ -0,0 +1,2407 @@
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/cdev.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/android_pmem.h>
+#include <linux/clk.h>
+#include <linux/timer.h>
+#include <mach/msm_subsystem_map.h>
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
+#include "mpq_dvb_video_internal.h"
+
+
+#define DBG(x...) pr_debug(x)
+#define INFO(x...) pr_info(x)
+#define ERR(x...) pr_err(x)
+
+#define MPQ_VID_DEC_NAME "mpq_vidc_dec"
+static unsigned int vidc_mmu_subsystem[] = {
+	MSM_SUBSYSTEM_VIDEO};
+
+static char vid_thread_names[DVB_MPQ_NUM_VIDEO_DEVICES][10] = {
+				"dvb-vid-0",
+				"dvb-vid-1",
+				"dvb-vid-2",
+				"dvb-vid-3",
+};
+
+static int mpq_int_vid_dec_decode_frame(struct video_client_ctx *client_ctx,
+				struct video_data_buffer *input_frame);
+
+static struct mpq_dvb_video_dev *mpq_dvb_video_device;
+
+static int mpq_get_dev_frm_client(struct video_client_ctx *client_ctx,
+				struct mpq_dvb_video_inst **dev_inst)
+{
+	int i;
+
+	mutex_lock(&mpq_dvb_video_device->lock);
+	for (i = 0; i < DVB_MPQ_NUM_VIDEO_DEVICES; i++) {
+		if (mpq_dvb_video_device->dev_inst[i].client_ctx ==
+						client_ctx) {
+			*dev_inst = &mpq_dvb_video_device->dev_inst[i];
+			break;
+		}
+	}
+	mutex_unlock(&mpq_dvb_video_device->lock);
+
+	if (i == DVB_MPQ_NUM_VIDEO_DEVICES)
+		return -ENODEV;
+
+	return 0;
+}
+
+static u32 mpq_int_check_bcast_mq(struct mpq_dmx_src_data *dmx_data)
+{
+	u32 islist_empty = 0;
+	mutex_lock(&dmx_data->msg_queue_lock);
+	islist_empty = list_empty(&dmx_data->msg_queue);
+	mutex_unlock(&dmx_data->msg_queue_lock);
+
+	return !islist_empty;
+}
+
+static void mpq_get_frame_and_write(struct mpq_dvb_video_inst *dev_inst,
+				unsigned int free_buf)
+{
+	struct mpq_dmx_src_data *dmx_data = dev_inst->dmx_src_data;
+	struct mpq_streambuffer *streambuff = dmx_data->stream_buffer;
+	struct mpq_streambuffer_packet_header pkt_hdr;
+	struct mpq_adapter_video_meta_data meta_data;
+	ssize_t indx = -1;
+	ssize_t bytes_read = 0;
+	size_t pktlen = 0;
+	int frame_found = true;
+	unsigned long kernel_vaddr, phy_addr, user_vaddr;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+	size_t size = 0;
+
+	do {
+		wait_event_interruptible(streambuff->packet_data.queue,
+			(!dvb_ringbuffer_empty(&streambuff->packet_data) ||
+			streambuff->packet_data.error != 0) ||
+			kthread_should_stop());
+
+		if (kthread_should_stop()) {
+			DBG("STOP signal Received\n");
+			return;
+		}
+
+		DBG("Received Free Buffer : %d\n", free_buf);
+
+		indx = mpq_streambuffer_pkt_next(streambuff, -1, &pktlen);
+
+		if (-1 == indx) {
+			DBG("Invalid Index -1\n");
+			return;
+		}
+
+		bytes_read = mpq_streambuffer_pkt_read(streambuff, indx,
+			&pkt_hdr, (u8 *)&meta_data);
+
+		switch (meta_data.packet_type) {
+		case DMX_FRAMING_INFO_PACKET:
+			switch (meta_data.info.framing.pattern_type) {
+			case DMX_FRM_H264_SPS:
+			case DMX_FRM_MPEG2_SEQUENCE_HEADER:
+			case DMX_FRM_VC1_SEQUENCE_HEADER:
+				DBG("SPS FOUND\n");
+				frame_found = false;
+				break;
+			case DMX_FRM_H264_PPS:
+			case DMX_FRM_MPEG2_GOP_HEADER:
+			case DMX_FRM_VC1_ENTRY_POINT_HEADER:
+				DBG("PPS FOUND\n");
+				frame_found = false;
+				break;
+			case DMX_FRM_H264_IDR_PIC:
+			case DMX_FRM_H264_NON_IDR_PIC:
+			case DMX_FRM_MPEG2_I_PIC:
+			case DMX_FRM_MPEG2_P_PIC:
+			case DMX_FRM_MPEG2_B_PIC:
+			case DMX_FRM_VC1_FRAME_START_CODE:
+				DBG("FRAME FOUND\n");
+				frame_found = true;
+				break;
+			default:
+				break;
+			}
+			user_vaddr = (unsigned long)
+				dmx_data->in_buffer[free_buf].bufferaddr;
+			vidc_lookup_addr_table(dev_inst->client_ctx,
+				BUFFER_TYPE_INPUT, true, &user_vaddr,
+				&kernel_vaddr,	&phy_addr, &pmem_fd, &file,
+				&buffer_index);
+			bytes_read = 0;
+			bytes_read = mpq_streambuffer_data_read(streambuff,
+						(u8 *)(kernel_vaddr + size),
+						pkt_hdr.raw_data_len);
+			DBG("Data Read : %d from Packet Size : %d\n",
+				bytes_read, pkt_hdr.raw_data_len);
+			mpq_streambuffer_pkt_dispose(streambuff, indx, 0);
+			size +=	pkt_hdr.raw_data_len;
+			dmx_data->in_buffer[free_buf].pts =
+			(meta_data.info.framing.pts_dts_info.pts_exist) ?
+			(meta_data.info.framing.pts_dts_info.pts) : 0;
+			if (frame_found) {
+				dmx_data->in_buffer[free_buf].buffer_len =
+									size;
+				dmx_data->in_buffer[free_buf].client_data =
+							(void *)free_buf;
+				DBG("Size of Data Submitted : %d\n", size);
+				mpq_int_vid_dec_decode_frame(
+						dev_inst->client_ctx,
+						&dmx_data->in_buffer[free_buf]);
+			}
+			break;
+		case DMX_EOS_PACKET:
+			break;
+		case DMX_PES_PACKET:
+		case DMX_PADDING_PACKET:
+			break;
+		}
+	} while (!frame_found);
+
+}
+
+static int mpq_bcast_data_handler(void *arg)
+{
+	struct mpq_dvb_video_inst *dev_inst = arg;
+	struct mpq_dmx_src_data *dmx_data = dev_inst->dmx_src_data;
+	struct mpq_bcast_msg *pMesg;
+	struct mpq_bcast_msg_info msg = {0};
+
+	do {
+		wait_event_interruptible(dmx_data->msg_wait,
+					((dmx_data->stream_buffer != NULL) &&
+					mpq_int_check_bcast_mq(dmx_data)) ||
+					kthread_should_stop());
+
+		if (kthread_should_stop()) {
+			DBG("STOP signal Received\n");
+			break;
+		}
+
+		mutex_lock(&dmx_data->msg_queue_lock);
+		if (!list_empty(&dmx_data->msg_queue)) {
+			pMesg = list_first_entry(&dmx_data->msg_queue,
+					struct mpq_bcast_msg, list);
+			list_del(&pMesg->list);
+			memcpy(&msg, &pMesg->info,
+				sizeof(struct mpq_bcast_msg_info));
+			kfree(pMesg);
+		}
+		mutex_unlock(&dmx_data->msg_queue_lock);
+
+		switch (msg.code) {
+		case MPQ_BCAST_MSG_IBD:
+			DBG("Received IBD Mesg for :%d\n", msg.data);
+			mpq_get_frame_and_write(dev_inst, msg.data);
+			break;
+		default:
+			DBG("Received Mesg : %d\n", msg.code);
+		}
+	} while (1);
+
+	return 0;
+}
+
+static s32 mpq_int_vid_dec_get_empty_client_index(void)
+{
+	u32 i, found = false;
+
+	for (i = 0; i < VIDC_MAX_NUM_CLIENTS; i++) {
+		if (!mpq_dvb_video_device->vdec_clients[i].vcd_handle) {
+			found = true;
+			break;
+		}
+	}
+	if (!found) {
+		ERR("%s():ERROR No space for new client\n", __func__);
+		return -ENOMEM;
+	} else {
+		DBG("%s(): available client index = %u\n", __func__, i);
+		return i;
+	}
+}
+
+static u32 mpq_int_vid_dec_get_status(u32 status)
+{
+	u32 vdec_status;
+
+	switch (status) {
+	case VCD_ERR_SEQHDR_PARSE_FAIL:
+	case VCD_ERR_BITSTREAM_ERR:
+		vdec_status = VIDEO_STATUS_BITSTREAM_ERROR;
+		break;
+	case VCD_S_SUCCESS:
+		vdec_status = VIDEO_STATUS_SUCESS;
+		break;
+	case VCD_ERR_FAIL:
+		vdec_status = VIDEO_STATUS_FAILED;
+		break;
+	case VCD_ERR_ALLOC_FAIL:
+	case VCD_ERR_MAX_CLIENT:
+		vdec_status = VIDEO_STATUS_NORESOURCE;
+		break;
+	case VCD_ERR_ILLEGAL_OP:
+		vdec_status = VIDEO_STATUS_INVALID_CMD;
+		break;
+	case VCD_ERR_ILLEGAL_PARM:
+		vdec_status = VIDEO_STATUS_INVALID_PARAM;
+		break;
+	case VCD_ERR_BAD_POINTER:
+	case VCD_ERR_BAD_HANDLE:
+		vdec_status = VIDEO_STATUS_INVALID_HANDLE;
+		break;
+	case VCD_ERR_NOT_SUPPORTED:
+		vdec_status = VIDEO_STATUS_NO_SUPPORT;
+		break;
+	case VCD_ERR_BAD_STATE:
+		vdec_status = VIDEO_STATUS_INVALID_STATE;
+		break;
+	case VCD_ERR_BUSY:
+		vdec_status = VIDEO_STATUS_BUSY;
+		break;
+	default:
+		vdec_status = VIDEO_STATUS_FAILED;
+		break;
+	}
+
+	return vdec_status;
+}
+
+static void mpq_int_vid_dec_notify_client(struct video_client_ctx *client_ctx)
+{
+	if (client_ctx)
+		complete(&client_ctx->event);
+}
+
+static void mpq_int_vid_dec_vcd_open_done(struct video_client_ctx *client_ctx,
+			   struct vcd_handle_container *handle_container)
+{
+	if (client_ctx) {
+		if (handle_container)
+			client_ctx->vcd_handle = handle_container->handle;
+		else
+			DBG("%s(): ERROR. handle_container is NULL\n",
+			    __func__);
+
+		mpq_int_vid_dec_notify_client(client_ctx);
+	} else
+		DBG("%s(): ERROR. client_ctx is NULL\n", __func__);
+}
+
+static void mpq_int_vid_dec_handle_field_drop(
+	struct video_client_ctx *client_ctx,
+	u32 event, u32 status, int64_t time_stamp)
+{
+	struct vid_dec_msg *vdec_msg;
+
+	if (!client_ctx) {
+		DBG("%s() NULL pointer\n", __func__);
+		return;
+	}
+
+	vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+	if (!vdec_msg) {
+		DBG("%s(): cannot allocate vid_dec_msg "\
+			" buffer\n", __func__);
+		return;
+	}
+	vdec_msg->vdec_msg_info.status_code =
+		mpq_int_vid_dec_get_status(status);
+	if (event == VCD_EVT_IND_INFO_FIELD_DROPPED) {
+		vdec_msg->vdec_msg_info.msgcode =
+			VDEC_MSG_EVT_INFO_FIELD_DROPPED;
+		vdec_msg->vdec_msg_info.msgdata.output_frame.time_stamp
+		= time_stamp;
+		DBG("Send FIELD_DROPPED message to client = %p\n",
+						client_ctx);
+	} else {
+		DBG("mpq_int_vid_dec_input_frame_done(): "\
+			"invalid event type: %d\n", event);
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_INVALID;
+	}
+	vdec_msg->vdec_msg_info.msgdatasize =
+		sizeof(struct vdec_output_frameinfo);
+	mutex_lock(&client_ctx->msg_queue_lock);
+	list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	wake_up(&client_ctx->msg_wait);
+}
+
+static void mpq_int_vid_dec_input_frame_done(
+			struct video_client_ctx *client_ctx, u32 event,
+			u32 status, struct vcd_frame_data *vcd_frame_data)
+{
+	struct vid_dec_msg *vdec_msg;
+	struct mpq_bcast_msg *bcast_msg;
+	struct mpq_dvb_video_inst *dev_inst;
+	struct mpq_dmx_src_data *dmx_data;
+	int rc = 0;
+
+	if (!client_ctx || !vcd_frame_data) {
+		DBG("mpq_int_vid_dec_input_frame_done() NULL pointer\n");
+		return;
+	}
+
+	kfree(vcd_frame_data->desc_buf);
+	vcd_frame_data->desc_buf = NULL;
+	vcd_frame_data->desc_size = 0;
+
+	rc = mpq_get_dev_frm_client(client_ctx, &dev_inst);
+	if (rc) {
+		DBG("Failed to obtain device instance\n");
+		return;
+	}
+
+	if (dev_inst->source == VIDEO_SOURCE_MEMORY) {
+		vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+		if (!vdec_msg) {
+			DBG("mpq_int_vid_dec_input_frame_done(): "\
+			"cannot allocate vid_dec_msg buffer\n");
+			return;
+		}
+
+		vdec_msg->vdec_msg_info.status_code =
+				mpq_int_vid_dec_get_status(status);
+
+		if (event == VCD_EVT_RESP_INPUT_DONE) {
+			vdec_msg->vdec_msg_info.msgcode =
+			VDEC_MSG_RESP_INPUT_BUFFER_DONE;
+			DBG("Send INPUT_DON message to client = %p\n",
+						client_ctx);
+
+		} else if (event == VCD_EVT_RESP_INPUT_FLUSHED) {
+			vdec_msg->vdec_msg_info.msgcode =
+					VDEC_MSG_RESP_INPUT_FLUSHED;
+			DBG("Send INPUT_FLUSHED message to client = %p\n",
+						client_ctx);
+		} else {
+			DBG("mpq_int_vid_dec_input_frame_done(): "\
+				"invalid event type: %d\n", event);
+			vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_INVALID;
+		}
+
+		vdec_msg->vdec_msg_info.msgdata.input_frame_clientdata =
+			(void *)vcd_frame_data->frm_clnt_data;
+		vdec_msg->vdec_msg_info.msgdatasize = sizeof(void *);
+
+		mutex_lock(&client_ctx->msg_queue_lock);
+		list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+		mutex_unlock(&client_ctx->msg_queue_lock);
+		wake_up(&client_ctx->msg_wait);
+	} else {
+		bcast_msg = kzalloc(sizeof(struct mpq_bcast_msg),
+					GFP_KERNEL);
+		if (!bcast_msg) {
+			DBG("mpq_int_vid_dec_input_frame_done(): "\
+				"cannot allocate mpq_bcast_msg buffer\n");
+			return;
+		}
+
+		if (event == VCD_EVT_RESP_INPUT_DONE) {
+			bcast_msg->info.code = MPQ_BCAST_MSG_IBD;
+			bcast_msg->info.data =
+				(unsigned int)vcd_frame_data->frm_clnt_data;
+		}
+
+		dmx_data = dev_inst->dmx_src_data;
+
+		mutex_lock(&dmx_data->msg_queue_lock);
+		list_add_tail(&bcast_msg->list, &dmx_data->msg_queue);
+		mutex_unlock(&dmx_data->msg_queue_lock);
+		wake_up(&dmx_data->msg_wait);
+	}
+}
+
+static void mpq_int_vid_dec_output_frame_done(
+			struct video_client_ctx *client_ctx,
+			u32 event, u32 status,
+			struct vcd_frame_data *vcd_frame_data)
+{
+	struct vid_dec_msg *vdec_msg;
+
+	unsigned long kernel_vaddr = 0, phy_addr = 0, user_vaddr = 0;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+	enum vdec_picture pic_type;
+	u32 ion_flag = 0;
+	struct ion_handle *buff_handle = NULL;
+	struct vdec_output_frameinfo  *output_frame;
+
+	if (!client_ctx || !vcd_frame_data) {
+		DBG("mpq_int_vid_dec_input_frame_done() NULL pointer\n");
+		return;
+	}
+
+	vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+	if (!vdec_msg) {
+		DBG("mpq_int_vid_dec_input_frame_done(): "\
+		    "cannot allocate vid_dec_msg buffer\n");
+		return;
+	}
+
+	vdec_msg->vdec_msg_info.status_code =
+			mpq_int_vid_dec_get_status(status);
+
+	if (event == VCD_EVT_RESP_OUTPUT_DONE)
+		vdec_msg->vdec_msg_info.msgcode =
+		    VDEC_MSG_RESP_OUTPUT_BUFFER_DONE;
+	else if (event == VCD_EVT_RESP_OUTPUT_FLUSHED)
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_OUTPUT_FLUSHED;
+	else {
+		DBG("QVD: mpq_int_vid_dec_output_frame_done"\
+			"invalid cmd type : %d\n", event);
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_INVALID;
+	}
+
+	kernel_vaddr = (unsigned long)vcd_frame_data->virtual;
+
+	if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+				      false, &user_vaddr, &kernel_vaddr,
+				      &phy_addr, &pmem_fd, &file,
+				      &buffer_index) ||
+		(vcd_frame_data->flags & VCD_FRAME_FLAG_EOS)) {
+		/* Buffer address in user space */
+		vdec_msg->vdec_msg_info.msgdata.output_frame.bufferaddr =
+		    (u8 *) user_vaddr;
+		/* Data length */
+		vdec_msg->vdec_msg_info.msgdata.output_frame.len =
+		    vcd_frame_data->data_len;
+		vdec_msg->vdec_msg_info.msgdata.output_frame.flags =
+		    vcd_frame_data->flags;
+		/* Timestamp pass-through from input frame */
+		vdec_msg->vdec_msg_info.msgdata.output_frame.time_stamp =
+		    vcd_frame_data->time_stamp;
+		/* Output frame client data */
+		vdec_msg->vdec_msg_info.msgdata.output_frame.client_data =
+		    (void *)vcd_frame_data->frm_clnt_data;
+		/* Associated input frame client data */
+		vdec_msg->vdec_msg_info.msgdata.output_frame.
+		    input_frame_clientdata =
+		    (void *)vcd_frame_data->ip_frm_tag;
+		/* Decoded picture width and height */
+		vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.
+		bottom =
+		    vcd_frame_data->dec_op_prop.disp_frm.bottom;
+		vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.left =
+		    vcd_frame_data->dec_op_prop.disp_frm.left;
+		vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.right =
+			vcd_frame_data->dec_op_prop.disp_frm.right;
+		vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.top =
+			vcd_frame_data->dec_op_prop.disp_frm.top;
+		if (vcd_frame_data->interlaced) {
+			vdec_msg->vdec_msg_info.msgdata.
+				output_frame.interlaced_format =
+				VDEC_InterlaceInterleaveFrameTopFieldFirst;
+		} else {
+			vdec_msg->vdec_msg_info.msgdata.
+				output_frame.interlaced_format =
+				VDEC_InterlaceFrameProgressive;
+		}
+		/* Decoded picture type */
+		switch (vcd_frame_data->frame) {
+		case VCD_FRAME_I:
+			pic_type = PICTURE_TYPE_I;
+			break;
+		case VCD_FRAME_P:
+			pic_type = PICTURE_TYPE_P;
+			break;
+		case VCD_FRAME_B:
+			pic_type = PICTURE_TYPE_B;
+			break;
+		case VCD_FRAME_NOTCODED:
+			pic_type = PICTURE_TYPE_SKIP;
+			break;
+		case VCD_FRAME_IDR:
+			pic_type = PICTURE_TYPE_IDR;
+			break;
+		default:
+			pic_type = PICTURE_TYPE_UNKNOWN;
+		}
+		vdec_msg->vdec_msg_info.msgdata.output_frame.pic_type =
+			pic_type;
+		output_frame = &vdec_msg->vdec_msg_info.msgdata.output_frame;
+		output_frame->aspect_ratio_info.aspect_ratio =
+			vcd_frame_data->aspect_ratio_info.aspect_ratio;
+		output_frame->aspect_ratio_info.par_width =
+			vcd_frame_data->aspect_ratio_info.par_width;
+		output_frame->aspect_ratio_info.par_height =
+			vcd_frame_data->aspect_ratio_info.par_height;
+		vdec_msg->vdec_msg_info.msgdatasize =
+		    sizeof(struct vdec_output_frameinfo);
+	} else {
+		DBG("mpq_int_vid_dec_output_frame_done UVA"\
+				"can not be found\n");
+		vdec_msg->vdec_msg_info.status_code = VDEC_S_EFATAL;
+	}
+	if (vcd_frame_data->data_len > 0) {
+		ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
+				pmem_fd, kernel_vaddr, buffer_index,
+				&buff_handle);
+		if (ion_flag == CACHED && buff_handle) {
+			msm_ion_do_cache_op(
+				client_ctx->user_ion_client,
+				buff_handle,
+				(unsigned long *) kernel_vaddr,
+				(unsigned long)vcd_frame_data->data_len,
+				ION_IOC_INV_CACHES);
+		}
+	}
+	mutex_lock(&client_ctx->msg_queue_lock);
+	list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	wake_up(&client_ctx->msg_wait);
+}
+
+static void mpq_int_vid_dec_lean_event(struct video_client_ctx *client_ctx,
+			       u32 event, u32 status)
+{
+	struct vid_dec_msg *vdec_msg;
+
+	if (!client_ctx) {
+		DBG("%s(): !client_ctx pointer\n", __func__);
+		return;
+	}
+
+	vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+	if (!vdec_msg) {
+		DBG("%s(): cannot allocate vid_dec_msg buffer\n",
+					__func__);
+		return;
+	}
+
+	vdec_msg->vdec_msg_info.status_code =
+			mpq_int_vid_dec_get_status(status);
+
+	switch (event) {
+	case VCD_EVT_IND_OUTPUT_RECONFIG:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_EVT_CONFIG_CHANGED"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_EVT_CONFIG_CHANGED;
+		break;
+	case VCD_EVT_IND_RESOURCES_LOST:
+		DBG("msm_vidc_dec: Sending VDEC_EVT_RESOURCES_LOST"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_EVT_RESOURCES_LOST;
+		break;
+	case VCD_EVT_RESP_FLUSH_INPUT_DONE:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_FLUSH_INPUT_DONE"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode =
+		    VDEC_MSG_RESP_FLUSH_INPUT_DONE;
+		break;
+	case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_FLUSH_OUTPUT_DONE"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode =
+		    VDEC_MSG_RESP_FLUSH_OUTPUT_DONE;
+		break;
+	case VCD_EVT_IND_HWERRFATAL:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_EVT_HW_ERROR"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_EVT_HW_ERROR;
+		break;
+	case VCD_EVT_RESP_START:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_START_DONE"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_START_DONE;
+		break;
+	case VCD_EVT_RESP_STOP:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_STOP_DONE"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_STOP_DONE;
+		break;
+	case VCD_EVT_RESP_PAUSE:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_PAUSE_DONE"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_PAUSE_DONE;
+		break;
+	case VCD_EVT_IND_INFO_OUTPUT_RECONFIG:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_EVT_INFO_CONFIG_CHANGED"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode =
+			 VDEC_MSG_EVT_INFO_CONFIG_CHANGED;
+		break;
+	default:
+		DBG("%s() : unknown event type\n", __func__);
+		break;
+	}
+
+	vdec_msg->vdec_msg_info.msgdatasize = 0;
+	if (client_ctx->stop_sync_cb &&
+	   (event == VCD_EVT_RESP_STOP || event == VCD_EVT_IND_HWERRFATAL)) {
+		client_ctx->stop_sync_cb = false;
+		complete(&client_ctx->event);
+		kfree(vdec_msg);
+		return;
+	}
+	mutex_lock(&client_ctx->msg_queue_lock);
+	list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	wake_up(&client_ctx->msg_wait);
+}
+
+static void mpq_int_state_play(struct video_client_ctx *client_ctx,
+			       u32 event, u32 status)
+{
+	struct mpq_bcast_msg *bcast_msg;
+	struct mpq_dvb_video_inst *dev_inst;
+	int i;
+	int rc = 0;
+	struct mpq_dmx_src_data *dmx_data = NULL;
+
+	if (!client_ctx->seq_header_set) {
+		rc = mpq_get_dev_frm_client(client_ctx, &dev_inst);
+		if (rc) {
+			DBG("Failed to get dev_instance in %s\n", __func__);
+			return;
+		}
+
+		if (VIDEO_SOURCE_DEMUX == dev_inst->source) {
+			dmx_data = dev_inst->dmx_src_data;
+			for (i = 0; i < DVB_VID_NUM_IN_BUFFERS; i++) {
+				bcast_msg = kzalloc(
+						sizeof(struct mpq_bcast_msg),
+						GFP_KERNEL);
+				if (!bcast_msg) {
+					DBG("cannot allocate mpq_bcast_msg"\
+						"buffer\n");
+					return;
+				}
+
+				bcast_msg->info.code = MPQ_BCAST_MSG_IBD;
+				bcast_msg->info.data = (unsigned int)i;
+
+				mutex_lock(&dmx_data->msg_queue_lock);
+				list_add_tail(&bcast_msg->list,
+						&dmx_data->msg_queue);
+				mutex_unlock(&dmx_data->msg_queue_lock);
+				wake_up(&dmx_data->msg_wait);
+			}
+		}
+		mpq_int_vid_dec_lean_event(client_ctx, event, status);
+	} else
+		mpq_int_vid_dec_notify_client(client_ctx);
+
+}
+
+static void mpq_int_vid_dec_vcd_cb(u32 event, u32 status,
+		   void *info, size_t sz, void *handle,
+		   void *const client_data)
+{
+	struct video_client_ctx *client_ctx = client_data;
+
+	DBG("Entering %s()\n", __func__);
+
+	if (!client_ctx) {
+		DBG("%s(): client_ctx is NULL\n", __func__);
+		return;
+	}
+
+	client_ctx->event_status = status;
+
+	switch (event) {
+	case VCD_EVT_RESP_OPEN:
+		mpq_int_vid_dec_vcd_open_done(client_ctx,
+				      (struct vcd_handle_container *)
+				      info);
+		break;
+	case VCD_EVT_RESP_INPUT_DONE:
+	case VCD_EVT_RESP_INPUT_FLUSHED:
+		mpq_int_vid_dec_input_frame_done(client_ctx, event, status,
+					 (struct vcd_frame_data *)info);
+		break;
+	case VCD_EVT_IND_INFO_FIELD_DROPPED:
+		if (info)
+			mpq_int_vid_dec_handle_field_drop(client_ctx, event,
+			status,	*((int64_t *)info));
+		else
+			DBG("Wrong Payload for Field dropped\n");
+		break;
+	case VCD_EVT_RESP_OUTPUT_DONE:
+	case VCD_EVT_RESP_OUTPUT_FLUSHED:
+		mpq_int_vid_dec_output_frame_done(client_ctx, event, status,
+					  (struct vcd_frame_data *)info);
+		break;
+	case VCD_EVT_RESP_PAUSE:
+	case VCD_EVT_RESP_STOP:
+	case VCD_EVT_RESP_FLUSH_INPUT_DONE:
+	case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+	case VCD_EVT_IND_OUTPUT_RECONFIG:
+	case VCD_EVT_IND_HWERRFATAL:
+	case VCD_EVT_IND_RESOURCES_LOST:
+	case VCD_EVT_IND_INFO_OUTPUT_RECONFIG:
+		mpq_int_vid_dec_lean_event(client_ctx, event, status);
+		break;
+	case VCD_EVT_RESP_START:
+		mpq_int_state_play(client_ctx, event, status);
+		break;
+	default:
+		DBG("%s() :  Error - Invalid event type =%u\n", __func__,
+		    event);
+		break;
+	}
+}
+
+static int mpq_int_vid_dec_set_cont_on_reconfig(
+			struct video_client_ctx *client_ctx)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	u32 vcd_status = VCD_ERR_FAIL;
+	u32 enable = true;
+	if (!client_ctx)
+		return -EINVAL;
+	vcd_property_hdr.prop_id = VCD_I_CONT_ON_RECONFIG;
+	vcd_property_hdr.sz = sizeof(u32);
+	vcd_status = vcd_set_property(client_ctx->vcd_handle,
+		&vcd_property_hdr, &enable);
+	if (vcd_status)
+		return -EIO;
+	return 0;
+}
+
+static int mpq_int_vid_dec_set_frame_resolution(
+				struct video_client_ctx *client_ctx,
+				struct vdec_picsize *video_resoultion)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_frame_size frame_resolution;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !video_resoultion)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_frame_size);
+	frame_resolution.width = video_resoultion->frame_width;
+	frame_resolution.height = video_resoultion->frame_height;
+	frame_resolution.stride = video_resoultion->stride;
+	frame_resolution.scan_lines = video_resoultion->scan_lines;
+
+	vcd_status = vcd_set_property(client_ctx->vcd_handle,
+				      &vcd_property_hdr, &frame_resolution);
+
+	if (vcd_status)
+		return -EIO;
+	else
+		return 0;
+}
+
+static int mpq_int_set_full_hd_frame_resolution(
+				struct video_client_ctx *client_ctx)
+{
+	struct vdec_picsize pic_res;
+	int rc;
+
+	pic_res.frame_height = 1080;
+	pic_res.frame_width  = 1920;
+	pic_res.scan_lines   = 1080;
+	pic_res.stride       = 1920;
+
+	rc = mpq_int_vid_dec_set_frame_resolution(client_ctx,
+						&pic_res);
+	if (rc)
+		DBG("Failed in mpq_int_vid_dec_set_frame_resolution : %d\n",\
+			rc);
+
+	rc = mpq_int_vid_dec_set_cont_on_reconfig(client_ctx);
+	if (rc)
+		DBG("Failed in mpq_int_vid_dec_set_cont_on_reconfig : %d\n",\
+			rc);
+
+	return rc;
+
+}
+
+static int mpq_int_vid_dec_get_frame_resolution(
+			struct video_client_ctx *client_ctx,
+			struct video_pic_res *video_resoultion)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_frame_size frame_resolution;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !video_resoultion)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_frame_size);
+
+	vcd_status = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &frame_resolution);
+
+	video_resoultion->width  = frame_resolution.width;
+	video_resoultion->height = frame_resolution.height;
+	video_resoultion->scan_lines = frame_resolution.scan_lines;
+	video_resoultion->stride = frame_resolution.stride;
+
+	if (vcd_status)
+		return -EINVAL;
+	else
+		return 0;
+}
+
+static int mpq_int_vid_dec_get_codec(struct video_client_ctx *client_ctx,
+					enum video_codec_t *video_codec)
+{
+	unsigned int result = 0;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_codec codec;
+
+	if ((client_ctx == NULL) || (video_codec == NULL))
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_CODEC;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+
+	result = vcd_get_property(client_ctx->vcd_handle,
+					&vcd_property_hdr, &codec);
+	if (result)
+		return -EINVAL;
+
+	switch (codec.codec) {
+	case VCD_CODEC_MPEG4:
+		*video_codec = VIDEO_CODECTYPE_MPEG4;
+		break;
+	case VCD_CODEC_H264:
+		*video_codec = VIDEO_CODECTYPE_H264;
+		break;
+	case VCD_CODEC_MPEG2:
+		*video_codec = VIDEO_CODECTYPE_MPEG2;
+		break;
+	case VCD_CODEC_VC1:
+		*video_codec = VIDEO_CODECTYPE_VC1;
+		break;
+	default:
+		*video_codec = VIDEO_CODECTYPE_NONE;
+		break;
+	}
+
+	return result;
+}
+
+static int mpq_int_vid_dec_set_codec(struct video_client_ctx *client_ctx,
+				enum video_codec_t video_codec)
+{
+	unsigned int result = 0;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_codec codec;
+	unsigned int vcd_status = VCD_ERR_FAIL;
+
+	if (client_ctx == NULL)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_CODEC;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+
+	switch (video_codec) {
+	case VIDEO_CODECTYPE_MPEG4:
+		codec.codec = VCD_CODEC_MPEG4;
+		break;
+	case VIDEO_CODECTYPE_H264:
+		codec.codec = VCD_CODEC_H264;
+		break;
+	case VIDEO_CODECTYPE_MPEG2:
+		codec.codec = VCD_CODEC_MPEG2;
+		break;
+	case VIDEO_CODECTYPE_VC1:
+		codec.codec = VCD_CODEC_VC1;
+		break;
+	default:
+		result = -EINVAL;
+		break;
+	}
+
+	if (!result) {
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+					      &vcd_property_hdr, &codec);
+		if (vcd_status)
+			result = -EINVAL;
+	}
+
+	result = mpq_int_set_full_hd_frame_resolution(client_ctx);
+
+	return result;
+}
+
+static int mpq_int_vid_dec_set_output_format(
+		struct video_client_ctx *client_ctx,
+		enum video_out_format_t format)
+{
+	unsigned int result = 0;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_buffer_format vcd_prop_buffer_format;
+	unsigned int vcd_status = VCD_ERR_FAIL;
+
+	if (client_ctx == NULL)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_BUFFER_FORMAT;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_format);
+
+	switch (format) {
+	case VIDEO_YUV_FORMAT_NV12:
+		vcd_prop_buffer_format.buffer_format = VCD_BUFFER_FORMAT_NV12;
+		break;
+	case VIDEO_YUV_FORMAT_TILE_4x2:
+		vcd_prop_buffer_format.buffer_format =
+					VCD_BUFFER_FORMAT_TILE_4x2;
+		break;
+	default:
+		result = -EINVAL;
+		break;
+	}
+
+	if (!result)
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+					      &vcd_property_hdr,
+					      &vcd_prop_buffer_format);
+
+	if (vcd_status)
+		return -EINVAL;
+
+	return 0;
+
+}
+
+static int mpq_int_vid_dec_get_output_format(
+			struct video_client_ctx *client_ctx,
+			enum video_out_format_t *format)
+{
+	unsigned int result = 0;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_buffer_format vcd_prop_buffer_format;
+
+	if ((client_ctx == NULL) || (format == NULL))
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_BUFFER_FORMAT;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_format);
+
+	result = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+					&vcd_prop_buffer_format);
+
+	if (result)
+		return -EINVAL;
+
+	switch (vcd_prop_buffer_format.buffer_format) {
+	case VCD_BUFFER_FORMAT_NV12:
+		*format = VIDEO_YUV_FORMAT_NV12;
+		break;
+	case VCD_BUFFER_FORMAT_TILE_4x2:
+		*format = VIDEO_YUV_FORMAT_TILE_4x2;
+		break;
+	default:
+		result = -EINVAL;
+		break;
+	}
+
+	return result;
+}
+
+static int mpq_int_vid_dec_set_h264_mv_buffers(
+				struct video_client_ctx *client_ctx,
+				struct video_h264_mv *mv_data)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_h264_mv_buffer *vcd_h264_mv_buffer = NULL;
+	struct msm_mapped_buffer *mapped_buffer = NULL;
+	u32 vcd_status = VCD_ERR_FAIL;
+	u32 len = 0, flags = 0;
+	struct file *file;
+	int rc = 0;
+	unsigned long ionflag = 0;
+	unsigned long buffer_size = 0;
+	unsigned long iova = 0;
+
+	if (!client_ctx || !mv_data)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_H264_MV_BUFFER;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_h264_mv_buffer);
+	vcd_h264_mv_buffer = &client_ctx->vcd_h264_mv_buffer;
+
+	memset(&client_ctx->vcd_h264_mv_buffer, 0,
+		   sizeof(struct vcd_property_h264_mv_buffer));
+	vcd_h264_mv_buffer->size = mv_data->size;
+	vcd_h264_mv_buffer->count = mv_data->count;
+	vcd_h264_mv_buffer->pmem_fd = mv_data->ion_fd;
+	vcd_h264_mv_buffer->offset = mv_data->offset;
+
+	if (!vcd_get_ion_status()) {
+		if (get_pmem_file(vcd_h264_mv_buffer->pmem_fd,
+			(unsigned long *) (&(vcd_h264_mv_buffer->
+			physical_addr)),
+			(unsigned long *) (&vcd_h264_mv_buffer->
+						kernel_virtual_addr),
+			(unsigned long *) (&len), &file)) {
+			ERR("%s(): get_pmem_file failed\n", __func__);
+			return -EIO;
+		}
+		put_pmem_file(file);
+		flags = MSM_SUBSYSTEM_MAP_IOVA;
+		mapped_buffer = msm_subsystem_map_buffer(
+			(unsigned long)vcd_h264_mv_buffer->physical_addr, len,
+				flags, vidc_mmu_subsystem,
+				sizeof(vidc_mmu_subsystem)/
+				sizeof(unsigned int));
+		if (IS_ERR(mapped_buffer)) {
+			ERR("buffer map failed");
+			return PTR_ERR(mapped_buffer);
+		}
+		vcd_h264_mv_buffer->client_data = (void *) mapped_buffer;
+		vcd_h264_mv_buffer->dev_addr = (u8 *)mapped_buffer->iova[0];
+	} else {
+		client_ctx->h264_mv_ion_handle = ion_import_dma_buf(
+					client_ctx->user_ion_client,
+					vcd_h264_mv_buffer->pmem_fd);
+		if (IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
+			DBG("%s(): get_ION_handle failed\n", __func__);
+			goto import_ion_error;
+		}
+		rc = ion_handle_get_flags(client_ctx->user_ion_client,
+					client_ctx->h264_mv_ion_handle,
+					&ionflag);
+		if (rc) {
+			DBG("%s():get_ION_flags fail\n",
+					 __func__);
+			goto import_ion_error;
+		}
+		vcd_h264_mv_buffer->kernel_virtual_addr =
+			(u8 *) ion_map_kernel(client_ctx->user_ion_client,
+					client_ctx->h264_mv_ion_handle,
+					ionflag);
+		if (!vcd_h264_mv_buffer->kernel_virtual_addr) {
+			DBG("%s(): get_ION_kernel virtual addr failed\n",
+				 __func__);
+			goto import_ion_error;
+		}
+
+		rc = ion_map_iommu(client_ctx->user_ion_client,
+				client_ctx->h264_mv_ion_handle,
+				VIDEO_DOMAIN, VIDEO_MAIN_POOL,
+				SZ_4K, 0, (unsigned long *)&iova,
+				(unsigned long *)&buffer_size,
+				UNCACHED, 0);
+		if (rc) {
+			DBG("%s():get_ION_kernel physical addr fail\n",
+						 __func__);
+			goto ion_map_error;
+		}
+		vcd_h264_mv_buffer->physical_addr = (u8 *) iova;
+		vcd_h264_mv_buffer->client_data = NULL;
+		vcd_h264_mv_buffer->dev_addr = (u8 *) iova;
+
+	}
+	DBG("Virt: %p, Phys %p, fd: %d", vcd_h264_mv_buffer->
+		kernel_virtual_addr, vcd_h264_mv_buffer->physical_addr,
+		vcd_h264_mv_buffer->pmem_fd);
+	DBG("Dev addr %p", vcd_h264_mv_buffer->dev_addr);
+	vcd_status = vcd_set_property(client_ctx->vcd_handle,
+				      &vcd_property_hdr, vcd_h264_mv_buffer);
+
+	if (vcd_status)
+		return -EIO;
+	else
+		return 0;
+ion_map_error:
+	if (vcd_h264_mv_buffer->kernel_virtual_addr) {
+		ion_unmap_kernel(client_ctx->user_ion_client,
+				client_ctx->h264_mv_ion_handle);
+		vcd_h264_mv_buffer->kernel_virtual_addr = NULL;
+	}
+	if (!IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
+		ion_free(client_ctx->user_ion_client,
+			client_ctx->h264_mv_ion_handle);
+		 client_ctx->h264_mv_ion_handle = NULL;
+	}
+import_ion_error:
+	return -EIO;
+}
+
+static int mpq_int_vid_dec_get_h264_mv_buffer_size(
+				struct video_client_ctx *client_ctx,
+				struct video_mv_buff_size *mv_buff)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_buffer_size h264_mv_buffer_size;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !mv_buff)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_GET_H264_MV_SIZE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_size);
+
+	h264_mv_buffer_size.width = mv_buff->width;
+	h264_mv_buffer_size.height = mv_buff->height;
+
+	vcd_status = vcd_get_property(client_ctx->vcd_handle,
+				      &vcd_property_hdr, &h264_mv_buffer_size);
+
+	mv_buff->width = h264_mv_buffer_size.width;
+	mv_buff->height = h264_mv_buffer_size.height;
+	mv_buff->size = h264_mv_buffer_size.size;
+	mv_buff->alignment = h264_mv_buffer_size.alignment;
+
+	if (vcd_status)
+		return -EIO;
+	else
+		return 0;
+}
+
+static int mpq_int_vid_dec_free_h264_mv_buffers(
+				struct video_client_ctx *client_ctx)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_buffer_size h264_mv_buffer_size;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx)
+		return -EINVAL;
+	if (client_ctx->vcd_h264_mv_buffer.client_data)
+		msm_subsystem_unmap_buffer((struct msm_mapped_buffer *)
+		client_ctx->vcd_h264_mv_buffer.client_data);
+
+	vcd_property_hdr.prop_id = VCD_I_FREE_H264_MV_BUFFER;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_size);
+
+	vcd_status = vcd_set_property(client_ctx->vcd_handle,
+				      &vcd_property_hdr, &h264_mv_buffer_size);
+
+	if (!IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
+		ion_unmap_kernel(client_ctx->user_ion_client,
+					client_ctx->h264_mv_ion_handle);
+		ion_unmap_iommu(client_ctx->user_ion_client,
+				client_ctx->h264_mv_ion_handle,
+				VIDEO_DOMAIN,
+				VIDEO_MAIN_POOL);
+		ion_free(client_ctx->user_ion_client,
+					client_ctx->h264_mv_ion_handle);
+		 client_ctx->h264_mv_ion_handle = NULL;
+	}
+
+	if (vcd_status)
+		return -EIO;
+	else
+		return 0;
+}
+
+
+static int mpq_int_vid_dec_get_buffer_req(struct video_client_ctx *client_ctx,
+				  struct video_buffer_req *vdec_buf_req)
+{
+	u32 vcd_status = VCD_ERR_FAIL;
+	struct vcd_buffer_requirement vcd_buf_req;
+
+	if (!client_ctx || !vdec_buf_req)
+		return -EINVAL;
+
+	vcd_status = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+					VCD_BUFFER_INPUT, &vcd_buf_req);
+
+	if (vcd_status)
+		return -EINVAL;
+
+	vdec_buf_req->input_buf_prop.alignment  = vcd_buf_req.align;
+	vdec_buf_req->input_buf_prop.buf_poolid = vcd_buf_req.buf_pool_id;
+	vdec_buf_req->input_buf_prop.buf_size   = vcd_buf_req.sz;
+	vdec_buf_req->num_input_buffers         = vcd_buf_req.actual_count;
+
+	vcd_status = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+					VCD_BUFFER_OUTPUT, &vcd_buf_req);
+
+	if (vcd_status)
+		return -EINVAL;
+
+	vdec_buf_req->output_buf_prop.alignment  = vcd_buf_req.align;
+	vdec_buf_req->output_buf_prop.buf_poolid = vcd_buf_req.buf_pool_id;
+	vdec_buf_req->output_buf_prop.buf_size   = vcd_buf_req.sz;
+	vdec_buf_req->num_output_buffers         = vcd_buf_req.actual_count;
+
+	return 0;
+}
+
+static int mpq_int_vid_dec_set_buffer(struct mpq_dvb_video_inst *dev_inst,
+			      struct video_data_buffer *data_buffer,
+			      enum buffer_dir dir_buffer)
+{
+	struct video_client_ctx *client_ctx =
+		(struct video_client_ctx *)dev_inst->client_ctx;
+	enum vcd_buffer_type buffer = VCD_BUFFER_INPUT;
+	u32 vcd_status = VCD_ERR_FAIL;
+	unsigned long kernel_vaddr, buf_adr_offset = 0, length;
+	int buffer_num = 0;
+
+	if (!client_ctx || !data_buffer)
+		return -EINVAL;
+
+	if (dir_buffer == BUFFER_TYPE_OUTPUT) {
+		buffer = VCD_BUFFER_OUTPUT;
+		buf_adr_offset = (unsigned long)data_buffer->offset;
+	}
+	length = data_buffer->buffer_len;
+	/*If buffer cannot be set, ignore */
+	if (!vidc_insert_addr_table(client_ctx, dir_buffer,
+		(unsigned long)data_buffer->bufferaddr,
+		&kernel_vaddr, data_buffer->ion_fd,
+		buf_adr_offset, MAX_VIDEO_NUM_OF_BUFF, length)) {
+		ERR("%s() : user_virt_addr = %p cannot be set.",
+		    __func__, data_buffer->bufferaddr);
+		return -EINVAL;
+	}
+
+	vcd_status = vcd_set_buffer(client_ctx->vcd_handle,
+		buffer, (u8 *) kernel_vaddr, data_buffer->buffer_len);
+
+	if (!vcd_status) {
+		mutex_lock(&client_ctx->enrty_queue_lock);
+		if ((VIDEO_SOURCE_DEMUX == dev_inst->source) &&
+			(BUFFER_TYPE_INPUT == dir_buffer)) {
+			buffer_num = client_ctx->num_of_input_buffers - 1;
+			memcpy(&dev_inst->dmx_src_data->in_buffer[buffer_num],
+				data_buffer,
+				sizeof(struct video_data_buffer));
+		}
+		mutex_unlock(&client_ctx->enrty_queue_lock);
+		return 0;
+	} else
+		return -EINVAL;
+}
+
+static int mpq_int_vid_dec_free_buffer(struct video_client_ctx *client_ctx,
+				struct video_data_buffer *data_buffer,
+				enum buffer_dir dir_buffer)
+
+{
+	enum vcd_buffer_type buffer = VCD_BUFFER_INPUT;
+	u32 vcd_status = VCD_ERR_FAIL;
+	unsigned long kernel_vaddr;
+
+	if (!client_ctx || !data_buffer)
+		return -EINVAL;
+
+	if (dir_buffer == BUFFER_TYPE_OUTPUT)
+		buffer = VCD_BUFFER_OUTPUT;
+
+	/*If buffer NOT set, ignore */
+	if (!vidc_delete_addr_table(client_ctx, dir_buffer,
+				(unsigned long)data_buffer->bufferaddr,
+				&kernel_vaddr)) {
+		DBG("%s() : user_virt_addr = %p has not been set.",
+		    __func__, data_buffer->bufferaddr);
+		return 0;
+	}
+	vcd_status = vcd_free_buffer(client_ctx->vcd_handle, buffer,
+					 (u8 *)kernel_vaddr);
+
+	if (vcd_status)
+		return -EIO;
+	else
+		return 0;
+}
+
+static int mpq_int_vid_dec_pause_resume(struct video_client_ctx *client_ctx,
+					u32 pause)
+{
+	u32 vcd_status;
+
+	if (!client_ctx) {
+		DBG("%s(): Invalid client_ctx\n", __func__);
+		return -EINVAL;
+	}
+
+	if (pause) {
+		DBG("msm_vidc_dec: PAUSE command from client = %p\n",
+			 client_ctx);
+		vcd_status = vcd_pause(client_ctx->vcd_handle);
+	} else {
+		DBG("msm_vidc_dec: RESUME command from client = %p\n",
+			 client_ctx);
+		vcd_status = vcd_resume(client_ctx->vcd_handle);
+	}
+
+	if (vcd_status)
+		return -EIO;
+	else
+		return 0;
+}
+
+static int mpq_int_vid_dec_start_stop(struct video_client_ctx *client_ctx,
+					u32 start)
+{
+	struct vid_dec_msg *vdec_msg = NULL;
+	u32 vcd_status;
+
+	DBG("Inside %s()", __func__);
+	if (!client_ctx) {
+		DBG("Invalid client_ctx\n");
+		return -EINVAL;
+	}
+
+	if (start) {
+		if (client_ctx->seq_header_set) {
+			DBG("%s(): Seq Hdr set: Send START_DONE to client",
+				 __func__);
+			vdec_msg = kzalloc(sizeof(*vdec_msg), GFP_KERNEL);
+			if (!vdec_msg) {
+				DBG("mpq_int_vid_dec_start_stop:"\
+				    " cannot allocate buffer\n");
+				return -ENOMEM;
+			}
+			vdec_msg->vdec_msg_info.msgcode =
+			    VDEC_MSG_RESP_START_DONE;
+			vdec_msg->vdec_msg_info.status_code = VDEC_S_SUCCESS;
+			vdec_msg->vdec_msg_info.msgdatasize = 0;
+			mutex_lock(&client_ctx->msg_queue_lock);
+			list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+			mutex_unlock(&client_ctx->msg_queue_lock);
+
+			wake_up(&client_ctx->msg_wait);
+
+			DBG("Send START_DONE message to client = %p\n",
+			    client_ctx);
+
+		} else {
+			DBG("%s(): Calling decode_start()", __func__);
+			vcd_status =
+			    vcd_decode_start(client_ctx->vcd_handle, NULL);
+
+			if (vcd_status) {
+				DBG("%s(): vcd_decode_start failed."\
+				    " vcd_status = %u\n", __func__,
+				    vcd_status);
+				return -EIO;
+			}
+		}
+	} else {
+		DBG("%s(): Calling vcd_stop()", __func__);
+		mutex_lock(&mpq_dvb_video_device->lock);
+		vcd_status = VCD_ERR_FAIL;
+		if (!client_ctx->stop_called) {
+			client_ctx->stop_called = true;
+			vcd_status = vcd_stop(client_ctx->vcd_handle);
+		}
+		if (vcd_status) {
+			DBG("%s(): vcd_stop failed.  vcd_status = %u\n",
+				__func__, vcd_status);
+			mutex_unlock(&mpq_dvb_video_device->lock);
+			return -EIO;
+		}
+		DBG("Send STOP_DONE message to client = %p\n", client_ctx);
+		mutex_unlock(&mpq_dvb_video_device->lock);
+	}
+	return 0;
+}
+
+static int mpq_int_vid_dec_decode_frame(struct video_client_ctx *client_ctx,
+				struct video_data_buffer *input_frame)
+{
+	struct vcd_frame_data vcd_input_buffer;
+	unsigned long kernel_vaddr, phy_addr, user_vaddr;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+	u32 vcd_status = VCD_ERR_FAIL;
+	u32 ion_flag = 0;
+	struct ion_handle *buff_handle = NULL;
+
+	if (!client_ctx || !input_frame)
+		return -EINVAL;
+
+	user_vaddr = (unsigned long)input_frame->bufferaddr;
+
+	if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_INPUT,
+				      true, &user_vaddr, &kernel_vaddr,
+				      &phy_addr, &pmem_fd, &file,
+				      &buffer_index)) {
+
+		/* kernel_vaddr  is found. send the frame to VCD */
+		memset((void *)&vcd_input_buffer, 0,
+		       sizeof(struct vcd_frame_data));
+		vcd_input_buffer.virtual =
+		    (u8 *) (kernel_vaddr + input_frame->offset);
+		vcd_input_buffer.offset = 0;
+		vcd_input_buffer.frm_clnt_data =
+		    (u32) input_frame->client_data;
+		vcd_input_buffer.ip_frm_tag =
+		    (u32) input_frame->client_data;
+		vcd_input_buffer.data_len = input_frame->buffer_len;
+		vcd_input_buffer.time_stamp = input_frame->pts;
+		/* Rely on VCD using the same flags as OMX */
+		vcd_input_buffer.flags = 0;
+		vcd_input_buffer.desc_buf = NULL;
+		vcd_input_buffer.desc_size = 0;
+		if (vcd_input_buffer.data_len > 0) {
+			ion_flag = vidc_get_fd_info(client_ctx,
+						BUFFER_TYPE_INPUT,
+						pmem_fd,
+						kernel_vaddr,
+						buffer_index,
+						&buff_handle);
+			if (ion_flag == CACHED && buff_handle) {
+				msm_ion_do_cache_op(
+				client_ctx->user_ion_client,
+				buff_handle,
+				(unsigned long *)kernel_vaddr,
+				(unsigned long) vcd_input_buffer.data_len,
+				ION_IOC_CLEAN_CACHES);
+			}
+		}
+		vcd_status = vcd_decode_frame(client_ctx->vcd_handle,
+					      &vcd_input_buffer);
+		if (!vcd_status)
+			return 0;
+		else {
+			DBG("%s(): vcd_decode_frame failed = %u\n", __func__,
+			    vcd_status);
+			return -EIO;
+		}
+
+	} else {
+		DBG("%s(): kernel_vaddr not found\n", __func__);
+		return -EIO;
+	}
+}
+
+static int mpq_int_vid_dec_fill_output_buffer(
+		struct video_client_ctx *client_ctx,
+		struct video_data_buffer *fill_buffer)
+{
+	unsigned long kernel_vaddr, phy_addr, user_vaddr;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+	u32 vcd_status = VCD_ERR_FAIL;
+	struct ion_handle *buff_handle = NULL;
+
+	struct vcd_frame_data vcd_frame;
+
+	if (!client_ctx || !fill_buffer)
+		return -EINVAL;
+
+	user_vaddr = (unsigned long)fill_buffer->bufferaddr;
+
+	if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+				      true, &user_vaddr, &kernel_vaddr,
+				      &phy_addr, &pmem_fd, &file,
+				      &buffer_index)) {
+
+		memset((void *)&vcd_frame, 0,
+		       sizeof(struct vcd_frame_data));
+		vcd_frame.virtual = (u8 *) kernel_vaddr;
+		vcd_frame.frm_clnt_data = (u32) fill_buffer->client_data;
+		vcd_frame.alloc_len = fill_buffer->buffer_len;
+		vcd_frame.ion_flag = vidc_get_fd_info(client_ctx,
+						 BUFFER_TYPE_OUTPUT,
+						pmem_fd, kernel_vaddr,
+						buffer_index,
+						&buff_handle);
+		vcd_frame.buff_ion_handle = buff_handle;
+		vcd_status = vcd_fill_output_buffer(client_ctx->vcd_handle,
+						    &vcd_frame);
+		if (!vcd_status)
+			return 0;
+		else {
+			DBG("%s(): vcd_fill_output_buffer failed = %u\n",
+			    __func__, vcd_status);
+			return -EINVAL;
+		}
+	} else {
+		DBG("%s(): kernel_vaddr not found\n", __func__);
+		return -EIO;
+	}
+}
+
+
+static int mpq_int_vid_dec_flush(struct video_client_ctx *client_ctx,
+			 enum vdec_bufferflush flush_dir)
+{
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	DBG("msm_vidc_dec: %s() called with dir = %u", __func__,
+		 flush_dir);
+	if (!client_ctx) {
+		DBG("Invalid client_ctx\n");
+		return -EINVAL;
+	}
+
+	switch (flush_dir) {
+	case VDEC_FLUSH_TYPE_INPUT:
+		vcd_status = vcd_flush(client_ctx->vcd_handle,
+					VCD_FLUSH_INPUT);
+		break;
+	case VDEC_FLUSH_TYPE_OUTPUT:
+		vcd_status = vcd_flush(client_ctx->vcd_handle,
+				       VCD_FLUSH_OUTPUT);
+		break;
+	case VDEC_FLUSH_TYPE_ALL:
+		vcd_status = vcd_flush(client_ctx->vcd_handle, VCD_FLUSH_ALL);
+		break;
+	default:
+		ERR("%s(): Inavlid flush cmd. flush_dir = %u\n", __func__,
+		    flush_dir);
+		return -EINVAL;
+		break;
+	}
+
+	if (!vcd_status)
+		return 0;
+	else {
+		DBG("%s(): vcd_flush failed. vcd_status = %u "\
+		    " flush_dir = %u\n", __func__, vcd_status, flush_dir);
+		return -EIO;
+	}
+}
+
+static u32 mpq_int_vid_dec_msg_pending(struct video_client_ctx *client_ctx)
+{
+	u32 islist_empty = 0;
+	mutex_lock(&client_ctx->msg_queue_lock);
+	islist_empty = list_empty(&client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+
+	if (islist_empty) {
+		DBG("%s(): vid_dec msg queue empty\n", __func__);
+		if (client_ctx->stop_msg) {
+			DBG("%s(): List empty and Stop Msg set\n",
+				__func__);
+			return client_ctx->stop_msg;
+		}
+	} else {
+		DBG("%s(): vid_dec msg queue Not empty\n", __func__);
+	}
+
+	return !islist_empty;
+}
+
+static int mpq_int_vid_dec_get_next_msg(struct video_client_ctx *client_ctx,
+				struct vdec_msginfo *vdec_msg_info)
+{
+	struct vid_dec_msg *vid_dec_msg = NULL;
+
+	if (!client_ctx)
+		return -EINVAL;
+
+	mutex_lock(&client_ctx->msg_queue_lock);
+	if (!list_empty(&client_ctx->msg_queue)) {
+		DBG("%s(): After Wait\n", __func__);
+		vid_dec_msg = list_first_entry(&client_ctx->msg_queue,
+					       struct vid_dec_msg, list);
+		list_del(&vid_dec_msg->list);
+		memcpy(vdec_msg_info, &vid_dec_msg->vdec_msg_info,
+		       sizeof(struct vdec_msginfo));
+		kfree(vid_dec_msg);
+	}
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	return 0;
+}
+
+static u32 mpq_int_vid_dec_close_client(struct video_client_ctx *client_ctx)
+{
+	struct vid_dec_msg *vdec_msg;
+	u32 vcd_status;
+
+	DBG("msm_vidc_dec: Inside %s()", __func__);
+	if (!client_ctx || (!client_ctx->vcd_handle)) {
+		DBG("Invalid client_ctx\n");
+		return false;
+	}
+
+	mutex_lock(&mpq_dvb_video_device->lock);
+	if (!client_ctx->stop_called) {
+		client_ctx->stop_called = true;
+		client_ctx->stop_sync_cb = true;
+		vcd_status = vcd_stop(client_ctx->vcd_handle);
+		DBG("Stuck at the stop call\n");
+		if (!vcd_status)
+			wait_for_completion(&client_ctx->event);
+		DBG("Came out of wait event\n");
+	}
+	mutex_lock(&client_ctx->msg_queue_lock);
+	while (!list_empty(&client_ctx->msg_queue)) {
+		DBG("%s(): Delete remaining entries\n", __func__);
+		vdec_msg = list_first_entry(&client_ctx->msg_queue,
+						   struct vid_dec_msg, list);
+		if (vdec_msg) {
+			list_del(&vdec_msg->list);
+			kfree(vdec_msg);
+		}
+	}
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	vcd_status = vcd_close(client_ctx->vcd_handle);
+
+	if (vcd_status) {
+		mutex_unlock(&mpq_dvb_video_device->lock);
+		return false;
+	}
+	client_ctx->user_ion_client = NULL;
+	mutex_destroy(&client_ctx->msg_queue_lock);
+	mutex_destroy(&client_ctx->enrty_queue_lock);
+	memset((void *)client_ctx, 0, sizeof(struct video_client_ctx));
+	mpq_dvb_video_device->num_clients--;
+	mutex_unlock(&mpq_dvb_video_device->lock);
+	return true;
+}
+
+static int mpq_int_vid_dec_open_client(struct video_client_ctx **vid_clnt_ctx,
+					int flags)
+{
+	int rc = 0;
+	s32 client_index;
+	struct video_client_ctx *client_ctx = NULL;
+	u8 client_count;
+
+	if (!vid_clnt_ctx) {
+		DBG("Invalid input\n");
+		return -EINVAL;
+	}
+	*vid_clnt_ctx = NULL;
+	client_count = vcd_get_num_of_clients();
+	if (client_count == VIDC_MAX_NUM_CLIENTS) {
+		ERR("ERROR : vid_dec_open() max number of clients"\
+			"limit reached\n");
+		return -ENOMEM;
+	}
+
+	DBG(" Virtual Address of ioremap is %p\n",
+				mpq_dvb_video_device->virt_base);
+	if (!mpq_dvb_video_device->num_clients)
+		if (!vidc_load_firmware())
+			return -ENOMEM;
+
+	client_index = mpq_int_vid_dec_get_empty_client_index();
+	if (client_index == -1) {
+		DBG("%s() : No free clients client_index == -1\n", __func__);
+		vidc_release_firmware();
+		return -ENOMEM;
+	}
+	client_ctx = &mpq_dvb_video_device->vdec_clients[client_index];
+	mpq_dvb_video_device->num_clients++;
+	init_completion(&client_ctx->event);
+	mutex_init(&client_ctx->msg_queue_lock);
+	mutex_init(&client_ctx->enrty_queue_lock);
+	INIT_LIST_HEAD(&client_ctx->msg_queue);
+	init_waitqueue_head(&client_ctx->msg_wait);
+	client_ctx->stop_msg = 0;
+	client_ctx->stop_called = false;
+	client_ctx->stop_sync_cb = false;
+	client_ctx->dmx_disable = 0;
+	if (vcd_get_ion_status()) {
+		client_ctx->user_ion_client = vcd_get_ion_client();
+		if (!client_ctx->user_ion_client) {
+			ERR("vcd_open ion client get failed");
+			rc = -ENOMEM;
+			goto client_failure;
+		}
+	}
+	rc = vcd_open(mpq_dvb_video_device->device_handle, true,
+				  mpq_int_vid_dec_vcd_cb, client_ctx, flags);
+	if (!rc) {
+		wait_for_completion(&client_ctx->event);
+		if (client_ctx->event_status) {
+			DBG("callback for vcd_open returned error: %u",
+				client_ctx->event_status);
+			rc = -ENODEV;
+			goto client_failure;
+		}
+	} else {
+		DBG("vcd_open returned error: %u", rc);
+		goto client_failure;
+	}
+	client_ctx->seq_header_set = false;
+	*vid_clnt_ctx = client_ctx;
+
+	return 0;
+
+client_failure:
+	vidc_release_firmware();
+	mpq_dvb_video_device->num_clients--;
+	mutex_destroy(&client_ctx->msg_queue_lock);
+	mutex_destroy(&client_ctx->enrty_queue_lock);
+	memset((void *)client_ctx, 0, sizeof(struct video_client_ctx));
+	return rc;
+}
+
+static int mpq_dvb_video_open(struct inode *inode, struct file *file)
+{
+	int rc;
+	struct mpq_dvb_video_inst *dev_inst   = NULL;
+	struct dvb_device         *device     = NULL;
+
+	DBG("Inside %s()", __func__);
+	mutex_lock(&mpq_dvb_video_device->lock);
+
+	/* Open the dvb/video instance */
+	rc = dvb_generic_open(inode, file);
+	if (rc) {
+		DBG("Failed in dvb_generic_open with return value :%d\n",
+					rc);
+		mutex_unlock(&mpq_dvb_video_device->lock);
+		return rc;
+
+	}
+
+	device   = (struct dvb_device *)file->private_data;
+	dev_inst = (struct mpq_dvb_video_inst *)device->priv;
+
+	if (dev_inst->client_ctx) {
+		dvb_generic_release(inode, file);
+		mutex_unlock(&mpq_dvb_video_device->lock);
+		return -EEXIST;
+	}
+
+	rc = mpq_int_vid_dec_open_client(&dev_inst->client_ctx, 0);
+	if (rc) {
+		dvb_generic_release(inode, file);
+		mutex_unlock(&mpq_dvb_video_device->lock);
+		return rc;
+	}
+
+	if (!dev_inst->client_ctx) {
+		dvb_generic_release(inode, file);
+		mutex_unlock(&mpq_dvb_video_device->lock);
+		return -ENOMEM;
+	}
+
+	/* Set default source to memory for easier handling */
+	dev_inst->source = VIDEO_SOURCE_MEMORY;
+
+	mutex_unlock(&mpq_dvb_video_device->lock);
+
+	return rc;
+}
+
+static int mpq_dvb_video_term_dmx_src(struct mpq_dvb_video_inst *dev_inst)
+{
+
+	struct mpq_dmx_src_data *dmx_data = dev_inst->dmx_src_data;
+
+	if (NULL == dmx_data)
+		return 0;
+
+	kthread_stop(dmx_data->data_task);
+	mutex_destroy(&dmx_data->msg_queue_lock);
+
+	kfree(dmx_data);
+	dev_inst->dmx_src_data = NULL;
+
+	return 0;
+
+}
+
+static int mpq_dvb_video_release(struct inode *inode, struct file *file)
+{
+	struct dvb_device *device = file->private_data;
+	struct mpq_dvb_video_inst *dev_inst = device->priv;
+
+	vidc_cleanup_addr_table(dev_inst->client_ctx, BUFFER_TYPE_OUTPUT);
+	vidc_cleanup_addr_table(dev_inst->client_ctx, BUFFER_TYPE_INPUT);
+	if (dev_inst->source == VIDEO_SOURCE_DEMUX)
+		mpq_dvb_video_term_dmx_src(dev_inst);
+	mpq_int_vid_dec_close_client(dev_inst->client_ctx);
+	memset((void *)dev_inst, 0, sizeof(struct mpq_dvb_video_inst));
+	vidc_release_firmware();
+	dvb_generic_release(inode, file);
+	return 0;
+}
+
+static void *mpq_int_vid_dec_map_dev_base_addr(void *device_name)
+{
+	return mpq_dvb_video_device->virt_base;
+}
+
+static int mpq_int_vid_dec_vcd_init(void)
+{
+	int rc;
+	struct vcd_init_config vcd_init_config;
+	u32 i;
+
+	/* init_timer(&hw_timer); */
+	DBG("msm_vidc_dec: Inside %s()", __func__);
+	mpq_dvb_video_device->num_clients = 0;
+
+	for (i = 0; i < VIDC_MAX_NUM_CLIENTS; i++) {
+		memset((void *)&mpq_dvb_video_device->vdec_clients[i], 0,
+		       sizeof(mpq_dvb_video_device->vdec_clients[i]));
+	}
+
+	mutex_init(&mpq_dvb_video_device->lock);
+	mpq_dvb_video_device->virt_base = vidc_get_ioaddr();
+	DBG("%s() : base address for VIDC core %u\n", __func__, \
+		(int)mpq_dvb_video_device->virt_base);
+
+	if (!mpq_dvb_video_device->virt_base) {
+		DBG("%s() : ioremap failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	vcd_init_config.device_name = "MPQ_VIDC";
+	vcd_init_config.map_dev_base_addr = mpq_int_vid_dec_map_dev_base_addr;
+	vcd_init_config.interrupt_clr = NULL;
+	vcd_init_config.register_isr = NULL;
+	vcd_init_config.deregister_isr = NULL;
+	vcd_init_config.timer_create = vidc_timer_create;
+	vcd_init_config.timer_release = vidc_timer_release;
+	vcd_init_config.timer_start = vidc_timer_start;
+	vcd_init_config.timer_stop = vidc_timer_stop;
+
+	rc = vcd_init(&vcd_init_config,
+			&mpq_dvb_video_device->device_handle);
+
+	if (rc) {
+		DBG("%s() : vcd_init failed\n", __func__);
+		mutex_destroy(&mpq_dvb_video_device->lock);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int mpq_int_vdec_get_fps(struct video_client_ctx *client_ctx,
+				unsigned int *fps)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_frame_rate vcd_frame_rate;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (NULL == fps)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_FRAME_RATE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_frame_rate);
+	vcd_frame_rate.fps_numerator = 0;
+	vcd_frame_rate.fps_denominator = 1;
+
+	*fps = 0;
+	vcd_status = vcd_get_property(client_ctx->vcd_handle,
+				      &vcd_property_hdr, &vcd_frame_rate);
+
+	if (vcd_status)
+		return -EINVAL;
+	else {
+		*fps = (vcd_frame_rate.fps_numerator * 1000)
+			/(vcd_frame_rate.fps_denominator);
+		return 0;
+	}
+}
+
+static int mpq_dvb_video_command_handler(struct mpq_dvb_video_inst *dev_inst,
+					void *parg)
+{
+	struct video_client_ctx *client_ctx = dev_inst->client_ctx;
+	struct video_command *cmd = parg;
+	int rc = 0;
+
+	if (cmd == NULL)
+		return -EINVAL;
+
+	switch (cmd->cmd) {
+	case VIDEO_CMD_SET_CODEC:
+		DBG("cmd : VIDEO_CMD_SET_CODEC\n");
+		rc = mpq_int_vid_dec_set_codec(client_ctx, cmd->codec);
+		break;
+	case VIDEO_CMD_GET_CODEC:
+		DBG("cmd : VIDEO_CMD_GET_CODEC\n");
+		rc = mpq_int_vid_dec_get_codec(client_ctx, &cmd->codec);
+		break;
+	case VIDEO_CMD_SET_OUTPUT_FORMAT:
+		DBG("cmd : VIDEO_CMD_SET_OUTPUT_FORMAT\n");
+		rc = mpq_int_vid_dec_set_output_format(client_ctx,
+							cmd->format);
+		break;
+	case VIDEO_CMD_GET_OUTPUT_FORMAT:
+		DBG("cmd : VIDEO_CMD_GET_OUTPUT_FORMAT\n");
+		rc = mpq_int_vid_dec_get_output_format(client_ctx,
+							&cmd->format);
+		break;
+	case VIDEO_CMD_GET_PIC_RES:
+		DBG("cmd : VIDEO_CMD_GET_PIC_RES\n");
+		rc = mpq_int_vid_dec_get_frame_resolution(client_ctx,
+						&cmd->frame_res);
+		break;
+	case VIDEO_CMD_SET_INPUT_BUFFERS:
+		DBG("cmd : VIDEO_CMD_SET_INPUT_BUFFERS\n");
+		rc = mpq_int_vid_dec_set_buffer(dev_inst, &cmd->buffer,
+						BUFFER_TYPE_INPUT);
+		break;
+	case VIDEO_CMD_SET_OUTPUT_BUFFERS:
+		DBG("cmd : VIDEO_CMD_SET_OUTPUT_BUFFERS\n");
+		rc = mpq_int_vid_dec_set_buffer(dev_inst, &cmd->buffer,
+						BUFFER_TYPE_OUTPUT);
+		break;
+	case VIDEO_CMD_FREE_INPUT_BUFFERS:
+		DBG("cmd : VIDEO_CMD_FREE_INPUT_BUFFERS\n");
+		rc = mpq_int_vid_dec_free_buffer(client_ctx, &cmd->buffer,
+						BUFFER_TYPE_INPUT);
+		break;
+	case VIDEO_CMD_FREE_OUTPUT_BUFFERS:
+		DBG("cmd : VIDEO_CMD_FREE_OUTPUT_BUFFERS\n");
+		rc = mpq_int_vid_dec_free_buffer(client_ctx, &cmd->buffer,
+							BUFFER_TYPE_OUTPUT);
+		break;
+	case VIDEO_CMD_GET_BUFFER_REQ:
+		DBG("cmd : VIDEO_CMD_GET_BUFFER_REQ\n");
+		rc = mpq_int_vid_dec_get_buffer_req(client_ctx, &cmd->buf_req);
+		break;
+	case VIDEO_CMD_READ_RAW_OUTPUT:
+		DBG("cmd : VIDEO_CMD_READ_RAW_OUTPUT\n");
+		rc = mpq_int_vid_dec_fill_output_buffer(client_ctx,
+							&cmd->buffer);
+		break;
+	case VIDEO_CMD_SET_H264_MV_BUFFER:
+		DBG("cmd : VIDEO_CMD_SET_H264_MV_BUFFER\n");
+		rc = mpq_int_vid_dec_set_h264_mv_buffers(client_ctx,
+							&cmd->mv_buffer_prop);
+		break;
+	case VIDEO_CMD_GET_H264_MV_BUFFER:
+		DBG("cmd : VIDEO_CMD_GET_H264_MV_BUFFER\n");
+		rc = mpq_int_vid_dec_get_h264_mv_buffer_size(client_ctx,
+							&cmd->mv_buffer_req);
+		break;
+	case VIDEO_CMD_FREE_H264_MV_BUFFER:
+		DBG("cmd : VIDEO_CMD_FREE_H264_MV_BUFFER\n");
+		rc = mpq_int_vid_dec_free_h264_mv_buffers(client_ctx);
+		break;
+	case VIDEO_CMD_CLEAR_INPUT_BUFFER:
+		DBG("cmd : VIDEO_CMD_CLEAR_INPUT_BUFFER\n");
+		rc = mpq_int_vid_dec_flush(client_ctx, VDEC_FLUSH_TYPE_INPUT);
+		break;
+	case VIDEO_CMD_CLEAR_OUTPUT_BUFFER:
+		DBG("cmd : VIDEO_CMD_CLEAR_OUTPUT_BUFFER\n");
+		rc = mpq_int_vid_dec_flush(client_ctx, VDEC_FLUSH_TYPE_OUTPUT);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+
+static ssize_t mpq_dvb_video_write(struct file *file, const char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	int rc = 0;
+	struct dvb_device *device = file->private_data;
+	struct mpq_dvb_video_inst *dev_inst = NULL;
+
+	struct video_data_buffer *input_frame =
+				(struct video_data_buffer *)buf;
+
+	if ((device == NULL) || (input_frame == NULL))
+		return -EINVAL;
+
+	dev_inst = device->priv;
+	if (dev_inst == NULL)
+		return -EINVAL;
+
+	rc = mpq_int_vid_dec_decode_frame(dev_inst->client_ctx, input_frame);
+	if (rc)
+		return -EIO;
+
+	return input_frame->buffer_len;
+}
+
+static int mpq_dvb_video_get_event(struct video_client_ctx *client_ctx,
+				struct video_event *ev)
+{
+	int rc;
+	struct vdec_msginfo vdec_msg_info;
+
+	memset(ev, 0, sizeof(struct video_event));
+
+	rc = mpq_int_vid_dec_get_next_msg(client_ctx, &vdec_msg_info);
+	if (rc)
+		return rc;
+
+	ev->status = vdec_msg_info.status_code;
+	/* Map the Message here */
+	switch (vdec_msg_info.msgcode) {
+	case VDEC_MSG_INVALID:
+		DBG("VDEC_MSG_INVALID\n");
+		break;
+	case VDEC_MSG_RESP_INPUT_BUFFER_DONE:
+		DBG("VIDEO_EVENT_INPUT_BUFFER_DONE\n");
+		ev->type = VIDEO_EVENT_INPUT_BUFFER_DONE;
+		ev->u.buffer.client_data =
+				vdec_msg_info.msgdata.input_frame_clientdata;
+		break;
+	case VDEC_MSG_RESP_OUTPUT_BUFFER_DONE:
+		DBG("VIDEO_EVENT_OUTPUT_BUFFER_DONE\n");
+		ev->type = VIDEO_EVENT_OUTPUT_BUFFER_DONE;
+		ev->u.buffer.bufferaddr  =
+				vdec_msg_info.msgdata.output_frame.bufferaddr;
+		ev->u.buffer.buffer_len  =
+				vdec_msg_info.msgdata.output_frame.len;
+		ev->u.buffer.ip_buffer_tag = vdec_msg_info.msgdata.\
+					output_frame.input_frame_clientdata;
+		ev->u.buffer.client_data = vdec_msg_info.msgdata.\
+					output_frame.client_data;
+		ev->u.buffer.pts         =
+				vdec_msg_info.msgdata.output_frame.time_stamp;
+		ev->u.buffer.offset      =
+				vdec_msg_info.msgdata.output_frame.offset;
+		break;
+	case VDEC_MSG_RESP_START_DONE:
+		DBG("VIDEO_EVENT_DECODER_PLAYING\n");
+		ev->type = VIDEO_EVENT_DECODER_PLAYING;
+		break;
+	case VDEC_MSG_RESP_STOP_DONE:
+		DBG("VIDEO_EVENT_DECODER_FREEZED\n");
+		ev->type = VIDEO_EVENT_DECODER_STOPPED;
+		break;
+	case VDEC_MSG_RESP_PAUSE_DONE:
+		DBG("VDEC_MSG_RESP_PAUSE_DONE\n");
+		ev->type = VIDEO_EVENT_DECODER_FREEZED;
+		break;
+	case VDEC_MSG_RESP_RESUME_DONE:
+		DBG("VIDEO_EVENT_DECODER_RESUMED\n");
+		ev->type = VIDEO_EVENT_DECODER_RESUMED;
+		break;
+	case VDEC_MSG_EVT_CONFIG_CHANGED:
+	case VDEC_MSG_EVT_INFO_CONFIG_CHANGED:
+		DBG("VIDEO_EVENT_SEQ_HDR_FOUND\n");
+		ev->type = VIDEO_EVENT_SEQ_HDR_FOUND;
+		break;
+	case VDEC_MSG_RESP_FLUSH_OUTPUT_DONE:
+		DBG("VIDEO_EVENT_OUTPUT_FLUSH_DONE\n");
+		ev->type = VIDEO_EVENT_OUTPUT_FLUSH_DONE;
+		break;
+	case VDEC_MSG_RESP_OUTPUT_FLUSHED:
+		DBG("VIDEO_EVENT_OUTPUT_FLUSHED\n");
+		ev->type = VIDEO_EVENT_OUTPUT_FLUSHED;
+		ev->u.buffer.bufferaddr  =
+				vdec_msg_info.msgdata.output_frame.bufferaddr;
+		ev->u.buffer.buffer_len  =
+				vdec_msg_info.msgdata.output_frame.len;
+		ev->u.buffer.ip_buffer_tag = vdec_msg_info.msgdata.\
+				output_frame.input_frame_clientdata;
+		ev->u.buffer.client_data = vdec_msg_info.msgdata.\
+				output_frame.client_data;
+		ev->u.buffer.pts         =
+				vdec_msg_info.msgdata.output_frame.time_stamp;
+		ev->u.buffer.offset      =
+				vdec_msg_info.msgdata.output_frame.offset;
+		break;
+	case VDEC_MSG_RESP_FLUSH_INPUT_DONE:
+		DBG("VIDEO_EVENT_INPUT_FLUSH_DONE\n");
+		ev->type = VIDEO_EVENT_INPUT_FLUSH_DONE;
+		break;
+	case VDEC_MSG_RESP_INPUT_FLUSHED:
+		DBG("VIDEO_EVENT_INPUT_FLUSHED\n");
+		ev->type = VIDEO_EVENT_INPUT_FLUSHED;
+		ev->u.buffer.client_data =
+				vdec_msg_info.msgdata.input_frame_clientdata;
+		break;
+	}
+	return 0;
+}
+
+static int mpq_dvb_video_play(struct mpq_dvb_video_inst *dev_inst)
+{
+	return mpq_int_vid_dec_start_stop(dev_inst->client_ctx, true);
+}
+
+static int mpq_dvb_video_stop(struct video_client_ctx *client_ctx)
+{
+	return mpq_int_vid_dec_start_stop(client_ctx, false);
+}
+
+static void mpq_dvb_video_get_stream_if(
+				enum mpq_adapter_stream_if interface_id,
+				void *arg)
+{
+	struct mpq_dvb_video_inst *dev_inst = arg;
+
+	DBG("In mpq_dvb_video_get_stream_if : %d\n", interface_id);
+
+	mpq_adapter_get_stream_if(interface_id,
+			&dev_inst->dmx_src_data->stream_buffer);
+
+	wake_up(&dev_inst->dmx_src_data->msg_wait);
+}
+
+static int mpq_dvb_video_init_dmx_src(struct mpq_dvb_video_inst *dev_inst,
+					int device_id)
+{
+	int rc;
+
+	dev_inst->dmx_src_data =  kzalloc(sizeof(struct mpq_dmx_src_data),
+						GFP_KERNEL);
+	if (dev_inst->dmx_src_data == NULL)
+		return -ENOMEM;
+
+	rc = mpq_adapter_get_stream_if(
+		(enum mpq_adapter_stream_if)device_id,
+		&dev_inst->dmx_src_data->stream_buffer);
+
+	if (rc) {
+		kfree(dev_inst->dmx_src_data);
+		return -ENODEV;
+	} else if (dev_inst->dmx_src_data->stream_buffer == NULL) {
+		DBG("Stream Buffer is NULL. Resigtering Notifier.\n");
+		rc = mpq_adapter_notify_stream_if(
+			(enum mpq_adapter_stream_if)device_id,
+			mpq_dvb_video_get_stream_if,
+			(void *)dev_inst);
+		if (rc) {
+			kfree(dev_inst->dmx_src_data);
+			return -ENODEV;
+		}
+	}
+
+	mutex_init(&dev_inst->dmx_src_data->msg_queue_lock);
+	INIT_LIST_HEAD(&dev_inst->dmx_src_data->msg_queue);
+	init_waitqueue_head(&dev_inst->dmx_src_data->msg_wait);
+
+	dev_inst->dmx_src_data->data_task = kthread_run(
+			mpq_bcast_data_handler,	(void *)dev_inst,
+			vid_thread_names[device_id]);
+
+	return 0;
+}
+
+static int mpq_dvb_video_set_source(struct dvb_device *device,
+				video_stream_source_t source)
+{
+	int rc = 0;
+	struct mpq_dvb_video_inst *dev_inst =
+			(struct mpq_dvb_video_inst *)device->priv;
+
+	if (dev_inst->source == source)
+		return rc;
+
+	if ((VIDEO_SOURCE_MEMORY == source) &&
+		(VIDEO_SOURCE_DEMUX == dev_inst->source))
+		mpq_dvb_video_term_dmx_src(dev_inst);
+
+	dev_inst->source = source;
+	if (VIDEO_SOURCE_DEMUX == source)
+		rc = mpq_dvb_video_init_dmx_src(dev_inst, device->id);
+
+	return rc;
+}
+
+static int mpq_dvb_video_ioctl(struct file *file,
+				unsigned int cmd, void *parg)
+{
+	int rc;
+	struct dvb_device *device = (struct dvb_device *)file->private_data;
+	struct video_client_ctx *client_ctx = NULL;
+	struct mpq_dvb_video_inst *dev_inst = NULL;
+
+	if (device == NULL)
+		return -EINVAL;
+
+	dev_inst = (struct mpq_dvb_video_inst *)device->priv;
+	if (dev_inst == NULL)
+		return -EINVAL;
+
+	client_ctx = (struct video_client_ctx *)dev_inst->client_ctx;
+	if (client_ctx == NULL)
+		return -EINVAL;
+
+	switch (cmd) {
+	case VIDEO_PLAY:
+		DBG("ioctl : VIDEO_PLAY\n");
+		rc = mpq_dvb_video_play(dev_inst);
+		break;
+	case VIDEO_STOP:
+		DBG("ioctl : VIDEO_STOP\n");
+		rc = mpq_dvb_video_stop(client_ctx);
+		break;
+	case VIDEO_FREEZE:
+		DBG("ioctl : VIDEO_FREEZE\n");
+		rc = mpq_int_vid_dec_pause_resume(client_ctx, true);
+		break;
+	case VIDEO_CONTINUE:
+		DBG("ioctl : VIDEO_CONTINUE\n");
+		rc = mpq_int_vid_dec_pause_resume(client_ctx, false);
+		break;
+	case VIDEO_CLEAR_BUFFER:
+		DBG("ioctl : VIDEO_CLEAR_BUFFER\n");
+		rc = mpq_int_vid_dec_flush(client_ctx,
+				VDEC_FLUSH_TYPE_ALL);
+		break;
+	case VIDEO_COMMAND:
+	case VIDEO_TRY_COMMAND:
+		DBG("ioctl : VIDEO_COMMAND\n");
+		rc = mpq_dvb_video_command_handler(dev_inst, parg);
+		break;
+	case VIDEO_GET_FRAME_RATE:
+		DBG("ioctl : VIDEO_GET_FRAME_RATE\n");
+		rc = mpq_int_vdec_get_fps(client_ctx,
+				(unsigned int *)parg);
+		break;
+	case VIDEO_GET_EVENT:
+		DBG("ioctl : VIDEO_GET_EVENT\n");
+		rc = mpq_dvb_video_get_event(client_ctx,
+				(struct video_event *)parg);
+		break;
+	case VIDEO_SELECT_SOURCE:
+		DBG("ioctl : VIDEO_SELECT_SOURCE\n");
+		rc = mpq_dvb_video_set_source(device,
+				(video_stream_source_t)parg);
+		break;
+	default:
+		ERR("Invalid IOCTL\n");
+		rc = -EINVAL;
+	}
+
+	return rc;
+
+}
+
+static unsigned int mpq_dvb_video_poll(struct file *file, poll_table *wait)
+{
+	struct dvb_device *device = file->private_data;
+	struct video_client_ctx *client_ctx = NULL;
+	struct mpq_dvb_video_inst *dev_inst = NULL;
+	unsigned int mask = 0;
+
+	DBG("In %s\n", __func__);
+
+	if (device == NULL)
+		return -EINVAL;
+
+	dev_inst = device->priv;
+	if (dev_inst == NULL)
+		return -EINVAL;
+
+	client_ctx = dev_inst->client_ctx;
+	if (client_ctx == NULL)
+		return -EINVAL;
+
+	poll_wait(file, &client_ctx->msg_wait, wait);
+	if (mpq_int_vid_dec_msg_pending(client_ctx))
+		mask |= POLLIN;
+	else
+		mask = 0;
+
+	return mask;
+}
+
+/*
+ * Driver Registration.
+ */
+static const struct file_operations mpq_dvb_video_fops = {
+	.owner		= THIS_MODULE,
+	.write		= mpq_dvb_video_write,
+	.unlocked_ioctl	= dvb_generic_ioctl,
+	.open		= mpq_dvb_video_open,
+	.release	= mpq_dvb_video_release,
+	.poll		= mpq_dvb_video_poll,
+	.llseek		= noop_llseek,
+};
+
+static const struct dvb_device mpq_dvb_video_device_ctrl = {
+	.priv		= NULL,
+	.users		= 4,
+	.readers	= 4,	/* arbitrary */
+	.writers	= 4,
+	.fops		= &mpq_dvb_video_fops,
+	.kernel_ioctl	= mpq_dvb_video_ioctl,
+};
+
+static int __init mpq_dvb_video_init(void)
+{
+	int rc, i = 0, j;
+
+	mpq_dvb_video_device = kzalloc(sizeof(struct mpq_dvb_video_dev),
+				GFP_KERNEL);
+	if (!mpq_dvb_video_device) {
+		ERR("%s Unable to allocate memory for mpq_dvb_video_dev\n",
+		       __func__);
+		return -ENOMEM;
+	}
+
+	mpq_dvb_video_device->mpq_adapter = mpq_adapter_get();
+	if (!mpq_dvb_video_device->mpq_adapter) {
+		ERR("%s Unable to get MPQ Adapter\n", __func__);
+		rc = -ENODEV;
+		goto free_region;
+	}
+
+	rc = mpq_int_vid_dec_vcd_init();
+	if (rc)
+		goto free_region;
+
+	for (i = 0; i < DVB_MPQ_NUM_VIDEO_DEVICES; i++) {
+
+		rc = dvb_register_device(mpq_dvb_video_device->mpq_adapter,
+				&mpq_dvb_video_device->dev_inst[i].video_dev,
+				&mpq_dvb_video_device_ctrl,
+				&mpq_dvb_video_device->dev_inst[i],
+				DVB_DEVICE_VIDEO);
+
+		if (rc) {
+			ERR("Failed in %s with at %d return value :%d\n",
+				__func__, i, rc);
+			goto free_region;
+		}
+
+	}
+
+	return 0;
+
+free_region:
+	for (j = 0; j < i; j++)
+		dvb_unregister_device(
+			mpq_dvb_video_device->dev_inst[j].video_dev);
+
+	kfree(mpq_dvb_video_device);
+	return rc;
+}
+
+static void __exit mpq_dvb_video_exit(void)
+{
+	int i;
+
+	for (i = 0; i < DVB_MPQ_NUM_VIDEO_DEVICES; i++)
+		dvb_unregister_device(
+			mpq_dvb_video_device->dev_inst[i].video_dev);
+
+	mutex_destroy(&mpq_dvb_video_device->lock);
+	kfree(mpq_dvb_video_device);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MPQ DVB Video driver");
+
+module_init(mpq_dvb_video_init);
+module_exit(mpq_dvb_video_exit);
diff --git a/drivers/media/dvb/mpq/video/mpq_dvb_video_internal.h b/drivers/media/dvb/mpq/video/mpq_dvb_video_internal.h
new file mode 100644
index 0000000..df337b9
--- /dev/null
+++ b/drivers/media/dvb/mpq/video/mpq_dvb_video_internal.h
@@ -0,0 +1,93 @@
+/* Copyright (c) 2010,2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 MPQ_DVB_VIDEO_INTERNAL_H
+#define MPQ_DVB_VIDEO_INTERNAL_H
+
+#include <linux/msm_vidc_dec.h>
+#include <media/msm/vidc_init.h>
+#include <linux/dvb/video.h>
+
+/*
+ * MPQ Specific Includes.
+ */
+#include "mpq_dvb_debug.h"
+#include "mpq_adapter.h"
+#include "mpq_stream_buffer.h"
+
+#define DVB_MPQ_NUM_VIDEO_DEVICES CONFIG_DVB_MPQ_NUM_VIDEO_DEVICES
+
+/*
+ * Input Buffer Requirements for Video Decoder.
+ */
+#define DVB_VID_NUM_IN_BUFFERS (2)
+#define DVB_VID_IN_BUFFER_SIZE (2*1024*1024)
+#define DVB_VID_IN_BUFFER_ALGN (8*1024)
+
+struct vid_dec_msg {
+	struct list_head list;
+	struct vdec_msginfo vdec_msg_info;
+};
+
+enum mpq_bcast_msgcode {
+	MPQ_BCAST_MSG_START,
+	MPQ_BCAST_MSG_IBD,
+	MPQ_BCAST_MSG_FLUSH,
+	MPQ_BCAST_MSG_TERM
+};
+
+struct mpq_bcast_msg_info {
+	enum mpq_bcast_msgcode code;
+	unsigned int data;
+};
+
+struct mpq_bcast_msg {
+	struct list_head list;
+	struct mpq_bcast_msg_info info;
+};
+
+struct mpq_dmx_src_data {
+	struct mpq_streambuffer *stream_buffer;
+	struct video_data_buffer in_buffer[DVB_VID_NUM_IN_BUFFERS];
+	struct list_head msg_queue;
+	wait_queue_head_t msg_wait;
+	struct mutex msg_queue_lock;
+	struct task_struct *data_task;
+};
+
+struct mpq_dvb_video_inst {
+	struct dvb_device  *video_dev;
+	video_stream_source_t source;
+	struct mpq_dmx_src_data *dmx_src_data;
+	struct video_client_ctx *client_ctx;
+};
+
+struct mpq_dvb_video_dev {
+
+	resource_size_t phys_base;
+	void __iomem *virt_base;
+	unsigned int irq;
+	struct clk *hclk;
+	struct clk *hclk_div2;
+	struct clk *pclk;
+	unsigned long hclk_rate;
+	struct mutex lock;
+	s32 device_handle;
+	struct dvb_adapter *mpq_adapter;
+	struct mpq_dvb_video_inst dev_inst[DVB_MPQ_NUM_VIDEO_DEVICES];
+	struct video_client_ctx vdec_clients[DVB_MPQ_NUM_VIDEO_DEVICES];
+	u32 num_clients;
+	void(*timer_handler)(void *);
+};
+
+#endif /* MPQ_DVB_VIDEO_INTERNAL_H */
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index 7996ed1..e5258f1 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -195,6 +195,14 @@
 		rc = -EINVAL;
 		return rc;
 	}
+
+	if (csid_dev->csid_state == CSID_POWER_UP) {
+		pr_err("%s: csid invalid state %d\n", __func__,
+			csid_dev->csid_state);
+		rc = -EINVAL;
+		return rc;
+	}
+
 	csid_dev->base = ioremap(csid_dev->mem->start,
 		resource_size(csid_dev->mem));
 	if (!csid_dev->base) {
@@ -262,6 +270,7 @@
 	enable_irq(csid_dev->irq->start);
 
 	msm_csid_reset(csid_dev);
+	csid_dev->csid_state = CSID_POWER_UP;
 	return rc;
 
 clk_enable_failed:
@@ -294,6 +303,12 @@
 {
 	uint32_t irq;
 
+	if (csid_dev->csid_state != CSID_POWER_UP) {
+		pr_err("%s: csid invalid state %d\n", __func__,
+			csid_dev->csid_state);
+		return -EINVAL;
+	}
+
 	irq = msm_camera_io_r(csid_dev->base + CSID_IRQ_STATUS_ADDR);
 	msm_camera_io_w(irq, csid_dev->base + CSID_IRQ_CLEAR_CMD_ADDR);
 	msm_camera_io_w(0, csid_dev->base + CSID_IRQ_MASK_ADDR);
@@ -326,6 +341,7 @@
 
 	iounmap(csid_dev->base);
 	csid_dev->base = NULL;
+	csid_dev->csid_state = CSID_POWER_DOWN;
 	return 0;
 }
 
@@ -528,6 +544,7 @@
 		goto csid_no_resource;
 	}
 
+	new_csid_dev->csid_state = CSID_POWER_DOWN;
 	return 0;
 
 csid_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_csid.h b/drivers/media/video/msm/csi/msm_csid.h
index 398acbc..1d4de01 100644
--- a/drivers/media/video/msm/csi/msm_csid.h
+++ b/drivers/media/video/msm/csi/msm_csid.h
@@ -18,6 +18,11 @@
 #include <media/v4l2-subdev.h>
 #include <media/msm_camera.h>
 
+enum msm_csid_state_t {
+	CSID_POWER_UP,
+	CSID_POWER_DOWN,
+};
+
 struct csid_device {
 	struct platform_device *pdev;
 	struct v4l2_subdev subdev;
@@ -29,6 +34,7 @@
 	struct mutex mutex;
 	struct completion reset_complete;
 	uint32_t hw_version;
+	enum msm_csid_state_t csid_state;
 
 	struct clk *csid_clk[5];
 };
diff --git a/drivers/media/video/msm/csi/msm_csiphy.c b/drivers/media/video/msm/csi/msm_csiphy.c
index 3113295..065ba34 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.c
+++ b/drivers/media/video/msm/csi/msm_csiphy.c
@@ -162,6 +162,13 @@
 		return rc;
 	}
 
+	if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) {
+		pr_err("%s: csiphy invalid state %d\n", __func__,
+			csiphy_dev->csiphy_state);
+		rc = -EINVAL;
+		return rc;
+	}
+
 	if (csiphy_dev->ref_count++) {
 		CDBG("%s csiphy refcount = %d\n", __func__,
 			csiphy_dev->ref_count);
@@ -202,6 +209,7 @@
 	csiphy_dev->hw_version =
 		msm_camera_io_r(csiphy_dev->base + MIPI_CSIPHY_HW_VERSION_ADDR);
 
+	csiphy_dev->csiphy_state = CSIPHY_POWER_UP;
 	return 0;
 }
 
@@ -217,6 +225,13 @@
 		pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__);
 		return 0;
 	}
+
+	if (csiphy_dev->csiphy_state != CSIPHY_POWER_UP) {
+		pr_err("%s: csiphy invalid state %d\n", __func__,
+			csiphy_dev->csiphy_state);
+		return -EINVAL;
+	}
+
 	CDBG("%s csiphy_params, lane assign %x mask = %x\n",
 		__func__,
 		csi_lane_params->csi_lane_assign,
@@ -264,6 +279,7 @@
 
 	iounmap(csiphy_dev->base);
 	csiphy_dev->base = NULL;
+	csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN;
 	return 0;
 }
 
@@ -408,6 +424,7 @@
 	new_csiphy_dev->subdev.entity.name = pdev->name;
 	new_csiphy_dev->subdev.entity.revision =
 		new_csiphy_dev->subdev.devnode->num;
+	new_csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN;
 	return 0;
 
 csiphy_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_csiphy.h b/drivers/media/video/msm/csi/msm_csiphy.h
index 4b2e68e..2fb21d2 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.h
+++ b/drivers/media/video/msm/csi/msm_csiphy.h
@@ -20,6 +20,11 @@
 
 #define MAX_CSIPHY 3
 
+enum msm_csiphy_state_t {
+	CSIPHY_POWER_UP,
+	CSIPHY_POWER_DOWN,
+};
+
 struct csiphy_device {
 	struct platform_device *pdev;
 	struct v4l2_subdev subdev;
@@ -29,6 +34,7 @@
 	void __iomem *base;
 	struct mutex mutex;
 	uint32_t hw_version;
+	enum msm_csiphy_state_t csiphy_state;
 
 	struct clk *csiphy_clk[3];
 	uint8_t ref_count;
diff --git a/drivers/media/video/msm/csi/msm_ispif.c b/drivers/media/video/msm/csi/msm_ispif.c
index ab97138..912e2ce 100644
--- a/drivers/media/video/msm/csi/msm_ispif.c
+++ b/drivers/media/video/msm/csi/msm_ispif.c
@@ -679,6 +679,14 @@
 {
 	int rc = 0;
 	CDBG("%s called %d\n", __func__, __LINE__);
+
+	if (ispif->ispif_state == ISPIF_POWER_UP) {
+		pr_err("%s: ispif invalid state %d\n", __func__,
+			ispif->ispif_state);
+		rc = -EINVAL;
+		return rc;
+	}
+
 	spin_lock_init(&ispif_tasklet_lock);
 	INIT_LIST_HEAD(&ispif_tasklet_q);
 	rc = request_irq(ispif->irq->start, msm_io_ispif_irq,
@@ -701,11 +709,18 @@
 			return rc;
 	}
 	rc = msm_ispif_reset(ispif);
+	ispif->ispif_state = ISPIF_POWER_UP;
 	return rc;
 }
 
 static void msm_ispif_release(struct ispif_device *ispif)
 {
+	if (ispif->ispif_state != ISPIF_POWER_UP) {
+		pr_err("%s: ispif invalid state %d\n", __func__,
+			ispif->ispif_state);
+		return;
+	}
+
 	CDBG("%s, free_irq\n", __func__);
 	free_irq(ispif->irq->start, ispif);
 	tasklet_kill(&ispif->ispif_tasklet);
@@ -717,6 +732,7 @@
 		msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
 			ispif->ispif_clk, ARRAY_SIZE(ispif_8960_clk_info), 0);
 	}
+	ispif->ispif_state = ISPIF_POWER_DOWN;
 }
 
 static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg)
@@ -853,6 +869,7 @@
 	ispif->subdev.entity.group_id = ISPIF_DEV;
 	ispif->subdev.entity.name = pdev->name;
 	ispif->subdev.entity.revision = ispif->subdev.devnode->num;
+	ispif->ispif_state = ISPIF_POWER_DOWN;
 	return 0;
 
 ispif_no_mem:
diff --git a/drivers/media/video/msm/csi/msm_ispif.h b/drivers/media/video/msm/csi/msm_ispif.h
index a581a37..ea69959 100644
--- a/drivers/media/video/msm/csi/msm_ispif.h
+++ b/drivers/media/video/msm/csi/msm_ispif.h
@@ -23,6 +23,11 @@
 	uint32_t ispifIrqStatus2;
 };
 
+enum msm_ispif_state_t {
+	ISPIF_POWER_UP,
+	ISPIF_POWER_DOWN,
+};
+
 struct ispif_device {
 	struct platform_device *pdev;
 	struct v4l2_subdev subdev;
@@ -40,6 +45,7 @@
 	uint32_t rdi1_sof_count;
 	uint32_t rdi2_sof_count;
 	struct tasklet_struct ispif_tasklet;
+	enum msm_ispif_state_t ispif_state;
 };
 
 struct ispif_isr_queue_cmd {
diff --git a/drivers/media/video/msm/io/msm_camera_io_util.c b/drivers/media/video/msm/io/msm_camera_io_util.c
index 5dfa6a2..613850b 100644
--- a/drivers/media/video/msm/io/msm_camera_io_util.c
+++ b/drivers/media/video/msm/io/msm_camera_io_util.c
@@ -458,3 +458,39 @@
 	}
 	return rc;
 }
+
+void msm_camera_bus_scale_cfg(uint32_t bus_perf_client,
+		enum msm_bus_perf_setting perf_setting)
+{
+	int rc = 0;
+	if (!bus_perf_client) {
+		pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+		return;
+	}
+
+	switch (perf_setting) {
+	case S_EXIT:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 1);
+		msm_bus_scale_unregister_client(bus_perf_client);
+		break;
+	case S_PREVIEW:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 1);
+		break;
+	case S_VIDEO:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 2);
+		break;
+	case S_CAPTURE:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 3);
+		break;
+	case S_ZSL:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 4);
+		break;
+	case S_LIVESHOT:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 5);
+		break;
+	case S_DEFAULT:
+		break;
+	default:
+		pr_warning("%s: INVALID CASE\n", __func__);
+	}
+}
diff --git a/drivers/media/video/msm/vfe/Makefile b/drivers/media/video/msm/vfe/Makefile
index 91f0e7f..250b55f 100644
--- a/drivers/media/video/msm/vfe/Makefile
+++ b/drivers/media/video/msm/vfe/Makefile
@@ -16,5 +16,5 @@
 obj-$(CONFIG_ARCH_MSM_ARM11) += msm_vfe7x.o
 obj-$(CONFIG_ARCH_QSD8X50) += msm_vfe8x.o msm_vfe8x_proc.o
 obj-$(CONFIG_ARCH_MSM8960) += msm_vfe32.o
-obj-$(CONFIG_ARCH_MSM8974) += msm_vfe40.o msm_vfe40_axi.o
+obj-$(CONFIG_ARCH_MSM8974) += msm_vfe40.o
 obj-$(CONFIG_MSM_CAMERA_V4L2) += msm_vfe_stats_buf.o
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c
index 875e034..1297379 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.c
+++ b/drivers/media/video/msm/vfe/msm_vfe40.c
@@ -15,226 +15,597 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/io.h>
+#include <linux/of.h>
 #include <linux/atomic.h>
 #include <linux/regulator/consumer.h>
 #include <linux/clk.h>
-#include <linux/of.h>
 #include <mach/irqs.h>
 #include <mach/camera.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
 #include <media/msm_isp.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
 
 #include "msm.h"
+#include "msm_cam_server.h"
 #include "msm_vfe40.h"
 
+atomic_t irq_cnt;
+
+#define VFE_WM_CFG_BASE 0x0070
+#define VFE_WM_CFG_LEN 0x0024
+
+#define vfe40_get_ch_ping_addr(base, chn) \
+	(msm_camera_io_r((base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn)))
+#define vfe40_get_ch_pong_addr(base, chn) \
+	(msm_camera_io_r((base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn) + 4))
+#define vfe40_get_ch_addr(ping_pong, base, chn) \
+	((((ping_pong) & (1 << (chn))) == 0) ? \
+	(vfe40_get_ch_pong_addr((base), chn)) : \
+	(vfe40_get_ch_ping_addr((base), chn)))
+
+#define vfe40_put_ch_ping_addr(base, chn, addr) \
+	(msm_camera_io_w((addr), \
+	(base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn)))
+#define vfe40_put_ch_pong_addr(base, chn, addr) \
+	(msm_camera_io_w((addr), \
+	(base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn) + 4))
+#define vfe40_put_ch_addr(ping_pong, base, chn, addr) \
+	(((ping_pong) & (1 << (chn))) == 0 ?   \
+	vfe40_put_ch_pong_addr((base), (chn), (addr)) : \
+	vfe40_put_ch_ping_addr((base), (chn), (addr)))
+
+static uint32_t vfe_clk_rate;
+static void vfe40_send_isp_msg(struct v4l2_subdev *sd,
+	uint32_t vfeFrameId, uint32_t isp_msg_id);
+
+
 struct vfe40_isr_queue_cmd {
 	struct list_head list;
 	uint32_t                           vfeInterruptStatus0;
 	uint32_t                           vfeInterruptStatus1;
 };
 
-static const char * const vfe40_general_cmd[] = {
-	"DUMMY_0",  /* 0 */
-	"SET_CLK",
-	"RESET",
-	"START",
-	"TEST_GEN_START",
-	"OPERATION_CFG",  /* 5 */
-	"AXI_OUT_CFG",
-	"CAMIF_CFG",
-	"AXI_INPUT_CFG",
-	"BLACK_LEVEL_CFG",
-	"ROLL_OFF_CFG",  /* 10 */
-	"DEMUX_CFG",
-	"FOV_CFG",
-	"MAIN_SCALER_CFG",
-	"WB_CFG",
-	"COLOR_COR_CFG", /* 15 */
-	"RGB_G_CFG",
-	"LA_CFG",
-	"CHROMA_EN_CFG",
-	"CHROMA_SUP_CFG",
-	"MCE_CFG", /* 20 */
-	"SK_ENHAN_CFG",
-	"ASF_CFG",
-	"S2Y_CFG",
-	"S2CbCr_CFG",
-	"CHROMA_SUBS_CFG",  /* 25 */
-	"OUT_CLAMP_CFG",
-	"FRAME_SKIP_CFG",
-	"DUMMY_1",
-	"DUMMY_2",
-	"DUMMY_3",  /* 30 */
-	"UPDATE",
-	"BL_LVL_UPDATE",
-	"DEMUX_UPDATE",
-	"FOV_UPDATE",
-	"MAIN_SCALER_UPDATE",  /* 35 */
-	"WB_UPDATE",
-	"COLOR_COR_UPDATE",
-	"RGB_G_UPDATE",
-	"LA_UPDATE",
-	"CHROMA_EN_UPDATE",  /* 40 */
-	"CHROMA_SUP_UPDATE",
-	"MCE_UPDATE",
-	"SK_ENHAN_UPDATE",
-	"S2CbCr_UPDATE",
-	"S2Y_UPDATE",  /* 45 */
-	"ASF_UPDATE",
-	"FRAME_SKIP_UPDATE",
-	"CAMIF_FRAME_UPDATE",
-	"STATS_AF_UPDATE",
-	"STATS_AE_UPDATE",  /* 50 */
-	"STATS_AWB_UPDATE",
-	"STATS_RS_UPDATE",
-	"STATS_CS_UPDATE",
-	"STATS_SKIN_UPDATE",
-	"STATS_IHIST_UPDATE",  /* 55 */
-	"DUMMY_4",
-	"EPOCH1_ACK",
-	"EPOCH2_ACK",
-	"START_RECORDING",
-	"STOP_RECORDING",  /* 60 */
-	"DUMMY_5",
-	"DUMMY_6",
-	"CAPTURE",
-	"DUMMY_7",
-	"STOP",  /* 65 */
-	"GET_HW_VERSION",
-	"GET_FRAME_SKIP_COUNTS",
-	"OUTPUT1_BUFFER_ENQ",
-	"OUTPUT2_BUFFER_ENQ",
-	"OUTPUT3_BUFFER_ENQ",  /* 70 */
-	"JPEG_OUT_BUF_ENQ",
-	"RAW_OUT_BUF_ENQ",
-	"RAW_IN_BUF_ENQ",
-	"STATS_AF_ENQ",
-	"STATS_AE_ENQ",  /* 75 */
-	"STATS_AWB_ENQ",
-	"STATS_RS_ENQ",
-	"STATS_CS_ENQ",
-	"STATS_SKIN_ENQ",
-	"STATS_IHIST_ENQ",  /* 80 */
-	"DUMMY_8",
-	"JPEG_ENC_CFG",
-	"DUMMY_9",
-	"STATS_AF_START",
-	"STATS_AF_STOP",  /* 85 */
-	"STATS_AE_START",
-	"STATS_AE_STOP",
-	"STATS_AWB_START",
-	"STATS_AWB_STOP",
-	"STATS_RS_START",  /* 90 */
-	"STATS_RS_STOP",
-	"STATS_CS_START",
-	"STATS_CS_STOP",
-	"STATS_SKIN_START",
-	"STATS_SKIN_STOP",  /* 95 */
-	"STATS_IHIST_START",
-	"STATS_IHIST_STOP",
-	"DUMMY_10",
-	"SYNC_TIMER_SETTING",
-	"ASYNC_TIMER_SETTING",  /* 100 */
-	"LIVESHOT",
-	"LA_SETUP",
-	"LINEARIZATION_CFG",
-	"DEMOSAICV3",
-	"DEMOSAICV3_ABCC_CFG", /* 105 */
-	"DEMOSAICV3_DBCC_CFG",
-	"DEMOSAICV3_DBPC_CFG",
-	"DEMOSAICV3_ABF_CFG",
-	"DEMOSAICV3_ABCC_UPDATE",
-	"DEMOSAICV3_DBCC_UPDATE", /* 110 */
-	"DEMOSAICV3_DBPC_UPDATE",
-	"XBAR_CFG",
-	"EZTUNE_CFG",
-	"V40_ZSL",
-	"LINEARIZATION_UPDATE", /*115*/
-	"DEMOSAICV3_ABF_UPDATE",
-	"CLF_CFG",
-	"CLF_LUMA_UPDATE",
-	"CLF_CHROMA_UPDATE",
-	"PCA_ROLL_OFF_CFG", /*120*/
-	"PCA_ROLL_OFF_UPDATE",
-	"GET_REG_DUMP",
-	"GET_LINEARIZATON_TABLE",
-	"GET_MESH_ROLLOFF_TABLE",
-	"GET_PCA_ROLLOFF_TABLE", /*125*/
-	"GET_RGB_G_TABLE",
-	"GET_LA_TABLE",
-	"DEMOSAICV3_UPDATE",
-	"ACTIVE_REGION_CONFIG",
-	"COLOR_PROCESSING_CONFIG", /*130*/
-	"STATS_WB_AEC_CONFIG",
-	"STATS_WB_AEC_UPDATE",
-	"Y_GAMMA_CONFIG",
-	"SCALE_OUTPUT1_CONFIG",
-	"SCALE_OUTPUT2_CONFIG", /*135*/
-	"CAPTURE_RAW",
-	"STOP_LIVESHOT",
-	"RECONFIG_VFE",
-	"STATS_REQBUF_CFG",
-	"STATS_ENQUEUEBUF_CFG",/*140*/
-	"STATS_FLUSH_BUFQ_CFG",
-	"FOV_ENC_CFG",
-	"FOV_VIEW_CFG",
-	"FOV_ENC_UPDATE",
-	"FOV_VIEW_UPDATE",/*145*/
-	"SCALER_ENC_CFG",
-	"SCALER_VIEW_CFG",
-	"SCALER_ENC_UPDATE",
-	"SCALER_VIEW_UPDATE",
-	"COLORXFORM_ENC_CFG",/*150*/
-	"COLORXFORM_VIEW_CFG",
-	"COLORXFORM_ENC_UPDATE",
-	"COLORXFORM_VIEW_UPDATE",
+static struct vfe40_cmd_type vfe40_cmd[] = {
+	[1] = {VFE_CMD_SET_CLK},
+	[2] = {VFE_CMD_RESET},
+	[3] = {VFE_CMD_START},
+	[4] = {VFE_CMD_TEST_GEN_START},
+	[5] = {VFE_CMD_OPERATION_CFG, V40_OPERATION_CFG_LEN},
+	[6] = {VFE_CMD_AXI_OUT_CFG, V40_AXI_OUT_LEN, V40_AXI_BUS_CMD_OFF, 0xFF},
+	[7] = {VFE_CMD_CAMIF_CFG, V40_CAMIF_LEN, V40_CAMIF_OFF, 0xFF},
+	[8] = {VFE_CMD_AXI_INPUT_CFG},
+	[9] = {VFE_CMD_BLACK_LEVEL_CFG},
+	[10] = {VFE_CMD_MESH_ROLL_OFF_CFG, V40_MESH_ROLL_OFF_CFG_LEN,
+		V40_MESH_ROLL_OFF_CFG_OFF, 0xFF},
+	[11] = {VFE_CMD_DEMUX_CFG, V40_DEMUX_LEN, V40_DEMUX_OFF, 0xFF},
+	[12] = {VFE_CMD_FOV_CFG},
+	[13] = {VFE_CMD_MAIN_SCALER_CFG},
+	[14] = {VFE_CMD_WB_CFG, V40_WB_LEN, V40_WB_OFF, 0xFF},
+	[15] = {VFE_CMD_COLOR_COR_CFG, V40_COLOR_COR_LEN,
+		V40_COLOR_COR_OFF, 0xFF},
+	[16] = {VFE_CMD_RGB_G_CFG, V40_RGB_G_LEN, V40_RGB_G_OFF, 0xFF},
+	[17] = {VFE_CMD_LA_CFG, V40_LA_LEN, V40_LA_OFF, 0xFF },
+	[18] = {VFE_CMD_CHROMA_EN_CFG, V40_CHROMA_EN_LEN, V40_CHROMA_EN_OFF,
+		0xFF},
+	[19] = {VFE_CMD_CHROMA_SUP_CFG, V40_CHROMA_SUP_LEN,
+		V40_CHROMA_SUP_OFF, 0xFF},
+	[20] = {VFE_CMD_MCE_CFG, V40_MCE_LEN, V40_MCE_OFF, 0xFF},
+	[21] = {VFE_CMD_SK_ENHAN_CFG, V40_SCE_LEN, V40_SCE_OFF, 0xFF},
+	[22] = {VFE_CMD_ASF_CFG, V40_ASF_LEN, V40_ASF_OFF, 0xFF},
+	[23] = {VFE_CMD_S2Y_CFG},
+	[24] = {VFE_CMD_S2CbCr_CFG},
+	[25] = {VFE_CMD_CHROMA_SUBS_CFG},
+	[26] = {VFE_CMD_OUT_CLAMP_CFG, V40_OUT_CLAMP_LEN, V40_OUT_CLAMP_OFF,
+		0xFF},
+	[27] = {VFE_CMD_FRAME_SKIP_CFG},
+	[31] = {VFE_CMD_UPDATE},
+	[32] = {VFE_CMD_BL_LVL_UPDATE},
+	[33] = {VFE_CMD_DEMUX_UPDATE, V40_DEMUX_LEN, V40_DEMUX_OFF, 0xFF},
+	[34] = {VFE_CMD_FOV_UPDATE},
+	[35] = {VFE_CMD_MAIN_SCALER_UPDATE},
+	[36] = {VFE_CMD_WB_UPDATE, V40_WB_LEN, V40_WB_OFF, 0xFF},
+	[37] = {VFE_CMD_COLOR_COR_UPDATE, V40_COLOR_COR_LEN,
+		V40_COLOR_COR_OFF, 0xFF},
+	[38] = {VFE_CMD_RGB_G_UPDATE, V40_RGB_G_LEN, V40_CHROMA_EN_OFF, 0xFF},
+	[39] = {VFE_CMD_LA_UPDATE, V40_LA_LEN, V40_LA_OFF, 0xFF },
+	[40] = {VFE_CMD_CHROMA_EN_UPDATE, V40_CHROMA_EN_LEN,
+		V40_CHROMA_EN_OFF, 0xFF},
+	[41] = {VFE_CMD_CHROMA_SUP_UPDATE, V40_CHROMA_SUP_LEN,
+		V40_CHROMA_SUP_OFF, 0xFF},
+	[42] = {VFE_CMD_MCE_UPDATE, V40_MCE_LEN, V40_MCE_OFF, 0xFF},
+	[43] = {VFE_CMD_SK_ENHAN_UPDATE, V40_SCE_LEN, V40_SCE_OFF, 0xFF},
+	[44] = {VFE_CMD_S2CbCr_UPDATE},
+	[45] = {VFE_CMD_S2Y_UPDATE},
+	[46] = {VFE_CMD_ASF_UPDATE, V40_ASF_UPDATE_LEN, V40_ASF_OFF, 0xFF},
+	[47] = {VFE_CMD_FRAME_SKIP_UPDATE},
+	[48] = {VFE_CMD_CAMIF_FRAME_UPDATE},
+	[49] = {VFE_CMD_STATS_AF_UPDATE},
+	[50] = {VFE_CMD_STATS_AE_UPDATE},
+	[51] = {VFE_CMD_STATS_AWB_UPDATE, V40_STATS_AWB_LEN,
+		V40_STATS_AWB_OFF},
+	[52] = {VFE_CMD_STATS_RS_UPDATE, V40_STATS_RS_LEN, V40_STATS_RS_OFF},
+	[53] = {VFE_CMD_STATS_CS_UPDATE, V40_STATS_CS_LEN, V40_STATS_CS_OFF},
+	[54] = {VFE_CMD_STATS_SKIN_UPDATE},
+	[55] = {VFE_CMD_STATS_IHIST_UPDATE, V40_STATS_IHIST_LEN,
+		V40_STATS_IHIST_OFF},
+	[57] = {VFE_CMD_EPOCH1_ACK},
+	[58] = {VFE_CMD_EPOCH2_ACK},
+	[59] = {VFE_CMD_START_RECORDING},
+	[60] = {VFE_CMD_STOP_RECORDING},
+	[63] = {VFE_CMD_CAPTURE, V40_CAPTURE_LEN, 0xFF},
+	[65] = {VFE_CMD_STOP},
+	[66] = {VFE_CMD_GET_HW_VERSION, V40_GET_HW_VERSION_LEN,
+		V40_GET_HW_VERSION_OFF},
+	[67] = {VFE_CMD_GET_FRAME_SKIP_COUNTS},
+	[68] = {VFE_CMD_OUTPUT1_BUFFER_ENQ},
+	[69] = {VFE_CMD_OUTPUT2_BUFFER_ENQ},
+	[70] = {VFE_CMD_OUTPUT3_BUFFER_ENQ},
+	[71] = {VFE_CMD_JPEG_OUT_BUF_ENQ},
+	[72] = {VFE_CMD_RAW_OUT_BUF_ENQ},
+	[73] = {VFE_CMD_RAW_IN_BUF_ENQ},
+	[74] = {VFE_CMD_STATS_AF_ENQ},
+	[75] = {VFE_CMD_STATS_AE_ENQ},
+	[76] = {VFE_CMD_STATS_AWB_ENQ},
+	[77] = {VFE_CMD_STATS_RS_ENQ},
+	[78] = {VFE_CMD_STATS_CS_ENQ},
+	[79] = {VFE_CMD_STATS_SKIN_ENQ},
+	[80] = {VFE_CMD_STATS_IHIST_ENQ},
+	[82] = {VFE_CMD_JPEG_ENC_CFG},
+	[84] = {VFE_CMD_STATS_AF_START},
+	[85] = {VFE_CMD_STATS_AF_STOP},
+	[86] = {VFE_CMD_STATS_AE_START},
+	[87] = {VFE_CMD_STATS_AE_STOP},
+	[88] = {VFE_CMD_STATS_AWB_START, V40_STATS_AWB_LEN, V40_STATS_AWB_OFF},
+	[89] = {VFE_CMD_STATS_AWB_STOP},
+	[90] = {VFE_CMD_STATS_RS_START, V40_STATS_RS_LEN, V40_STATS_RS_OFF},
+	[91] = {VFE_CMD_STATS_RS_STOP},
+	[92] = {VFE_CMD_STATS_CS_START, V40_STATS_CS_LEN, V40_STATS_CS_OFF},
+	[93] = {VFE_CMD_STATS_CS_STOP},
+	[94] = {VFE_CMD_STATS_SKIN_START},
+	[95] = {VFE_CMD_STATS_SKIN_STOP},
+	[96] = {VFE_CMD_STATS_IHIST_START,
+		V40_STATS_IHIST_LEN, V40_STATS_IHIST_OFF},
+	[97] = {VFE_CMD_STATS_IHIST_STOP},
+	[99] = {VFE_CMD_SYNC_TIMER_SETTING, V40_SYNC_TIMER_LEN,
+			V40_SYNC_TIMER_OFF},
+	[100] = {VFE_CMD_ASYNC_TIMER_SETTING, V40_ASYNC_TIMER_LEN,
+		V40_ASYNC_TIMER_OFF},
+	[101] = {VFE_CMD_LIVESHOT},
+	[102] = {VFE_CMD_LA_SETUP},
+	[103] = {VFE_CMD_LINEARIZATION_CFG, V40_LINEARIZATION_LEN1,
+			V40_LINEARIZATION_OFF1},
+	[104] = {VFE_CMD_DEMOSAICV3},
+	[105] = {VFE_CMD_DEMOSAICV3_ABCC_CFG},
+	[106] = {VFE_CMD_DEMOSAICV3_DBCC_CFG, V40_DEMOSAICV3_DBCC_LEN,
+			V40_DEMOSAICV3_DBCC_OFF},
+	[107] = {VFE_CMD_DEMOSAICV3_DBPC_CFG},
+	[108] = {VFE_CMD_DEMOSAICV3_ABF_CFG, V40_DEMOSAICV3_ABF_LEN,
+			V40_DEMOSAICV3_ABF_OFF},
+	[109] = {VFE_CMD_DEMOSAICV3_ABCC_UPDATE},
+	[110] = {VFE_CMD_DEMOSAICV3_DBCC_UPDATE, V40_DEMOSAICV3_DBCC_LEN,
+			V40_DEMOSAICV3_DBCC_OFF},
+	[111] = {VFE_CMD_DEMOSAICV3_DBPC_UPDATE},
+	[112] = {VFE_CMD_XBAR_CFG},
+	[113] = {VFE_CMD_MODULE_CFG, V40_MODULE_CFG_LEN, V40_MODULE_CFG_OFF},
+	[114] = {VFE_CMD_ZSL},
+	[115] = {VFE_CMD_LINEARIZATION_UPDATE, V40_LINEARIZATION_LEN1,
+			V40_LINEARIZATION_OFF1},
+	[116] = {VFE_CMD_DEMOSAICV3_ABF_UPDATE, V40_DEMOSAICV3_ABF_LEN,
+			V40_DEMOSAICV3_ABF_OFF},
+	[117] = {VFE_CMD_CLF_CFG, V40_CLF_CFG_LEN, V40_CLF_CFG_OFF},
+	[118] = {VFE_CMD_CLF_LUMA_UPDATE, V40_CLF_LUMA_UPDATE_LEN,
+			V40_CLF_LUMA_UPDATE_OFF},
+	[119] = {VFE_CMD_CLF_CHROMA_UPDATE, V40_CLF_CHROMA_UPDATE_LEN,
+			V40_CLF_CHROMA_UPDATE_OFF},
+	[120] = {VFE_CMD_PCA_ROLL_OFF_CFG},
+	[121] = {VFE_CMD_PCA_ROLL_OFF_UPDATE},
+	[122] = {VFE_CMD_GET_REG_DUMP},
+	[123] = {VFE_CMD_GET_LINEARIZATON_TABLE},
+	[124] = {VFE_CMD_GET_MESH_ROLLOFF_TABLE},
+	[125] = {VFE_CMD_GET_PCA_ROLLOFF_TABLE},
+	[126] = {VFE_CMD_GET_RGB_G_TABLE},
+	[127] = {VFE_CMD_GET_LA_TABLE},
+	[128] = {VFE_CMD_DEMOSAICV3_UPDATE},
+	[129] = {VFE_CMD_ACTIVE_REGION_CFG},
+	[130] = {VFE_CMD_COLOR_PROCESSING_CONFIG},
+	[131] = {VFE_CMD_STATS_WB_AEC_CONFIG},
+	[132] = {VFE_CMD_STATS_WB_AEC_UPDATE},
+	[133] = {VFE_CMD_Y_GAMMA_CONFIG},
+	[134] = {VFE_CMD_SCALE_OUTPUT1_CONFIG},
+	[135] = {VFE_CMD_SCALE_OUTPUT2_CONFIG},
+	[136] = {VFE_CMD_CAPTURE_RAW},
+	[137] = {VFE_CMD_STOP_LIVESHOT},
+	[138] = {VFE_CMD_RECONFIG_VFE},
+	[139] = {VFE_CMD_STATS_REQBUF},
+	[140] = {VFE_CMD_STATS_ENQUEUEBUF},
+	[141] = {VFE_CMD_STATS_FLUSH_BUFQ},
+	[142] = {VFE_CMD_STATS_UNREGBUF},
+	[143] = {VFE_CMD_STATS_BG_START, V40_STATS_BG_LEN, V40_STATS_BG_OFF},
+	[144] = {VFE_CMD_STATS_BG_STOP},
+	[145] = {VFE_CMD_STATS_BF_START, V40_STATS_BF_LEN, V40_STATS_BF_OFF},
+	[146] = {VFE_CMD_STATS_BF_STOP},
+	[147] = {VFE_CMD_STATS_BHIST_START, V40_STATS_BHIST_LEN,
+			V40_STATS_BHIST_OFF},
+	[148] = {VFE_CMD_STATS_BHIST_STOP},
+	[149] = {VFE_CMD_RESET_2},
+	[150] = {VFE_CMD_FOV_ENC_CFG, V40_FOV_ENC_LEN,
+		V40_FOV_ENC_OFF, 0xFF},
+	[151] = {VFE_CMD_FOV_VIEW_CFG, V40_FOV_VIEW_LEN,
+		V40_FOV_VIEW_OFF, 0xFF},
+	[152] = {VFE_CMD_FOV_ENC_UPDATE, V40_FOV_ENC_LEN,
+		V40_FOV_ENC_OFF, 0xFF},
+	[153] = {VFE_CMD_FOV_VIEW_UPDATE, V40_FOV_VIEW_LEN,
+		V40_FOV_VIEW_OFF, 0xFF},
+	[154] = {VFE_CMD_SCALER_ENC_CFG, V40_SCALER_ENC_LEN,
+		V40_SCALER_ENC_OFF, 0xFF},
+	[155] = {VFE_CMD_SCALER_VIEW_CFG, V40_SCALER_VIEW_LEN,
+		V40_SCALER_VIEW_OFF, 0xFF},
+	[156] = {VFE_CMD_SCALER_ENC_UPDATE, V40_SCALER_ENC_LEN,
+		V40_SCALER_ENC_OFF, 0xFF},
+	[157] = {VFE_CMD_SCALER_VIEW_UPDATE, V40_SCALER_VIEW_LEN,
+		V40_SCALER_VIEW_OFF, 0xFF},
+	[158] = {VFE_CMD_COLORXFORM_ENC_CFG, V40_COLORXFORM_ENC_CFG_LEN,
+		V40_COLORXFORM_ENC_CFG_OFF, 0xFF},
+	[159] = {VFE_CMD_COLORXFORM_VIEW_CFG, V40_COLORXFORM_VIEW_CFG_LEN,
+		V40_COLORXFORM_VIEW_CFG_OFF},
+	[160] = {VFE_CMD_COLORXFORM_ENC_UPDATE, V40_COLORXFORM_ENC_CFG_LEN,
+		V40_COLORXFORM_ENC_CFG_OFF, 0xFF},
+	[161] = {VFE_CMD_COLORXFORM_VIEW_UPDATE, V40_COLORXFORM_VIEW_CFG_LEN,
+		V40_COLORXFORM_VIEW_CFG_OFF, 0xFF},
 };
 
-static void vfe40_stop(struct vfe40_ctrl_type *vfe40_ctrl)
+static const uint32_t vfe40_AXI_WM_CFG[] = {
+	0x0000006C,
+	0x00000090,
+	0x000000B4,
+	0x000000D8,
+	0x000000FC,
+	0x00000120,
+	0x00000144,
+};
+
+static const char * const vfe40_general_cmd[] = {
+	[1] = "SET_CLK",
+	[2] = "RESET",
+	[3] = "START",
+	[4] = "TEST_GEN_START",
+	[5] = "OPERATION_CFG",  /* 5 */
+	[6] = "AXI_OUT_CFG",
+	[7] = "CAMIF_CFG",
+	[8] = "AXI_INPUT_CFG",
+	[9] = "BLACK_LEVEL_CFG",
+	[10] = "ROLL_OFF_CFG",  /* 10 */
+	[11] = "DEMUX_CFG",
+	[12] = "FOV_CFG",
+	[13] = "MAIN_SCALER_CFG",
+	[14] = "WB_CFG",
+	[15] = "COLOR_COR_CFG", /* 15 */
+	[16] = "RGB_G_CFG",
+	[17] = "LA_CFG",
+	[18] = "CHROMA_EN_CFG",
+	[19] = "CHROMA_SUP_CFG",
+	[20] = "MCE_CFG", /* 20 */
+	[21] = "SK_ENHAN_CFG",
+	[22] = "ASF_CFG",
+	[23] = "S2Y_CFG",
+	[24] = "S2CbCr_CFG",
+	[25] = "CHROMA_SUBS_CFG",  /* 25 */
+	[26] = "OUT_CLAMP_CFG",
+	[27] = "FRAME_SKIP_CFG",
+	[31] = "UPDATE",
+	[32] = "BL_LVL_UPDATE",
+	[33] = "DEMUX_UPDATE",
+	[34] = "FOV_UPDATE",
+	[35] = "MAIN_SCALER_UPDATE",  /* 35 */
+	[36] = "WB_UPDATE",
+	[37] = "COLOR_COR_UPDATE",
+	[38] = "RGB_G_UPDATE",
+	[39] = "LA_UPDATE",
+	[40] = "CHROMA_EN_UPDATE",  /* 40 */
+	[41] = "CHROMA_SUP_UPDATE",
+	[42] = "MCE_UPDATE",
+	[43] = "SK_ENHAN_UPDATE",
+	[44] = "S2CbCr_UPDATE",
+	[45] = "S2Y_UPDATE",  /* 45 */
+	[46] = "ASF_UPDATE",
+	[47] = "FRAME_SKIP_UPDATE",
+	[48] = "CAMIF_FRAME_UPDATE",
+	[49] = "STATS_AF_UPDATE",
+	[50] = "STATS_AE_UPDATE",  /* 50 */
+	[51] = "STATS_AWB_UPDATE",
+	[52] = "STATS_RS_UPDATE",
+	[53] = "STATS_CS_UPDATE",
+	[54] = "STATS_SKIN_UPDATE",
+	[55] = "STATS_IHIST_UPDATE",  /* 55 */
+	[57] = "EPOCH1_ACK",
+	[58] = "EPOCH2_ACK",
+	[59] = "START_RECORDING",
+	[60] = "STOP_RECORDING",  /* 60 */
+	[63] = "CAPTURE",
+	[65] = "STOP",  /* 65 */
+	[66] = "GET_HW_VERSION",
+	[67] = "GET_FRAME_SKIP_COUNTS",
+	[68] = "OUTPUT1_BUFFER_ENQ",
+	[69] = "OUTPUT2_BUFFER_ENQ",
+	[70] = "OUTPUT3_BUFFER_ENQ",  /* 70 */
+	[71] = "JPEG_OUT_BUF_ENQ",
+	[72] = "RAW_OUT_BUF_ENQ",
+	[73] = "RAW_IN_BUF_ENQ",
+	[74] = "STATS_AF_ENQ",
+	[75] = "STATS_AE_ENQ",  /* 75 */
+	[76] = "STATS_AWB_ENQ",
+	[77] = "STATS_RS_ENQ",
+	[78] = "STATS_CS_ENQ",
+	[79] = "STATS_SKIN_ENQ",
+	[80] = "STATS_IHIST_ENQ",  /* 80 */
+	[82] = "JPEG_ENC_CFG",
+	[84] = "STATS_AF_START",
+	[85] = "STATS_AF_STOP",  /* 85 */
+	[86] = "STATS_AE_START",
+	[87] = "STATS_AE_STOP",
+	[88] = "STATS_AWB_START",
+	[89] = "STATS_AWB_STOP",
+	[90] = "STATS_RS_START",  /* 90 */
+	[91] = "STATS_RS_STOP",
+	[92] = "STATS_CS_START",
+	[93] = "STATS_CS_STOP",
+	[94] = "STATS_SKIN_START",
+	[95] = "STATS_SKIN_STOP",  /* 95 */
+	[96] = "STATS_IHIST_START",
+	[97] = "STATS_IHIST_STOP",
+	[99] = "SYNC_TIMER_SETTING",
+	[100] = "ASYNC_TIMER_SETTING",  /* 100 */
+	[101] = "LIVESHOT",
+	[102] = "LA_SETUP",
+	[103] = "LINEARIZATION_CFG",
+	[104] = "DEMOSAICV3",
+	[105] = "DEMOSAICV3_ABCC_CFG", /* 105 */
+	[106] = "DEMOSAICV3_DBCC_CFG",
+	[107] = "DEMOSAICV3_DBPC_CFG",
+	[108] = "DEMOSAICV3_ABF_CFG",
+	[109] = "DEMOSAICV3_ABCC_UPDATE",
+	[110] = "DEMOSAICV3_DBCC_UPDATE", /* 110 */
+	[111] = "DEMOSAICV3_DBPC_UPDATE",
+	[112] = "XBAR_CFG",
+	[113] = "EZTUNE_CFG",
+	[114] = "V40_ZSL",
+	[115] = "LINEARIZATION_UPDATE", /*115*/
+	[116] = "DEMOSAICV3_ABF_UPDATE",
+	[117] = "CLF_CFG",
+	[118] = "CLF_LUMA_UPDATE",
+	[119] = "CLF_CHROMA_UPDATE",
+	[120] = "PCA_ROLL_OFF_CFG", /*120*/
+	[121] = "PCA_ROLL_OFF_UPDATE",
+	[122] = "GET_REG_DUMP",
+	[123] = "GET_LINEARIZATON_TABLE",
+	[124] = "GET_MESH_ROLLOFF_TABLE",
+	[125] = "GET_PCA_ROLLOFF_TABLE", /*125*/
+	[126] = "GET_RGB_G_TABLE",
+	[127] = "GET_LA_TABLE",
+	[128] = "DEMOSAICV3_UPDATE",
+	[139] = "STATS_REQBUF",
+	[140] = "STATS_ENQUEUEBUF", /*140*/
+	[141] = "STATS_FLUSH_BUFQ",
+	[142] = "STATS_UNREGBUF",
+	[143] = "STATS_BG_START",
+	[144] = "STATS_BG_STOP",
+	[145] = "STATS_BF_START", /*145*/
+	[146] = "STATS_BF_STOP",
+	[147] = "STATS_BHIST_START",
+	[148] = "STATS_BHIST_STOP",
+	[149] = "RESET_2",
+};
+
+/*Temporary use fixed bus vectors in VFE */
+static struct msm_bus_vectors vfe_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors vfe_preview_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 27648000,
+		.ib  = 110592000,
+	},
+};
+
+static struct msm_bus_vectors vfe_video_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 154275840,
+		.ib  = 617103360,
+	},
+};
+
+static struct msm_bus_vectors vfe_snapshot_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 274423680,
+		.ib  = 1097694720,
+	},
+};
+
+static struct msm_bus_vectors vfe_zsl_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 302071680,
+		.ib  = 1208286720,
+	},
+};
+
+static struct msm_bus_paths vfe_bus_client_config[] = {
+	{
+		ARRAY_SIZE(vfe_init_vectors),
+		vfe_init_vectors,
+	},
+	{
+		ARRAY_SIZE(vfe_preview_vectors),
+		vfe_preview_vectors,
+	},
+	{
+		ARRAY_SIZE(vfe_video_vectors),
+		vfe_video_vectors,
+	},
+	{
+		ARRAY_SIZE(vfe_snapshot_vectors),
+		vfe_snapshot_vectors,
+	},
+	{
+		ARRAY_SIZE(vfe_zsl_vectors),
+		vfe_zsl_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata vfe_bus_client_pdata = {
+		vfe_bus_client_config,
+		ARRAY_SIZE(vfe_bus_client_config),
+		.name = "msm_camera_vfe",
+};
+
+uint8_t vfe40_use_bayer_stats(struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	unsigned long flags;
+	if (vfe40_ctrl->ver_num.main >= 4) {
+		/* VFE 4 or above uses bayer stats */
+		return TRUE;
+	} else {
+		return FALSE;
+	}
+}
 
-	atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
+static void axi_enable_irq(struct vfe_share_ctrl_t *share_ctrl)
+{
+	uint32_t irq_mask;
+	uint16_t vfe_operation_mode =
+		share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+			VFE_OUTPUTS_RDI1);
+	irq_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
 
-	/* for reset hw modules, and send msg when reset_irq comes.*/
-	spin_lock_irqsave(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
-	vfe40_ctrl->share_ctrl->stop_ack_pending = TRUE;
-	spin_unlock_irqrestore(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+	irq_mask |= VFE_IMASK_WHILE_STOPPING_0;
+
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
+		irq_mask |= VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK;
+
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1)
+		irq_mask |= VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK;
+
+	msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+		VFE_IRQ_MASK_0);
+
+	if (vfe_operation_mode) {
+		irq_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		irq_mask |= 0x00000021;
+		if (share_ctrl->stats_comp)
+			irq_mask |= VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0;
+		else
+			irq_mask |= 0x00FF0000;
+		msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		atomic_set(&share_ctrl->vstate, 1);
+	}
+	atomic_set(&share_ctrl->handle_common_irq, 1);
+}
+
+static void axi_disable_irq(struct vfe_share_ctrl_t *share_ctrl)
+{
 
 	/* disable all interrupts.  */
+
+	uint32_t irq_mask = 0;
+	uint16_t vfe_operation_mode =
+		share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+			VFE_OUTPUTS_RDI1);
+
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+		irq_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		irq_mask &= ~(VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK);
+		msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		msm_camera_io_w(VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK,
+			share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	}
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+		irq_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		irq_mask &= ~(VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK);
+		msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		msm_camera_io_w(VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK,
+			share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	}
+	if (vfe_operation_mode) {
+		atomic_set(&share_ctrl->vstate, 0);
+		irq_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		irq_mask &= ~(0x00000011);
+		if (share_ctrl->stats_comp)
+			irq_mask &= ~(VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0);
+		else
+			irq_mask &= ~0x00FF0000;
+		msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+	}
+
+	if (share_ctrl->axi_ref_cnt == 1) {
+		atomic_set(&share_ctrl->handle_common_irq, 0);
 	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+		share_ctrl->vfebase + VFE_IRQ_MASK_0);
 	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
-			vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+		share_ctrl->vfebase + VFE_IRQ_MASK_1);
 
 	/* clear all pending interrupts*/
-	msm_camera_io_w(VFE_CLEAR_ALL_IRQ0,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
-	msm_camera_io_w(VFE_CLEAR_ALL_IRQ1,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+	msm_camera_io_w(0xFFFFFFFF,
+		share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	msm_camera_io_w(0xFFFFFFFF,
+		share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
 	/* Ensure the write order while writing
 	to the command register using the barrier */
 	msm_camera_io_w_mb(1,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
+		share_ctrl->vfebase + VFE_IRQ_CMD);
+	}
+}
+
+static void vfe40_stop(struct vfe40_ctrl_type *vfe40_ctrl)
+{
 
 	/* in either continuous or snapshot mode, stop command can be issued
 	 * at any time. stop camif immediately. */
 	msm_camera_io_w(CAMIF_COMMAND_STOP_IMMEDIATELY,
 		vfe40_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
+	vfe40_ctrl->share_ctrl->operation_mode &=
+		~(vfe40_ctrl->share_ctrl->current_mode);
+	vfe40_ctrl->share_ctrl->current_mode = 0;
 }
 
-void vfe40_subdev_notify(int id, int path, int image_mode,
+static void vfe40_subdev_notify(int id, int path, uint32_t inst_handle,
 	struct v4l2_subdev *sd, struct vfe_share_ctrl_t *share_ctrl)
 {
 	struct msm_vfe_resp rp;
 	struct msm_frame_info frame_info;
 	unsigned long flags = 0;
 	spin_lock_irqsave(&share_ctrl->sd_notify_lock, flags);
-	CDBG("%s: msgId = %d\n", __func__, id);
+	CDBG("vfe40_subdev_notify : msgId = %d\n", id);
 	memset(&rp, 0, sizeof(struct msm_vfe_resp));
 	rp.evt_msg.type   = MSM_CAMERA_MSG;
-	frame_info.image_mode = image_mode;
+	frame_info.inst_handle = inst_handle;
 	frame_info.path = path;
 	rp.evt_msg.data = &frame_info;
 	rp.type	   = id;
@@ -242,45 +613,249 @@
 	spin_unlock_irqrestore(&share_ctrl->sd_notify_lock, flags);
 }
 
+static int vfe40_config_axi(
+	struct axi_ctrl_t *axi_ctrl, int mode, uint32_t *ao)
+{
+	uint32_t *ch_info;
+	uint32_t *axi_cfg = ao;
+	int vfe_mode = (mode & ~(OUTPUT_TERT1|OUTPUT_TERT2));
+
+	/* Update the corresponding write masters for each output*/
+	ch_info = axi_cfg + V40_AXI_CFG_LEN;
+	axi_ctrl->share_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
+	axi_ctrl->share_ctrl->outpath.out0.ch1 =
+		0x0000FFFF & (*ch_info++ >> 16);
+	axi_ctrl->share_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info++;
+	axi_ctrl->share_ctrl->outpath.out0.inst_handle = *ch_info++;
+
+	axi_ctrl->share_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info;
+	axi_ctrl->share_ctrl->outpath.out1.ch1 =
+		0x0000FFFF & (*ch_info++ >> 16);
+	axi_ctrl->share_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info++;
+	axi_ctrl->share_ctrl->outpath.out1.inst_handle = *ch_info++;
+
+	axi_ctrl->share_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info;
+	axi_ctrl->share_ctrl->outpath.out2.ch1 =
+		0x0000FFFF & (*ch_info++ >> 16);
+	axi_ctrl->share_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++;
+	axi_ctrl->share_ctrl->outpath.out2.inst_handle = *ch_info++;
+
+	axi_ctrl->share_ctrl->outpath.out3.ch0 = 0x0000FFFF & *ch_info;
+	axi_ctrl->share_ctrl->outpath.out3.ch1 =
+		0x0000FFFF & (*ch_info++ >> 16);
+	axi_ctrl->share_ctrl->outpath.out3.ch2 = 0x0000FFFF & *ch_info++;
+	axi_ctrl->share_ctrl->outpath.out3.inst_handle = *ch_info++;
+
+	axi_ctrl->share_ctrl->outpath.output_mode = 0;
+
+	if (mode & OUTPUT_TERT1)
+		axi_ctrl->share_ctrl->outpath.output_mode |=
+			VFE40_OUTPUT_MODE_TERTIARY1;
+	if (mode & OUTPUT_TERT2)
+		axi_ctrl->share_ctrl->outpath.output_mode |=
+			VFE40_OUTPUT_MODE_TERTIARY2;
+	if (mode == OUTPUT_TERT1 || mode == OUTPUT_TERT1
+		|| mode == (OUTPUT_TERT1|OUTPUT_TERT2))
+			goto bus_cfg;
+
+	switch (vfe_mode) {
+	case OUTPUT_PRIM:
+		axi_ctrl->share_ctrl->outpath.output_mode |=
+			VFE40_OUTPUT_MODE_PRIMARY;
+		break;
+	case OUTPUT_PRIM_ALL_CHNLS:
+		axi_ctrl->share_ctrl->outpath.output_mode |=
+			VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+		break;
+	case OUTPUT_PRIM|OUTPUT_SEC:
+		axi_ctrl->share_ctrl->outpath.output_mode |=
+			VFE40_OUTPUT_MODE_PRIMARY;
+		axi_ctrl->share_ctrl->outpath.output_mode |=
+			VFE40_OUTPUT_MODE_SECONDARY;
+		break;
+	case OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS:
+		axi_ctrl->share_ctrl->outpath.output_mode |=
+			VFE40_OUTPUT_MODE_PRIMARY;
+		axi_ctrl->share_ctrl->outpath.output_mode |=
+			VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS;
+		break;
+	case OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC:
+		axi_ctrl->share_ctrl->outpath.output_mode |=
+			VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+		axi_ctrl->share_ctrl->outpath.output_mode |=
+			VFE40_OUTPUT_MODE_SECONDARY;
+		break;
+	default:
+		pr_err("%s Invalid AXI mode %d ", __func__, mode);
+		return -EINVAL;
+	}
+
+bus_cfg:
+	msm_camera_io_memcpy(axi_ctrl->share_ctrl->vfebase +
+		vfe40_cmd[VFE_CMD_AXI_OUT_CFG].offset, axi_cfg,
+		V40_AXI_BUS_CFG_LEN);
+	msm_camera_io_w(*ch_info++,
+		axi_ctrl->share_ctrl->vfebase + VFE_RDI0_CFG);
+	msm_camera_io_w(*ch_info++,
+		axi_ctrl->share_ctrl->vfebase + VFE_RDI1_CFG);
+	msm_camera_io_w(*ch_info++,
+		axi_ctrl->share_ctrl->vfebase + VFE_RDI2_CFG);
+	return 0;
+}
+
+static void axi_reset_internal_variables(
+	struct axi_ctrl_t *axi_ctrl)
+{
+	unsigned long flags;
+	/* state control variables */
+	axi_ctrl->share_ctrl->start_ack_pending = FALSE;
+	atomic_set(&irq_cnt, 0);
+
+	spin_lock_irqsave(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+	axi_ctrl->share_ctrl->stop_ack_pending  = FALSE;
+	spin_unlock_irqrestore(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+
+	spin_lock_irqsave(&axi_ctrl->share_ctrl->update_ack_lock, flags);
+	axi_ctrl->share_ctrl->update_ack_pending = FALSE;
+	spin_unlock_irqrestore(&axi_ctrl->share_ctrl->update_ack_lock, flags);
+
+	axi_ctrl->share_ctrl->recording_state = VFE_STATE_IDLE;
+	axi_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
+
+	atomic_set(&axi_ctrl->share_ctrl->vstate, 0);
+	atomic_set(&axi_ctrl->share_ctrl->handle_common_irq, 0);
+	atomic_set(&axi_ctrl->share_ctrl->pix0_update_ack_pending, 0);
+	atomic_set(&axi_ctrl->share_ctrl->rdi0_update_ack_pending, 0);
+	atomic_set(&axi_ctrl->share_ctrl->rdi1_update_ack_pending, 0);
+	atomic_set(&axi_ctrl->share_ctrl->rdi2_update_ack_pending, 0);
+
+	/* 0 for continuous mode, 1 for snapshot mode */
+	axi_ctrl->share_ctrl->operation_mode = 0;
+	axi_ctrl->share_ctrl->current_mode = 0;
+	axi_ctrl->share_ctrl->outpath.output_mode = 0;
+	axi_ctrl->share_ctrl->comp_output_mode = 0;
+	axi_ctrl->share_ctrl->vfe_capture_count = 0;
+
+	/* this is unsigned 32 bit integer. */
+	axi_ctrl->share_ctrl->vfeFrameId = 0;
+	axi_ctrl->share_ctrl->rdi0FrameId = 0;
+	axi_ctrl->share_ctrl->rdi1FrameId = 0;
+	axi_ctrl->share_ctrl->rdi2FrameId = 0;
+}
+
+static void vfe40_program_dmi_cfg(
+	enum VFE40_DMI_RAM_SEL bankSel,
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	/* set bit 8 for auto increment. */
+	uint32_t value = VFE_DMI_CFG_DEFAULT;
+	value += (uint32_t)bankSel;
+	CDBG("%s: banksel = %d\n", __func__, bankSel);
+
+	msm_camera_io_w(value, vfe40_ctrl->share_ctrl->vfebase +
+		VFE_DMI_CFG);
+	/* by default, always starts with offset 0.*/
+	msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+		VFE_DMI_ADDR);
+}
+
+static void vfe40_reset_dmi_tables(
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	int i = 0;
+
+	/* Reset Histogram LUTs */
+	CDBG("Reset Bayer histogram LUT : 0\n");
+	vfe40_program_dmi_cfg(STATS_BHIST_RAM0, vfe40_ctrl);
+	/* Loop for configuring LUT */
+	for (i = 0; i < 256; i++) {
+		msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_HI);
+		msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_LO);
+	}
+	vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+
+	CDBG("Reset Bayer Histogram LUT: 1\n");
+	vfe40_program_dmi_cfg(STATS_BHIST_RAM1, vfe40_ctrl);
+	/* Loop for configuring LUT */
+	for (i = 0; i < 256; i++) {
+		msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_HI);
+		msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_LO);
+	}
+	vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+
+	CDBG("Reset IHistogram LUT\n");
+	vfe40_program_dmi_cfg(STATS_IHIST_RAM, vfe40_ctrl);
+	/* Loop for configuring LUT */
+	for (i = 0; i < 256; i++) {
+		msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_HI);
+		msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_LO);
+	}
+	vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+}
+
+static void vfe40_set_default_reg_values(
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	msm_camera_io_w(0x800080,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_0);
+	msm_camera_io_w(0x800080,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_1);
+	msm_camera_io_w(0xFFFFF,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_CGC_OVERRIDE);
+
+	msm_camera_io_w(0,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_ENC_MIN);
+	msm_camera_io_w(0xFFFFFF,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_ENC_MAX);
+	msm_camera_io_w(0,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_VIEW_MIN);
+	msm_camera_io_w(0xFFFFFF,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_VIEW_MAX);
+
+	/* stats UB config */
+	CDBG("%s: Use bayer stats = %d\n", __func__,
+		 vfe40_use_bayer_stats(vfe40_ctrl));
+	msm_camera_io_w(0x350001F,
+	vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_HIST_WR_UB_CFG);
+	msm_camera_io_w(0x370002F,
+		vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_BG_WR_UB_CFG);
+	msm_camera_io_w(0x3A0002F,
+		vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_BF_WR_UB_CFG);
+	msm_camera_io_w(0x3D00007,
+		vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_RS_WR_UB_CFG);
+	msm_camera_io_w(0x3D8001F,
+		vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_CS_WR_UB_CFG);
+	msm_camera_io_w(0x3F80007,
+		vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_SKIN_WR_UB_CFG);
+	vfe40_reset_dmi_tables(vfe40_ctrl);
+}
+
 static void vfe40_reset_internal_variables(
 	struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	unsigned long flags;
-	vfe40_ctrl->vfeImaskCompositePacked = 0;
-	/* state control variables */
-	vfe40_ctrl->start_ack_pending = FALSE;
-	atomic_set(&vfe40_ctrl->share_ctrl->irq_cnt, 0);
-
-	spin_lock_irqsave(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
-	vfe40_ctrl->share_ctrl->stop_ack_pending  = FALSE;
-	spin_unlock_irqrestore(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
-
-	vfe40_ctrl->reset_ack_pending  = FALSE;
-
-	spin_lock_irqsave(&vfe40_ctrl->update_ack_lock, flags);
-	vfe40_ctrl->update_ack_pending = FALSE;
-	spin_unlock_irqrestore(&vfe40_ctrl->update_ack_lock, flags);
-
-	vfe40_ctrl->recording_state = VFE_STATE_IDLE;
-	vfe40_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
-
-	atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
-
-	/* 0 for continuous mode, 1 for snapshot mode */
-	vfe40_ctrl->share_ctrl->operation_mode = 0;
-	vfe40_ctrl->share_ctrl->outpath.output_mode = 0;
-	vfe40_ctrl->share_ctrl->vfe_capture_count = 0;
-
-	/* this is unsigned 32 bit integer. */
-	vfe40_ctrl->share_ctrl->vfeFrameId = 0;
 	/* Stats control variables. */
-	memset(&(vfe40_ctrl->afStatsControl), 0,
+	memset(&(vfe40_ctrl->afbfStatsControl), 0,
 		sizeof(struct vfe_stats_control));
 
 	memset(&(vfe40_ctrl->awbStatsControl), 0,
 		sizeof(struct vfe_stats_control));
 
-	memset(&(vfe40_ctrl->aecStatsControl), 0,
+	memset(&(vfe40_ctrl->aecbgStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe40_ctrl->bhistStatsControl), 0,
 		sizeof(struct vfe_stats_control));
 
 	memset(&(vfe40_ctrl->ihistStatsControl), 0,
@@ -295,32 +870,59 @@
 	vfe40_ctrl->frame_skip_cnt = 31;
 	vfe40_ctrl->frame_skip_pattern = 0xffffffff;
 	vfe40_ctrl->snapshot_frame_cnt = 0;
+	vfe40_set_default_reg_values(vfe40_ctrl);
 }
 
-static void vfe40_reset(struct vfe40_ctrl_type *vfe40_ctrl)
+static int vfe40_reset(struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	vfe40_reset_internal_variables(vfe40_ctrl);
+	uint32_t irq_mask;
+	atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
+	msm_camera_io_w(VFE_MODULE_RESET_CMD,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_RESET);
+	msm_camera_io_w(0,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_RESET);
+
+	irq_mask =
+		msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+	irq_mask &= ~(0x00FF0011|VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0);
+
+	/* enable reset_ack interrupt.  */
+	irq_mask |= VFE_IMASK_WHILE_STOPPING_0;
+	msm_camera_io_w(irq_mask, vfe40_ctrl->share_ctrl->vfebase +
+		VFE_IRQ_MASK_0);
+
+	msm_camera_io_w_mb(VFE_ONLY_RESET_CMD,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+
+	return wait_for_completion_interruptible(
+			&vfe40_ctrl->share_ctrl->reset_complete);
+}
+
+static int axi_reset(struct axi_ctrl_t *axi_ctrl)
+{
+	axi_reset_internal_variables(axi_ctrl);
 	/* disable all interrupts.  vfeImaskLocal is also reset to 0
 	* to begin with. */
 	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
 
 	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
 
 	/* clear all pending interrupts*/
-	msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
-	msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+	msm_camera_io_w(VFE_CLEAR_ALL_IRQ0,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	msm_camera_io_w(VFE_CLEAR_ALL_IRQ1,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
 
 	/* Ensure the write order while writing
 	to the command register using the barrier */
-	msm_camera_io_w_mb(1, vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
+	msm_camera_io_w_mb(1, axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
 
 	/* enable reset_ack interrupt.  */
-	msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
-	vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+	msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_0,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
 
 	/* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset
 	 * is done, hardware interrupt will be generated.  VFE ist processes
@@ -330,24 +932,10 @@
 	/* Ensure the write order while writing
 	to the command register using the barrier */
 	msm_camera_io_w_mb(VFE_RESET_UPON_RESET_CMD,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+		axi_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
 
-	msm_camera_io_w(0xAAAAAAAA,
-	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_0);
-	msm_camera_io_w(0xAAAAAAAA,
-	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_1);
-	msm_camera_io_w(0xAAAAAAAA,
-	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_2);
-	msm_camera_io_w(0xAAAAAAAA,
-	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_3);
-	msm_camera_io_w(0xAAAAAAAA,
-	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_4);
-	msm_camera_io_w(0xAAAAAAAA,
-	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_5);
-	msm_camera_io_w(0xAAAAAAAA,
-	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_6);
-	msm_camera_io_w(0x0002AAAA,
-	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_7);
+	return wait_for_completion_interruptible(
+			&axi_ctrl->share_ctrl->reset_complete);
 }
 
 static int vfe40_operation_config(uint32_t *cmd,
@@ -355,7 +943,6 @@
 {
 	uint32_t *p = cmd;
 
-	vfe40_ctrl->share_ctrl->operation_mode = *p;
 	vfe40_ctrl->share_ctrl->stats_comp = *(++p);
 	vfe40_ctrl->hfr_mode = *(++p);
 
@@ -425,6 +1012,26 @@
 	return 0L;
 }
 
+
+static unsigned long vfe40_stats_unregbuf(
+	struct vfe40_ctrl_type *vfe40_ctrl,
+	struct msm_stats_reqbuf *req_buf, int domain_num)
+{
+	int i = 0, rc = 0;
+
+	for (i = 0; i < req_buf->num_buf; i++) {
+		rc = vfe40_ctrl->stats_ops.buf_unprepare(
+			vfe40_ctrl->stats_ops.stats_ctrl,
+			req_buf->stats_type, i,
+			vfe40_ctrl->stats_ops.client, domain_num);
+		if (rc < 0) {
+			pr_err("%s: unreg stats buf (type = %d) err = %d",
+				__func__, req_buf->stats_type, rc);
+		return rc;
+		}
+	}
+	return 0L;
+}
 static int vfe_stats_awb_buf_init(
 	struct vfe40_ctrl_type *vfe40_ctrl,
 	struct vfe_cmd_stats_buf *in)
@@ -456,14 +1063,18 @@
 	return 0;
 }
 
-static int vfe_stats_aec_buf_init(
-	struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+static uint32_t vfe_stats_aec_bg_buf_init(
+	struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	uint32_t addr;
 	unsigned long flags;
+	uint32_t stats_type;
 
+	stats_type =
+		(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AEC
+			: MSM_STATS_TYPE_BG;
 	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
-	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AEC);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
 	if (!addr) {
 		pr_err("%s: dq aec ping buf from free buf queue",
@@ -472,9 +1083,9 @@
 	}
 	msm_camera_io_w(addr,
 		vfe40_ctrl->share_ctrl->vfebase +
-		VFE_BUS_STATS_AEC_WR_PING_ADDR);
+		VFE_BUS_STATS_BG_WR_PING_ADDR);
 	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
-	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AEC);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
 	if (!addr) {
 		pr_err("%s: dq aec pong buf from free buf queue",
@@ -483,26 +1094,31 @@
 	}
 	msm_camera_io_w(addr,
 		vfe40_ctrl->share_ctrl->vfebase +
-		VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+		VFE_BUS_STATS_BG_WR_PONG_ADDR);
 	return 0;
 }
 
-static int vfe_stats_af_buf_init(
-	struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_af_bf_buf_init(
+	struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	uint32_t addr;
 	unsigned long flags;
 	int rc = 0;
 
+	uint32_t stats_type;
+	stats_type =
+		(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AF
+			: MSM_STATS_TYPE_BF;
+
 	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
-	rc = vfe40_stats_flush_enqueue(vfe40_ctrl, MSM_STATS_TYPE_AF);
+	rc = vfe40_stats_flush_enqueue(vfe40_ctrl, stats_type);
 	if (rc < 0) {
 		pr_err("%s: dq stats buf err = %d",
 			   __func__, rc);
 		spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
 		return -EINVAL;
 	}
-	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AF);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
 	if (!addr) {
 		pr_err("%s: dq af ping buf from free buf queue", __func__);
@@ -510,9 +1126,9 @@
 	}
 	msm_camera_io_w(addr,
 		vfe40_ctrl->share_ctrl->vfebase +
-		VFE_BUS_STATS_AF_WR_PING_ADDR);
+		VFE_BUS_STATS_BF_WR_PING_ADDR);
 	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
-	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AF);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
 	if (!addr) {
 		pr_err("%s: dq af pong buf from free buf queue", __func__);
@@ -520,13 +1136,44 @@
 	}
 	msm_camera_io_w(addr,
 		vfe40_ctrl->share_ctrl->vfebase +
-		VFE_BUS_STATS_AF_WR_PONG_ADDR);
+		VFE_BUS_STATS_BF_WR_PONG_ADDR);
+	return 0;
+}
+
+static uint32_t vfe_stats_bhist_buf_init(
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	uint32_t addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_BHIST);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq ihist ping buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_SKIN_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_BHIST);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq ihist pong buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_SKIN_WR_PONG_ADDR);
 
 	return 0;
 }
 
 static int vfe_stats_ihist_buf_init(
-	struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+	struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	uint32_t addr;
 	unsigned long flags;
@@ -558,7 +1205,7 @@
 }
 
 static int vfe_stats_rs_buf_init(
-	struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+	struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	uint32_t addr;
 	unsigned long flags;
@@ -587,7 +1234,7 @@
 }
 
 static int vfe_stats_cs_buf_init(
-	struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+	struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	uint32_t addr;
 	unsigned long flags;
@@ -614,39 +1261,45 @@
 	return 0;
 }
 
+static void vfe40_cfg_qos_parms(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	void __iomem *vfebase = vfe40_ctrl->share_ctrl->vfebase;
+	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_0);
+	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_1);
+	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_2);
+	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_3);
+	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_4);
+	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_5);
+	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_6);
+	msm_camera_io_w(0x0002AAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_7);
+}
+
 static void vfe40_start_common(struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	uint32_t irq_mask = 0x1E000011;
-	vfe40_ctrl->start_ack_pending = TRUE;
+	uint16_t vfe_operation_mode =
+		vfe40_ctrl->share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+			VFE_OUTPUTS_RDI1);
 	CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n",
-		vfe40_ctrl->share_ctrl->operation_mode,
+		vfe40_ctrl->share_ctrl->current_mode,
 		vfe40_ctrl->share_ctrl->outpath.output_mode);
 
-	msm_camera_io_w(irq_mask,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
-	msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+	vfe40_cfg_qos_parms(vfe40_ctrl);
 
-	/* Ensure the write order while writing
-	to the command register using the barrier */
-	msm_camera_io_w_mb(1,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
-	msm_camera_io_w_mb(1,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
+	msm_camera_io_w_mb(0x1,
+			vfe40_ctrl->share_ctrl->vfebase +
+			VFE_REG_UPDATE_CMD);
 
-	msm_camera_io_dump(vfe40_ctrl->share_ctrl->vfebase,
-		vfe40_ctrl->share_ctrl->register_total*4);
-
-	atomic_set(&vfe40_ctrl->share_ctrl->vstate, 1);
+	if (vfe_operation_mode) {
+		msm_camera_io_w_mb(1, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_CAMIF_COMMAND);
+	}
 }
 
 static int vfe40_start_recording(
 	struct msm_cam_media_controller *pmctl,
 	struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	msm_camio_bus_scale_cfg(
-		pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
-	vfe40_ctrl->recording_state = VFE_STATE_START_REQUESTED;
+	vfe40_ctrl->share_ctrl->recording_state = VFE_STATE_START_REQUESTED;
 	msm_camera_io_w_mb(1,
 		vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 	return 0;
@@ -656,11 +1309,9 @@
 	struct msm_cam_media_controller *pmctl,
 	struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	vfe40_ctrl->recording_state = VFE_STATE_STOP_REQUESTED;
+	vfe40_ctrl->share_ctrl->recording_state = VFE_STATE_STOP_REQUESTED;
 	msm_camera_io_w_mb(1,
 		vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
-	msm_camio_bus_scale_cfg(
-		pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 	return 0;
 }
 
@@ -678,97 +1329,21 @@
 		share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 }
 
+static void vfe40_stop_liveshot(
+	struct msm_cam_media_controller *pmctl,
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	vfe40_ctrl->share_ctrl->liveshot_state = VFE_STATE_STOP_REQUESTED;
+	msm_camera_io_w_mb(1,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+}
+
 static int vfe40_zsl(
 	struct msm_cam_media_controller *pmctl,
 	struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	uint32_t irq_comp_mask = 0;
-	/* capture command is valid for both idle and active state. */
-	irq_comp_mask	=
-		msm_camera_io_r(vfe40_ctrl->
-		share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
-
-	CDBG("%s:op mode %d O/P Mode %d\n", __func__,
-		vfe40_ctrl->share_ctrl->operation_mode,
-		vfe40_ctrl->share_ctrl->outpath.output_mode);
-
-	if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-		VFE40_OUTPUT_MODE_PRIMARY) {
-		irq_comp_mask |= (
-			(0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch0)) |
-			(0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch1)));
-	} else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-			VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
-		irq_comp_mask |= (
-			(0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch0)) |
-			(0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch1)) |
-			(0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch2)));
-	}
-
-	if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-		VFE40_OUTPUT_MODE_SECONDARY) {
-		irq_comp_mask |= ((0x1 << (vfe40_ctrl->
-				share_ctrl->outpath.out1.ch0 + 8)) |
-			(0x1 << (vfe40_ctrl->
-				share_ctrl->outpath.out1.ch1 + 8)));
-	} else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-			   VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
-		irq_comp_mask |= (
-			(0x1 << (vfe40_ctrl->
-				share_ctrl->outpath.out1.ch0 + 8)) |
-			(0x1 << (vfe40_ctrl->
-				share_ctrl->outpath.out1.ch1 + 8)) |
-			(0x1 << (vfe40_ctrl->
-				share_ctrl->outpath.out1.ch2 + 8)));
-	}
-
-	if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-			VFE40_OUTPUT_MODE_PRIMARY) {
-		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-			vfe40_AXI_WM_CFG[vfe40_ctrl->
-			share_ctrl->outpath.out0.ch0]);
-		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-			vfe40_AXI_WM_CFG[vfe40_ctrl->
-			share_ctrl->outpath.out0.ch1]);
-	} else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-				VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
-		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-			vfe40_AXI_WM_CFG[vfe40_ctrl->
-			share_ctrl->outpath.out0.ch0]);
-		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-			vfe40_AXI_WM_CFG[vfe40_ctrl->
-			share_ctrl->outpath.out0.ch1]);
-		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-			vfe40_AXI_WM_CFG[vfe40_ctrl->
-			share_ctrl->outpath.out0.ch2]);
-	}
-
-	if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-			VFE40_OUTPUT_MODE_SECONDARY) {
-		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-			vfe40_AXI_WM_CFG[vfe40_ctrl->
-			share_ctrl->outpath.out1.ch0]);
-		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-			vfe40_AXI_WM_CFG[vfe40_ctrl->
-			share_ctrl->outpath.out1.ch1]);
-	} else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-				VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
-		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-			vfe40_AXI_WM_CFG[vfe40_ctrl->
-			share_ctrl->outpath.out1.ch0]);
-		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-			vfe40_AXI_WM_CFG[vfe40_ctrl->
-			share_ctrl->outpath.out1.ch1]);
-		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-			vfe40_AXI_WM_CFG[vfe40_ctrl->
-			share_ctrl->outpath.out1.ch2]);
-	}
-
-	msm_camera_io_w(irq_comp_mask,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+	vfe40_ctrl->share_ctrl->start_ack_pending = TRUE;
 	vfe40_start_common(vfe40_ctrl);
-	msm_camio_bus_scale_cfg(
-		pmctl->sdata->pdata->cam_bus_scale_table, S_ZSL);
 
 	msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x18C);
 	msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x188);
@@ -779,28 +1354,8 @@
 	struct vfe40_ctrl_type *vfe40_ctrl,
 	uint32_t num_frames_capture)
 {
-	uint32_t irq_comp_mask = 0;
-
 	vfe40_ctrl->share_ctrl->outpath.out0.capture_cnt = num_frames_capture;
 	vfe40_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
-
-	irq_comp_mask	=
-		msm_camera_io_r(
-			vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
-
-	if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-		VFE40_OUTPUT_MODE_PRIMARY) {
-		irq_comp_mask |=
-			(0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch0));
-		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-			vfe40_AXI_WM_CFG[vfe40_ctrl->
-			share_ctrl->outpath.out0.ch0]);
-	}
-
-	msm_camera_io_w(irq_comp_mask,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
-	msm_camio_bus_scale_cfg(
-		pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
 	vfe40_start_common(vfe40_ctrl);
 	return 0;
 }
@@ -810,75 +1365,24 @@
 	uint32_t num_frames_capture,
 	struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	uint32_t irq_comp_mask = 0;
-
 	/* capture command is valid for both idle and active state. */
 	vfe40_ctrl->share_ctrl->outpath.out1.capture_cnt = num_frames_capture;
-	if (vfe40_ctrl->share_ctrl->operation_mode ==
+	if (vfe40_ctrl->share_ctrl->current_mode ==
 			VFE_OUTPUTS_MAIN_AND_THUMB ||
-		vfe40_ctrl->share_ctrl->operation_mode ==
+		vfe40_ctrl->share_ctrl->current_mode ==
 			VFE_OUTPUTS_THUMB_AND_MAIN ||
-		vfe40_ctrl->share_ctrl->operation_mode ==
+		vfe40_ctrl->share_ctrl->current_mode ==
 			VFE_OUTPUTS_JPEG_AND_THUMB ||
-		vfe40_ctrl->share_ctrl->operation_mode ==
+		vfe40_ctrl->share_ctrl->current_mode ==
 			VFE_OUTPUTS_THUMB_AND_JPEG) {
 		vfe40_ctrl->share_ctrl->outpath.out0.capture_cnt =
 			num_frames_capture;
 	}
 
 	vfe40_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
-	irq_comp_mask = msm_camera_io_r(
-			vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
-
-	if (vfe40_ctrl->share_ctrl->operation_mode ==
-			VFE_OUTPUTS_MAIN_AND_THUMB ||
-		vfe40_ctrl->share_ctrl->operation_mode ==
-			VFE_OUTPUTS_JPEG_AND_THUMB ||
-		vfe40_ctrl->share_ctrl->operation_mode ==
-			VFE_OUTPUTS_THUMB_AND_MAIN) {
-		if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-			VFE40_OUTPUT_MODE_PRIMARY) {
-			irq_comp_mask |= (0x1 << vfe40_ctrl->
-				share_ctrl->outpath.out0.ch0 |
-				0x1 << vfe40_ctrl->
-				share_ctrl->outpath.out0.ch1);
-		}
-		if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-			VFE40_OUTPUT_MODE_SECONDARY) {
-			irq_comp_mask |=
-				(0x1 << (vfe40_ctrl->
-					share_ctrl->outpath.out1.ch0 + 8) |
-				0x1 << (vfe40_ctrl->
-					share_ctrl->outpath.out1.ch1 + 8));
-		}
-		if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-			VFE40_OUTPUT_MODE_PRIMARY) {
-			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
-				share_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
-				share_ctrl->outpath.out0.ch1]);
-		}
-		if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-			VFE40_OUTPUT_MODE_SECONDARY) {
-			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
-				share_ctrl->outpath.out1.ch0]);
-			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
-				share_ctrl->outpath.out1.ch1]);
-		}
-	}
 
 	vfe40_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
 
-	msm_camera_io_w(irq_comp_mask,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
-	msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
-	msm_camio_bus_scale_cfg(
-		pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
-
 	vfe40_start_common(vfe40_ctrl);
 	/* for debug */
 	msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x18C);
@@ -890,41 +1394,6 @@
 	struct msm_cam_media_controller *pmctl,
 	struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	uint32_t irq_comp_mask = 0;
-	irq_comp_mask	=
-		msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
-			VFE_IRQ_COMP_MASK);
-
-	if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-			VFE40_OUTPUT_MODE_PRIMARY) {
-		irq_comp_mask |= (
-			0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch0 |
-			0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch1);
-	} else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-			   VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
-		irq_comp_mask |= (
-			0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch0 |
-			0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch1 |
-			0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch2);
-	}
-	if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-			VFE40_OUTPUT_MODE_SECONDARY) {
-		irq_comp_mask |= (
-			0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
-			0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch1 + 8));
-	} else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-			VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
-		irq_comp_mask |= (
-			0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
-			0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch1 + 8) |
-			0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch2 + 8));
-	}
-	msm_camera_io_w(irq_comp_mask,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
-
-	/*
-	msm_camio_bus_scale_cfg(
-		pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);*/
 	vfe40_start_common(vfe40_ctrl);
 	return 0;
 }
@@ -967,9 +1436,9 @@
 		vfe40_ctrl->update_gamma = false;
 	}
 
-	spin_lock_irqsave(&vfe40_ctrl->update_ack_lock, flags);
-	vfe40_ctrl->update_ack_pending = TRUE;
-	spin_unlock_irqrestore(&vfe40_ctrl->update_ack_lock, flags);
+	spin_lock_irqsave(&vfe40_ctrl->share_ctrl->update_ack_lock, flags);
+	vfe40_ctrl->share_ctrl->update_ack_pending = TRUE;
+	spin_unlock_irqrestore(&vfe40_ctrl->share_ctrl->update_ack_lock, flags);
 	/* Ensure the write order while writing
 	to the command register using the barrier */
 	msm_camera_io_w_mb(1,
@@ -1031,7 +1500,7 @@
 			 8 + ((vfe40_ctrl->sync_timer_number) * 12));
 	/* Sync Timer Pixel Duration */
 	value = *tbl++;
-	val = vfe40_ctrl->share_ctrl->vfe_clk_rate / 10000;
+	val = vfe_clk_rate / 10000;
 	val = 10000000 / val;
 	val = value * 10000 / val;
 	CDBG("%s: Pixel Clk Cycles!!! %d\n", __func__, val);
@@ -1048,19 +1517,7 @@
 		vfe40_ctrl->share_ctrl->vfebase + V40_TIMER_SELECT_OFF);
 }
 
-static void vfe40_program_dmi_cfg(
-	enum VFE40_DMI_RAM_SEL bankSel,
-	struct vfe40_ctrl_type *vfe40_ctrl)
-{
-	/* set bit 8 for auto increment. */
-	uint32_t value = VFE_DMI_CFG_DEFAULT;
-	value += (uint32_t)bankSel;
-	CDBG("%s: banksel = %d\n", __func__, bankSel);
 
-	msm_camera_io_w(value, vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_CFG);
-	/* by default, always starts with offset 0.*/
-	msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_ADDR);
-}
 static void vfe40_write_gamma_cfg(
 	enum VFE40_DMI_RAM_SEL channel_sel,
 	const uint32_t *tbl,
@@ -1119,7 +1576,7 @@
 	vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
 }
 
-struct vfe40_output_ch *vfe40_get_ch(
+static struct vfe40_output_ch *vfe40_get_ch(
 	int path, struct vfe_share_ctrl_t *share_ctrl)
 {
 	struct vfe40_output_ch *ch = NULL;
@@ -1128,6 +1585,10 @@
 		ch = &share_ctrl->outpath.out0;
 	else if (path == VFE_MSG_OUTPUT_SECONDARY)
 		ch = &share_ctrl->outpath.out1;
+	else if (path == VFE_MSG_OUTPUT_TERTIARY1)
+		ch = &share_ctrl->outpath.out2;
+	else if (path == VFE_MSG_OUTPUT_TERTIARY2)
+		ch = &share_ctrl->outpath.out3;
 	else
 		pr_err("%s: Invalid path %d\n", __func__,
 			path);
@@ -1135,49 +1596,76 @@
 	BUG_ON(ch == NULL);
 	return ch;
 }
+static struct msm_free_buf *vfe40_check_free_buffer(
+	int id, int path, struct axi_ctrl_t *axi_ctrl)
+{
+	struct vfe40_output_ch *outch = NULL;
+	struct msm_free_buf *b = NULL;
+	uint32_t inst_handle = 0;
 
-static int vfe40_configure_pingpong_buffers(
-	int id, int path, struct vfe40_ctrl_type *vfe40_ctrl)
+	if (path == VFE_MSG_OUTPUT_PRIMARY)
+		inst_handle = axi_ctrl->share_ctrl->outpath.out0.inst_handle;
+	else if (path == VFE_MSG_OUTPUT_SECONDARY)
+		inst_handle = axi_ctrl->share_ctrl->outpath.out1.inst_handle;
+	else if (path == VFE_MSG_OUTPUT_TERTIARY1)
+		inst_handle = axi_ctrl->share_ctrl->outpath.out2.inst_handle;
+	else if (path == VFE_MSG_OUTPUT_TERTIARY2)
+		inst_handle = axi_ctrl->share_ctrl->outpath.out3.inst_handle;
+
+	vfe40_subdev_notify(id, path, inst_handle,
+		&axi_ctrl->subdev, axi_ctrl->share_ctrl);
+	outch = vfe40_get_ch(path, axi_ctrl->share_ctrl);
+	if (outch->free_buf.ch_paddr[0])
+		b = &outch->free_buf;
+	return b;
+}
+static int configure_pingpong_buffers(
+	int id, int path, struct axi_ctrl_t *axi_ctrl)
 {
 	struct vfe40_output_ch *outch = NULL;
 	int rc = 0;
-	uint32_t image_mode = 0;
+	uint32_t inst_handle = 0;
 	if (path == VFE_MSG_OUTPUT_PRIMARY)
-		image_mode = vfe40_ctrl->share_ctrl->outpath.out0.image_mode;
-	else
-		image_mode = vfe40_ctrl->share_ctrl->outpath.out1.image_mode;
+		inst_handle = axi_ctrl->share_ctrl->outpath.out0.inst_handle;
+	else if (path == VFE_MSG_OUTPUT_SECONDARY)
+		inst_handle = axi_ctrl->share_ctrl->outpath.out1.inst_handle;
+	else if (path == VFE_MSG_OUTPUT_TERTIARY1)
+		inst_handle = axi_ctrl->share_ctrl->outpath.out2.inst_handle;
+	else if (path == VFE_MSG_OUTPUT_TERTIARY2)
+		inst_handle = axi_ctrl->share_ctrl->outpath.out3.inst_handle;
 
-	vfe40_subdev_notify(id, path, image_mode,
-		&vfe40_ctrl->subdev, vfe40_ctrl->share_ctrl);
-	outch = vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
+	vfe40_subdev_notify(id, path, inst_handle,
+		&axi_ctrl->subdev, axi_ctrl->share_ctrl);
+	outch = vfe40_get_ch(path, axi_ctrl->share_ctrl);
 	if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
 		/* Configure Preview Ping Pong */
-		CDBG("%s Configure ping/pong address for %d",
+		pr_info("%s Configure ping/pong address for %d",
 						__func__, path);
 		vfe40_put_ch_ping_addr(
-			vfe40_ctrl->share_ctrl->vfebase, outch->ch0,
+			axi_ctrl->share_ctrl->vfebase, outch->ch0,
 			outch->ping.ch_paddr[0]);
 		vfe40_put_ch_pong_addr(
-			vfe40_ctrl->share_ctrl->vfebase, outch->ch0,
+			axi_ctrl->share_ctrl->vfebase, outch->ch0,
 			outch->pong.ch_paddr[0]);
 
-		if (vfe40_ctrl->share_ctrl->operation_mode !=
-			VFE_OUTPUTS_RAW) {
+		if ((axi_ctrl->share_ctrl->current_mode !=
+			VFE_OUTPUTS_RAW) && (path != VFE_MSG_OUTPUT_TERTIARY1)
+			&& (path != VFE_MSG_OUTPUT_TERTIARY2)) {
 			vfe40_put_ch_ping_addr(
-				vfe40_ctrl->share_ctrl->vfebase, outch->ch1,
+				axi_ctrl->share_ctrl->vfebase, outch->ch1,
 				outch->ping.ch_paddr[1]);
 			vfe40_put_ch_pong_addr(
-				vfe40_ctrl->share_ctrl->vfebase, outch->ch1,
+				axi_ctrl->share_ctrl->vfebase, outch->ch1,
 				outch->pong.ch_paddr[1]);
 		}
 
 		if (outch->ping.num_planes > 2)
 			vfe40_put_ch_ping_addr(
-				vfe40_ctrl->share_ctrl->vfebase, outch->ch2,
+				axi_ctrl->share_ctrl->vfebase, outch->ch2,
 				outch->ping.ch_paddr[2]);
 		if (outch->pong.num_planes > 2)
 			vfe40_put_ch_pong_addr(
-				vfe40_ctrl->share_ctrl->vfebase, outch->ch2,
+				axi_ctrl->share_ctrl->vfebase, outch->ch2,
 				outch->pong.ch_paddr[2]);
 
 		/* avoid stale info */
@@ -1207,7 +1695,7 @@
 	vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
 }
 
-void vfe40_send_isp_msg(
+static void vfe40_send_isp_msg(
 	struct v4l2_subdev *sd,
 	uint32_t vfeFrameId,
 	uint32_t isp_msg_id)
@@ -1227,142 +1715,76 @@
 	struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	int i , rc = 0;
-	uint32_t old_val = 0 , new_val = 0;
+	uint32_t old_val = 0 , new_val = 0, module_val = 0;
 	uint32_t *cmdp = NULL;
 	uint32_t *cmdp_local = NULL;
 	uint32_t snapshot_cnt = 0;
 	uint32_t temp1 = 0, temp2 = 0;
+	struct msm_camera_vfe_params_t vfe_params;
 
 	CDBG("vfe40_proc_general: cmdID = %s, length = %d\n",
 		vfe40_general_cmd[cmd->id], cmd->length);
 	switch (cmd->id) {
 	case VFE_CMD_RESET:
-		CDBG("vfe40_proc_general: cmdID = %s\n",
+		pr_info("vfe40_proc_general: cmdID = %s\n",
 			vfe40_general_cmd[cmd->id]);
+		vfe40_ctrl->share_ctrl->vfe_reset_flag = true;
 		vfe40_reset(vfe40_ctrl);
 		break;
 	case VFE_CMD_START:
-		CDBG("vfe40_proc_general: cmdID = %s\n",
+		pr_info("vfe40_proc_general: cmdID = %s\n",
 			vfe40_general_cmd[cmd->id]);
-		if ((vfe40_ctrl->share_ctrl->operation_mode ==
-				VFE_OUTPUTS_PREVIEW_AND_VIDEO) ||
-				(vfe40_ctrl->share_ctrl->operation_mode ==
-				VFE_OUTPUTS_PREVIEW))
-			/* Configure primary channel */
-			rc = vfe40_configure_pingpong_buffers(
-				VFE_MSG_START, VFE_MSG_OUTPUT_PRIMARY,
-				vfe40_ctrl);
-		else
-			/* Configure secondary channel */
-			rc = vfe40_configure_pingpong_buffers(
-				VFE_MSG_START, VFE_MSG_OUTPUT_SECONDARY,
-				vfe40_ctrl);
-		if (rc < 0) {
-			pr_err(
-				"%s error configuring pingpong buffers for preview",
-				__func__);
-			rc = -EINVAL;
-			goto proc_general_done;
+		if (copy_from_user(&vfe_params,
+				(void __user *)(cmd->value),
+				sizeof(struct msm_camera_vfe_params_t))) {
+				rc = -EFAULT;
+				goto proc_general_done;
 		}
 
+		vfe40_ctrl->share_ctrl->current_mode =
+			vfe_params.operation_mode;
+
 		rc = vfe40_start(pmctl, vfe40_ctrl);
 		break;
 	case VFE_CMD_UPDATE:
 		vfe40_update(vfe40_ctrl);
 		break;
 	case VFE_CMD_CAPTURE_RAW:
-		CDBG("%s: cmdID = VFE_CMD_CAPTURE_RAW\n", __func__);
-		if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
-				sizeof(uint32_t))) {
-			rc = -EFAULT;
-			goto proc_general_done;
+		pr_info("%s: cmdID = VFE_CMD_CAPTURE_RAW\n", __func__);
+		if (copy_from_user(&vfe_params,
+				(void __user *)(cmd->value),
+				sizeof(struct msm_camera_vfe_params_t))) {
+				rc = -EFAULT;
+				goto proc_general_done;
 		}
-		rc = vfe40_configure_pingpong_buffers(
-			VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_PRIMARY,
-			vfe40_ctrl);
-		if (rc < 0) {
-			pr_err(
-				"%s error configuring pingpong buffers for snapshot",
-				__func__);
-			rc = -EINVAL;
-			goto proc_general_done;
-		}
+
+		snapshot_cnt = vfe_params.capture_count;
+		vfe40_ctrl->share_ctrl->current_mode =
+			vfe_params.operation_mode;
 		rc = vfe40_capture_raw(pmctl, vfe40_ctrl, snapshot_cnt);
 		break;
 	case VFE_CMD_CAPTURE:
-		if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
-				sizeof(uint32_t))) {
-			rc = -EFAULT;
-			goto proc_general_done;
+		pr_info("%s: cmdID = VFE_CMD_CAPTURE\n", __func__);
+		if (copy_from_user(&vfe_params,
+				(void __user *)(cmd->value),
+				sizeof(struct msm_camera_vfe_params_t))) {
+				rc = -EFAULT;
+				goto proc_general_done;
 		}
 
-		if (vfe40_ctrl->share_ctrl->operation_mode ==
-			VFE_OUTPUTS_JPEG_AND_THUMB ||
-		vfe40_ctrl->share_ctrl->operation_mode ==
-			VFE_OUTPUTS_THUMB_AND_JPEG) {
-			if (snapshot_cnt != 1) {
-				pr_err("only support 1 inline snapshot\n");
-				rc = -EINVAL;
-				goto proc_general_done;
-			}
-			/* Configure primary channel for JPEG */
-			rc = vfe40_configure_pingpong_buffers(
-				VFE_MSG_JPEG_CAPTURE,
-				VFE_MSG_OUTPUT_PRIMARY,
-				vfe40_ctrl);
-		} else {
-			/* Configure primary channel */
-			rc = vfe40_configure_pingpong_buffers(
-				VFE_MSG_CAPTURE,
-				VFE_MSG_OUTPUT_PRIMARY,
-				vfe40_ctrl);
-		}
-		if (rc < 0) {
-			pr_err(
-			"%s error configuring pingpong buffers for primary output",
-			__func__);
-			rc = -EINVAL;
-			goto proc_general_done;
-		}
-		/* Configure secondary channel */
-		rc = vfe40_configure_pingpong_buffers(
-				VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_SECONDARY,
-				vfe40_ctrl);
-		if (rc < 0) {
-			pr_err(
-			"%s error configuring pingpong buffers for secondary output",
-			__func__);
-			rc = -EINVAL;
-			goto proc_general_done;
-		}
+		snapshot_cnt = vfe_params.capture_count;
+		vfe40_ctrl->share_ctrl->current_mode =
+			vfe_params.operation_mode;
+
 		rc = vfe40_capture(pmctl, snapshot_cnt, vfe40_ctrl);
 		break;
 	case VFE_CMD_START_RECORDING:
-		CDBG("vfe40_proc_general: cmdID = %s\n",
+		pr_info("vfe40_proc_general: cmdID = %s\n",
 			vfe40_general_cmd[cmd->id]);
-		if (vfe40_ctrl->share_ctrl->operation_mode ==
-			VFE_OUTPUTS_PREVIEW_AND_VIDEO)
-			rc = vfe40_configure_pingpong_buffers(
-				VFE_MSG_START_RECORDING,
-				VFE_MSG_OUTPUT_SECONDARY,
-				vfe40_ctrl);
-		else if (vfe40_ctrl->share_ctrl->operation_mode ==
-			VFE_OUTPUTS_VIDEO_AND_PREVIEW)
-			rc = vfe40_configure_pingpong_buffers(
-				VFE_MSG_START_RECORDING,
-				VFE_MSG_OUTPUT_PRIMARY,
-				vfe40_ctrl);
-		if (rc < 0) {
-			pr_err(
-				"%s error configuring pingpong buffers for video\n",
-				__func__);
-			rc = -EINVAL;
-			goto proc_general_done;
-		}
 		rc = vfe40_start_recording(pmctl, vfe40_ctrl);
 		break;
 	case VFE_CMD_STOP_RECORDING:
-		CDBG("vfe40_proc_general: cmdID = %s\n",
+		pr_info("vfe40_proc_general: cmdID = %s\n",
 			vfe40_general_cmd[cmd->id]);
 		rc = vfe40_stop_recording(pmctl, vfe40_ctrl);
 		break;
@@ -1383,7 +1805,12 @@
 		break;
 
 	case VFE_CMD_STATS_AE_START: {
-		rc = vfe_stats_aec_buf_init(vfe40_ctrl, NULL);
+		if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		rc = vfe_stats_aec_bg_buf_init(vfe40_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of AEC",
 				 __func__);
@@ -1412,7 +1839,12 @@
 		}
 		break;
 	case VFE_CMD_STATS_AF_START: {
-		rc = vfe_stats_af_buf_init(vfe40_ctrl, NULL);
+		if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		rc = vfe_stats_af_bf_buf_init(vfe40_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of AF",
 				__func__);
@@ -1440,8 +1872,12 @@
 			cmdp, (vfe40_cmd[cmd->id].length));
 		}
 		break;
-
 	case VFE_CMD_STATS_AWB_START: {
+		if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
 		rc = vfe_stats_awb_buf_init(vfe40_ctrl, NULL);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of AWB",
@@ -1472,7 +1908,7 @@
 		break;
 
 	case VFE_CMD_STATS_IHIST_START: {
-		rc = vfe_stats_ihist_buf_init(vfe40_ctrl, NULL);
+		rc = vfe_stats_ihist_buf_init(vfe40_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of IHIST",
 				 __func__);
@@ -1503,7 +1939,7 @@
 
 
 	case VFE_CMD_STATS_RS_START: {
-		rc = vfe_stats_rs_buf_init(vfe40_ctrl, NULL);
+		rc = vfe_stats_rs_buf_init(vfe40_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of RS",
 				__func__);
@@ -1528,7 +1964,7 @@
 		break;
 
 	case VFE_CMD_STATS_CS_START: {
-		rc = vfe_stats_cs_buf_init(vfe40_ctrl, NULL);
+		rc = vfe_stats_cs_buf_init(vfe40_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of CS",
 				__func__);
@@ -1552,6 +1988,65 @@
 		}
 		break;
 
+	case VFE_CMD_STATS_BG_START:
+	case VFE_CMD_STATS_BF_START:
+	case VFE_CMD_STATS_BHIST_START: {
+		if (!vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
+		module_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		if (VFE_CMD_STATS_BG_START == cmd->id) {
+			module_val |= BG_ENABLE_MASK;
+			rc = vfe_stats_aec_bg_buf_init(vfe40_ctrl);
+			if (rc < 0) {
+				pr_err("%s: cannot config ping/pong address of CS",
+					__func__);
+				goto proc_general_done;
+			}
+		} else if (VFE_CMD_STATS_BF_START == cmd->id) {
+			module_val |= BF_ENABLE_MASK;
+			rc = vfe_stats_af_bf_buf_init(vfe40_ctrl);
+			if (rc < 0) {
+				pr_err("%s: cannot config ping/pong address of CS",
+					__func__);
+				goto proc_general_done;
+			}
+		} else {
+			module_val |= BHIST_ENABLE_MASK;
+			old_val |= STATS_BHIST_ENABLE_MASK;
+			rc = vfe_stats_bhist_buf_init(vfe40_ctrl);
+			if (rc < 0) {
+				pr_err("%s: cannot config ping/pong address of CS",
+					__func__);
+				goto proc_general_done;
+			}
+		}
+		msm_camera_io_w(old_val, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_STATS_CFG);
+		msm_camera_io_w(module_val,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+				(void __user *)(cmd->value),
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp, (vfe40_cmd[cmd->id].length));
+		}
+		break;
 	case VFE_CMD_MCE_UPDATE:
 	case VFE_CMD_MCE_CFG:{
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
@@ -1638,6 +2133,38 @@
 		rc = -EFAULT;
 		goto proc_general_done;
 
+	case VFE_CMD_MESH_ROLL_OFF_CFG: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value) , cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp_local, V40_MESH_ROLL_OFF_CFG_LEN);
+		cmdp_local += 9;
+		vfe40_program_dmi_cfg(ROLLOFF_RAM0_BANK0, vfe40_ctrl);
+		/* for loop for extrcting table. */
+		for (i = 0; i < (V40_MESH_ROLL_OFF_TABLE_SIZE * 2); i++) {
+			msm_camera_io_w(*cmdp_local,
+				vfe40_ctrl->share_ctrl->vfebase +
+				VFE_DMI_DATA_LO);
+			cmdp_local++;
+		}
+		CDBG("done writing mesh table\n");
+		vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+	}
+	break;
+	case VFE_CMD_GET_MESH_ROLLOFF_TABLE:
+		break;
+
 	case VFE_CMD_LA_CFG:
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
@@ -1746,15 +2273,6 @@
 
 	case VFE_CMD_LIVESHOT:
 		/* Configure primary channel */
-		rc = vfe40_configure_pingpong_buffers(VFE_MSG_CAPTURE,
-					VFE_MSG_OUTPUT_PRIMARY, vfe40_ctrl);
-		if (rc < 0) {
-			pr_err(
-			"%s error configuring pingpong buffers for primary output\n",
-			__func__);
-			rc = -EINVAL;
-			goto proc_general_done;
-		}
 		vfe40_start_liveshot(pmctl, vfe40_ctrl);
 		break;
 
@@ -1774,7 +2292,6 @@
 			vfe40_ctrl->share_ctrl->vfebase +
 			V40_LINEARIZATION_OFF1,
 			cmdp_local, V40_LINEARIZATION_LEN1);
-
 		cmdp_local = cmdp + 17;
 		vfe40_write_linear_cfg(BLACK_LUT_RAM_BANK0,
 					cmdp_local, vfe40_ctrl);
@@ -2126,6 +2643,11 @@
 		break;
 
 	case VFE_CMD_STATS_AWB_STOP: {
+		if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
 		old_val = msm_camera_io_r(
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		old_val &= ~AWB_ENABLE_MASK;
@@ -2133,27 +2655,30 @@
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		}
 		break;
-
 	case VFE_CMD_STATS_AE_STOP: {
+		if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
 		old_val = msm_camera_io_r(
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
-		old_val &= ~BG_ENABLE_MASK;
+		old_val &= BG_ENABLE_MASK;
 		msm_camera_io_w(old_val,
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		}
 		break;
 	case VFE_CMD_STATS_AF_STOP: {
+		if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
 		old_val = msm_camera_io_r(
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		old_val &= ~BF_ENABLE_MASK;
 		msm_camera_io_w(old_val,
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
-		rc = vfe40_stats_flush_enqueue(vfe40_ctrl, MSM_STATS_TYPE_AF);
-		if (rc < 0) {
-			pr_err("%s: dq stats buf err = %d",
-				   __func__, rc);
-			return -EINVAL;
-		}
 		}
 		break;
 
@@ -2183,9 +2708,47 @@
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		}
 		break;
+
+	case VFE_CMD_STATS_BG_STOP:
+	case VFE_CMD_STATS_BF_STOP:
+	case VFE_CMD_STATS_BHIST_STOP: {
+		if (!vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
+
+		if (VFE_CMD_STATS_BHIST_STOP == cmd->id)
+			old_val &= ~STATS_BHIST_ENABLE_MASK;
+
+		msm_camera_io_w(old_val,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
+		if (VFE_CMD_STATS_BF_STOP == cmd->id) {
+			rc = vfe40_stats_flush_enqueue(vfe40_ctrl,
+					MSM_STATS_TYPE_BF);
+			if (rc < 0) {
+				pr_err("%s: dq stats buf err = %d",
+					   __func__, rc);
+				return -EINVAL;
+			}
+		}
+		}
+		break;
+
 	case VFE_CMD_STOP:
-		CDBG("vfe40_proc_general: cmdID = %s\n",
+		pr_info("vfe40_proc_general: cmdID = %s\n",
 			vfe40_general_cmd[cmd->id]);
+		if (copy_from_user(&vfe_params,
+				(void __user *)(cmd->value),
+				sizeof(struct msm_camera_vfe_params_t))) {
+				rc = -EFAULT;
+				goto proc_general_done;
+		}
+
+		vfe40_ctrl->share_ctrl->current_mode =
+			vfe_params.operation_mode;
 		vfe40_stop(vfe40_ctrl);
 		break;
 
@@ -2229,14 +2792,15 @@
 		break;
 
 	case VFE_CMD_ZSL:
-		rc = vfe40_configure_pingpong_buffers(VFE_MSG_START,
-			VFE_MSG_OUTPUT_PRIMARY, vfe40_ctrl);
-		if (rc < 0)
-			goto proc_general_done;
-		rc = vfe40_configure_pingpong_buffers(VFE_MSG_START,
-			VFE_MSG_OUTPUT_SECONDARY, vfe40_ctrl);
-		if (rc < 0)
-			goto proc_general_done;
+		if (copy_from_user(&vfe_params,
+				(void __user *)(cmd->value),
+				sizeof(struct msm_camera_vfe_params_t))) {
+				rc = -EFAULT;
+				goto proc_general_done;
+		}
+
+		vfe40_ctrl->share_ctrl->current_mode =
+			vfe_params.operation_mode;
 
 		rc = vfe40_zsl(pmctl, vfe40_ctrl);
 		break;
@@ -2331,6 +2895,10 @@
 			*cmdp & VFE_FRAME_SKIP_PERIOD_MASK) + 1;
 		vfe40_ctrl->frame_skip_pattern = (uint32_t)(*(cmdp + 2));
 		break;
+	case VFE_CMD_STOP_LIVESHOT:
+		CDBG("%s Stopping liveshot ", __func__);
+		vfe40_stop_liveshot(pmctl, vfe40_ctrl);
+		break;
 	default:
 		if (cmd->length != vfe40_cmd[cmd->id].length)
 			return -EINVAL;
@@ -2389,221 +2957,505 @@
 
 }
 
+void axi_stop_pix(struct vfe_share_ctrl_t *share_ctrl)
+{
+	uint32_t operation_mode =
+	share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+		VFE_OUTPUTS_RDI1);
+	uint32_t irq_comp_mask, irq_mask;
+	uint32_t reg_update = 0x1;
+
+	irq_comp_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_COMP_MASK);
+	irq_mask = msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+
+	switch (share_ctrl->cmd_type) {
+	case AXI_CMD_PREVIEW: {
+		switch (operation_mode) {
+		case VFE_OUTPUTS_PREVIEW:
+		case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
+			if (share_ctrl->comp_output_mode &
+				VFE40_OUTPUT_MODE_PRIMARY) {
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out0.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out0.ch1]);
+				irq_comp_mask &= ~(
+					0x1 << share_ctrl->outpath.out0.ch0 |
+					0x1 << share_ctrl->outpath.out0.ch1);
+				share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_PRIMARY;
+			} else if (share_ctrl->comp_output_mode &
+					VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out0.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out0.ch1]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out0.ch2]);
+				irq_comp_mask &= ~(
+					0x1 << share_ctrl->outpath.out0.ch0 |
+					0x1 << share_ctrl->outpath.out0.ch1 |
+					0x1 << share_ctrl->outpath.out0.ch2);
+				share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+			}
+			irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+			break;
+		default:
+			if (share_ctrl->comp_output_mode &
+				VFE40_OUTPUT_MODE_SECONDARY) {
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out1.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out1.ch1]);
+				irq_comp_mask &= ~(
+					0x1 << share_ctrl->outpath.out1.ch0 |
+					0x1 << share_ctrl->outpath.out1.ch1);
+				share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_SECONDARY;
+			} else if (share_ctrl->comp_output_mode &
+				VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out1.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out1.ch1]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out1.ch2]);
+				irq_comp_mask &= ~(
+					0x1 << share_ctrl->outpath.out1.ch0 |
+					0x1 << share_ctrl->outpath.out1.ch1 |
+					0x1 << share_ctrl->outpath.out1.ch2);
+				share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS;
+			}
+			irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+			break;
+			}
+		}
+		break;
+	default:
+		if (share_ctrl->comp_output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->
+				outpath.out0.ch0]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->
+				outpath.out0.ch1]);
+			irq_comp_mask &= ~(
+				0x1 << share_ctrl->outpath.out0.ch0 |
+				0x1 << share_ctrl->outpath.out0.ch1);
+			irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+			share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_PRIMARY;
+		} else if (share_ctrl->comp_output_mode &
+				VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->
+				outpath.out0.ch0]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->
+				outpath.out0.ch1]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->
+				outpath.out0.ch2]);
+			irq_comp_mask &= ~(
+				0x1 << share_ctrl->outpath.out0.ch0 |
+				0x1 << share_ctrl->outpath.out0.ch1 |
+				0x1 << share_ctrl->outpath.out0.ch2);
+			irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+			share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+		}
+
+		if (share_ctrl->comp_output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY) {
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->
+				outpath.out1.ch0]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->outpath.out1.ch1]);
+			irq_comp_mask &= ~(
+				0x1 << share_ctrl->outpath.out1.ch0 |
+				0x1 << share_ctrl->outpath.out1.ch1);
+			irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+			share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_SECONDARY;
+		} else if (share_ctrl->comp_output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->outpath.out1.ch1]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->outpath.out1.ch2]);
+			irq_comp_mask &= ~(
+				0x1 << share_ctrl->outpath.out1.ch0 |
+				0x1 << share_ctrl->outpath.out1.ch1 |
+				0x1 << share_ctrl->outpath.out1.ch2);
+			irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+			share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS;
+		}
+		break;
+	}
+
+	msm_camera_io_w_mb(reg_update,
+		share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	msm_camera_io_w(irq_comp_mask,
+		share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+	msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+}
+
+void axi_stop_rdi0(struct vfe_share_ctrl_t *share_ctrl)
+{
+	uint32_t reg_update = 0x2;
+	uint32_t irq_mask;
+	irq_mask = msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+		msm_camera_io_w(0, share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[share_ctrl->outpath.out2.ch0]);
+		irq_mask &= ~(0x1 << (share_ctrl->outpath.out2.ch0 +
+				VFE_WM_OFFSET));
+	}
+	msm_camera_io_w_mb(reg_update,
+		share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+}
+
+void axi_stop_rdi1(struct vfe_share_ctrl_t *share_ctrl)
+{
+	uint32_t reg_update = 0x4;
+	uint32_t irq_mask;
+	irq_mask = msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+		msm_camera_io_w(1, share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[share_ctrl->outpath.out3.ch0]);
+		irq_mask &= ~(0x1 << (share_ctrl->outpath.out3.ch0 +
+			VFE_WM_OFFSET));
+	}
+
+	msm_camera_io_w_mb(reg_update,
+		share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+}
+
+void axi_stop_process(struct vfe_share_ctrl_t *share_ctrl)
+{
+	uint32_t operation_mode =
+	share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+		VFE_OUTPUTS_RDI1);
+
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+		axi_stop_rdi0(share_ctrl);
+		share_ctrl->comp_output_mode &= ~VFE40_OUTPUT_MODE_TERTIARY1;
+	}
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+		axi_stop_rdi1(share_ctrl);
+		share_ctrl->comp_output_mode &= ~VFE40_OUTPUT_MODE_TERTIARY2;
+	}
+	if (operation_mode) {
+		axi_stop_pix(share_ctrl);
+		share_ctrl->comp_output_mode &=
+				~(share_ctrl->outpath.output_mode);
+	}
+}
+
 static void vfe40_process_reg_update_irq(
 		struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	unsigned long flags;
+	struct vfe_share_ctrl_t *share_ctrl = vfe40_ctrl->share_ctrl;
 
-	if (vfe40_ctrl->recording_state == VFE_STATE_START_REQUESTED) {
-		if (vfe40_ctrl->share_ctrl->operation_mode ==
+	if (atomic_cmpxchg(
+		&share_ctrl->pix0_update_ack_pending, 2, 0) == 2) {
+		axi_stop_pix(share_ctrl);
+		msm_camera_io_w_mb(
+				CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+				share_ctrl->vfebase + VFE_CAMIF_COMMAND);
+		axi_disable_irq(share_ctrl);
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			share_ctrl->vfeFrameId,
+			MSG_ID_PIX0_UPDATE_ACK);
+		share_ctrl->comp_output_mode &=
+				~(share_ctrl->outpath.output_mode);
+		share_ctrl->current_mode &=
+			(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI0);
+	}  else {
+		if (share_ctrl->recording_state == VFE_STATE_START_REQUESTED) {
+			if (share_ctrl->operation_mode &
 				VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
-			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(1,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(1,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out0.ch1]);
-		} else if (vfe40_ctrl->share_ctrl->operation_mode ==
+			} else if (share_ctrl->operation_mode &
 				VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
-			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(1,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out1.ch0]);
-			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(1,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out1.ch1]);
 		}
-		vfe40_ctrl->recording_state = VFE_STATE_STARTED;
+			share_ctrl->recording_state = VFE_STATE_STARTED;
 		msm_camera_io_w_mb(1,
-			vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+				share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 		CDBG("start video triggered .\n");
-	} else if (vfe40_ctrl->recording_state ==
+		} else if (share_ctrl->recording_state ==
 			VFE_STATE_STOP_REQUESTED) {
-		if (vfe40_ctrl->share_ctrl->operation_mode ==
+			if (share_ctrl->operation_mode &
 				VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
-			msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(0,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(0,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out0.ch1]);
-		} else if (vfe40_ctrl->share_ctrl->operation_mode ==
+			} else if (share_ctrl->operation_mode &
 				VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
-			msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(0,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out1.ch0]);
-			msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(0,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out1.ch1]);
 		}
 		CDBG("stop video triggered .\n");
 	}
 
-	if (vfe40_ctrl->start_ack_pending == TRUE) {
+		if (atomic_cmpxchg(
+			&share_ctrl->pix0_update_ack_pending, 1, 0) == 1) {
+			share_ctrl->comp_output_mode |=
+				(share_ctrl->outpath.output_mode
+				& ~(VFE40_OUTPUT_MODE_TERTIARY1|
+					VFE40_OUTPUT_MODE_TERTIARY2));
 		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
-			vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK);
-		vfe40_ctrl->start_ack_pending = FALSE;
+				share_ctrl->vfeFrameId, MSG_ID_PIX0_UPDATE_ACK);
+			share_ctrl->current_mode &=
+				(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI0);
 	} else {
-		if (vfe40_ctrl->recording_state ==
-				VFE_STATE_STOP_REQUESTED) {
-			vfe40_ctrl->recording_state = VFE_STATE_STOPPED;
+		if (share_ctrl->recording_state ==
+			VFE_STATE_STOP_REQUESTED) {
+				share_ctrl->recording_state = VFE_STATE_STOPPED;
 			/* request a reg update and send STOP_REC_ACK
 			 * when we process the next reg update irq.
 			 */
-			msm_camera_io_w_mb(1,
-			vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
-		} else if (vfe40_ctrl->recording_state ==
+			msm_camera_io_w_mb(1, share_ctrl->vfebase +
+						VFE_REG_UPDATE_CMD);
+		} else if (share_ctrl->recording_state ==
 					VFE_STATE_STOPPED) {
 			vfe40_send_isp_msg(&vfe40_ctrl->subdev,
-				vfe40_ctrl->share_ctrl->vfeFrameId,
+					share_ctrl->vfeFrameId,
 				MSG_ID_STOP_REC_ACK);
-			vfe40_ctrl->recording_state = VFE_STATE_IDLE;
+				share_ctrl->recording_state = VFE_STATE_IDLE;
 		}
-		spin_lock_irqsave(&vfe40_ctrl->update_ack_lock, flags);
-		if (vfe40_ctrl->update_ack_pending == TRUE) {
-			vfe40_ctrl->update_ack_pending = FALSE;
+		spin_lock_irqsave(&share_ctrl->update_ack_lock, flags);
+		if (share_ctrl->update_ack_pending == TRUE) {
+			share_ctrl->update_ack_pending = FALSE;
 			spin_unlock_irqrestore(
-				&vfe40_ctrl->update_ack_lock, flags);
+				&share_ctrl->update_ack_lock, flags);
 			vfe40_send_isp_msg(&vfe40_ctrl->subdev,
-				vfe40_ctrl->share_ctrl->vfeFrameId,
-				MSG_ID_UPDATE_ACK);
+				share_ctrl->vfeFrameId, MSG_ID_UPDATE_ACK);
 		} else {
 			spin_unlock_irqrestore(
-				&vfe40_ctrl->update_ack_lock, flags);
+					&share_ctrl->update_ack_lock, flags);
 		}
 	}
 
-	if (vfe40_ctrl->share_ctrl->liveshot_state ==
-		VFE_STATE_START_REQUESTED) {
+	switch (share_ctrl->liveshot_state) {
+	case VFE_STATE_START_REQUESTED:
 		CDBG("%s enabling liveshot output\n", __func__);
-		if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-				VFE40_OUTPUT_MODE_PRIMARY) {
-			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+			if (share_ctrl->comp_output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+				msm_camera_io_w(1, share_ctrl->vfebase +
+					vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-			vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(1, share_ctrl->vfebase +
+					vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out0.ch1]);
-			vfe40_ctrl->share_ctrl->liveshot_state =
+
+				share_ctrl->liveshot_state =
 				VFE_STATE_STARTED;
 		}
-	}
-
-	if (vfe40_ctrl->share_ctrl->liveshot_state == VFE_STATE_STARTED) {
-		vfe40_ctrl->share_ctrl->vfe_capture_count--;
-		if (!vfe40_ctrl->share_ctrl->vfe_capture_count)
-			vfe40_ctrl->share_ctrl->liveshot_state =
-				VFE_STATE_STOP_REQUESTED;
-		msm_camera_io_w_mb(1, vfe40_ctrl->
-			share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
-	} else if (vfe40_ctrl->share_ctrl->liveshot_state ==
-			VFE_STATE_STOP_REQUESTED) {
-		CDBG("%s: disabling liveshot output\n", __func__);
-		if (vfe40_ctrl->share_ctrl->outpath.output_mode &
-			VFE40_OUTPUT_MODE_PRIMARY) {
-			msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+		break;
+	case VFE_STATE_STARTED:
+			share_ctrl->vfe_capture_count--;
+			if (!share_ctrl->vfe_capture_count &&
+				(share_ctrl->comp_output_mode &
+				VFE40_OUTPUT_MODE_PRIMARY)) {
+				msm_camera_io_w(0, share_ctrl->vfebase +
+					vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(0, share_ctrl->vfebase +
+					vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out0.ch1]);
-			vfe40_ctrl->share_ctrl->liveshot_state =
-				VFE_STATE_STOPPED;
-			msm_camera_io_w_mb(1, vfe40_ctrl->share_ctrl->vfebase +
+		}
+		break;
+	case VFE_STATE_STOP_REQUESTED:
+		if (share_ctrl->comp_output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+			/* Stop requested, stop write masters, and
+			 * trigger REG_UPDATE. Send STOP_LS_ACK in
+			 * next reg update. */
+				msm_camera_io_w(0, share_ctrl->vfebase +
+					vfe40_AXI_WM_CFG[
+				share_ctrl->outpath.out0.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase +
+					vfe40_AXI_WM_CFG[
+				share_ctrl->outpath.out0.ch1]);
+
+				share_ctrl->liveshot_state = VFE_STATE_STOPPED;
+				msm_camera_io_w_mb(1, share_ctrl->vfebase +
 				VFE_REG_UPDATE_CMD);
 		}
-	} else if (vfe40_ctrl->share_ctrl->liveshot_state ==
-			VFE_STATE_STOPPED) {
-		vfe40_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
+		break;
+	case VFE_STATE_STOPPED:
+		CDBG("%s Sending STOP_LS ACK\n", __func__);
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+				share_ctrl->vfeFrameId, MSG_ID_STOP_LS_ACK);
+			share_ctrl->liveshot_state = VFE_STATE_IDLE;
+		break;
+	default:
+		break;
 	}
 
-	if ((vfe40_ctrl->share_ctrl->operation_mode ==
-			VFE_OUTPUTS_THUMB_AND_MAIN) ||
-		(vfe40_ctrl->share_ctrl->operation_mode ==
-			VFE_OUTPUTS_MAIN_AND_THUMB) ||
-		(vfe40_ctrl->share_ctrl->operation_mode ==
-			VFE_OUTPUTS_THUMB_AND_JPEG) ||
-		(vfe40_ctrl->share_ctrl->operation_mode ==
-			VFE_OUTPUTS_JPEG_AND_THUMB)) {
+	if ((share_ctrl->operation_mode & VFE_OUTPUTS_THUMB_AND_MAIN) ||
+		(share_ctrl->operation_mode &
+		VFE_OUTPUTS_MAIN_AND_THUMB) ||
+		(share_ctrl->operation_mode &
+		VFE_OUTPUTS_THUMB_AND_JPEG) ||
+		(share_ctrl->operation_mode &
+		VFE_OUTPUTS_JPEG_AND_THUMB)) {
 		/* in snapshot mode */
 		/* later we need to add check for live snapshot mode. */
 		if (vfe40_ctrl->frame_skip_pattern & (0x1 <<
 			(vfe40_ctrl->snapshot_frame_cnt %
 				vfe40_ctrl->frame_skip_cnt))) {
-			vfe40_ctrl->share_ctrl->vfe_capture_count--;
+				share_ctrl->vfe_capture_count--;
 			/* if last frame to be captured: */
-			if (vfe40_ctrl->share_ctrl->vfe_capture_count == 0) {
-				/* stop the bus output:write master enable = 0*/
-				if (vfe40_ctrl->share_ctrl->outpath.output_mode
+				if (share_ctrl->vfe_capture_count == 0) {
+					/* stop the bus output: */
+					if (share_ctrl->comp_output_mode
 					& VFE40_OUTPUT_MODE_PRIMARY) {
-					msm_camera_io_w(0,
-						vfe40_ctrl->share_ctrl->vfebase+
-						vfe40_AXI_WM_CFG[vfe40_ctrl->
-						share_ctrl->outpath.out0.ch0]);
-					msm_camera_io_w(0,
-						vfe40_ctrl->share_ctrl->vfebase+
-						vfe40_AXI_WM_CFG[vfe40_ctrl->
-						share_ctrl->outpath.out0.ch1]);
-				}
-				if (vfe40_ctrl->share_ctrl->outpath.output_mode&
+						msm_camera_io_w(0,
+							share_ctrl->vfebase+
+							vfe40_AXI_WM_CFG[
+							share_ctrl->
+							outpath.out0.ch0]);
+						msm_camera_io_w(0,
+							share_ctrl->vfebase+
+							vfe40_AXI_WM_CFG[
+							share_ctrl->
+							outpath.out0.ch1]);
+					}
+					if (share_ctrl->comp_output_mode &
 						VFE40_OUTPUT_MODE_SECONDARY) {
-					msm_camera_io_w(0,
-						vfe40_ctrl->share_ctrl->vfebase+
-						vfe40_AXI_WM_CFG[vfe40_ctrl->
-						share_ctrl->outpath.out1.ch0]);
-					msm_camera_io_w(0,
-						vfe40_ctrl->share_ctrl->vfebase+
-						vfe40_AXI_WM_CFG[vfe40_ctrl->
-						share_ctrl->outpath.out1.ch1]);
+						msm_camera_io_w(0,
+							share_ctrl->vfebase+
+							vfe40_AXI_WM_CFG[
+							share_ctrl->
+							outpath.out1.ch0]);
+						msm_camera_io_w(0,
+							share_ctrl->vfebase+
+							vfe40_AXI_WM_CFG[
+							share_ctrl->
+							outpath.out1.ch1]);
 				}
 				msm_camera_io_w_mb
 				(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
-				vfe40_ctrl->share_ctrl->vfebase +
+					share_ctrl->vfebase +
 				VFE_CAMIF_COMMAND);
 				vfe40_ctrl->snapshot_frame_cnt = -1;
 				vfe40_ctrl->frame_skip_cnt = 31;
-				vfe40_ctrl->frame_skip_pattern = 0xffffffff;
+					vfe40_ctrl->frame_skip_pattern =
+								0xffffffff;
 			} /*if snapshot count is 0*/
 		} /*if frame is not being dropped*/
 		vfe40_ctrl->snapshot_frame_cnt++;
 		/* then do reg_update. */
 		msm_camera_io_w(1,
-			vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+				share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 	} /* if snapshot mode. */
 }
+}
 
-static void vfe40_set_default_reg_values(
-			struct vfe40_ctrl_type *vfe40_ctrl)
+static void vfe40_process_rdi0_reg_update_irq(
+	struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	msm_camera_io_w(0x800080,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_0);
-	msm_camera_io_w(0x800080,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_1);
-	/* What value should we program CGC_OVERRIDE to? */
-	msm_camera_io_w(0xFFFFF,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_CGC_OVERRIDE);
+	if (atomic_cmpxchg(
+		&vfe40_ctrl->share_ctrl->rdi0_update_ack_pending, 2, 0) == 2) {
+		axi_stop_rdi0(vfe40_ctrl->share_ctrl);
+		axi_disable_irq(vfe40_ctrl->share_ctrl);
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			vfe40_ctrl->share_ctrl->vfeFrameId,
+			MSG_ID_RDI0_UPDATE_ACK);
+		vfe40_ctrl->share_ctrl->comp_output_mode &=
+			~VFE40_OUTPUT_MODE_TERTIARY1;
+		vfe40_ctrl->share_ctrl->current_mode &=
+			~(VFE_OUTPUTS_RDI0);
+	}
 
-	/* default frame drop period and pattern */
-	msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_ENC_MIN);
-	msm_camera_io_w(0xFFFFFF,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_ENC_MAX);
-	msm_camera_io_w(0,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_VIEW_MIN);
-	msm_camera_io_w(0xFFFFFF,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_VIEW_MAX);
+	if (atomic_cmpxchg(
+		&vfe40_ctrl->share_ctrl->rdi0_update_ack_pending, 1, 0) == 1) {
+		vfe40_ctrl->share_ctrl->comp_output_mode |=
+			VFE40_OUTPUT_MODE_TERTIARY1;
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			vfe40_ctrl->share_ctrl->vfeFrameId,
+			MSG_ID_RDI0_UPDATE_ACK);
+		vfe40_ctrl->share_ctrl->current_mode &=
+			~(VFE_OUTPUTS_RDI0);
+	}
+}
 
-	/* stats UB config */
-	msm_camera_io_w(0x3980007,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AEC_UB_CFG);
-	msm_camera_io_w(0x3A00007,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AF_UB_CFG);
-	msm_camera_io_w(0x3A8000F,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AWB_UB_CFG);
-	msm_camera_io_w(0x3B80007,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_RS_UB_CFG);
-	msm_camera_io_w(0x3C0001F,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_CS_UB_CFG);
-	msm_camera_io_w(0x3E0001F,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_HIST_UB_CFG);
+static void vfe40_process_rdi1_reg_update_irq(
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	if (atomic_cmpxchg(
+		&vfe40_ctrl->share_ctrl->rdi1_update_ack_pending, 2, 0) == 2) {
+		axi_stop_rdi1(vfe40_ctrl->share_ctrl);
+		axi_disable_irq(vfe40_ctrl->share_ctrl);
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			vfe40_ctrl->share_ctrl->vfeFrameId,
+			MSG_ID_RDI1_UPDATE_ACK);
+			vfe40_ctrl->share_ctrl->comp_output_mode &=
+				~VFE40_OUTPUT_MODE_TERTIARY2;
+		vfe40_ctrl->share_ctrl->current_mode &=
+			~(VFE_OUTPUTS_RDI1);
+	}
+
+	if (atomic_cmpxchg(
+		&vfe40_ctrl->share_ctrl->rdi1_update_ack_pending, 1, 0) == 1) {
+		vfe40_ctrl->share_ctrl->comp_output_mode |=
+			VFE40_OUTPUT_MODE_TERTIARY2;
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			vfe40_ctrl->share_ctrl->vfeFrameId,
+			MSG_ID_RDI1_UPDATE_ACK);
+		vfe40_ctrl->share_ctrl->current_mode &=
+			~(VFE_OUTPUTS_RDI1);
+	}
 }
 
 static void vfe40_process_reset_irq(
@@ -2612,39 +3464,45 @@
 	unsigned long flags;
 
 	atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
+	atomic_set(&vfe40_ctrl->share_ctrl->handle_common_irq, 0);
 
 	spin_lock_irqsave(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
 	if (vfe40_ctrl->share_ctrl->stop_ack_pending) {
 		vfe40_ctrl->share_ctrl->stop_ack_pending = FALSE;
 		spin_unlock_irqrestore(
 			&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+		if (vfe40_ctrl->share_ctrl->sync_abort)
+			complete(&vfe40_ctrl->share_ctrl->reset_complete);
+		else
 		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
-			vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_STOP_ACK);
+				vfe40_ctrl->share_ctrl->vfeFrameId,
+				MSG_ID_STOP_ACK);
 	} else {
 		spin_unlock_irqrestore(
 			&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
 		/* this is from reset command. */
-		vfe40_set_default_reg_values(vfe40_ctrl);
-
+		vfe40_reset_internal_variables(vfe40_ctrl);
+		if (vfe40_ctrl->share_ctrl->vfe_reset_flag) {
+			vfe40_ctrl->share_ctrl->vfe_reset_flag = false;
+			msm_camera_io_w(0xFF00,
+				vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
+		} else {
 		/* reload all write masters. (frame & line)*/
-		msm_camera_io_w(0x7FFF,
+		msm_camera_io_w(0xFF7F,
 			vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
-		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
-			vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_RESET_ACK);
+		}
+		complete(&vfe40_ctrl->share_ctrl->reset_complete);
 	}
 }
 
 static void vfe40_process_camif_sof_irq(
 		struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	if (vfe40_ctrl->share_ctrl->operation_mode ==
+	if (vfe40_ctrl->share_ctrl->operation_mode &
 		VFE_OUTPUTS_RAW) {
-		if (vfe40_ctrl->start_ack_pending) {
-			vfe40_send_isp_msg(&vfe40_ctrl->subdev,
-				vfe40_ctrl->share_ctrl->vfeFrameId,
-				MSG_ID_START_ACK);
-			vfe40_ctrl->start_ack_pending = FALSE;
-		}
+		if (vfe40_ctrl->share_ctrl->start_ack_pending)
+			vfe40_ctrl->share_ctrl->start_ack_pending = FALSE;
+
 		vfe40_ctrl->share_ctrl->vfe_capture_count--;
 		/* if last frame to be captured: */
 		if (vfe40_ctrl->share_ctrl->vfe_capture_count == 0) {
@@ -2659,11 +3517,15 @@
 			VFE_MODE_OF_OPERATION_VIDEO) &&
 		(vfe40_ctrl->share_ctrl->vfeFrameId %
 			vfe40_ctrl->hfr_mode != 0)) {
-		vfe40_ctrl->share_ctrl->vfeFrameId++;
+		if (vfe40_ctrl->vfe_sof_count_enable)
+			vfe40_ctrl->share_ctrl->vfeFrameId++;
 		CDBG("Skip the SOF notification when HFR enabled\n");
 		return;
 	}
-	vfe40_ctrl->share_ctrl->vfeFrameId++;
+
+	if (vfe40_ctrl->vfe_sof_count_enable)
+		vfe40_ctrl->share_ctrl->vfeFrameId++;
+
 	vfe40_send_isp_msg(&vfe40_ctrl->subdev,
 		vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_SOF_ACK);
 	CDBG("camif_sof_irq, frameId = %d\n",
@@ -2681,11 +3543,19 @@
 	struct axi_ctrl_t *axi_ctrl, uint32_t errStatus)
 {
 	uint32_t reg_value;
+	if (errStatus & VFE40_IMASK_VIOLATION) {
+		pr_err("vfe40_irq: violation interrupt\n");
+		reg_value = msm_camera_io_r(
+			axi_ctrl->share_ctrl->vfebase + VFE_VIOLATION_STATUS);
+		pr_err("%s: violationStatus  = 0x%x\n", __func__, reg_value);
+	}
 
 	if (errStatus & VFE40_IMASK_CAMIF_ERROR) {
 		pr_err("vfe40_irq: camif errors\n");
 		reg_value = msm_camera_io_r(
 			axi_ctrl->share_ctrl->vfebase + VFE_CAMIF_STATUS);
+		v4l2_subdev_notify(&axi_ctrl->subdev,
+			NOTIFY_VFE_CAMIF_ERROR, (void *)NULL);
 		pr_err("camifStatus  = 0x%x\n", reg_value);
 		vfe40_send_isp_msg(&axi_ctrl->subdev,
 			axi_ctrl->share_ctrl->vfeFrameId, MSG_ID_CAMIF_ERROR);
@@ -2709,12 +3579,34 @@
 	if (errStatus & VFE40_IMASK_REALIGN_BUF_CR_OVFL)
 		pr_err("vfe40_irq: realign bug CR overflow\n");
 
-	if (errStatus & VFE40_IMASK_VIOLATION) {
-		pr_err("vfe40_irq: violation interrupt\n");
-		reg_value = msm_camera_io_r(
-			axi_ctrl->share_ctrl->vfebase + VFE_VIOLATION_STATUS);
-		pr_err("%s: violationStatus  = 0x%x\n", __func__, reg_value);
-	}
+	if (errStatus & VFE40_IMASK_STATS_BE_BUS_OVFL)
+		pr_err("vfe40_irq: be stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_BG_BUS_OVFL)
+		pr_err("vfe40_irq: bg stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_BF_BUS_OVFL)
+		pr_err("vfe40_irq: bf stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_AWB_BUS_OVFL)
+		pr_err("vfe40_irq: awb stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_RS_BUS_OVFL)
+		pr_err("vfe40_irq: rs stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_CS_BUS_OVFL)
+		pr_err("vfe40_irq: cs stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_IHIST_BUS_OVFL)
+		pr_err("vfe40_irq: ihist stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_SKIN_BHIST_BUS_OVFL)
+		pr_err("vfe40_irq: skin/bhist stats bus overflow\n");
+}
+
+static void vfe40_process_common_error_irq(
+	struct axi_ctrl_t *axi_ctrl, uint32_t errStatus)
+{
 
 	if (errStatus & VFE40_IMASK_IMG_MAST_0_BUS_OVFL)
 		pr_err("vfe40_irq: image master 0 bus overflow\n");
@@ -2737,29 +3629,294 @@
 	if (errStatus & VFE40_IMASK_IMG_MAST_6_BUS_OVFL)
 		pr_err("vfe40_irq: image master 6 bus overflow\n");
 
-	if (errStatus & VFE40_IMASK_STATS_AE_BG_BUS_OVFL)
-		pr_err("vfe40_irq: ae/bg stats bus overflow\n");
+}
 
-	if (errStatus & VFE40_IMASK_STATS_AF_BF_BUS_OVFL)
-		pr_err("vfe40_irq: af/bf stats bus overflow\n");
+static void vfe_send_outmsg(
+	struct axi_ctrl_t *axi_ctrl, uint8_t msgid,
+	uint32_t ch0_paddr, uint32_t ch1_paddr,
+	uint32_t ch2_paddr, uint32_t inst_handle)
+{
+	struct isp_msg_output msg;
 
-	if (errStatus & VFE40_IMASK_STATS_AWB_BUS_OVFL)
-		pr_err("vfe40_irq: awb stats bus overflow\n");
+	msg.output_id = msgid;
+	msg.buf.inst_handle = inst_handle;
+	msg.buf.ch_paddr[0]	= ch0_paddr;
+	msg.buf.ch_paddr[1]	= ch1_paddr;
+	msg.buf.ch_paddr[2]	= ch2_paddr;
+	switch (msgid) {
+	case MSG_ID_OUTPUT_TERTIARY1:
+		msg.frameCounter = axi_ctrl->share_ctrl->rdi0FrameId;
+		break;
+	case MSG_ID_OUTPUT_TERTIARY2:
+		msg.frameCounter = axi_ctrl->share_ctrl->rdi1FrameId;
+		break;
+	default:
+		msg.frameCounter = axi_ctrl->share_ctrl->vfeFrameId;
+		break;
+	}
 
-	if (errStatus & VFE40_IMASK_STATS_RS_BUS_OVFL)
-		pr_err("vfe40_irq: rs stats bus overflow\n");
+	v4l2_subdev_notify(&axi_ctrl->subdev,
+			NOTIFY_VFE_MSG_OUT,
+			&msg);
+	return;
+}
 
-	if (errStatus & VFE40_IMASK_STATS_CS_BUS_OVFL)
-		pr_err("vfe40_irq: cs stats bus overflow\n");
+static void vfe40_process_output_path_irq_0(
+	struct axi_ctrl_t *axi_ctrl)
+{
+	uint32_t ping_pong;
+	uint32_t ch0_paddr, ch1_paddr, ch2_paddr;
+	uint8_t out_bool = 0;
+	struct msm_free_buf *free_buf = NULL;
 
-	if (errStatus & VFE40_IMASK_STATS_IHIST_BUS_OVFL)
-		pr_err("vfe40_irq: ihist stats bus overflow\n");
+	free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+		VFE_MSG_OUTPUT_PRIMARY, axi_ctrl);
 
-	if (errStatus & VFE40_IMASK_STATS_SKIN_BHIST_BUS_OVFL)
-		pr_err("vfe40_irq: skin/bhist stats bus overflow\n");
+	/* we render frames in the following conditions:
+	1. Continuous mode and the free buffer is avaialable.
+	2. In snapshot shot mode, free buffer is not always available.
+	when pending snapshot count is <=1,  then no need to use
+	free buffer.
+	*/
+	out_bool = (
+		(axi_ctrl->share_ctrl->operation_mode &
+			VFE_OUTPUTS_THUMB_AND_MAIN ||
+		axi_ctrl->share_ctrl->operation_mode &
+			VFE_OUTPUTS_MAIN_AND_THUMB ||
+		axi_ctrl->share_ctrl->operation_mode &
+			VFE_OUTPUTS_THUMB_AND_JPEG ||
+		axi_ctrl->share_ctrl->operation_mode &
+			VFE_OUTPUTS_JPEG_AND_THUMB ||
+		axi_ctrl->share_ctrl->operation_mode &
+			VFE_OUTPUTS_RAW ||
+		axi_ctrl->share_ctrl->liveshot_state ==
+			VFE_STATE_STARTED ||
+		axi_ctrl->share_ctrl->liveshot_state ==
+			VFE_STATE_STOP_REQUESTED ||
+		axi_ctrl->share_ctrl->liveshot_state ==
+			VFE_STATE_STOPPED) &&
+		(axi_ctrl->share_ctrl->vfe_capture_count <= 1)) ||
+			free_buf;
 
-	if (errStatus & VFE40_IMASK_AXI_ERROR)
-		pr_err("vfe40_irq: axi error\n");
+	if (out_bool) {
+		ping_pong = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+			VFE_BUS_PING_PONG_STATUS);
+
+		/* Channel 0*/
+		ch0_paddr = vfe40_get_ch_addr(
+			ping_pong, axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out0.ch0);
+		/* Channel 1*/
+		ch1_paddr = vfe40_get_ch_addr(
+			ping_pong, axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out0.ch1);
+		/* Channel 2*/
+		ch2_paddr = vfe40_get_ch_addr(
+			ping_pong, axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out0.ch2);
+
+		CDBG("output path 0, ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
+			ch0_paddr, ch1_paddr, ch2_paddr);
+		if (free_buf) {
+			/* Y channel */
+			vfe40_put_ch_addr(ping_pong,
+			axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out0.ch0,
+			free_buf->ch_paddr[0]);
+			/* Chroma channel */
+			vfe40_put_ch_addr(ping_pong,
+			axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out0.ch1,
+			free_buf->ch_paddr[1]);
+			if (free_buf->num_planes > 2)
+				vfe40_put_ch_addr(ping_pong,
+					axi_ctrl->share_ctrl->vfebase,
+					axi_ctrl->share_ctrl->outpath.out0.ch2,
+					free_buf->ch_paddr[2]);
+		}
+		if (axi_ctrl->share_ctrl->operation_mode &
+				VFE_OUTPUTS_THUMB_AND_MAIN ||
+			axi_ctrl->share_ctrl->operation_mode &
+				VFE_OUTPUTS_MAIN_AND_THUMB ||
+			axi_ctrl->share_ctrl->operation_mode &
+				VFE_OUTPUTS_THUMB_AND_JPEG ||
+			axi_ctrl->share_ctrl->operation_mode &
+				VFE_OUTPUTS_JPEG_AND_THUMB ||
+			axi_ctrl->share_ctrl->operation_mode &
+				VFE_OUTPUTS_RAW ||
+			axi_ctrl->share_ctrl->liveshot_state ==
+				VFE_STATE_STOPPED)
+			axi_ctrl->share_ctrl->outpath.out0.capture_cnt--;
+
+		vfe_send_outmsg(axi_ctrl,
+			MSG_ID_OUTPUT_PRIMARY, ch0_paddr,
+			ch1_paddr, ch2_paddr,
+			axi_ctrl->share_ctrl->outpath.out0.inst_handle);
+
+	} else {
+		axi_ctrl->share_ctrl->outpath.out0.frame_drop_cnt++;
+		CDBG("path_irq_0 - no free buffer!\n");
+	}
+}
+
+static void vfe40_process_output_path_irq_1(
+	struct axi_ctrl_t *axi_ctrl)
+{
+	uint32_t ping_pong;
+	uint32_t ch0_paddr, ch1_paddr, ch2_paddr;
+	/* this must be snapshot main image output. */
+	uint8_t out_bool = 0;
+	struct msm_free_buf *free_buf = NULL;
+
+	free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+		VFE_MSG_OUTPUT_SECONDARY, axi_ctrl);
+	out_bool = ((axi_ctrl->share_ctrl->operation_mode &
+				VFE_OUTPUTS_THUMB_AND_MAIN ||
+			axi_ctrl->share_ctrl->operation_mode &
+				VFE_OUTPUTS_MAIN_AND_THUMB ||
+			axi_ctrl->share_ctrl->operation_mode &
+				VFE_OUTPUTS_RAW ||
+			axi_ctrl->share_ctrl->operation_mode &
+				VFE_OUTPUTS_JPEG_AND_THUMB) &&
+			(axi_ctrl->share_ctrl->vfe_capture_count <= 1)) ||
+				free_buf;
+
+	if (out_bool) {
+		ping_pong = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+			VFE_BUS_PING_PONG_STATUS);
+
+		/* Y channel */
+		ch0_paddr = vfe40_get_ch_addr(ping_pong,
+			axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out1.ch0);
+		/* Chroma channel */
+		ch1_paddr = vfe40_get_ch_addr(ping_pong,
+			axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out1.ch1);
+		ch2_paddr = vfe40_get_ch_addr(ping_pong,
+			axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out1.ch2);
+
+		CDBG("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
+			__func__, ch0_paddr, ch1_paddr, ch2_paddr);
+		if (free_buf) {
+			/* Y channel */
+			vfe40_put_ch_addr(ping_pong,
+			axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out1.ch0,
+			free_buf->ch_paddr[0]);
+			/* Chroma channel */
+			vfe40_put_ch_addr(ping_pong,
+			axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out1.ch1,
+			free_buf->ch_paddr[1]);
+			if (free_buf->num_planes > 2)
+				vfe40_put_ch_addr(ping_pong,
+					axi_ctrl->share_ctrl->vfebase,
+					axi_ctrl->share_ctrl->outpath.out1.ch2,
+					free_buf->ch_paddr[2]);
+		}
+		if (axi_ctrl->share_ctrl->operation_mode &
+				VFE_OUTPUTS_THUMB_AND_MAIN ||
+			axi_ctrl->share_ctrl->operation_mode &
+				VFE_OUTPUTS_MAIN_AND_THUMB ||
+			axi_ctrl->share_ctrl->operation_mode &
+				VFE_OUTPUTS_RAW ||
+			axi_ctrl->share_ctrl->operation_mode &
+				VFE_OUTPUTS_JPEG_AND_THUMB)
+			axi_ctrl->share_ctrl->outpath.out1.capture_cnt--;
+
+		vfe_send_outmsg(axi_ctrl,
+			MSG_ID_OUTPUT_SECONDARY, ch0_paddr,
+			ch1_paddr, ch2_paddr,
+			axi_ctrl->share_ctrl->outpath.out1.inst_handle);
+
+	} else {
+		axi_ctrl->share_ctrl->outpath.out1.frame_drop_cnt++;
+		CDBG("path_irq_1 - no free buffer!\n");
+	}
+}
+
+static void vfe40_process_output_path_irq_rdi0(
+			struct axi_ctrl_t *axi_ctrl)
+{
+	uint32_t ping_pong;
+	uint32_t ch0_paddr = 0;
+	/* this must be rdi image output. */
+	struct msm_free_buf *free_buf = NULL;
+	/*RDI0*/
+	if (axi_ctrl->share_ctrl->operation_mode & VFE_OUTPUTS_RDI0) {
+		free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+			VFE_MSG_OUTPUT_TERTIARY1, axi_ctrl);
+		if (free_buf) {
+			ping_pong = msm_camera_io_r(axi_ctrl->
+				share_ctrl->vfebase +
+				VFE_BUS_PING_PONG_STATUS);
+
+			/* Y only channel */
+			ch0_paddr = vfe40_get_ch_addr(ping_pong,
+				axi_ctrl->share_ctrl->vfebase,
+				axi_ctrl->share_ctrl->outpath.out2.ch0);
+
+			pr_debug("%s ch0 = 0x%x\n",
+				__func__, ch0_paddr);
+
+			/* Y channel */
+			vfe40_put_ch_addr(ping_pong,
+				axi_ctrl->share_ctrl->vfebase,
+				axi_ctrl->share_ctrl->outpath.out2.ch0,
+				free_buf->ch_paddr[0]);
+
+			vfe_send_outmsg(axi_ctrl,
+				MSG_ID_OUTPUT_TERTIARY1, ch0_paddr,
+				0, 0,
+				axi_ctrl->share_ctrl->outpath.out2.inst_handle);
+
+		} else {
+			axi_ctrl->share_ctrl->outpath.out2.frame_drop_cnt++;
+			pr_err("path_irq_2 irq - no free buffer for rdi0!\n");
+		}
+	}
+}
+
+static void vfe40_process_output_path_irq_rdi1(
+	struct axi_ctrl_t *axi_ctrl)
+{
+	uint32_t ping_pong;
+	uint32_t ch0_paddr = 0;
+	/* this must be rdi image output. */
+	struct msm_free_buf *free_buf = NULL;
+	/*RDI1*/
+	if (axi_ctrl->share_ctrl->operation_mode & VFE_OUTPUTS_RDI1) {
+		free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+			VFE_MSG_OUTPUT_TERTIARY2, axi_ctrl);
+		if (free_buf) {
+			ping_pong = msm_camera_io_r(axi_ctrl->
+				share_ctrl->vfebase +
+				VFE_BUS_PING_PONG_STATUS);
+
+			/* Y channel */
+			ch0_paddr = vfe40_get_ch_addr(ping_pong,
+				axi_ctrl->share_ctrl->vfebase,
+				axi_ctrl->share_ctrl->outpath.out3.ch0);
+			pr_debug("%s ch0 = 0x%x\n",
+				__func__, ch0_paddr);
+
+			/* Y channel */
+			vfe40_put_ch_addr(ping_pong,
+				axi_ctrl->share_ctrl->vfebase,
+				axi_ctrl->share_ctrl->outpath.out3.ch0,
+				free_buf->ch_paddr[0]);
+
+			vfe_send_outmsg(axi_ctrl,
+				MSG_ID_OUTPUT_TERTIARY2, ch0_paddr,
+				0, 0,
+				axi_ctrl->share_ctrl->outpath.out3.inst_handle);
+		} else {
+			axi_ctrl->share_ctrl->outpath.out3.frame_drop_cnt++;
+			pr_err("path_irq irq - no free buffer for rdi1!\n");
+		}
+	}
 }
 
 static uint32_t  vfe40_process_stats_irq_common(
@@ -2786,8 +3943,8 @@
 	return returnAddr;
 }
 
-static void
-vfe_send_stats_msg(struct vfe40_ctrl_type *vfe40_ctrl,
+static void vfe_send_stats_msg(
+	struct vfe40_ctrl_type *vfe40_ctrl,
 	uint32_t bufAddress, uint32_t statsNum)
 {
 	int rc = 0;
@@ -2796,24 +3953,36 @@
 	/* @todo This is causing issues, need further investigate */
 	/* spin_lock_irqsave(&ctrl->state_lock, flags); */
 	struct isp_msg_stats msgStats;
+	uint32_t stats_type;
 	msgStats.frameCounter = vfe40_ctrl->share_ctrl->vfeFrameId;
+	if (vfe40_ctrl->simultaneous_sof_stat)
+		msgStats.frameCounter--;
 	msgStats.buffer = bufAddress;
-
 	switch (statsNum) {
 	case statsAeNum:{
-		msgStats.id = MSG_ID_STATS_AEC;
+		msgStats.id =
+			(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSG_ID_STATS_AEC
+				: MSG_ID_STATS_BG;
+		stats_type =
+			(!vfe40_use_bayer_stats(vfe40_ctrl)) ?
+				MSM_STATS_TYPE_AEC : MSM_STATS_TYPE_BG;
 		rc = vfe40_ctrl->stats_ops.dispatch(
 				vfe40_ctrl->stats_ops.stats_ctrl,
-				MSM_STATS_TYPE_AEC, bufAddress,
+				stats_type, bufAddress,
 				&msgStats.buf_idx, &vaddr, &msgStats.fd,
 				vfe40_ctrl->stats_ops.client);
 		}
 		break;
 	case statsAfNum:{
-		msgStats.id = MSG_ID_STATS_AF;
+		msgStats.id =
+			(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSG_ID_STATS_AF
+				: MSG_ID_STATS_BF;
+		stats_type =
+			(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AF
+				: MSM_STATS_TYPE_BF;
 		rc = vfe40_ctrl->stats_ops.dispatch(
 				vfe40_ctrl->stats_ops.stats_ctrl,
-				MSM_STATS_TYPE_AF, bufAddress,
+				stats_type, bufAddress,
 				&msgStats.buf_idx, &vaddr, &msgStats.fd,
 				vfe40_ctrl->stats_ops.client);
 		}
@@ -2855,6 +4024,15 @@
 				vfe40_ctrl->stats_ops.client);
 		}
 		break;
+	case statsSkinNum: {
+		msgStats.id = MSG_ID_STATS_BHIST;
+		rc = vfe40_ctrl->stats_ops.dispatch(
+				vfe40_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_BHIST, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe40_ctrl->stats_ops.client);
+		}
+		break;
 
 	default:
 		goto stats_done;
@@ -2869,7 +4047,7 @@
 			 __func__, msgStats.id, msgStats.buffer);
 	}
 stats_done:
-	spin_unlock_irqrestore(&ctrl->state_lock, flags);
+	/* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
 	return;
 }
 
@@ -2880,11 +4058,14 @@
 	uint32_t temp;
 
 	msgStats.frame_id = vfe40_ctrl->share_ctrl->vfeFrameId;
+	if (vfe40_ctrl->simultaneous_sof_stat)
+		msgStats.frame_id--;
+
 	msgStats.status_bits = status_bits;
 
-	msgStats.aec.buff = vfe40_ctrl->aecStatsControl.bufToRender;
+	msgStats.aec.buff = vfe40_ctrl->aecbgStatsControl.bufToRender;
 	msgStats.awb.buff = vfe40_ctrl->awbStatsControl.bufToRender;
-	msgStats.af.buff = vfe40_ctrl->afStatsControl.bufToRender;
+	msgStats.af.buff = vfe40_ctrl->afbfStatsControl.bufToRender;
 
 	msgStats.ihist.buff = vfe40_ctrl->ihistStatsControl.bufToRender;
 	msgStats.rs.buff = vfe40_ctrl->rsStatsControl.bufToRender;
@@ -2899,6 +4080,31 @@
 				&msgStats);
 }
 
+static void vfe40_process_stats_bg_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	unsigned long flags;
+	uint32_t addr;
+	uint32_t stats_type;
+	stats_type =
+		(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AEC
+			: MSM_STATS_TYPE_BG;
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (addr) {
+		vfe40_ctrl->aecbgStatsControl.bufToRender =
+			vfe40_process_stats_irq_common(vfe40_ctrl, statsAeNum,
+			addr);
+
+		vfe_send_stats_msg(vfe40_ctrl,
+			vfe40_ctrl->aecbgStatsControl.bufToRender, statsAeNum);
+	} else{
+		vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount++;
+		CDBG("%s: droppedStatsFrameCount = %d", __func__,
+			vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount);
+	}
+}
+
 static void vfe40_process_stats_awb_irq(struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	unsigned long flags;
@@ -2920,6 +4126,53 @@
 	}
 }
 
+static void vfe40_process_stats_bf_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	unsigned long flags;
+	uint32_t addr;
+	uint32_t stats_type;
+	stats_type =
+		(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AF
+			: MSM_STATS_TYPE_BF;
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (addr) {
+		vfe40_ctrl->afbfStatsControl.bufToRender =
+			vfe40_process_stats_irq_common(vfe40_ctrl, statsAfNum,
+			addr);
+
+		vfe_send_stats_msg(vfe40_ctrl,
+			vfe40_ctrl->afbfStatsControl.bufToRender, statsAfNum);
+	} else{
+		vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount++;
+		CDBG("%s: droppedStatsFrameCount = %d", __func__,
+			vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount);
+	}
+}
+
+static void vfe40_process_stats_bhist_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_BHIST);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (addr) {
+		vfe40_ctrl->bhistStatsControl.bufToRender =
+			vfe40_process_stats_irq_common(vfe40_ctrl,
+				statsSkinNum, addr);
+
+		vfe_send_stats_msg(vfe40_ctrl,
+			vfe40_ctrl->bhistStatsControl.bufToRender,
+			statsSkinNum);
+	} else{
+		vfe40_ctrl->bhistStatsControl.droppedStatsFrameCount++;
+		CDBG("%s: droppedStatsFrameCount = %d", __func__,
+			vfe40_ctrl->bhistStatsControl.droppedStatsFrameCount);
+	}
+}
+
 static void vfe40_process_stats_ihist_irq(struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	unsigned long flags;
@@ -2975,8 +4228,9 @@
 			vfe40_process_stats_irq_common(vfe40_ctrl, statsCsNum,
 			addr);
 
-		vfe_send_stats_msg(vfe40_ctrl,
-			vfe40_ctrl->csStatsControl.bufToRender, statsCsNum);
+			vfe_send_stats_msg(vfe40_ctrl,
+				vfe40_ctrl->csStatsControl.bufToRender,
+				statsCsNum);
 	} else {
 		vfe40_ctrl->csStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
@@ -2990,9 +4244,30 @@
 	unsigned long flags;
 	int32_t process_stats = false;
 	uint32_t addr;
+	uint32_t stats_type;
 
 	CDBG("%s, stats = 0x%x\n", __func__, status_bits);
 	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	stats_type =
+		(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AEC
+			: MSM_STATS_TYPE_BG;
+
+	if (status_bits & VFE_IRQ_STATUS0_STATS_BG) {
+		addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+				stats_type);
+		if (addr) {
+			vfe40_ctrl->aecbgStatsControl.bufToRender =
+				vfe40_process_stats_irq_common(
+				vfe40_ctrl, statsAeNum,	addr);
+			process_stats = true;
+		} else{
+			vfe40_ctrl->aecbgStatsControl.bufToRender = 0;
+			vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount++;
+		}
+	} else {
+		vfe40_ctrl->aecbgStatsControl.bufToRender = 0;
+	}
+
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
 		addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
 			MSM_STATS_TYPE_AWB);
@@ -3010,6 +4285,26 @@
 		vfe40_ctrl->awbStatsControl.bufToRender = 0;
 	}
 
+	stats_type =
+		(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AF
+			: MSM_STATS_TYPE_BF;
+	if (status_bits & VFE_IRQ_STATUS0_STATS_BF) {
+		addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+					stats_type);
+		if (addr) {
+			vfe40_ctrl->afbfStatsControl.bufToRender =
+				vfe40_process_stats_irq_common(
+				vfe40_ctrl, statsAfNum,
+				addr);
+			process_stats = true;
+		} else {
+			vfe40_ctrl->afbfStatsControl.bufToRender = 0;
+			vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount++;
+		}
+	} else {
+		vfe40_ctrl->afbfStatsControl.bufToRender = 0;
+	}
+
 	if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
 		addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
 					MSM_STATS_TYPE_IHIST);
@@ -3071,7 +4366,6 @@
 	struct vfe40_ctrl_type *vfe40_ctrl, uint32_t irqstatus)
 {
 	uint32_t status_bits = VFE_COM_STATUS & irqstatus;
-
 	if ((vfe40_ctrl->hfr_mode != HFR_MODE_OFF) &&
 		(vfe40_ctrl->share_ctrl->vfeFrameId %
 		 vfe40_ctrl->hfr_mode != 0)) {
@@ -3101,14 +4395,34 @@
 		CDBG("irq	regUpdateIrq\n");
 		vfe40_process_reg_update_irq(vfe40_ctrl);
 		break;
+	case VFE_IRQ_STATUS0_RDI0_REG_UPDATE:
+		CDBG("irq	rdi0 regUpdateIrq\n");
+		vfe40_process_rdi0_reg_update_irq(vfe40_ctrl);
+		break;
+	case VFE_IRQ_STATUS0_RDI1_REG_UPDATE:
+		CDBG("irq	rdi1 regUpdateIrq\n");
+		vfe40_process_rdi1_reg_update_irq(vfe40_ctrl);
+		break;
 	case VFE_IMASK_WHILE_STOPPING_0:
 		CDBG("irq	resetAckIrq\n");
 		vfe40_process_reset_irq(vfe40_ctrl);
 		break;
+	case VFE_IRQ_STATUS0_STATS_BG:
+		CDBG("Stats BG irq occured.\n");
+		vfe40_process_stats_bg_irq(vfe40_ctrl);
+		break;
+	case VFE_IRQ_STATUS0_STATS_BF:
+		CDBG("Stats BF irq occured.\n");
+		vfe40_process_stats_bf_irq(vfe40_ctrl);
+		break;
 	case VFE_IRQ_STATUS0_STATS_AWB:
 		CDBG("Stats AWB irq occured.\n");
 		vfe40_process_stats_awb_irq(vfe40_ctrl);
 		break;
+	case VFE_IRQ_STATUS0_STATS_SKIN_BHIST:
+		CDBG("Stats BHIST irq occured.\n");
+		vfe40_process_stats_bhist_irq(vfe40_ctrl);
+		break;
 	case VFE_IRQ_STATUS0_STATS_IHIST:
 		CDBG("Stats IHIST irq occured.\n");
 		vfe40_process_stats_ihist_irq(vfe40_ctrl);
@@ -3148,15 +4462,17 @@
 {
 	unsigned long flags;
 	struct axi_ctrl_t *axi_ctrl = (struct axi_ctrl_t *)data;
+	struct vfe40_ctrl_type *vfe40_ctrl = axi_ctrl->share_ctrl->vfe40_ctrl;
 	struct vfe40_isr_queue_cmd *qcmd = NULL;
+	int stat_interrupt;
 
 	CDBG("=== axi40_do_tasklet start ===\n");
 
-	while (atomic_read(&axi_ctrl->share_ctrl->irq_cnt)) {
+	while (atomic_read(&irq_cnt)) {
 		spin_lock_irqsave(&axi_ctrl->tasklet_lock, flags);
 		qcmd = list_first_entry(&axi_ctrl->tasklet_q,
 			struct vfe40_isr_queue_cmd, list);
-		atomic_sub(1, &axi_ctrl->share_ctrl->irq_cnt);
+		atomic_sub(1, &irq_cnt);
 
 		if (!qcmd) {
 			spin_unlock_irqrestore(&axi_ctrl->tasklet_lock,
@@ -3168,38 +4484,82 @@
 		spin_unlock_irqrestore(&axi_ctrl->tasklet_lock,
 			flags);
 
+		if (axi_ctrl->share_ctrl->stats_comp) {
+			stat_interrupt = (qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0);
+		} else {
+			stat_interrupt =
+				(qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_BG) |
+				(qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_AWB) |
+				(qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_BF) |
+				(qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_IHIST) |
+				(qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_RS) |
+				(qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_CS);
+		}
 		if (qcmd->vfeInterruptStatus0 &
-				VFE_IRQ_STATUS0_CAMIF_SOF_MASK)
-			v4l2_subdev_notify(&axi_ctrl->subdev,
+				VFE_IRQ_STATUS0_CAMIF_SOF_MASK) {
+			if (stat_interrupt)
+				vfe40_ctrl->simultaneous_sof_stat = 1;
+			v4l2_subdev_notify(&vfe40_ctrl->subdev,
 				NOTIFY_VFE_IRQ,
 				(void *)VFE_IRQ_STATUS0_CAMIF_SOF_MASK);
+		}
 
 		/* interrupt to be processed,  *qcmd has the payload.  */
 		if (qcmd->vfeInterruptStatus0 &
-				VFE_IRQ_STATUS0_REG_UPDATE_MASK) {
-			v4l2_subdev_notify(&axi_ctrl->subdev,
+				VFE_IRQ_STATUS0_REG_UPDATE_MASK)
+			v4l2_subdev_notify(&vfe40_ctrl->subdev,
 				NOTIFY_VFE_IRQ,
 				(void *)VFE_IRQ_STATUS0_REG_UPDATE_MASK);
-		}
+
+		if (qcmd->vfeInterruptStatus1 &
+				VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK)
+			v4l2_subdev_notify(&vfe40_ctrl->subdev,
+				NOTIFY_VFE_IRQ,
+				(void *)VFE_IRQ_STATUS0_RDI0_REG_UPDATE);
+
+		if (qcmd->vfeInterruptStatus1 &
+				VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK)
+			v4l2_subdev_notify(&vfe40_ctrl->subdev,
+				NOTIFY_VFE_IRQ,
+				(void *)VFE_IRQ_STATUS0_RDI1_REG_UPDATE);
 
 		if (qcmd->vfeInterruptStatus0 &
 				VFE_IMASK_WHILE_STOPPING_0)
-			v4l2_subdev_notify(&axi_ctrl->subdev,
+			v4l2_subdev_notify(&vfe40_ctrl->subdev,
 				NOTIFY_VFE_IRQ,
 				(void *)VFE_IMASK_WHILE_STOPPING_0);
 
+		if (atomic_read(&axi_ctrl->share_ctrl->handle_common_irq)) {
+			if (qcmd->vfeInterruptStatus1 &
+					VFE40_IMASK_COMMON_ERROR_ONLY_1) {
+				pr_err("irq	errorIrq\n");
+				vfe40_process_common_error_irq(
+					axi_ctrl,
+					qcmd->vfeInterruptStatus1 &
+					VFE40_IMASK_COMMON_ERROR_ONLY_1);
+			}
+
+			v4l2_subdev_notify(&axi_ctrl->subdev,
+				NOTIFY_AXI_IRQ,
+				(void *)qcmd->vfeInterruptStatus0);
+		}
+
 		if (atomic_read(&axi_ctrl->share_ctrl->vstate)) {
 			if (qcmd->vfeInterruptStatus1 &
-					VFE40_IMASK_ERROR_ONLY_1) {
+					VFE40_IMASK_VFE_ERROR_ONLY_1) {
 				pr_err("irq	errorIrq\n");
 				vfe40_process_error_irq(
 					axi_ctrl,
 					qcmd->vfeInterruptStatus1 &
-					VFE40_IMASK_ERROR_ONLY_1);
+					VFE40_IMASK_VFE_ERROR_ONLY_1);
 			}
-			v4l2_subdev_notify(&axi_ctrl->subdev,
-				NOTIFY_AXI_IRQ,
-				(void *)qcmd->vfeInterruptStatus0);
 
 			/* then process stats irq. */
 			if (axi_ctrl->share_ctrl->stats_comp) {
@@ -3207,54 +4567,74 @@
 				if (qcmd->vfeInterruptStatus0 &
 					VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0) {
 					CDBG("Stats composite irq occured.\n");
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)qcmd->vfeInterruptStatus0);
 				}
 			} else {
 				/* process individual stats interrupt. */
 				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_BG)
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_BG);
+
+				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_AWB)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_AWB);
+
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_BF)
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_BF);
+				if (qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_SKIN_BHIST)
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)
+					VFE_IRQ_STATUS0_STATS_SKIN_BHIST);
+
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_IHIST)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_IHIST);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_RS)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_RS);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_CS)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_CS);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS1_SYNC_TIMER0)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS1_SYNC_TIMER0);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS1_SYNC_TIMER1)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS1_SYNC_TIMER1);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS1_SYNC_TIMER2)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS1_SYNC_TIMER2);
 			}
 		}
+		vfe40_ctrl->simultaneous_sof_stat = 0;
 		kfree(qcmd);
 	}
 	CDBG("=== axi40_do_tasklet end ===\n");
@@ -3299,12 +4679,22 @@
 	spin_lock_irqsave(&axi_ctrl->tasklet_lock, flags);
 	list_add_tail(&qcmd->list, &axi_ctrl->tasklet_q);
 
-	atomic_add(1, &axi_ctrl->share_ctrl->irq_cnt);
+	atomic_add(1, &irq_cnt);
 	spin_unlock_irqrestore(&axi_ctrl->tasklet_lock, flags);
 	tasklet_schedule(&axi_ctrl->vfe40_tasklet);
 	return IRQ_HANDLED;
 }
 
+int msm_axi_subdev_isr_routine(struct v4l2_subdev *sd,
+	u32 status, bool *handled)
+{
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	irqreturn_t ret;
+	CDBG("%s E ", __func__);
+	ret = vfe40_parse_irq(axi_ctrl->vfeirq->start, axi_ctrl);
+	*handled = TRUE;
+	return 0;
+}
 
 static long vfe_stats_bufq_sub_ioctl(
 	struct vfe40_ctrl_type *vfe_ctrl,
@@ -3378,6 +4768,22 @@
 			vfe_ctrl->stats_ops.client);
 	}
 	break;
+	case VFE_CMD_STATS_UNREGBUF:
+	{
+		struct msm_stats_reqbuf *req_buf = NULL;
+		req_buf = (struct msm_stats_reqbuf *)cmd->value;
+		if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats reqbuf input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				 __func__, cmd->length,
+				sizeof(struct msm_stats_reqbuf));
+			rc = -EINVAL ;
+			goto end;
+		}
+		rc = vfe40_stats_unregbuf(vfe_ctrl, req_buf, domain_num);
+	}
+	break;
 	default:
 		rc = -1;
 		pr_err("%s: cmd_type %d not supported", __func__,
@@ -3396,10 +4802,9 @@
 	struct vfe40_ctrl_type *vfe40_ctrl =
 		(struct vfe40_ctrl_type *)v4l2_get_subdevdata(sd);
 	struct msm_isp_cmd vfecmd;
-	struct msm_camvfe_params *vfe_params =
-		(struct msm_camvfe_params *)arg;
-	struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg;
-	void *data = vfe_params->data;
+	struct msm_camvfe_params *vfe_params;
+	struct msm_vfe_cfg_cmd *cmd;
+	void *data;
 
 	long rc = 0;
 	struct vfe_cmd_stats_buf *scfg = NULL;
@@ -3410,6 +4815,17 @@
 		return -EFAULT;
 	}
 
+	CDBG("%s\n", __func__);
+	if (subdev_cmd == VIDIOC_MSM_VFE_INIT) {
+		CDBG("%s init\n", __func__);
+		return msm_vfe_subdev_init(sd);
+	} else if (subdev_cmd == VIDIOC_MSM_VFE_RELEASE) {
+		msm_vfe_subdev_release(sd);
+		return 0;
+	}
+	vfe_params = (struct msm_camvfe_params *)arg;
+	cmd = vfe_params->vfe_cfg;
+	data = vfe_params->data;
 	switch (cmd->cmd_type) {
 	case CMD_VFE_PROCESS_IRQ:
 		vfe40_process_irq(vfe40_ctrl, (uint32_t) data);
@@ -3417,27 +4833,33 @@
 	case VFE_CMD_STATS_REQBUF:
 	case VFE_CMD_STATS_ENQUEUEBUF:
 	case VFE_CMD_STATS_FLUSH_BUFQ:
+	case VFE_CMD_STATS_UNREGBUF:
 		/* for easy porting put in one envelope */
 		rc = vfe_stats_bufq_sub_ioctl(vfe40_ctrl,
 				cmd, vfe_params->data, pmctl->domain_num);
 		return rc;
 	default:
 		if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
-			cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
-			cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
-			cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
-			cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
-			cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
-			cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
-			cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
-			cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
-				if (copy_from_user(&vfecmd,
+		cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+		cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+		cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_BG_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_BF_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_BHIST_BUF_RELEASE &&
+		cmd->cmd_type != CMD_VFE_PIX_SOF_COUNT_UPDATE &&
+		cmd->cmd_type != CMD_VFE_COUNT_PIX_SOF_ENABLE) {
+			if (copy_from_user(&vfecmd,
 					(void __user *)(cmd->value),
 					sizeof(vfecmd))) {
-						pr_err("%s %d: copy_from_user failed\n",
-							__func__, __LINE__);
-					return -EFAULT;
-				}
+				pr_err("%s %d: copy_from_user failed\n",
+					__func__, __LINE__);
+				return -EFAULT;
+			}
 		} else {
 			/* here eith stats release or frame release. */
 			if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
@@ -3459,6 +4881,25 @@
 				sack->nextStatsBuf = *(uint32_t *)data;
 			}
 		}
+	}
+
+	CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+	if ((cmd->cmd_type == CMD_STATS_AF_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_AWB_ENABLE)   ||
+		(cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
+		(cmd->cmd_type == CMD_STATS_RS_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_CS_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_AEC_ENABLE)   ||
+		(cmd->cmd_type == CMD_STATS_BG_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_BF_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_BHIST_ENABLE)) {
+		struct axidata *axid;
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			goto vfe40_config_done;
+		}
 		CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
 
 		if ((cmd->cmd_type == CMD_STATS_AF_ENABLE)    ||
@@ -3472,39 +4913,69 @@
 				goto vfe40_config_done;
 		}
 		switch (cmd->cmd_type) {
-		case CMD_GENERAL:
-			rc = vfe40_proc_general(pmctl, &vfecmd, vfe40_ctrl);
-		break;
-		case CMD_CONFIG_PING_ADDR: {
-			int path = *((int *)cmd->value);
-			struct vfe40_output_ch *outch =
-				vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
-			outch->ping = *((struct msm_free_buf *)data);
-		}
-		break;
-
-		case CMD_CONFIG_PONG_ADDR: {
-			int path = *((int *)cmd->value);
-			struct vfe40_output_ch *outch =
-				vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
-			outch->pong = *((struct msm_free_buf *)data);
-		}
-		break;
-
-		case CMD_CONFIG_FREE_BUF_ADDR: {
-			int path = *((int *)cmd->value);
-			struct vfe40_output_ch *outch =
-				vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
-			outch->free_buf = *((struct msm_free_buf *)data);
-		}
-		break;
-		case CMD_SNAP_BUF_RELEASE:
-			break;
+		case CMD_STATS_AEC_ENABLE:
+		case CMD_STATS_BG_ENABLE:
+		case CMD_STATS_BF_ENABLE:
+		case CMD_STATS_BHIST_ENABLE:
+		case CMD_STATS_AWB_ENABLE:
+		case CMD_STATS_IHIST_ENABLE:
+		case CMD_STATS_RS_ENABLE:
+		case CMD_STATS_CS_ENABLE:
 		default:
-			pr_err("%s Unsupported AXI configuration %x ", __func__,
-				cmd->cmd_type);
-		break;
+			pr_err("%s Unsupported cmd type %d",
+				__func__, cmd->cmd_type);
+			break;
 		}
+		goto vfe40_config_done;
+	}
+	switch (cmd->cmd_type) {
+	case CMD_GENERAL:
+		rc = vfe40_proc_general(pmctl, &vfecmd, vfe40_ctrl);
+	break;
+	case CMD_VFE_COUNT_PIX_SOF_ENABLE: {
+		int enable = *((int *)cmd->value);
+		if (enable)
+			vfe40_ctrl->vfe_sof_count_enable = TRUE;
+		else
+			vfe40_ctrl->vfe_sof_count_enable = false;
+	}
+	break;
+	case CMD_VFE_PIX_SOF_COUNT_UPDATE:
+		if (!vfe40_ctrl->vfe_sof_count_enable)
+			vfe40_ctrl->share_ctrl->vfeFrameId =
+			*((uint32_t *)vfe_params->data);
+	break;
+	case CMD_CONFIG_PING_ADDR: {
+		int path = *((int *)cmd->value);
+		struct vfe40_output_ch *outch =
+			vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
+		outch->ping = *((struct msm_free_buf *)data);
+	}
+	break;
+
+	case CMD_CONFIG_PONG_ADDR: {
+		int path = *((int *)cmd->value);
+		struct vfe40_output_ch *outch =
+			vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
+		outch->pong = *((struct msm_free_buf *)data);
+	}
+	break;
+
+	case CMD_CONFIG_FREE_BUF_ADDR: {
+		int path = *((int *)cmd->value);
+		struct vfe40_output_ch *outch =
+			vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
+		outch->free_buf = *((struct msm_free_buf *)data);
+	}
+	break;
+
+	case CMD_SNAP_BUF_RELEASE:
+		break;
+
+	default:
+		pr_err("%s Unsupported AXI configuration %x ", __func__,
+			cmd->cmd_type);
+	break;
 	}
 vfe40_config_done:
 	kfree(scfg);
@@ -3513,6 +4984,39 @@
 	return rc;
 }
 
+static struct msm_cam_clk_info vfe40_clk_info[] = {
+	{"camss_top_ahb_clk", -1},
+	{"vfe_clk_src", 266670000},
+	{"camss_vfe_vfe_clk", -1},
+	{"camss_csi_vfe_clk", -1},
+	{"iface_clk", -1},
+	{"bus_clk", -1},
+	{"alt_bus_clk", -1},
+};
+
+static int msm_axi_subdev_s_crystal_freq(struct v4l2_subdev *sd,
+						u32 freq, u32 flags)
+{
+	int rc = 0;
+	int round_rate;
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+
+	round_rate = clk_round_rate(axi_ctrl->vfe_clk[1], freq);
+	if (rc < 0) {
+		pr_err("%s: clk_round_rate failed %d\n",
+					__func__, rc);
+		return rc;
+	}
+
+	vfe_clk_rate = round_rate;
+	rc = clk_set_rate(axi_ctrl->vfe_clk[1], round_rate);
+	if (rc < 0)
+		pr_err("%s: clk_set_rate failed %d\n",
+					__func__, rc);
+
+	return rc;
+}
+
 static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = {
 	.ioctl = msm_vfe_subdev_ioctl,
 };
@@ -3521,46 +5025,1088 @@
 	.core = &msm_vfe_subdev_core_ops,
 };
 
-int msm_vfe_subdev_init(struct v4l2_subdev *sd,
-			struct msm_cam_media_controller *mctl)
+static void msm_vfe40_init_vbif_parms(void __iomem *vfe_vbif_base)
+{
+	msm_camera_io_w_mb(0x1,
+		vfe_vbif_base + VFE40_VBIF_CLKON);
+	msm_camera_io_w_mb(0x1,
+		vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+	msm_camera_io_w_mb(0xFFFF,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+	msm_camera_io_w_mb(0xFFFFFFFF,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+
+	msm_camera_io_w_mb(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+	msm_camera_io_w_mb(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+	msm_camera_io_w_mb(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
+	msm_camera_io_w_mb(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+	msm_camera_io_w_mb(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+	msm_camera_io_w_mb(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
+	msm_camera_io_w_mb(0x00001010,
+		vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+	msm_camera_io_w_mb(0x00001010,
+		vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+	msm_camera_io_w_mb(0x00000707,
+		vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+	msm_camera_io_w_mb(0x00000030,
+		vfe_vbif_base + VFE40_VBIF_ARB_CTL);
+	msm_camera_io_w_mb(0x04210842,
+		vfe_vbif_base + VFE40_VBIF_DDR_ARB_CONF0);
+	msm_camera_io_w_mb(0x04210842,
+		vfe_vbif_base + VFE40_VBIF_DDR_ARB_CONF1);
+}
+
+int msm_axi_subdev_init(struct v4l2_subdev *sd)
+{
+	int rc = 0;
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	struct msm_cam_media_controller *mctl;
+	mctl = v4l2_get_subdev_hostdata(sd);
+	if (mctl == NULL) {
+		pr_err("%s: mctl is NULL\n", __func__);
+		rc = -EINVAL;
+		goto mctl_failed;
+	}
+	axi_ctrl->share_ctrl->axi_ref_cnt++;
+	if (axi_ctrl->share_ctrl->axi_ref_cnt > 1)
+		return rc;
+
+	spin_lock_init(&axi_ctrl->tasklet_lock);
+	INIT_LIST_HEAD(&axi_ctrl->tasklet_q);
+	spin_lock_init(&axi_ctrl->share_ctrl->sd_notify_lock);
+
+	axi_ctrl->share_ctrl->vfebase = ioremap(axi_ctrl->vfemem->start,
+		resource_size(axi_ctrl->vfemem));
+	if (!axi_ctrl->share_ctrl->vfebase) {
+		rc = -ENOMEM;
+		pr_err("%s: vfe ioremap failed\n", __func__);
+		goto remap_failed;
+	}
+
+	axi_ctrl->share_ctrl->vfe_vbif_base =
+		ioremap(axi_ctrl->vfe_vbif_mem->start,
+			resource_size(axi_ctrl->vfe_vbif_mem));
+	if (!axi_ctrl->share_ctrl->vfe_vbif_base) {
+		rc = -ENOMEM;
+		pr_err("%s: vfe ioremap failed\n", __func__);
+		goto remap_failed;
+	}
+
+	if (axi_ctrl->fs_vfe) {
+		rc = regulator_enable(axi_ctrl->fs_vfe);
+		if (rc) {
+			pr_err("%s: Regulator enable failed\n",	__func__);
+			goto fs_failed;
+		}
+	}
+
+	rc = msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe40_clk_info,
+			axi_ctrl->vfe_clk, ARRAY_SIZE(vfe40_clk_info), 1);
+	if (rc < 0)
+		goto clk_enable_failed;
+
+	axi_ctrl->bus_perf_client =
+		msm_bus_scale_register_client(&vfe_bus_client_pdata);
+	if (!axi_ctrl->bus_perf_client) {
+		pr_err("%s: Registration Failed!\n", __func__);
+		axi_ctrl->bus_perf_client = 0;
+		goto bus_scale_register_failed;
+	}
+
+	msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_PREVIEW);
+
+	rc = iommu_attach_device(mctl->domain, axi_ctrl->iommu_ctx);
+	if (rc < 0) {
+		pr_err("%s: imgwr attach failed rc = %d\n", __func__, rc);
+		rc = -ENODEV;
+		goto device_imgwr_attach_failed;
+	}
+
+	msm_vfe40_init_vbif_parms(axi_ctrl->share_ctrl->vfe_vbif_base);
+
+	axi_ctrl->share_ctrl->register_total = VFE40_REGISTER_TOTAL;
+
+	spin_lock_init(&axi_ctrl->share_ctrl->stop_flag_lock);
+	spin_lock_init(&axi_ctrl->share_ctrl->update_ack_lock);
+	spin_lock_init(&axi_ctrl->share_ctrl->start_ack_lock);
+	init_completion(&axi_ctrl->share_ctrl->reset_complete);
+
+	if (!axi_ctrl->use_irq_router)
+		enable_irq(axi_ctrl->vfeirq->start);
+
+	return rc;
+
+bus_scale_register_failed:
+	msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe40_clk_info,
+		axi_ctrl->vfe_clk, ARRAY_SIZE(vfe40_clk_info), 0);
+clk_enable_failed:
+	if (axi_ctrl->fs_vfe)
+		regulator_disable(axi_ctrl->fs_vfe);
+fs_failed:
+	iounmap(axi_ctrl->share_ctrl->vfebase);
+	axi_ctrl->share_ctrl->vfebase = NULL;
+remap_failed:
+	iommu_detach_device(mctl->domain, axi_ctrl->iommu_ctx);
+device_imgwr_attach_failed:
+	if (!axi_ctrl->use_irq_router)
+		disable_irq(axi_ctrl->vfeirq->start);
+mctl_failed:
+	return rc;
+}
+
+int msm_vfe_subdev_init(struct v4l2_subdev *sd)
 {
 	int rc = 0;
 	struct vfe40_ctrl_type *vfe40_ctrl =
 		(struct vfe40_ctrl_type *)v4l2_get_subdevdata(sd);
-	v4l2_set_subdev_hostdata(sd, mctl);
 
-	spin_lock_init(&vfe40_ctrl->share_ctrl->stop_flag_lock);
 	spin_lock_init(&vfe40_ctrl->state_lock);
-	spin_lock_init(&vfe40_ctrl->io_lock);
-	spin_lock_init(&vfe40_ctrl->update_ack_lock);
 	spin_lock_init(&vfe40_ctrl->stats_bufq_lock);
 
-
 	vfe40_ctrl->update_linear = false;
 	vfe40_ctrl->update_rolloff = false;
 	vfe40_ctrl->update_la = false;
 	vfe40_ctrl->update_gamma = false;
+	vfe40_ctrl->vfe_sof_count_enable = true;
 	vfe40_ctrl->hfr_mode = HFR_MODE_OFF;
 
+	memset(&vfe40_ctrl->stats_ctrl, 0,
+		   sizeof(struct msm_stats_bufq_ctrl));
+	memset(&vfe40_ctrl->stats_ops, 0, sizeof(struct msm_stats_ops));
+
 	return rc;
 }
 
+void msm_axi_subdev_release(struct v4l2_subdev *sd)
+{
+	struct msm_cam_media_controller *pmctl =
+		(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	if (!axi_ctrl->share_ctrl->vfebase) {
+		pr_err("%s: base address unmapped\n", __func__);
+		return;
+	}
+
+	CDBG("%s, free_irq\n", __func__);
+	axi_ctrl->share_ctrl->axi_ref_cnt--;
+	if (axi_ctrl->share_ctrl->axi_ref_cnt > 0)
+		return;
+	if (!axi_ctrl->use_irq_router)
+		disable_irq(axi_ctrl->vfeirq->start);
+	tasklet_kill(&axi_ctrl->vfe40_tasklet);
+
+	iommu_detach_device(pmctl->domain, axi_ctrl->iommu_ctx);
+
+	msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe40_clk_info,
+			axi_ctrl->vfe_clk, ARRAY_SIZE(vfe40_clk_info), 0);
+	if (axi_ctrl->fs_vfe)
+		regulator_disable(axi_ctrl->fs_vfe);
+
+	iounmap(axi_ctrl->share_ctrl->vfebase);
+	iounmap(axi_ctrl->share_ctrl->vfe_vbif_base);
+	axi_ctrl->share_ctrl->vfebase = NULL;
+
+	if (atomic_read(&irq_cnt))
+		pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
+
+	msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_EXIT);
+	axi_ctrl->bus_perf_client = 0;
+
+	msm_vfe_subdev_release(&axi_ctrl->share_ctrl->vfe40_ctrl->subdev);
+}
+
 void msm_vfe_subdev_release(struct v4l2_subdev *sd)
 {
 	struct vfe40_ctrl_type *vfe40_ctrl =
 		(struct vfe40_ctrl_type *)v4l2_get_subdevdata(sd);
-	if (!vfe40_ctrl->share_ctrl->vfebase)
-		vfe40_ctrl->share_ctrl->vfebase = NULL;
+	CDBG("vfe subdev release %p\n",
+		vfe40_ctrl->share_ctrl->vfebase);
 }
 
+void axi_abort(struct axi_ctrl_t *axi_ctrl)
+{
+	uint8_t  axi_busy_flag = true;
+	unsigned long flags;
+	/* axi halt command. */
+
+	spin_lock_irqsave(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+	axi_ctrl->share_ctrl->stop_ack_pending  = TRUE;
+	spin_unlock_irqrestore(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+	msm_camera_io_w(AXI_HALT,
+		axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
+	wmb();
+	while (axi_busy_flag) {
+		if (msm_camera_io_r(
+			axi_ctrl->share_ctrl->vfebase + VFE_AXI_STATUS) & 0x1)
+			axi_busy_flag = false;
+	}
+	/* Ensure the write order while writing
+	* to the command register using the barrier */
+	msm_camera_io_w_mb(AXI_HALT_CLEAR,
+		axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
+
+	/* after axi halt, then ok to apply global reset.
+	* enable reset_ack and async timer interrupt only while
+	* stopping the pipeline.*/
+	msm_camera_io_w(0x80000000,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+	msm_camera_io_w(0xF0000000,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* Ensure the write order while writing
+	* to the command register using the barrier */
+	msm_camera_io_w_mb(VFE_RESET_UPON_STOP_CMD,
+		axi_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+	if (axi_ctrl->share_ctrl->sync_abort)
+		wait_for_completion_interruptible(
+			&axi_ctrl->share_ctrl->reset_complete);
+}
+
+int axi_config_buffers(struct axi_ctrl_t *axi_ctrl,
+	struct msm_camera_vfe_params_t vfe_params)
+{
+	uint16_t vfe_mode = axi_ctrl->share_ctrl->current_mode
+			& ~(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1);
+	int rc = 0;
+	switch (vfe_params.cmd_type) {
+	case AXI_CMD_PREVIEW:
+		if (vfe_mode) {
+			if ((axi_ctrl->share_ctrl->current_mode &
+				VFE_OUTPUTS_PREVIEW_AND_VIDEO) ||
+				(axi_ctrl->share_ctrl->current_mode &
+				VFE_OUTPUTS_PREVIEW))
+				/* Configure primary channel */
+				rc = configure_pingpong_buffers(
+					VFE_MSG_START,
+					VFE_MSG_OUTPUT_PRIMARY,
+					axi_ctrl);
+			else
+			/* Configure secondary channel */
+				rc = configure_pingpong_buffers(
+					VFE_MSG_START,
+					VFE_MSG_OUTPUT_SECONDARY,
+					axi_ctrl);
+		}
+		if (axi_ctrl->share_ctrl->current_mode &
+				VFE_OUTPUTS_RDI0)
+			rc = configure_pingpong_buffers(
+				VFE_MSG_START, VFE_MSG_OUTPUT_TERTIARY1,
+				axi_ctrl);
+		if (axi_ctrl->share_ctrl->current_mode &
+				VFE_OUTPUTS_RDI1)
+			rc = configure_pingpong_buffers(
+				VFE_MSG_START, VFE_MSG_OUTPUT_TERTIARY2,
+				axi_ctrl);
+
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers for preview",
+				__func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+		break;
+	case AXI_CMD_RAW_CAPTURE:
+		rc = configure_pingpong_buffers(
+			VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_PRIMARY,
+			axi_ctrl);
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers for snapshot",
+				__func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+		break;
+	case AXI_CMD_ZSL:
+		rc = configure_pingpong_buffers(VFE_MSG_START,
+			VFE_MSG_OUTPUT_PRIMARY, axi_ctrl);
+		if (rc < 0)
+			goto config_done;
+		rc = configure_pingpong_buffers(VFE_MSG_START,
+			VFE_MSG_OUTPUT_SECONDARY, axi_ctrl);
+		if (rc < 0)
+			goto config_done;
+		break;
+	case AXI_CMD_RECORD:
+		if (axi_ctrl->share_ctrl->current_mode &
+			VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+			axi_ctrl->share_ctrl->outpath.out1.inst_handle =
+				vfe_params.inst_handle;
+			rc = configure_pingpong_buffers(
+				VFE_MSG_START_RECORDING,
+				VFE_MSG_OUTPUT_SECONDARY,
+				axi_ctrl);
+		} else if (axi_ctrl->share_ctrl->current_mode &
+			VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+			axi_ctrl->share_ctrl->outpath.out0.inst_handle =
+				vfe_params.inst_handle;
+			rc = configure_pingpong_buffers(
+				VFE_MSG_START_RECORDING,
+				VFE_MSG_OUTPUT_PRIMARY,
+				axi_ctrl);
+		}
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers for video",
+				__func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+		break;
+	case AXI_CMD_LIVESHOT:
+		axi_ctrl->share_ctrl->outpath.out0.inst_handle =
+			vfe_params.inst_handle;
+		rc = configure_pingpong_buffers(VFE_MSG_CAPTURE,
+					VFE_MSG_OUTPUT_PRIMARY, axi_ctrl);
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers for primary output",
+				__func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+		break;
+	case AXI_CMD_CAPTURE:
+		if (axi_ctrl->share_ctrl->current_mode ==
+			VFE_OUTPUTS_JPEG_AND_THUMB ||
+		axi_ctrl->share_ctrl->current_mode ==
+			VFE_OUTPUTS_THUMB_AND_JPEG) {
+
+			/* Configure primary channel for JPEG */
+			rc = configure_pingpong_buffers(
+				VFE_MSG_JPEG_CAPTURE,
+				VFE_MSG_OUTPUT_PRIMARY,
+				axi_ctrl);
+		} else {
+			/* Configure primary channel */
+			rc = configure_pingpong_buffers(
+				VFE_MSG_CAPTURE,
+				VFE_MSG_OUTPUT_PRIMARY,
+				axi_ctrl);
+		}
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers for primary output",
+				__func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+		/* Configure secondary channel */
+		rc = configure_pingpong_buffers(
+				VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_SECONDARY,
+				axi_ctrl);
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers for secondary output",
+				__func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+
+	}
+config_done:
+	return rc;
+}
+
+void axi_start(struct msm_cam_media_controller *pmctl,
+	struct axi_ctrl_t *axi_ctrl, struct msm_camera_vfe_params_t vfe_params)
+{
+	uint32_t irq_comp_mask = 0, irq_mask = 0;
+	int rc = 0;
+	uint32_t reg_update = 0;
+	uint16_t operation_mode =
+		(axi_ctrl->share_ctrl->current_mode &
+		~(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1));
+	rc = axi_config_buffers(axi_ctrl, vfe_params);
+	if (rc < 0)
+		return;
+
+	switch (vfe_params.cmd_type) {
+	case AXI_CMD_PREVIEW:
+		msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_PREVIEW);
+		break;
+	case AXI_CMD_CAPTURE:
+	case AXI_CMD_RAW_CAPTURE:
+		msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_CAPTURE);
+		break;
+	case AXI_CMD_RECORD:
+		msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_VIDEO);
+		return;
+	case AXI_CMD_ZSL:
+		msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_ZSL);
+		break;
+	case AXI_CMD_LIVESHOT:
+		msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_LIVESHOT);
+		return;
+	default:
+		return;
+	}
+
+	irq_comp_mask =
+		msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+			VFE_IRQ_COMP_MASK);
+	irq_mask = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+
+	if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+		irq_comp_mask |= (
+			0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0 |
+			0x1 << axi_ctrl->share_ctrl->outpath.out0.ch1);
+		irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+	} else if (axi_ctrl->share_ctrl->outpath.output_mode &
+			   VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+		irq_comp_mask |= (
+			0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0 |
+			0x1 << axi_ctrl->share_ctrl->outpath.out0.ch1 |
+			0x1 << axi_ctrl->share_ctrl->outpath.out0.ch2);
+		irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+	}
+	if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY) {
+		irq_comp_mask |= (
+			0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
+			0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch1 + 8));
+		irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+	} else if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+		irq_comp_mask |= (
+			0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
+			0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch1 + 8) |
+			0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch2 + 8));
+		irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+	}
+	if (axi_ctrl->share_ctrl->outpath.output_mode &
+		VFE40_OUTPUT_MODE_TERTIARY1) {
+		irq_mask |= (0x1 << (axi_ctrl->share_ctrl->outpath.out2.ch0 +
+			VFE_WM_OFFSET));
+	}
+	if (axi_ctrl->share_ctrl->outpath.output_mode &
+		VFE40_OUTPUT_MODE_TERTIARY2) {
+		irq_mask |= (0x1 << (axi_ctrl->share_ctrl->outpath.out3.ch0 +
+			VFE_WM_OFFSET));
+	}
+
+	msm_camera_io_w(irq_comp_mask,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+	msm_camera_io_w(irq_mask, axi_ctrl->share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+
+	switch (vfe_params.cmd_type) {
+	case AXI_CMD_PREVIEW: {
+		switch (operation_mode) {
+		case VFE_OUTPUTS_PREVIEW:
+		case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
+			if (axi_ctrl->share_ctrl->outpath.output_mode &
+				VFE40_OUTPUT_MODE_PRIMARY) {
+				msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out0.ch0]);
+				msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out0.ch1]);
+			} else if (axi_ctrl->share_ctrl->outpath.output_mode &
+					VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+				msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out0.ch0]);
+				msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out0.ch1]);
+				msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out0.ch2]);
+			}
+			break;
+		default:
+			if (axi_ctrl->share_ctrl->outpath.output_mode &
+				VFE40_OUTPUT_MODE_SECONDARY) {
+				msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out1.ch0]);
+				msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out1.ch1]);
+			} else if (axi_ctrl->share_ctrl->outpath.output_mode &
+				VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+				msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out1.ch0]);
+				msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out1.ch1]);
+				msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out1.ch2]);
+			}
+			break;
+			}
+		}
+		break;
+	default:
+		if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out0.ch0]);
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out0.ch1]);
+		} else if (axi_ctrl->share_ctrl->outpath.output_mode &
+				VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out0.ch0]);
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out0.ch1]);
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out0.ch2]);
+		}
+
+		if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY) {
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out1.ch1]);
+		} else if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out1.ch1]);
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out1.ch2]);
+		}
+		break;
+	}
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
+		msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[axi_ctrl->share_ctrl->
+			outpath.out2.ch0]);
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1)
+		msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[axi_ctrl->share_ctrl->
+			outpath.out3.ch0]);
+
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+		irq_mask |= VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK;
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->rdi0_update_ack_pending,
+				0, 1))
+			reg_update |= 0x2;
+	}
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+		irq_mask |= VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK;
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->rdi1_update_ack_pending,
+				0, 1))
+			reg_update |= 0x4;
+	}
+	msm_camera_io_w(irq_mask, axi_ctrl->share_ctrl->vfebase +
+		VFE_IRQ_MASK_0);
+	if (operation_mode) {
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->pix0_update_ack_pending,
+				0, 1))
+			reg_update |= 0x1;
+	}
+
+	msm_camera_io_w_mb(reg_update,
+			axi_ctrl->share_ctrl->vfebase +
+			VFE_REG_UPDATE_CMD);
+	axi_ctrl->share_ctrl->operation_mode |=
+		axi_ctrl->share_ctrl->current_mode;
+	axi_enable_irq(axi_ctrl->share_ctrl);
+}
+
+void axi_stop(struct msm_cam_media_controller *pmctl,
+	struct axi_ctrl_t *axi_ctrl, struct msm_camera_vfe_params_t vfe_params)
+{
+	uint32_t reg_update = 0;
+	uint32_t operation_mode =
+	axi_ctrl->share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+		VFE_OUTPUTS_RDI1);
+
+	switch (vfe_params.cmd_type) {
+	case AXI_CMD_PREVIEW:
+	case AXI_CMD_CAPTURE:
+	case AXI_CMD_RAW_CAPTURE:
+	case AXI_CMD_ZSL:
+		break;
+	case AXI_CMD_RECORD:
+		msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_PREVIEW);
+		return;
+	case AXI_CMD_LIVESHOT:
+		msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_VIDEO);
+		return;
+	default:
+		return;
+	}
+
+	if (axi_ctrl->share_ctrl->stop_immediately) {
+		axi_disable_irq(axi_ctrl->share_ctrl);
+		axi_stop_process(axi_ctrl->share_ctrl);
+		return;
+	}
+
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->rdi0_update_ack_pending, 0, 2))
+			reg_update |= 0x2;
+	}
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->rdi1_update_ack_pending, 0, 2))
+			reg_update |= 0x4;
+	}
+	if (operation_mode) {
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->pix0_update_ack_pending, 0, 2))
+			reg_update |= 0x1;
+	}
+	msm_camera_io_w_mb(reg_update,
+		axi_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+}
+
+static int msm_axi_config(struct v4l2_subdev *sd, void __user *arg)
+{
+	struct msm_vfe_cfg_cmd cfgcmd;
+	struct msm_isp_cmd vfecmd;
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	struct msm_cam_media_controller *pmctl =
+		(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
+	int rc = 0, vfe_cmd_type = 0, rdi_mode = 0;
+
+	if (!axi_ctrl->share_ctrl->vfebase) {
+		pr_err("%s: base address unmapped\n", __func__);
+		return -EFAULT;
+	}
+	memset(&cfgcmd, 0, sizeof(struct msm_vfe_cfg_cmd));
+	if (NULL != arg) {
+		if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+		}
+	}
+	memset(&vfecmd, 0, sizeof(struct msm_isp_cmd));
+	if (NULL != cfgcmd.value) {
+		if (copy_from_user(&vfecmd,
+				(void __user *)(cfgcmd.value),
+				sizeof(vfecmd))) {
+			pr_err("%s %d: copy_from_user failed\n", __func__,
+				__LINE__);
+			return -EFAULT;
+		}
+	}
+
+	vfe_cmd_type = (cfgcmd.cmd_type & ~(CMD_AXI_CFG_TERT1|
+		CMD_AXI_CFG_TERT2));
+	switch (cfgcmd.cmd_type) {
+	case CMD_AXI_CFG_TERT1:{
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio)
+			return -ENOMEM;
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			return -EFAULT;
+		}
+		vfe40_config_axi(axi_ctrl, OUTPUT_TERT1, axio);
+		kfree(axio);
+		return rc;
+		}
+	case CMD_AXI_CFG_TERT2:{
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio)
+			return -ENOMEM;
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			return -EFAULT;
+		}
+		vfe40_config_axi(axi_ctrl, OUTPUT_TERT2, axio);
+		kfree(axio);
+		return rc;
+		}
+	case CMD_AXI_CFG_TERT1|CMD_AXI_CFG_TERT2:{
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio)
+			return -ENOMEM;
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			return -EFAULT;
+		}
+		vfe40_config_axi(axi_ctrl, OUTPUT_TERT1|OUTPUT_TERT2, axio);
+		kfree(axio);
+		return rc;
+		}
+	default:
+		if (cfgcmd.cmd_type & CMD_AXI_CFG_TERT1)
+			rdi_mode |= OUTPUT_TERT1;
+		if (cfgcmd.cmd_type & CMD_AXI_CFG_TERT2)
+			rdi_mode |= OUTPUT_TERT2;
+	}
+	switch (vfe_cmd_type) {
+	case CMD_AXI_CFG_PRIM: {
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe40_config_axi(axi_ctrl, rdi_mode|OUTPUT_PRIM, axio);
+		kfree(axio);
+		break;
+		}
+	case CMD_AXI_CFG_PRIM_ALL_CHNLS: {
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe40_config_axi(axi_ctrl, rdi_mode|OUTPUT_PRIM_ALL_CHNLS,
+			axio);
+		kfree(axio);
+		break;
+		}
+	case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC: {
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe40_config_axi(axi_ctrl,
+			rdi_mode|OUTPUT_PRIM|OUTPUT_SEC, axio);
+		kfree(axio);
+		break;
+		}
+	case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC_ALL_CHNLS: {
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe40_config_axi(axi_ctrl,
+			rdi_mode|OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS, axio);
+		kfree(axio);
+		break;
+		}
+	case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC: {
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe40_config_axi(axi_ctrl,
+			rdi_mode|OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC, axio);
+		kfree(axio);
+		break;
+		}
+
+	case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC_ALL_CHNLS:
+		pr_err("%s Invalid/Unsupported AXI configuration %x",
+			__func__, cfgcmd.cmd_type);
+		break;
+	case CMD_AXI_START: {
+		struct msm_camera_vfe_params_t vfe_params;
+		if (copy_from_user(&vfe_params,
+				(void __user *)(vfecmd.value),
+				sizeof(struct msm_camera_vfe_params_t))) {
+				return -EFAULT;
+		}
+		axi_ctrl->share_ctrl->current_mode =
+			vfe_params.operation_mode;
+		axi_start(pmctl, axi_ctrl, vfe_params);
+		}
+		break;
+	case CMD_AXI_STOP: {
+		struct msm_camera_vfe_params_t vfe_params;
+		if (copy_from_user(&vfe_params,
+				(void __user *)(vfecmd.value),
+				sizeof(struct msm_camera_vfe_params_t))) {
+				return -EFAULT;
+		}
+		axi_ctrl->share_ctrl->current_mode =
+			vfe_params.operation_mode;
+		axi_ctrl->share_ctrl->stop_immediately =
+			vfe_params.stop_immediately;
+		axi_stop(pmctl, axi_ctrl, vfe_params);
+		}
+		break;
+	case CMD_AXI_RESET:
+		axi_reset(axi_ctrl);
+		break;
+	case CMD_AXI_ABORT:
+		if (copy_from_user(&axi_ctrl->share_ctrl->sync_abort,
+				(void __user *)(vfecmd.value),
+				sizeof(uint8_t))) {
+				return -EFAULT;
+		}
+		axi_abort(axi_ctrl);
+		break;
+	default:
+		pr_err("%s Unsupported AXI configuration %x ", __func__,
+			cfgcmd.cmd_type);
+		break;
+	}
+	return rc;
+}
+
+static void msm_axi_process_irq(struct v4l2_subdev *sd, void *arg)
+{
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	uint32_t irqstatus = (uint32_t) arg;
+
+	if (!axi_ctrl->share_ctrl->vfebase) {
+		pr_err("%s: base address unmapped\n", __func__);
+		return;
+	}
+
+	/* next, check output path related interrupts. */
+	if (irqstatus &
+		VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) {
+		CDBG("Image composite done 0 irq occured.\n");
+		vfe40_process_output_path_irq_0(axi_ctrl);
+	}
+	if (irqstatus &
+		VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK) {
+		CDBG("Image composite done 1 irq occured.\n");
+		vfe40_process_output_path_irq_1(axi_ctrl);
+	}
+
+	if (axi_ctrl->share_ctrl->comp_output_mode &
+		VFE40_OUTPUT_MODE_TERTIARY1)
+		if (irqstatus & (0x1 << (axi_ctrl->share_ctrl->outpath.out2.ch0
+			+ VFE_WM_OFFSET)))
+			vfe40_process_output_path_irq_rdi0(axi_ctrl);
+	if (axi_ctrl->share_ctrl->comp_output_mode &
+		VFE40_OUTPUT_MODE_TERTIARY2)
+		if (irqstatus & (0x1 << (axi_ctrl->share_ctrl->outpath.out3.ch0
+			+ VFE_WM_OFFSET)))
+			vfe40_process_output_path_irq_rdi1(axi_ctrl);
+
+	/* in snapshot mode if done then send
+	snapshot done message */
+	if (
+		axi_ctrl->share_ctrl->operation_mode &
+			VFE_OUTPUTS_THUMB_AND_MAIN ||
+		axi_ctrl->share_ctrl->operation_mode &
+			VFE_OUTPUTS_MAIN_AND_THUMB ||
+		axi_ctrl->share_ctrl->operation_mode &
+			VFE_OUTPUTS_THUMB_AND_JPEG ||
+		axi_ctrl->share_ctrl->operation_mode &
+			VFE_OUTPUTS_JPEG_AND_THUMB ||
+		axi_ctrl->share_ctrl->operation_mode &
+			VFE_OUTPUTS_RAW) {
+		if ((axi_ctrl->share_ctrl->outpath.out0.capture_cnt == 0)
+				&& (axi_ctrl->share_ctrl->outpath.out1.
+				capture_cnt == 0)) {
+			msm_camera_io_w_mb(
+				CAMIF_COMMAND_STOP_IMMEDIATELY,
+				axi_ctrl->share_ctrl->vfebase +
+				VFE_CAMIF_COMMAND);
+			axi_disable_irq(axi_ctrl->share_ctrl);
+			vfe40_send_isp_msg(&axi_ctrl->subdev,
+				axi_ctrl->share_ctrl->vfeFrameId,
+				MSG_ID_PIX0_UPDATE_ACK);
+			vfe40_send_isp_msg(&axi_ctrl->subdev,
+				axi_ctrl->share_ctrl->vfeFrameId,
+				MSG_ID_SNAPSHOT_DONE);
+		}
+	}
+}
+
+static int msm_axi_buf_cfg(struct v4l2_subdev *sd, void __user *arg)
+{
+	struct msm_camvfe_params *vfe_params =
+		(struct msm_camvfe_params *)arg;
+	struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg;
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	void *data = vfe_params->data;
+	int rc = 0;
+
+	if (!axi_ctrl->share_ctrl->vfebase) {
+		pr_err("%s: base address unmapped\n", __func__);
+		return -EFAULT;
+	}
+
+	switch (cmd->cmd_type) {
+	case CMD_CONFIG_PING_ADDR: {
+		int path = *((int *)cmd->value);
+		struct vfe40_output_ch *outch =
+			vfe40_get_ch(path, axi_ctrl->share_ctrl);
+		outch->ping = *((struct msm_free_buf *)data);
+	}
+		break;
+
+	case CMD_CONFIG_PONG_ADDR: {
+		int path = *((int *)cmd->value);
+		struct vfe40_output_ch *outch =
+			vfe40_get_ch(path, axi_ctrl->share_ctrl);
+		outch->pong = *((struct msm_free_buf *)data);
+	}
+		break;
+
+	case CMD_CONFIG_FREE_BUF_ADDR: {
+		int path = *((int *)cmd->value);
+		struct vfe40_output_ch *outch =
+			vfe40_get_ch(path, axi_ctrl->share_ctrl);
+		outch->free_buf = *((struct msm_free_buf *)data);
+	}
+		break;
+	default:
+		pr_err("%s Unsupported AXI Buf config %x ", __func__,
+			cmd->cmd_type);
+	}
+	return rc;
+};
+
 static const struct v4l2_subdev_internal_ops msm_vfe_internal_ops;
 
+static long msm_axi_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	int rc = -ENOIOCTLCMD;
+	switch (cmd) {
+	case VIDIOC_MSM_AXI_INIT:
+		rc = msm_axi_subdev_init(sd);
+		break;
+	case VIDIOC_MSM_AXI_CFG:
+		rc = msm_axi_config(sd, arg);
+		break;
+	case VIDIOC_MSM_AXI_IRQ:
+		msm_axi_process_irq(sd, arg);
+		rc = 0;
+		break;
+	case VIDIOC_MSM_AXI_BUF_CFG:
+		msm_axi_buf_cfg(sd, arg);
+		rc = 0;
+		break;
+	case VIDIOC_MSM_AXI_RELEASE:
+		msm_axi_subdev_release(sd);
+		rc = 0;
+		break;
+	case VIDIOC_MSM_AXI_RDI_COUNT_UPDATE: {
+		struct rdi_count_msg *msg = (struct rdi_count_msg *)arg;
+		struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+		switch (msg->rdi_interface) {
+		case RDI_0:
+			axi_ctrl->share_ctrl->rdi0FrameId = msg->count;
+			rc = 0;
+			break;
+		case RDI_1:
+			axi_ctrl->share_ctrl->rdi1FrameId = msg->count;
+			rc = 0;
+			break;
+		case RDI_2:
+			axi_ctrl->share_ctrl->rdi2FrameId = msg->count;
+			rc = 0;
+			break;
+		default:
+			pr_err("%s: Incorrect interface sent\n", __func__);
+			rc = -EINVAL;
+			break;
+		}
+		break;
+	}
+	default:
+		pr_err("%s: command %d not found\n", __func__,
+						_IOC_NR(cmd));
+		break;
+	}
+	return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_axi_subdev_core_ops = {
+	.ioctl = msm_axi_subdev_ioctl,
+	.interrupt_service_routine = msm_axi_subdev_isr_routine,
+};
+
+static const struct v4l2_subdev_video_ops msm_axi_subdev_video_ops = {
+	.s_crystal_freq = msm_axi_subdev_s_crystal_freq,
+};
+
+static const struct v4l2_subdev_ops msm_axi_subdev_ops = {
+	.core = &msm_axi_subdev_core_ops,
+	.video = &msm_axi_subdev_video_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_axi_internal_ops;
+
 static int __devinit vfe40_probe(struct platform_device *pdev)
 {
 	int rc = 0;
 	struct axi_ctrl_t *axi_ctrl;
 	struct vfe40_ctrl_type *vfe40_ctrl;
 	struct vfe_share_ctrl_t *share_ctrl;
+	struct intr_table_entry irq_req;
 	struct msm_cam_subdev_info sd_info;
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
 
@@ -3593,8 +6139,25 @@
 	share_ctrl->vfe40_ctrl = vfe40_ctrl;
 	axi_ctrl->share_ctrl = share_ctrl;
 	vfe40_ctrl->share_ctrl = share_ctrl;
+	axi_ctrl->share_ctrl->axi_ref_cnt = 0;
+	v4l2_subdev_init(&axi_ctrl->subdev, &msm_axi_subdev_ops);
+	axi_ctrl->subdev.internal_ops = &msm_axi_internal_ops;
+	axi_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(axi_ctrl->subdev.name,
+			 sizeof(axi_ctrl->subdev.name), "axi");
+	v4l2_set_subdevdata(&axi_ctrl->subdev, axi_ctrl);
 	axi_ctrl->pdev = pdev;
-	vfe40_axi_probe(axi_ctrl);
+
+	sd_info.sdev_type = AXI_DEV;
+	sd_info.sd_index = pdev->id;
+	sd_info.irq_num = 0;
+	msm_cam_register_subdev_node(&axi_ctrl->subdev, &sd_info);
+
+	media_entity_init(&axi_ctrl->subdev.entity, 0, NULL, 0);
+	axi_ctrl->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+	axi_ctrl->subdev.entity.group_id = AXI_DEV;
+	axi_ctrl->subdev.entity.name = pdev->name;
+	axi_ctrl->subdev.entity.revision = axi_ctrl->subdev.devnode->num;
 
 	v4l2_subdev_init(&vfe40_ctrl->subdev, &msm_vfe_subdev_ops);
 	vfe40_ctrl->subdev.internal_ops = &msm_vfe_internal_ops;
@@ -3611,6 +6174,15 @@
 		rc = -ENODEV;
 		goto vfe40_no_resource;
 	}
+
+	axi_ctrl->vfe_vbif_mem = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "vfe_vbif");
+	if (!axi_ctrl->vfe_vbif_mem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto vfe40_no_resource;
+	}
+
 	axi_ctrl->vfeirq = platform_get_resource_byname(pdev,
 					IORESOURCE_IRQ, "vfe");
 	if (!axi_ctrl->vfeirq) {
@@ -3627,26 +6199,83 @@
 		goto vfe40_no_resource;
 	}
 
-	rc = request_irq(axi_ctrl->vfeirq->start, vfe40_parse_irq,
-		IRQF_TRIGGER_RISING, "vfe", axi_ctrl);
-	if (rc < 0) {
-		release_mem_region(axi_ctrl->vfemem->start,
-			resource_size(axi_ctrl->vfemem));
-		pr_err("%s: irq request fail\n", __func__);
-		rc = -EBUSY;
+	axi_ctrl->fs_vfe = regulator_get(&pdev->dev, "vdd");
+	if (IS_ERR(axi_ctrl->fs_vfe)) {
+		pr_err("%s: Regulator get failed %ld\n", __func__,
+			PTR_ERR(axi_ctrl->fs_vfe));
+		axi_ctrl->fs_vfe = NULL;
+	}
+
+	/* Register subdev node before requesting irq since
+	 * irq_num is needed by msm_cam_server */
+	sd_info.sdev_type = VFE_DEV;
+	sd_info.sd_index = pdev->id;
+	sd_info.irq_num = axi_ctrl->vfeirq->start;
+	msm_cam_register_subdev_node(&vfe40_ctrl->subdev, &sd_info);
+
+	media_entity_init(&vfe40_ctrl->subdev.entity, 0, NULL, 0);
+	vfe40_ctrl->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+	vfe40_ctrl->subdev.entity.group_id = VFE_DEV;
+	vfe40_ctrl->subdev.entity.name = pdev->name;
+	vfe40_ctrl->subdev.entity.revision = vfe40_ctrl->subdev.devnode->num;
+
+	/* Request for this device irq from the camera server. If the
+	 * IRQ Router is present on this target, the interrupt will be
+	 * handled by the camera server and the interrupt service
+	 * routine called. If the request_irq call returns ENXIO, then
+	 * the IRQ Router hardware is not present on this target. We
+	 * have to request for the irq ourselves and register the
+	 * appropriate interrupt handler. */
+	axi_ctrl->use_irq_router = true;
+	irq_req.cam_hw_idx       = MSM_CAM_HW_VFE0 + pdev->id;
+	irq_req.dev_name         = "vfe";
+	irq_req.irq_idx          = CAMERA_SS_IRQ_8;
+	irq_req.irq_num          = axi_ctrl->vfeirq->start;
+	irq_req.is_composite     = 0;
+	irq_req.irq_trigger_type = IRQF_TRIGGER_RISING;
+	irq_req.num_hwcore       = 1;
+	irq_req.subdev_list[0]   = &axi_ctrl->subdev;
+	irq_req.data             = (void *)axi_ctrl;
+	rc = msm_cam_server_request_irq(&irq_req);
+	if (rc == -ENXIO) {
+		/* IRQ Router hardware is not present on this hardware.
+		 * Request for the IRQ and register the interrupt handler. */
+		axi_ctrl->use_irq_router = false;
+		rc = request_irq(axi_ctrl->vfeirq->start, vfe40_parse_irq,
+			IRQF_TRIGGER_RISING, "vfe", axi_ctrl);
+		if (rc < 0) {
+			release_mem_region(axi_ctrl->vfemem->start,
+				resource_size(axi_ctrl->vfemem));
+			pr_err("%s: irq request fail\n", __func__);
+			rc = -EBUSY;
+			goto vfe40_no_resource;
+		}
+		disable_irq(axi_ctrl->vfeirq->start);
+	} else if (rc < 0) {
+		pr_err("%s Error registering irq ", __func__);
 		goto vfe40_no_resource;
 	}
 
-	disable_irq(axi_ctrl->vfeirq->start);
+	/*get device context for IOMMU*/
+	if (pdev->id == 0)
+		axi_ctrl->iommu_ctx = msm_iommu_get_ctx("vfe0");
+	else if (pdev->id == 1)
+		axi_ctrl->iommu_ctx = msm_iommu_get_ctx("vfe1");
+	if (!axi_ctrl->iommu_ctx) {
+		release_mem_region(axi_ctrl->vfemem->start,
+			resource_size(axi_ctrl->vfemem));
+		pr_err("%s: No iommu fw context found\n", __func__);
+		rc = -ENODEV;
+		goto vfe40_no_resource;
+	}
 
 	tasklet_init(&axi_ctrl->vfe40_tasklet,
 		axi40_do_tasklet, (unsigned long)axi_ctrl);
 
 	vfe40_ctrl->pdev = pdev;
-	sd_info.sdev_type = VFE_DEV;
-	sd_info.sd_index = pdev->id;
-	sd_info.irq_num = axi_ctrl->vfeirq->start;
-	msm_cam_register_subdev_node(&vfe40_ctrl->subdev, &sd_info);
+	/*disable bayer stats by default*/
+	vfe40_ctrl->ver_num.main = 0;
+
 	return 0;
 
 vfe40_no_resource:
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.h b/drivers/media/video/msm/vfe/msm_vfe40.h
index ab913e2..5b73751 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.h
+++ b/drivers/media/video/msm/vfe/msm_vfe40.h
@@ -50,7 +50,16 @@
 
 /* reset the pipeline when reset command.
  * bit 26-32 = 0, domain reset, bit 0-9 = 1 for module reset. */
-#define VFE_RESET_UPON_RESET_CMD  0x000001ff
+#define VFE_RESET_UPON_RESET_CMD  0x000003ff
+
+/* reset the vfe only when reset command*/
+#define VFE_ONLY_RESET_CMD  0x00000002
+
+/*Vfe module reset command*/
+#define VFE_MODULE_RESET_CMD 0x07ffffff
+
+/* wm bit offset for IRQ MASK and IRQ STATUS register */
+#define VFE_WM_OFFSET 6
 
 /* constants for irq registers */
 #define VFE_DISABLE_ALL_IRQS 0
@@ -60,6 +69,9 @@
 
 #define VFE_IRQ_STATUS0_CAMIF_SOF_MASK            (0x00000001<<0)
 #define VFE_IRQ_STATUS0_REG_UPDATE_MASK           (0x00000001<<4)
+#define VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK      (0x00000001<<5)
+#define VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK      (0x00000001<<6)
+#define VFE_IRQ_STATUS0_RDI2_REG_UPDATE_MASK      (0x00000001<<7)
 #define VFE_IRQ_STATUS0_STATS_BE                  (0x00000001<<16)
 #define VFE_IRQ_STATUS0_STATS_BG                  (0x00000001<<17)
 #define VFE_IRQ_STATUS0_STATS_BF                  (0x00000001<<18)
@@ -84,13 +96,22 @@
 #define VFE_IRQ_STATUS1_ASYNC_TIMER2              (0x00000001<<30)
 #define VFE_IRQ_STATUS1_ASYNC_TIMER3              (0x00000001<<31)
 
+/*TODOs the irq status passed from axi to vfe irq handler does not account
+* for 2 irq status registers. So below macro is added to differentiate between
+* same bit set on both irq status registers. This wil be fixed later by passing
+*entire payload to vfe irq handler and parsing there instead of passing just the
+*status bit*/
+
+#define VFE_IRQ_STATUS0_RDI0_REG_UPDATE  VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK
+#define VFE_IRQ_STATUS0_RDI1_REG_UPDATE  VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK
+
 /* imask for while waiting for stop ack,  driver has already
  * requested stop, waiting for reset irq, and async timer irq.
- * For irq_status_0, bit 28-32 are for async timer. For
- * irq_status_1, bit 22 for reset irq, bit 23 for axi_halt_ack
+ * For irq_status_1, bit 28-32 are for async timer. For
+ * irq_status_0, bit 31 for reset irq, bit 23 for axi_halt_ack
    irq */
 #define VFE_IMASK_WHILE_STOPPING_0  0x80000000
-#define VFE_IMASK_WHILE_STOPPING_1  0x00000100
+#define VFE_IMASK_WHILE_STOPPING_1  0xF0000000
 
 /* For ABF bit 4 is set to zero and other's 1 */
 #define ABF_MASK 0xFFFFFFF7
@@ -118,9 +139,12 @@
 #define CS_ENABLE_MASK    (0x00000001<<10)
 #define CLF_ENABLE_MASK   (0x00000001<<12)
 #define IHIST_ENABLE_MASK (0x00000001<<15)
+#define BHIST_ENABLE_MASK (0x00000001<<18)
 #define RS_CS_ENABLE_MASK (RS_ENABLE_MASK|CS_ENABLE_MASK)
 #define STATS_ENABLE_MASK 0x000487E0   /* bit 18,15,10,9,8,7,6,5*/
 
+#define STATS_BHIST_ENABLE_MASK (0x00000001<<1)
+
 #define VFE_DMI_CFG_DEFAULT              0x00000100
 
 #define HFR_MODE_OFF 1
@@ -175,9 +199,9 @@
 
 #define V40_OPERATION_CFG_LEN     32
 
-#define V40_AXI_OUT_OFF           0x0000004C
-#define V40_AXI_OUT_LEN           424
-#define V40_AXI_CH_INF_LEN        32
+#define V40_AXI_BUS_CMD_OFF       0x0000004C
+#define V40_AXI_BUS_CFG_LEN       284
+#define V40_AXI_OUT_LEN           344
 #define V40_AXI_CFG_LEN           71
 
 #define V40_FOV_ENC_OFF           0x00000854
@@ -213,7 +237,6 @@
 #define V40_MESH_ROLL_OFF_CFG_LEN             36
 #define V40_MESH_ROLL_OFF_TABLE_SIZE          130
 
-
 #define V40_COLOR_COR_OFF 0x000005D0
 #define V40_COLOR_COR_LEN 52
 
@@ -309,29 +332,6 @@
 
 #define VFE40_LINEARIZATON_TABLE_LENGTH    36
 
-#define VFE_WM_CFG_BASE 0x0070
-#define VFE_WM_CFG_LEN 0x0024
-
-#define vfe40_get_ch_ping_addr(base, chn) \
-	(msm_camera_io_r((base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn)))
-#define vfe40_get_ch_pong_addr(base, chn) \
-	(msm_camera_io_r((base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn) + 4))
-#define vfe40_get_ch_addr(ping_pong, base, chn) \
-	((((ping_pong) & (1 << (chn))) == 0) ? \
-	(vfe40_get_ch_pong_addr((base), chn)) : \
-	(vfe40_get_ch_ping_addr((base), chn)))
-
-#define vfe40_put_ch_ping_addr(base, chn, addr) \
-	(msm_camera_io_w((addr), \
-	(base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn)))
-#define vfe40_put_ch_pong_addr(base, chn, addr) \
-	(msm_camera_io_w((addr), \
-	(base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn) + 4))
-#define vfe40_put_ch_addr(ping_pong, base, chn, addr) \
-	(((ping_pong) & (1 << (chn))) == 0 ?   \
-	vfe40_put_ch_pong_addr((base), (chn), (addr)) : \
-	vfe40_put_ch_ping_addr((base), (chn), (addr)))
-
 struct vfe_cmd_hw_version {
 	uint32_t minorVersion;
 	uint32_t majorVersion;
@@ -704,7 +704,7 @@
 struct vfe40_output_ch {
 	struct list_head free_buf_queue;
 	spinlock_t free_buf_lock;
-	uint16_t image_mode;
+	uint32_t inst_handle;
 	int8_t ch0;
 	int8_t ch1;
 	int8_t ch2;
@@ -719,7 +719,8 @@
 #define VFE40_IMASK_ERROR_ONLY_0  0x0
 /* when normal case, don't want to block error status. */
 /* bit 0-21 are error irq bits */
-#define VFE40_IMASK_ERROR_ONLY_1               0x005FFFFF
+#define VFE40_IMASK_COMMON_ERROR_ONLY_1       0x0000FE00
+#define VFE40_IMASK_VFE_ERROR_ONLY_1          0x00FF01FF
 #define VFE40_IMASK_CAMIF_ERROR               (0x00000001<<0)
 #define VFE40_IMASK_BHIST_OVWR                (0x00000001<<1)
 #define VFE40_IMASK_STATS_CS_OVWR             (0x00000001<<2)
@@ -728,21 +729,21 @@
 #define VFE40_IMASK_REALIGN_BUF_CB_OVFL       (0x00000001<<5)
 #define VFE40_IMASK_REALIGN_BUF_CR_OVFL       (0x00000001<<6)
 #define VFE40_IMASK_VIOLATION                 (0x00000001<<7)
-#define VFE40_IMASK_IMG_MAST_0_BUS_OVFL       (0x00000001<<8)
-#define VFE40_IMASK_IMG_MAST_1_BUS_OVFL       (0x00000001<<9)
-#define VFE40_IMASK_IMG_MAST_2_BUS_OVFL       (0x00000001<<10)
-#define VFE40_IMASK_IMG_MAST_3_BUS_OVFL       (0x00000001<<11)
-#define VFE40_IMASK_IMG_MAST_4_BUS_OVFL       (0x00000001<<12)
-#define VFE40_IMASK_IMG_MAST_5_BUS_OVFL       (0x00000001<<13)
-#define VFE40_IMASK_IMG_MAST_6_BUS_OVFL       (0x00000001<<14)
-#define VFE40_IMASK_STATS_AE_BG_BUS_OVFL      (0x00000001<<15)
-#define VFE40_IMASK_STATS_AF_BF_BUS_OVFL      (0x00000001<<16)
-#define VFE40_IMASK_STATS_AWB_BUS_OVFL        (0x00000001<<17)
-#define VFE40_IMASK_STATS_RS_BUS_OVFL         (0x00000001<<18)
-#define VFE40_IMASK_STATS_CS_BUS_OVFL         (0x00000001<<19)
-#define VFE40_IMASK_STATS_IHIST_BUS_OVFL      (0x00000001<<20)
-#define VFE40_IMASK_STATS_SKIN_BHIST_BUS_OVFL (0x00000001<<21)
-#define VFE40_IMASK_AXI_ERROR                 (0x00000001<<22)
+#define VFE40_IMASK_IMG_MAST_0_BUS_OVFL       (0x00000001<<9)
+#define VFE40_IMASK_IMG_MAST_1_BUS_OVFL       (0x00000001<<10)
+#define VFE40_IMASK_IMG_MAST_2_BUS_OVFL       (0x00000001<<11)
+#define VFE40_IMASK_IMG_MAST_3_BUS_OVFL       (0x00000001<<12)
+#define VFE40_IMASK_IMG_MAST_4_BUS_OVFL       (0x00000001<<13)
+#define VFE40_IMASK_IMG_MAST_5_BUS_OVFL       (0x00000001<<14)
+#define VFE40_IMASK_IMG_MAST_6_BUS_OVFL       (0x00000001<<15)
+#define VFE40_IMASK_STATS_BE_BUS_OVFL         (0x00000001<<16)
+#define VFE40_IMASK_STATS_BG_BUS_OVFL         (0x00000001<<17)
+#define VFE40_IMASK_STATS_BF_BUS_OVFL         (0x00000001<<18)
+#define VFE40_IMASK_STATS_AWB_BUS_OVFL        (0x00000001<<19)
+#define VFE40_IMASK_STATS_RS_BUS_OVFL         (0x00000001<<10)
+#define VFE40_IMASK_STATS_CS_BUS_OVFL         (0x00000001<<21)
+#define VFE40_IMASK_STATS_IHIST_BUS_OVFL      (0x00000001<<22)
+#define VFE40_IMASK_STATS_SKIN_BHIST_BUS_OVFL (0x00000001<<23)
 
 #define VFE_COM_STATUS 0x000FE000
 
@@ -751,7 +752,8 @@
 
 	struct vfe40_output_ch out0; /* preview and thumbnail */
 	struct vfe40_output_ch out1; /* snapshot */
-	struct vfe40_output_ch out2; /* video    */
+	struct vfe40_output_ch out2; /* rdi0    */
+	struct vfe40_output_ch out3; /* rdi01   */
 };
 
 struct vfe40_frame_extra {
@@ -769,9 +771,7 @@
 	uint32_t  frameCounter;
 };
 
-#define VFE_CLEAR_ALL_IRQS              0xffffffff
-
-#define VFE_HW_VERSION			        0x00000000
+#define VFE_HW_VERSION			0x00000000
 #define VFE_GLOBAL_RESET                0x0000000C
 #define VFE_MODULE_RESET                0x00000010
 #define VFE_CGC_OVERRIDE                0x00000014
@@ -786,32 +786,67 @@
 #define VFE_IRQ_STATUS_1                0x0000003C
 #define VFE_IRQ_COMP_MASK               0x00000040
 #define VFE_BUS_CMD                     0x0000004C
-#define VFE_BUS_PING_PONG_STATUS        0x00000180
-#define VFE_AXI_CMD                     0x000001D8
-#define VFE_AXI_STATUS        0x000002C0
-#define VFE_BUS_STATS_PING_PONG_BASE    0x000000F4
+#define VFE_BUS_PING_PONG_STATUS        0x00000268
+#define VFE_AXI_CMD                     0x000002C0
+#define VFE_AXI_STATUS                  0x000002E4
+#define VFE_BUS_STATS_PING_PONG_BASE    0x00000168
 
-#define VFE_BUS_STATS_AEC_WR_PING_ADDR    0x000000F4
-#define VFE_BUS_STATS_AEC_WR_PONG_ADDR    0x000000F8
-#define VFE_BUS_STATS_AEC_UB_CFG          0x000000FC
-#define VFE_BUS_STATS_AF_WR_PING_ADDR     0x00000100
-#define VFE_BUS_STATS_AF_WR_PONG_ADDR     0x00000104
-#define VFE_BUS_STATS_AF_UB_CFG           0x00000108
-#define VFE_BUS_STATS_AWB_WR_PING_ADDR    0x0000010C
-#define VFE_BUS_STATS_AWB_WR_PONG_ADDR    0x00000110
-#define VFE_BUS_STATS_AWB_UB_CFG          0x00000114
-#define VFE_BUS_STATS_RS_WR_PING_ADDR    0x00000118
-#define VFE_BUS_STATS_RS_WR_PONG_ADDR    0x0000011C
-#define VFE_BUS_STATS_RS_UB_CFG          0x00000120
-#define VFE_BUS_STATS_CS_WR_PING_ADDR    0x00000124
-#define VFE_BUS_STATS_CS_WR_PONG_ADDR    0x00000128
-#define VFE_BUS_STATS_CS_UB_CFG          0x0000012C
-#define VFE_BUS_STATS_HIST_WR_PING_ADDR   0x00000130
-#define VFE_BUS_STATS_HIST_WR_PONG_ADDR   0x00000134
-#define VFE_BUS_STATS_HIST_UB_CFG          0x00000138
-#define VFE_BUS_STATS_SKIN_WR_PING_ADDR    0x0000013C
-#define VFE_BUS_STATS_SKIN_WR_PONG_ADDR    0x00000140
-#define VFE_BUS_STATS_SKIN_UB_CFG          0x00000144
+#define VFE_BUS_STATS_BE_WR_PING_ADDR    0x00000168
+#define VFE_BUS_STATS_BE_WR_PONG_ADDR    0x0000016C
+#define VFE_BUS_STATS_BE_WR_ADDR_CFG    0x00000170
+#define VFE_BUS_STATS_BE_UB_CFG          0x00000174
+#define VFE_BUS_STATS_BE_WR_FRAMEDROP_PATTERN  0x00000178
+#define VFE_BUS_STATS_BE_WR_IRQ_SUBSAMPLE_PATTERN 0x0000017C
+
+#define VFE_BUS_STATS_BG_WR_PING_ADDR     0x00000180
+#define VFE_BUS_STATS_BG_WR_PONG_ADDR     0x00000184
+#define VFE_BUS_STATS_BG_WR_ADDR_CFG      0x00000188
+#define VFE_BUS_STATS_BG_WR_UB_CFG        0x0000018C
+#define VFE_BUS_STATS_BG_WR_FRAMEDROP_PATTERN 0x00000190
+#define VFE_BUS_STATS_BG_WR_IRQ_SUBSAMPLE_PATTERN 0x00000194
+
+#define VFE_BUS_STATS_BF_WR_PING_ADDR     0x00000198
+#define VFE_BUS_STATS_BF_WR_PONG_ADDR     0x0000019C
+#define VFE_BUS_STATS_BF_WR_ADDR_CFG      0x000001A0
+#define VFE_BUS_STATS_BF_WR_UB_CFG        0x000001A4
+#define VFE_BUS_STATS_BF_WR_FRAMEDROP_PATTERN  0x000001A8
+#define VFE_BUS_STATS_BF_WR_IRQ_SUBSAMPLE_PATTERN  0x000001AC
+
+#define VFE_BUS_STATS_AWB_WR_PING_ADDR    0x000001B0
+#define VFE_BUS_STATS_AWB_WR_PONG_ADDR    0x000001B4
+#define VFE_BUS_STATS_AWB_WR_ADDR_CFG     0x000001B8
+#define VFE_BUS_STATS_AWB_WR_UB_CFG       0x000001BC
+#define VFE_BUS_STATS_AWB_WR_FRAMEDROP_PATTERN  0x000001C0
+#define VFE_BUS_STATS_AWB_WR_IRQ_SUBSAMPLE_PATTERN  0x000001C4
+
+#define VFE_BUS_STATS_RS_WR_PING_ADDR     0x000001C8
+#define VFE_BUS_STATS_RS_WR_PONG_ADDR     0x000001CC
+#define VFE_BUS_STATS_RS_WR_ADDR_CFG      0x000001D0
+#define VFE_BUS_STATS_RS_WR_UB_CFG    0x000001D4
+#define VFE_BUS_STATS_RS_WR_FRAMEDROP_PATTERN      0x000001D8
+#define VFE_BUS_STATS_RS_WR_IRQ_SUBSAMPLE_PATTERN  0x000001DC
+
+#define VFE_BUS_STATS_CS_WR_PING_ADDR     0x000001E0
+#define VFE_BUS_STATS_CS_WR_PONG_ADDR     0x000001E4
+#define VFE_BUS_STATS_CS_WR_ADDR_CFG      0x000001E8
+#define VFE_BUS_STATS_CS_WR_UB_CFG        0x000001EC
+#define VFE_BUS_STATS_CS_WR_FRAMEDROP_PATTERN     0x000001F0
+#define VFE_BUS_STATS_CS_WR_IRQ_SUBSAMPLE_PATTERN 0x000001F4
+
+#define VFE_BUS_STATS_HIST_WR_PING_ADDR   0x000001F8
+#define VFE_BUS_STATS_HIST_WR_PONG_ADDR   0x000001FC
+#define VFE_BUS_STATS_HIST_WR_ADDR_CFG    0x00000200
+#define VFE_BUS_STATS_HIST_WR_UB_CFG      0x00000204
+#define VFE_BUS_STATS_HIST_WR_FRAMEDROP_PATTERN      0x00000208
+#define VFE_BUS_STATS_HIST_WR_IRQ_SUBSAMPLE_PATTERN  0x0000020C
+
+
+#define VFE_BUS_STATS_SKIN_WR_PING_ADDR   0x00000210
+#define VFE_BUS_STATS_SKIN_WR_PONG_ADDR   0x00000214
+#define VFE_BUS_STATS_SKIN_WR_ADDR_CFG    0x00000218
+#define VFE_BUS_STATS_SKIN_WR_UB_CFG      0x0000021C
+#define VFE_BUS_STATS_SKIN_WR_FRAMEDROP_PATTERN       0x00000220
+#define VFE_BUS_STATS_SKIN_WR_IRQ_SUBSAMPLE_PATTERN   0x00000224
 
 #define VFE_0_BUS_BDG_QOS_CFG_0     0x000002C4
 #define VFE_0_BUS_BDG_QOS_CFG_1     0x000002C8
@@ -839,13 +874,14 @@
 #define VFE_STATS_AWB_SGW_CFG           0x000008CC
 #define VFE_DMI_CFG                     0x00000910
 #define VFE_DMI_ADDR                    0x00000914
+#define VFE_DMI_DATA_HI                 0x00000918
 #define VFE_DMI_DATA_LO                 0x0000091C
 #define VFE_BUS_IO_FORMAT_CFG           0x00000054
 #define VFE_RDI0_CFG                    0x000002E8
 #define VFE_RDI1_CFG                    0x000002EC
 #define VFE_RDI2_CFG                    0x000002F0
 
-#define VFE_VIOLATION_STATUS            0x000007B4
+#define VFE_VIOLATION_STATUS            0x00000048
 
 #define VFE40_DMI_DATA_HI               0x00000918
 #define VFE40_DMI_DATA_LO               0x0000091C
@@ -860,6 +896,25 @@
 #define VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS	BIT(7)
 #define VFE40_OUTPUT_MODE_SECONDARY		BIT(8)
 #define VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS	BIT(9)
+#define VFE40_OUTPUT_MODE_TERTIARY1		BIT(10)
+#define VFE40_OUTPUT_MODE_TERTIARY2		BIT(11)
+
+#define VFE40_VBIF_CLKON				0x4
+#define VFE40_VBIF_IN_RD_LIM_CONF0		0xB0
+#define VFE40_VBIF_IN_RD_LIM_CONF1		0xB4
+#define VFE40_VBIF_IN_RD_LIM_CONF2		0xB8
+#define VFE40_VBIF_IN_WR_LIM_CONF0		0xC0
+#define VFE40_VBIF_IN_WR_LIM_CONF1		0xC4
+#define VFE40_VBIF_IN_WR_LIM_CONF2		0xC8
+#define VFE40_VBIF_OUT_RD_LIM_CONF0		0xD0
+#define VFE40_VBIF_OUT_WR_LIM_CONF0		0xD4
+#define VFE40_VBIF_DDR_OUT_MAX_BURST	0xD8
+#define VFE40_VBIF_ARB_CTL				0xF0
+#define VFE40_VBIF_DDR_ARB_CONF0		0xF4
+#define VFE40_VBIF_DDR_ARB_CONF1		0xF8
+#define VFE40_VBIF_ROUND_ROBIN_QOS_ARB	0x124
+#define VFE40_VBIF_OUT_AXI_AOOO_EN		0x178
+#define VFE40_VBIF_OUT_AXI_AOOO			0x17C
 
 struct vfe_stats_control {
 	uint32_t droppedStatsFrameCount;
@@ -870,26 +925,50 @@
 
 struct vfe_share_ctrl_t {
 	void __iomem *vfebase;
+	void __iomem *vfe_vbif_base;
 	uint32_t register_total;
 
 	atomic_t vstate;
+	atomic_t handle_common_irq;
 	uint32_t vfeFrameId;
+	uint32_t rdi0FrameId;
+	uint32_t rdi1FrameId;
+	uint32_t rdi2FrameId;
 	uint32_t stats_comp;
+	spinlock_t  sd_notify_lock;
 	spinlock_t  stop_flag_lock;
 	int8_t stop_ack_pending;
 	enum vfe_output_state liveshot_state;
 	uint32_t vfe_capture_count;
 
-	uint16_t operation_mode;     /* streaming or snapshot */
+	uint32_t operation_mode;     /* streaming or snapshot */
+	uint32_t current_mode;
 	struct vfe40_output_path outpath;
 
-	uint32_t ref_count;
-	spinlock_t  sd_notify_lock;
-	uint32_t vfe_clk_rate;
+	uint16_t port_info;
+	uint8_t stop_immediately;
+	uint8_t sync_abort;
+	uint16_t cmd_type;
+	uint8_t vfe_reset_flag;
 
-	atomic_t irq_cnt;
+	uint8_t axi_ref_cnt;
+	uint16_t comp_output_mode;
+
+	struct completion reset_complete;
+
+	spinlock_t  update_ack_lock;
+	spinlock_t  start_ack_lock;
+
 	struct axi_ctrl_t *axi_ctrl;
 	struct vfe40_ctrl_type *vfe40_ctrl;
+	int8_t start_ack_pending;
+	int8_t update_ack_pending;
+	enum vfe_output_state recording_state;
+
+	atomic_t pix0_update_ack_pending;
+	atomic_t rdi0_update_ack_pending;
+	atomic_t rdi1_update_ack_pending;
+	atomic_t rdi2_update_ack_pending;
 };
 
 struct axi_ctrl_t {
@@ -902,27 +981,25 @@
 	void *syncdata;
 
 	struct resource	*vfemem;
+	struct resource	*vfe_vbif_mem;
 	struct resource *vfeio;
+	struct resource *vfe_vbif_io;
 	struct regulator *fs_vfe;
-	struct clk *vfe_clk[3];
+	struct clk *vfe_clk[7];
 	struct tasklet_struct vfe40_tasklet;
 	struct vfe_share_ctrl_t *share_ctrl;
+	struct device *iommu_ctx;
+	uint32_t bus_perf_client;
+	uint32_t use_irq_router;
 };
 
 struct vfe40_ctrl_type {
-	uint32_t vfeImaskCompositePacked;
-
-	spinlock_t  update_ack_lock;
 	spinlock_t  state_lock;
-	spinlock_t  io_lock;
 	spinlock_t  stats_bufq_lock;
 	uint32_t extlen;
 	void *extdata;
 
-	int8_t start_ack_pending;
-	int8_t reset_ack_pending;
-	int8_t update_ack_pending;
-	enum vfe_output_state recording_state;
+	int8_t vfe_sof_count_enable;
 	int8_t update_linear;
 	int8_t update_rolloff;
 	int8_t update_la;
@@ -934,18 +1011,14 @@
 	uint32_t sync_timer_state;
 	uint32_t sync_timer_number;
 
-	uint32_t output1Pattern;
-	uint32_t output1Period;
-	uint32_t output2Pattern;
-	uint32_t output2Period;
-	uint32_t vfeFrameSkipCount;
-	uint32_t vfeFrameSkipPeriod;
-	struct vfe_stats_control afStatsControl;
+	struct msm_ver_num_info ver_num;
+	struct vfe_stats_control afbfStatsControl;
 	struct vfe_stats_control awbStatsControl;
-	struct vfe_stats_control aecStatsControl;
+	struct vfe_stats_control aecbgStatsControl;
 	struct vfe_stats_control ihistStatsControl;
 	struct vfe_stats_control rsStatsControl;
 	struct vfe_stats_control csStatsControl;
+	struct vfe_stats_control bhistStatsControl;
 
 	/* v4l2 subdev */
 	struct v4l2_subdev subdev;
@@ -956,6 +1029,8 @@
 	uint32_t snapshot_frame_cnt;
 	struct msm_stats_bufq_ctrl stats_ctrl;
 	struct msm_stats_ops stats_ops;
+
+	uint32_t simultaneous_sof_stat;
 };
 
 #define statsAeNum      0
@@ -976,227 +1051,4 @@
 	uint32_t statsBuf[VFE_STATS_BUFFER_COUNT];
 };
 
-void vfe40_subdev_notify(int id, int path, int image_mode,
-	struct v4l2_subdev *sd, struct vfe_share_ctrl_t *share_ctrl);
-struct vfe40_output_ch *vfe40_get_ch(
-	int path, struct vfe_share_ctrl_t *share_ctrl);
-void vfe40_send_isp_msg(struct v4l2_subdev *sd,
-	uint32_t vfeFrameId, uint32_t isp_msg_id);
-void vfe40_axi_probe(struct axi_ctrl_t *axi_ctrl);
-
-static const uint32_t vfe40_AXI_WM_CFG[] = {
-	0x0000006C,
-	0x00000090,
-	0x000000B4,
-	0x000000D8,
-	0x000000FC,
-	0x00000120,
-	0x00000144,
-};
-
-static struct vfe40_cmd_type vfe40_cmd[] = {
-/*0*/
-	{VFE_CMD_DUMMY_0},
-	{VFE_CMD_SET_CLK},
-	{VFE_CMD_RESET},
-	{VFE_CMD_START},
-	{VFE_CMD_TEST_GEN_START},
-/*5*/
-	{VFE_CMD_OPERATION_CFG, V40_OPERATION_CFG_LEN},
-	{VFE_CMD_AXI_OUT_CFG, V40_AXI_OUT_LEN, V40_AXI_OUT_OFF, 0xFF},
-	{VFE_CMD_CAMIF_CFG, V40_CAMIF_LEN, V40_CAMIF_OFF, 0xFF},
-	{VFE_CMD_AXI_INPUT_CFG},
-	{VFE_CMD_BLACK_LEVEL_CFG},
-/*10*/
-	{VFE_CMD_MESH_ROLL_OFF_CFG},
-	{VFE_CMD_DEMUX_CFG, V40_DEMUX_LEN, V40_DEMUX_OFF, 0xFF},
-	{VFE_CMD_FOV_CFG},
-	{VFE_CMD_MAIN_SCALER_CFG},
-	{VFE_CMD_WB_CFG, V40_WB_LEN, V40_WB_OFF, 0xFF},
-/*15*/
-	{VFE_CMD_COLOR_COR_CFG, V40_COLOR_COR_LEN, V40_COLOR_COR_OFF, 0xFF},
-	{VFE_CMD_RGB_G_CFG, V40_RGB_G_LEN, V40_RGB_G_OFF, 0xFF},
-	{VFE_CMD_LA_CFG, V40_LA_LEN, V40_LA_OFF, 0xFF },
-	{VFE_CMD_CHROMA_EN_CFG, V40_CHROMA_EN_LEN, V40_CHROMA_EN_OFF, 0xFF},
-	{VFE_CMD_CHROMA_SUP_CFG, V40_CHROMA_SUP_LEN, V40_CHROMA_SUP_OFF, 0xFF},
-/*20*/
-	{VFE_CMD_MCE_CFG, V40_MCE_LEN, V40_MCE_OFF, 0xFF},
-	{VFE_CMD_SK_ENHAN_CFG, V40_SCE_LEN, V40_SCE_OFF, 0xFF},
-	{VFE_CMD_ASF_CFG, V40_ASF_LEN, V40_ASF_OFF, 0xFF},
-	{VFE_CMD_S2Y_CFG},
-	{VFE_CMD_S2CbCr_CFG},
-/*25*/
-	{VFE_CMD_CHROMA_SUBS_CFG},
-	{VFE_CMD_OUT_CLAMP_CFG, V40_OUT_CLAMP_LEN, V40_OUT_CLAMP_OFF, 0xFF},
-	{VFE_CMD_FRAME_SKIP_CFG},
-	{VFE_CMD_DUMMY_1},
-	{VFE_CMD_DUMMY_2},
-/*30*/
-	{VFE_CMD_DUMMY_3},
-	{VFE_CMD_UPDATE},
-	{VFE_CMD_BL_LVL_UPDATE},
-	{VFE_CMD_DEMUX_UPDATE, V40_DEMUX_LEN, V40_DEMUX_OFF, 0xFF},
-	{VFE_CMD_FOV_UPDATE},
-/*35*/
-	{VFE_CMD_MAIN_SCALER_UPDATE},
-	{VFE_CMD_WB_UPDATE, V40_WB_LEN, V40_WB_OFF, 0xFF},
-	{VFE_CMD_COLOR_COR_UPDATE, V40_COLOR_COR_LEN, V40_COLOR_COR_OFF, 0xFF},
-	{VFE_CMD_RGB_G_UPDATE, V40_RGB_G_LEN, V40_CHROMA_EN_OFF, 0xFF},
-	{VFE_CMD_LA_UPDATE, V40_LA_LEN, V40_LA_OFF, 0xFF },
-/*40*/
-	{VFE_CMD_CHROMA_EN_UPDATE, V40_CHROMA_EN_LEN, V40_CHROMA_EN_OFF, 0xFF},
-	{VFE_CMD_CHROMA_SUP_UPDATE, V40_CHROMA_SUP_LEN,
-		V40_CHROMA_SUP_OFF, 0xFF},
-	{VFE_CMD_MCE_UPDATE, V40_MCE_LEN, V40_MCE_OFF, 0xFF},
-	{VFE_CMD_SK_ENHAN_UPDATE, V40_SCE_LEN, V40_SCE_OFF, 0xFF},
-	{VFE_CMD_S2CbCr_UPDATE},
-/*45*/
-	{VFE_CMD_S2Y_UPDATE},
-	{VFE_CMD_ASF_UPDATE, V40_ASF_UPDATE_LEN, V40_ASF_OFF, 0xFF},
-	{VFE_CMD_FRAME_SKIP_UPDATE},
-	{VFE_CMD_CAMIF_FRAME_UPDATE},
-	{VFE_CMD_STATS_AF_UPDATE},
-/*50*/
-	{VFE_CMD_STATS_AE_UPDATE},
-	{VFE_CMD_STATS_AWB_UPDATE, V40_STATS_AWB_LEN, V40_STATS_AWB_OFF},
-	{VFE_CMD_STATS_RS_UPDATE, V40_STATS_RS_LEN, V40_STATS_RS_OFF},
-	{VFE_CMD_STATS_CS_UPDATE, V40_STATS_CS_LEN, V40_STATS_CS_OFF},
-	{VFE_CMD_STATS_SKIN_UPDATE},
-/*55*/
-	{VFE_CMD_STATS_IHIST_UPDATE, V40_STATS_IHIST_LEN, V40_STATS_IHIST_OFF},
-	{VFE_CMD_DUMMY_4},
-	{VFE_CMD_EPOCH1_ACK},
-	{VFE_CMD_EPOCH2_ACK},
-	{VFE_CMD_START_RECORDING},
-/*60*/
-	{VFE_CMD_STOP_RECORDING},
-	{VFE_CMD_DUMMY_5},
-	{VFE_CMD_DUMMY_6},
-	{VFE_CMD_CAPTURE, V40_CAPTURE_LEN, 0xFF},
-	{VFE_CMD_DUMMY_7},
-/*65*/
-	{VFE_CMD_STOP},
-	{VFE_CMD_GET_HW_VERSION, V40_GET_HW_VERSION_LEN,
-		V40_GET_HW_VERSION_OFF},
-	{VFE_CMD_GET_FRAME_SKIP_COUNTS},
-	{VFE_CMD_OUTPUT1_BUFFER_ENQ},
-	{VFE_CMD_OUTPUT2_BUFFER_ENQ},
-/*70*/
-	{VFE_CMD_OUTPUT3_BUFFER_ENQ},
-	{VFE_CMD_JPEG_OUT_BUF_ENQ},
-	{VFE_CMD_RAW_OUT_BUF_ENQ},
-	{VFE_CMD_RAW_IN_BUF_ENQ},
-	{VFE_CMD_STATS_AF_ENQ},
-/*75*/
-	{VFE_CMD_STATS_AE_ENQ},
-	{VFE_CMD_STATS_AWB_ENQ},
-	{VFE_CMD_STATS_RS_ENQ},
-	{VFE_CMD_STATS_CS_ENQ},
-	{VFE_CMD_STATS_SKIN_ENQ},
-/*80*/
-	{VFE_CMD_STATS_IHIST_ENQ},
-	{VFE_CMD_DUMMY_8},
-	{VFE_CMD_JPEG_ENC_CFG},
-	{VFE_CMD_DUMMY_9},
-	{VFE_CMD_STATS_AF_START},
-/*85*/
-	{VFE_CMD_STATS_AF_STOP},
-	{VFE_CMD_STATS_AE_START},
-	{VFE_CMD_STATS_AE_STOP},
-	{VFE_CMD_STATS_AWB_START, V40_STATS_AWB_LEN, V40_STATS_AWB_OFF},
-	{VFE_CMD_STATS_AWB_STOP},
-/*90*/
-	{VFE_CMD_STATS_RS_START, V40_STATS_RS_LEN, V40_STATS_RS_OFF},
-	{VFE_CMD_STATS_RS_STOP},
-	{VFE_CMD_STATS_CS_START, V40_STATS_CS_LEN, V40_STATS_CS_OFF},
-	{VFE_CMD_STATS_CS_STOP},
-	{VFE_CMD_STATS_SKIN_START},
-/*95*/
-	{VFE_CMD_STATS_SKIN_STOP},
-	{VFE_CMD_STATS_IHIST_START, V40_STATS_IHIST_LEN, V40_STATS_IHIST_OFF},
-	{VFE_CMD_STATS_IHIST_STOP},
-	{VFE_CMD_DUMMY_10},
-	{VFE_CMD_SYNC_TIMER_SETTING, V40_SYNC_TIMER_LEN, V40_SYNC_TIMER_OFF},
-/*100*/
-	{VFE_CMD_ASYNC_TIMER_SETTING, V40_ASYNC_TIMER_LEN, V40_ASYNC_TIMER_OFF},
-	{VFE_CMD_LIVESHOT},
-	{VFE_CMD_LA_SETUP},
-	{VFE_CMD_LINEARIZATION_CFG, V40_LINEARIZATION_LEN1,
-		V40_LINEARIZATION_OFF1},
-	{VFE_CMD_DEMOSAICV3},
-/*105*/
-	{VFE_CMD_DEMOSAICV3_ABCC_CFG},
-	{VFE_CMD_DEMOSAICV3_DBCC_CFG, V40_DEMOSAICV3_DBCC_LEN,
-		V40_DEMOSAICV3_DBCC_OFF},
-	{VFE_CMD_DEMOSAICV3_DBPC_CFG},
-	{VFE_CMD_DEMOSAICV3_ABF_CFG, V40_DEMOSAICV3_ABF_LEN,
-		V40_DEMOSAICV3_ABF_OFF},
-	{VFE_CMD_DEMOSAICV3_ABCC_UPDATE},
-/*110*/
-	{VFE_CMD_DEMOSAICV3_DBCC_UPDATE, V40_DEMOSAICV3_DBCC_LEN,
-		V40_DEMOSAICV3_DBCC_OFF},
-	{VFE_CMD_DEMOSAICV3_DBPC_UPDATE},
-	{VFE_CMD_XBAR_CFG},
-	{VFE_CMD_MODULE_CFG, V40_MODULE_CFG_LEN, V40_MODULE_CFG_OFF},
-	{VFE_CMD_ZSL},
-/*115*/
-	{VFE_CMD_LINEARIZATION_UPDATE, V40_LINEARIZATION_LEN1,
-		V40_LINEARIZATION_OFF1},
-	{VFE_CMD_DEMOSAICV3_ABF_UPDATE, V40_DEMOSAICV3_ABF_LEN,
-		V40_DEMOSAICV3_ABF_OFF},
-	{VFE_CMD_CLF_CFG, V40_CLF_CFG_LEN, V40_CLF_CFG_OFF},
-	{VFE_CMD_CLF_LUMA_UPDATE, V40_CLF_LUMA_UPDATE_LEN,
-		V40_CLF_LUMA_UPDATE_OFF},
-	{VFE_CMD_CLF_CHROMA_UPDATE, V40_CLF_CHROMA_UPDATE_LEN,
-		V40_CLF_CHROMA_UPDATE_OFF},
-/*120*/
-	{VFE_CMD_PCA_ROLL_OFF_CFG},
-	{VFE_CMD_PCA_ROLL_OFF_UPDATE},
-	{VFE_CMD_GET_REG_DUMP},
-	{VFE_CMD_GET_LINEARIZATON_TABLE},
-	{VFE_CMD_GET_MESH_ROLLOFF_TABLE},
-/*125*/
-	{VFE_CMD_GET_PCA_ROLLOFF_TABLE},
-	{VFE_CMD_GET_RGB_G_TABLE},
-	{VFE_CMD_GET_LA_TABLE},
-	{VFE_CMD_DEMOSAICV3_UPDATE},
-	{VFE_CMD_ACTIVE_REGION_CFG},
-/*130*/
-	{VFE_CMD_COLOR_PROCESSING_CONFIG},
-	{VFE_CMD_STATS_WB_AEC_CONFIG},
-	{VFE_CMD_STATS_WB_AEC_UPDATE},
-	{VFE_CMD_Y_GAMMA_CONFIG},
-	{VFE_CMD_SCALE_OUTPUT1_CONFIG},
-/*135*/
-	{VFE_CMD_SCALE_OUTPUT2_CONFIG},
-	{VFE_CMD_CAPTURE_RAW},
-	{VFE_CMD_STOP_LIVESHOT},
-	{VFE_CMD_RECONFIG_VFE},
-	{VFE_CMD_STATS_REQBUF},
-/*140*/
-	{VFE_CMD_STATS_ENQUEUEBUF},
-	{VFE_CMD_STATS_FLUSH_BUFQ},
-	{VFE_CMD_FOV_ENC_CFG, V40_FOV_ENC_LEN, V40_FOV_ENC_OFF, 0xFF},
-	{VFE_CMD_FOV_VIEW_CFG, V40_FOV_VIEW_LEN, V40_FOV_VIEW_OFF, 0xFF},
-	{VFE_CMD_FOV_ENC_UPDATE, V40_FOV_ENC_LEN, V40_FOV_ENC_OFF, 0xFF},
-/*145*/
-	{VFE_CMD_FOV_VIEW_UPDATE, V40_FOV_VIEW_LEN, V40_FOV_VIEW_OFF, 0xFF},
-	{VFE_CMD_SCALER_ENC_CFG, V40_SCALER_ENC_LEN, V40_SCALER_ENC_OFF, 0xFF},
-	{VFE_CMD_SCALER_VIEW_CFG, V40_SCALER_VIEW_LEN,
-		V40_SCALER_VIEW_OFF, 0xFF},
-	{VFE_CMD_SCALER_ENC_UPDATE, V40_SCALER_ENC_LEN,
-		V40_SCALER_ENC_OFF, 0xFF},
-	{VFE_CMD_SCALER_VIEW_UPDATE, V40_SCALER_VIEW_LEN,
-		V40_SCALER_VIEW_OFF, 0xFF},
-/*150*/
-	{VFE_CMD_COLORXFORM_ENC_CFG, V40_COLORXFORM_ENC_CFG_LEN,
-		V40_COLORXFORM_ENC_CFG_OFF, 0xFF},
-	{VFE_CMD_COLORXFORM_VIEW_CFG, V40_COLORXFORM_VIEW_CFG_LEN,
-		V40_COLORXFORM_VIEW_CFG_OFF},
-	{VFE_CMD_COLORXFORM_ENC_UPDATE, V40_COLORXFORM_ENC_CFG_LEN,
-		V40_COLORXFORM_ENC_CFG_OFF, 0xFF},
-	{VFE_CMD_COLORXFORM_VIEW_UPDATE, V40_COLORXFORM_VIEW_CFG_LEN,
-		V40_COLORXFORM_VIEW_CFG_OFF, 0xFF},
-};
-
 #endif /* __MSM_VFE40_H__ */
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index e8d9e04..407bf2e 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -1117,6 +1117,12 @@
 		return -ENOTRECOVERABLE;
 	}
 
+	if (!dev->vp_dummy_complete) {
+		pr_err("VCAP Err: %s: VP dummy read not complete",
+			__func__);
+		return -EINVAL;
+	}
+
 	switch (c_data->op_mode) {
 	case VC_VCAP_OP:
 		mutex_lock(&dev->dev_mutex);
@@ -1390,19 +1396,13 @@
 		}
 		dev->vc_resource = 0;
 		mutex_unlock(&dev->dev_mutex);
+		c_data->streaming = 0;
 		rc = vb2_streamoff(&c_data->vc_vidq,
 				V4L2_BUF_TYPE_VIDEO_CAPTURE);
-		if (rc >= 0) {
-			c_data->streaming = 0;
+		if (rc >= 0)
 			atomic_set(&c_data->dev->vc_enabled, 0);
-		}
 		return rc;
 	case VP_VCAP_OP:
-		if (!dev->vp_dummy_complete) {
-			pr_err("VCAP Err: %s: VP dummy read not complete",
-				__func__);
-			return -EINVAL;
-		}
 		if (c_data != dev->vp_client) {
 			pr_err("VCAP Err: %s: VP held by other client",
 				__func__);
@@ -1441,11 +1441,6 @@
 		atomic_set(&c_data->dev->vp_enabled, 0);
 		return rc;
 	case VC_AND_VP_VCAP_OP:
-		if (!dev->vp_dummy_complete) {
-			pr_err("VCAP Err: %s: VP dummy read not complete",
-				__func__);
-			return -EINVAL;
-		}
 		if (c_data != dev->vp_client || c_data != dev->vc_client) {
 			pr_err("VCAP Err: %s: VC/VP held by other client",
 				__func__);
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index 62cc306..966fa4b 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -120,6 +120,13 @@
 
 	dprintk(1, "%s: irq=0x%08x\n", __func__, irq);
 
+	c_data = dev->vc_client;
+	if (!c_data->streaming) {
+		writel_iowmb(irq, VCAP_VC_INT_CLEAR);
+		pr_err("VC no longer streaming\n");
+		return IRQ_HANDLED;
+	}
+
 	v4l2_evt.id = 0;
 	if (irq & 0x8000200) {
 		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
@@ -161,7 +168,6 @@
 		pr_err("VC: There is no active vc client\n");
 		return IRQ_HANDLED;
 	}
-	c_data = dev->vc_client;
 
 	spin_lock(&dev->vc_client->cap_slock);
 	if (list_empty(&dev->vc_client->vid_vc_action.active)) {
@@ -316,15 +322,34 @@
 void vc_stop_capture(struct vcap_client_data *c_data)
 {
 	struct vcap_dev *dev = c_data->dev;
-	int rc;
+	unsigned int reg;
+	int timeout;
 
-	rc = readl_relaxed(VCAP_VC_CTRL);
-	writel_iowmb(rc & ~(0x1), VCAP_VC_CTRL);
-
-	if (atomic_read(&dev->vc_enabled) == 1)
-		disable_irq(dev->vcirq->start);
-
+	writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
+	writel_iowmb(0x0, VCAP_VC_INT_MASK);
 	flush_workqueue(dev->vcap_wq);
+	if (atomic_read(&dev->vc_enabled) == 1)
+		disable_irq_nosync(dev->vcirq->start);
+
+	writel_iowmb(0x00000000, VCAP_VC_CTRL);
+	writel_iowmb(0x00000001, VCAP_SW_RESET_REQ);
+	timeout = 10000;
+	while (1) {
+		reg = (readl_relaxed(VCAP_SW_RESET_STATUS) & 0x1);
+		if (!reg)
+			break;
+		timeout--;
+		if (timeout == 0) {
+			/* This should not happen */
+			pr_err("VC is not resetting properly\n");
+			writel_iowmb(0x00000000, VCAP_SW_RESET_REQ);
+			break;
+		}
+	}
+
+	reg = readl_relaxed(VCAP_VC_NPL_CTRL);
+	reg = readl_relaxed(VCAP_VC_NPL_CTRL);
+	writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
 }
 
 int config_vc_format(struct vcap_client_data *c_data)
@@ -336,21 +361,20 @@
 	dev = c_data->dev;
 
 	/* restart VC */
-	writel_relaxed(0x00000001, VCAP_SW_RESET_REQ);
+	writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
+	writel_iowmb(0x00000001, VCAP_SW_RESET_REQ);
 	timeout = 10000;
 	while (1) {
-		rc = (readl_relaxed(VCAP_SW_RESET_STATUS) & 0x1);
-		if (!rc)
+		if (!(readl_relaxed(VCAP_SW_RESET_STATUS) & 0x1))
 			break;
 		timeout--;
 		if (timeout == 0) {
 			pr_err("VC is not resetting properly\n");
+			writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
 			return -EINVAL;
 		}
 	}
-	writel_relaxed(0x00000000, VCAP_SW_RESET_REQ);
 
-	writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
 	rc = readl_relaxed(VCAP_VC_NPL_CTRL);
 	rc = readl_relaxed(VCAP_VC_NPL_CTRL);
 	writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
diff --git a/drivers/media/video/vcap_vc.h b/drivers/media/video/vcap_vc.h
index 792fb14..76693bb 100644
--- a/drivers/media/video/vcap_vc.h
+++ b/drivers/media/video/vcap_vc.h
@@ -19,14 +19,8 @@
 
 #define VCAP_HARDWARE_VERSION 0x10000000
 
-#define VCAP_BASE (dev->vcapbase)
-#define VCAP_OFFSET(off) (VCAP_BASE + off)
-
 #define VCAP_HARDWARE_VERSION_REG (VCAP_BASE + 0x0000)
 
-#define VCAP_SW_RESET_REQ (VCAP_BASE + 0x0024)
-#define VCAP_SW_RESET_STATUS (VCAP_BASE + 0x0028)
-
 #define VCAP_VC_CTRL (VCAP_BASE + 0x0800)
 #define VCAP_VC_NPL_CTRL (VCAP_BASE + 0x0804)
 #define VCAP_VC_POLARITY (VCAP_BASE + 0x081c)
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index ba053f2..f8f27d4 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -74,6 +74,12 @@
 	dev = c_data->dev;
 	dprintk(2, "Start setup buffers\n");
 
+	if (dev->vp_shutdown) {
+		dprintk(1, "%s: VP shutting down, no buf setup\n",
+			__func__);
+		return -EPERM;
+	}
+
 	/* No need to verify vp_client is not NULL caller does so */
 	vp_act = &dev->vp_client->vid_vp_action;
 
@@ -262,6 +268,8 @@
 		writel_relaxed(0x00000000, VCAP_VP_INTERRUPT_ENABLE);
 		writel_iowmb(irq, VCAP_VP_INT_CLEAR);
 		atomic_set(&dev->vp_enabled, 0);
+		if (dev->vp_shutdown)
+			wake_up(&dev->vp_dummy_waitq);
 		return;
 	}
 
@@ -350,30 +358,60 @@
 	return IRQ_HANDLED;
 }
 
+int vp_sw_reset(struct vcap_dev *dev)
+{
+	int timeout;
+	writel_iowmb(0x00000010, VCAP_SW_RESET_REQ);
+	timeout = 10000;
+	while (1) {
+		if (!(readl_relaxed(VCAP_SW_RESET_STATUS) & 0x10))
+			break;
+		timeout--;
+		if (timeout == 0) {
+			/* This should not happen */
+			pr_err("VP is not resetting properly\n");
+			writel_iowmb(0x00000000, VCAP_SW_RESET_REQ);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
 void vp_stop_capture(struct vcap_client_data *c_data)
 {
 	struct vcap_dev *dev = c_data->dev;
+	int rc;
 
-	writel_iowmb(0x00000000, VCAP_VP_CTRL);
+	dev->vp_shutdown = true;
 	flush_workqueue(dev->vcap_wq);
 
-	if (atomic_read(&dev->vp_enabled) == 1)
-		disable_irq(dev->vpirq->start);
+	if (atomic_read(&dev->vp_enabled) == 1) {
+		rc = wait_event_interruptible_timeout(dev->vp_dummy_waitq,
+				!atomic_read(&dev->vp_enabled),
+				msecs_to_jiffies(50));
+		if (rc == 0 && atomic_read(&dev->vp_enabled) == 1) {
+			/* This should not happen, if it does hw is stuck */
+			pr_err("%s: VP Timeout and VP still running\n",
+				__func__);
+		}
+	}
 
-	writel_iowmb(0x00000001, VCAP_VP_SW_RESET);
-	writel_iowmb(0x00000000, VCAP_VP_SW_RESET);
+	vp_sw_reset(dev);
+	dev->vp_shutdown = false;
 }
 
 int config_vp_format(struct vcap_client_data *c_data)
 {
 	struct vcap_dev *dev = c_data->dev;
+	int rc;
 
 	INIT_WORK(&dev->vp_to_vc_work.work, mov_buf_to_vc);
 	dev->vp_to_vc_work.cd = c_data;
 
 	/* SW restart VP */
-	writel_iowmb(0x00000001, VCAP_VP_SW_RESET);
-	writel_iowmb(0x00000000, VCAP_VP_SW_RESET);
+	rc = vp_sw_reset(dev);
+	if (rc < 0)
+		return rc;
 
 	/* Film Mode related settings */
 	writel_iowmb(0x00000000, VCAP_VP_FILM_PROJECTION_T0);
@@ -668,20 +706,18 @@
 
 	dev->vp_dummy_event = true;
 
+	enable_irq(dev->vpirq->start);
 	writel_relaxed(0x01100101, VCAP_VP_INTERRUPT_ENABLE);
 	writel_iowmb(0x00000000, VCAP_VP_CTRL);
 	writel_iowmb(0x00010000, VCAP_VP_CTRL);
 
-	enable_irq(dev->vpirq->start);
 	rc = wait_event_interruptible_timeout(dev->vp_dummy_waitq,
 		dev->vp_dummy_complete, msecs_to_jiffies(50));
 	if (!rc && !dev->vp_dummy_complete) {
 		pr_err("%s: VP dummy event timeout", __func__);
 		rc = -ETIME;
-		writel_iowmb(0x00000000, VCAP_VP_CTRL);
 
-		writel_iowmb(0x00000001, VCAP_VP_SW_RESET);
-		writel_iowmb(0x00000000, VCAP_VP_SW_RESET);
+		vp_sw_reset(dev);
 		dev->vp_dummy_complete = false;
 	}
 
diff --git a/drivers/media/video/vcap_vp.h b/drivers/media/video/vcap_vp.h
index b2b00e9..2ad5848 100644
--- a/drivers/media/video/vcap_vp.h
+++ b/drivers/media/video/vcap_vp.h
@@ -17,9 +17,6 @@
 
 #include <media/vcap_v4l2.h>
 
-#define VCAP_BASE (dev->vcapbase)
-#define VCAP_OFFSET(off) (VCAP_BASE + off)
-
 #define VCAP_VP_INT_STATUS (VCAP_BASE + 0x404)
 #define VCAP_VP_INT_CLEAR (VCAP_BASE + 0x40C)
 
diff --git a/drivers/mfd/pm8xxx-misc.c b/drivers/mfd/pm8xxx-misc.c
index 0af013e..6bb1441 100644
--- a/drivers/mfd/pm8xxx-misc.c
+++ b/drivers/mfd/pm8xxx-misc.c
@@ -564,6 +564,7 @@
 					   : SLEEP_CTRL_SMPL_EN_PWR_OFF));
 			break;
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			rc = pm8xxx_misc_masked_write(chip,
 				REG_PM8921_SLEEP_CTRL, SLEEP_CTRL_SMPL_EN_MASK,
 				(enable ? SLEEP_CTRL_SMPL_EN_RESET
@@ -624,6 +625,7 @@
 				delay);
 			break;
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			rc = pm8xxx_misc_masked_write(chip,
 				REG_PM8921_SLEEP_CTRL, SLEEP_CTRL_SMPL_SEL_MASK,
 				delay);
@@ -703,6 +705,7 @@
 					REG_PM8058_COIN_CHG, reg);
 			break;
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			rc = pm8xxx_writeb(chip->dev->parent,
 					REG_PM8921_COIN_CHG, reg);
 			break;
@@ -747,6 +750,7 @@
 		case PM8XXX_VERSION_8018:
 		case PM8XXX_VERSION_8058:
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			rc = pm8xxx_misc_masked_write(chip,
 				REG_PM8XXX_PON_CTRL_1, PON_CTRL_1_WD_EN_MASK,
 				(enable ? PON_CTRL_1_WD_EN_RESET
@@ -793,6 +797,7 @@
 		case PM8XXX_VERSION_8018:
 		case PM8XXX_VERSION_8058:
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			rc = pm8xxx_writeb(chip->dev->parent,
 				REG_PM8XXX_GP_TEST_1, PM8XXX_STAY_ON_CFG);
 			break;
@@ -884,6 +889,7 @@
 				REG_PM8901_PON_CNTL_4, REG_PM8901_PON_CNTL_5);
 			break;
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			__pm8xxx_hard_reset_config(chip, config,
 				REG_PM8921_PON_CNTL_4, REG_PM8921_PON_CNTL_5);
 			break;
@@ -941,6 +947,7 @@
 		case PM8XXX_VERSION_8018:
 		case PM8XXX_VERSION_8058:
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			rc = pm8xxx_misc_masked_write(chip,
 				REG_PM8XXX_GPIO_MUX_CTRL, UART_PATH_SEL_MASK,
 				uart_path_sel << UART_PATH_SEL_SHIFT);
@@ -1091,6 +1098,7 @@
 		switch (chip->version) {
 		case PM8XXX_VERSION_8038:
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			pm8xxx_misc_masked_write(chip,
 					REG_PM8XXX_XO_CNTRL_2, clk_mask, value);
 			break;
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index b56f081..35ae29a 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -27,9 +27,9 @@
 #include <linux/i2c.h>
 #include <sound/soc.h>
 
-#define WCD9XXX_SLIM_GLA_MAX_RETRIES 5
 #define WCD9XXX_REGISTER_START_OFFSET 0x800
 #define WCD9XXX_SLIM_RW_MAX_TRIES 3
+#define SLIMBUS_PRESENT_TIMEOUT 100
 
 #define MAX_WCD9XXX_DEVICE	4
 #define TABLA_I2C_MODE	0x03
@@ -283,8 +283,6 @@
 			return ret;
 		}
 
-		gpio_direction_output(wcd9xxx->reset_gpio, 1);
-		msleep(20);
 		gpio_direction_output(wcd9xxx->reset_gpio, 0);
 		msleep(20);
 		gpio_direction_output(wcd9xxx->reset_gpio, 1);
@@ -1054,12 +1052,31 @@
 	return NULL;
 }
 
+static int wcd9xxx_slim_get_laddr(struct slim_device *sb,
+				  const u8 *e_addr, u8 e_len, u8 *laddr)
+{
+	int ret;
+	const unsigned long timeout = jiffies +
+				      msecs_to_jiffies(SLIMBUS_PRESENT_TIMEOUT);
+
+	do {
+		ret = slim_get_logical_addr(sb, e_addr, e_len, laddr);
+		if (!ret)
+			break;
+		/* Give SLIMBUS time to report present and be ready. */
+		usleep_range(1000, 1000);
+		pr_debug_ratelimited("%s: retyring get logical addr\n",
+				     __func__);
+	} while time_before(jiffies, timeout);
+
+	return ret;
+}
+
 static int wcd9xxx_slim_probe(struct slim_device *slim)
 {
 	struct wcd9xxx *wcd9xxx;
 	struct wcd9xxx_pdata *pdata;
 	int ret = 0;
-	int sgla_retry_cnt;
 
 	if (slim->dev.of_node) {
 		dev_info(&slim->dev, "Platform data from device tree\n");
@@ -1104,10 +1121,12 @@
 		goto err_supplies;
 	}
 
-	ret = slim_get_logical_addr(wcd9xxx->slim, wcd9xxx->slim->e_addr,
-		ARRAY_SIZE(wcd9xxx->slim->e_addr), &wcd9xxx->slim->laddr);
+	ret = wcd9xxx_slim_get_laddr(wcd9xxx->slim, wcd9xxx->slim->e_addr,
+				     ARRAY_SIZE(wcd9xxx->slim->e_addr),
+				     &wcd9xxx->slim->laddr);
 	if (ret) {
-		pr_err("fail to get slimbus logical address %d\n", ret);
+		pr_err("%s: failed to get slimbus %s logical address: %d\n",
+		       __func__, wcd9xxx->slim->name, ret);
 		goto err_reset;
 	}
 	wcd9xxx->read_dev = wcd9xxx_slim_read_device;
@@ -1116,11 +1135,8 @@
 	wcd9xxx->irq_base = pdata->irq_base;
 	wcd9xxx_pgd_la = wcd9xxx->slim->laddr;
 
-	if (pdata->num_irqs < TABLA_NUM_IRQS) {
-		pr_err("%s: Error, not enough interrupt lines allocated\n",
-			__func__);
-		goto err_reset;
-	}
+	if (pdata->num_irqs < TABLA_NUM_IRQS)
+		pr_warn("%s: Not enough interrupt lines allocated\n", __func__);
 
 	wcd9xxx->slim_slave = &pdata->slimbus_slave_device;
 
@@ -1130,28 +1146,14 @@
 		goto err_reset;
 	}
 
-	sgla_retry_cnt = 0;
-
-	while (1) {
-		ret = slim_get_logical_addr(wcd9xxx->slim_slave,
-			wcd9xxx->slim_slave->e_addr,
-			ARRAY_SIZE(wcd9xxx->slim_slave->e_addr),
-			&wcd9xxx->slim_slave->laddr);
-		if (ret) {
-			if (sgla_retry_cnt++ < WCD9XXX_SLIM_GLA_MAX_RETRIES) {
-				/* Give SLIMBUS slave time to report present
-				   and be ready.
-				 */
-				usleep_range(1000, 1000);
-				pr_debug("%s: retry slim_get_logical_addr()\n",
-					__func__);
-				continue;
-			}
-			pr_err("fail to get slimbus slave logical address"
-				" %d\n", ret);
-			goto err_slim_add;
-		}
-		break;
+	ret = wcd9xxx_slim_get_laddr(wcd9xxx->slim_slave,
+				     wcd9xxx->slim_slave->e_addr,
+				     ARRAY_SIZE(wcd9xxx->slim_slave->e_addr),
+				     &wcd9xxx->slim_slave->laddr);
+	if (ret) {
+		pr_err("%s: failed to get slimbus %s logical address: %d\n",
+		       __func__, wcd9xxx->slim->name, ret);
+		goto err_slim_add;
 	}
 	wcd9xxx_inf_la = wcd9xxx->slim_slave->laddr;
 	wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_SLIMBUS;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 2b278be..a86798d 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1351,9 +1351,11 @@
 		 */
 		if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
 			|| data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
-			pr_err("%s: CMD%d: Data timeout\n",
+			pr_err("%s: CMD%d: Data timeout. DAT0 => %d\n",
 				 mmc_hostname(host->mmc),
-				 data->mrq->cmd->opcode);
+				 data->mrq->cmd->opcode,
+				 (readl_relaxed(host->base
+				 + MCI_TEST_INPUT) & 0x2) ? 1 : 0);
 			data->error = -ETIMEDOUT;
 			msmsdcc_dump_sdcc_state(host);
 		}
@@ -3358,10 +3360,10 @@
 {
 	struct device *dev = mmc_dev(host->mmc);
 
-	pr_info("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
+	pr_err("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
 		mmc_hostname(host->mmc), host->sdcc_suspended,
 		host->pending_resume, host->sdcc_suspending);
-	pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
+	pr_err("%s: RPM: runtime_status=%d, usage_count=%d,"
 		" is_suspended=%d, disable_depth=%d, runtime_error=%d,"
 		" request_pending=%d, request=%d\n",
 		mmc_hostname(host->mmc), dev->power.runtime_status,
@@ -4847,10 +4849,10 @@
 	if (!base)
 		return;
 
-	pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
+	pr_err("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
 		" =====\n", name, phys_base, (u32)base);
 	for (i = 0; i < no_of_regs; i = i + 4) {
-		pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
+		pr_err("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
 			(u32)readl_relaxed(base + i*4),
 			(u32)readl_relaxed(base + ((i+1)*4)),
 			(u32)readl_relaxed(base + ((i+2)*4)),
@@ -4861,25 +4863,29 @@
 static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
 {
 	/* Dump current state of SDCC clocks, power and irq */
-	pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
+	pr_err("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
 		(host->pwr ? "ON" : "OFF"));
-	pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
+	pr_err("%s: SDCC clks are %s, MCLK rate=%d\n",
 		mmc_hostname(host->mmc),
 		(atomic_read(&host->clks_on) ? "ON" : "OFF"),
 		(u32)clk_get_rate(host->clk));
-	pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
+	pr_err("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
 		(host->sdcc_irq_disabled ? "disabled" : "enabled"));
 
 	/* Now dump SDCC registers. Don't print FIFO registers */
-	if (atomic_read(&host->clks_on))
+	if (atomic_read(&host->clks_on)) {
 		msmsdcc_print_regs("SDCC-CORE", host->base,
 				   host->core_memres->start, 28);
+		pr_err("%s: MCI_TEST_INPUT = 0x%.8x\n",
+			mmc_hostname(host->mmc),
+			readl_relaxed(host->base + MCI_TEST_INPUT));
+	}
 
 	if (host->curr.data) {
 		if (!msmsdcc_is_dma_possible(host, host->curr.data))
-			pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
+			pr_err("%s: PIO mode\n", mmc_hostname(host->mmc));
 		else if (is_dma_mode(host))
-			pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
+			pr_err("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
 				mmc_hostname(host->mmc), host->dma.busy,
 				host->dma.channel, host->dma.crci);
 		else if (is_sps_mode(host)) {
@@ -4887,16 +4893,16 @@
 				msmsdcc_print_regs("SDCC-DML", host->dml_base,
 						   host->dml_memres->start,
 						   16);
-			pr_info("%s: SPS mode: busy=%d\n",
+			pr_err("%s: SPS mode: busy=%d\n",
 				mmc_hostname(host->mmc), host->sps.busy);
 		}
 
-		pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
+		pr_err("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
 			mmc_hostname(host->mmc), host->curr.xfer_size,
 			host->curr.data_xfered, host->curr.xfer_remain);
 	}
 
-	pr_info("%s: got_dataend=%d, prog_enable=%d,"
+	pr_err("%s: got_dataend=%d, prog_enable=%d,"
 		" wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
 		" req_tout_ms=%d\n", mmc_hostname(host->mmc),
 		host->curr.got_dataend, host->prog_enable,
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index fbe8d3c..295c55c 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -29,6 +29,7 @@
 #include <linux/if_arp.h>
 #include <linux/msm_rmnet.h>
 #include <linux/platform_device.h>
+#include <net/pkt_sched.h>
 
 #ifdef CONFIG_HAS_EARLYSUSPEND
 #include <linux/earlysuspend.h>
@@ -638,6 +639,16 @@
 			dev->name);
 		break;
 
+	case RMNET_IOCTL_FLOW_ENABLE:
+		tc_qdisc_flow_control(dev, (u32)ifr->ifr_data, 1);
+		DBG0("[%s] rmnet_ioctl(): enabled flow", dev->name);
+		break;
+
+	case RMNET_IOCTL_FLOW_DISABLE:
+		tc_qdisc_flow_control(dev, (u32)ifr->ifr_data, 0);
+		DBG0("[%s] rmnet_ioctl(): disabled flow", dev->name);
+		break;
+
 	case RMNET_IOCTL_GET_QOS:           /* Get QoS header state    */
 		ifr->ifr_ifru.ifru_data =
 			(void *)(p->operation_mode & RMNET_MODE_QOS);
diff --git a/drivers/net/wireless/libra/libra_sdioif.c b/drivers/net/wireless/libra/libra_sdioif.c
index aa7970a..1d72a16 100644
--- a/drivers/net/wireless/libra/libra_sdioif.c
+++ b/drivers/net/wireless/libra/libra_sdioif.c
@@ -27,6 +27,12 @@
 /* SDIO Card ID / Device ID */
 static unsigned short  libra_sdio_card_id;
 
+/* completion variables */
+struct completion gCard_rem_event_var;
+EXPORT_SYMBOL(gCard_rem_event_var);
+struct completion gShutdown_event_var;
+EXPORT_SYMBOL(gShutdown_event_var);
+
 static suspend_handler_t *libra_suspend_hldr;
 static resume_handler_t *libra_resume_hldr;
 static notify_card_removal_t *libra_notify_card_removal_hdlr;
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index 7924578..eb9e8ee 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -1403,3 +1403,32 @@
 
 	SPS_INFO("--------------------  end of FIFO  --------------------\n");
 }
+
+/* output BAM_TEST_BUS_REG with specified TEST_BUS_SEL */
+void print_bam_test_bus_reg(void *base, u32 tb_sel)
+{
+	u32 i;
+	u32 test_bus_selection[] = {0x1, 0x2, 0x3, 0x4, 0xD, 0x10,
+			0x41, 0x42, 0x43, 0x44, 0x45, 0x46};
+	u32 size = sizeof(test_bus_selection) / sizeof(u32);
+
+	if ((base == NULL) || (tb_sel == 0))
+		return;
+
+	SPS_INFO("\nsps:Specified TEST_BUS_SEL value: 0x%x\n", tb_sel);
+	bam_write_reg_field(base, TEST_BUS_SEL, BAM_TESTBUS_SEL, tb_sel);
+	SPS_INFO("sps:BAM_TEST_BUS_REG: 0x%x when TEST_BUS_SEL: 0x%x\n\n",
+		bam_read_reg(base, TEST_BUS_REG),
+		bam_read_reg_field(base, TEST_BUS_SEL, BAM_TESTBUS_SEL));
+
+	/* output other selections */
+	for (i = 0; i < size; i++) {
+		bam_write_reg_field(base, TEST_BUS_SEL, BAM_TESTBUS_SEL,
+					test_bus_selection[i]);
+
+		SPS_INFO("sps:bam 0x%x(va);TEST_BUS_REG:0x%x;TEST_BUS_SEL:0x%x",
+			(u32) base, bam_read_reg(base, TEST_BUS_REG),
+			bam_read_reg_field(base, TEST_BUS_SEL,
+					BAM_TESTBUS_SEL));
+	}
+}
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 656d1fb..5bbcc84 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -89,6 +89,9 @@
 u8 debug_level_option;
 u8 print_limit_option;
 u8 reg_dump_option;
+u32 testbus_sel;
+u32 bam_pipe_sel;
+
 
 static char *debugfs_buf;
 static u32 debugfs_buf_size;
@@ -101,6 +104,8 @@
 struct dentry *dfile_debug_level_option;
 struct dentry *dfile_print_limit_option;
 struct dentry *dfile_reg_dump_option;
+struct dentry *dfile_testbus_sel;
+struct dentry *dfile_bam_pipe_sel;
 struct dentry *dfile_bam_addr;
 
 static struct sps_bam *phy2bam(u32 phys_addr);
@@ -325,30 +330,53 @@
 		for (i = 0; i < num_pipes; i++)
 			print_bam_pipe_selected_reg(vir_addr, i);
 		break;
-	case 5: /* output selected registers of some pipes */
+	case 5: /* output selected registers of selected pipes */
+		for (i = 0; i < num_pipes; i++)
+			if (bam_pipe_sel & (1UL << i))
+				print_bam_pipe_selected_reg(vir_addr, i);
+		break;
+	case 6: /* output selected registers of typical pipes */
 		print_bam_pipe_selected_reg(vir_addr, 4);
 		print_bam_pipe_selected_reg(vir_addr, 5);
 		break;
-	case 6: /* output desc FIFO of all active pipes */
+	case 7: /* output desc FIFO of all pipes */
 		for (i = 0; i < num_pipes; i++)
 			print_bam_pipe_desc_fifo(vir_addr, i);
 		break;
-	case 7: /* output desc FIFO of some pipes */
+	case 8: /* output desc FIFO of selected pipes */
+		for (i = 0; i < num_pipes; i++)
+			if (bam_pipe_sel & (1UL << i))
+				print_bam_pipe_desc_fifo(vir_addr, i);
+		break;
+	case 9: /* output desc FIFO of typical pipes */
 		print_bam_pipe_desc_fifo(vir_addr, 4);
 		print_bam_pipe_desc_fifo(vir_addr, 5);
 		break;
-	case 8: /* output selected registers and valid desc FIFO of all pipes */
+	case 10: /* output selected registers and desc FIFO of all pipes */
 		for (i = 0; i < num_pipes; i++) {
 			print_bam_pipe_selected_reg(vir_addr, i);
 			print_bam_pipe_desc_fifo(vir_addr, i);
 		}
 		break;
-	case 9: /* output selected registers and desc FIFO of some pipes */
+	case 11: /* output selected registers and desc FIFO of selected pipes */
+		for (i = 0; i < num_pipes; i++)
+			if (bam_pipe_sel & (1UL << i)) {
+				print_bam_pipe_selected_reg(vir_addr, i);
+				print_bam_pipe_desc_fifo(vir_addr, i);
+			}
+		break;
+	case 12: /* output selected registers and desc FIFO of typical pipes */
 		print_bam_pipe_selected_reg(vir_addr, 4);
 		print_bam_pipe_desc_fifo(vir_addr, 4);
 		print_bam_pipe_selected_reg(vir_addr, 5);
 		print_bam_pipe_desc_fifo(vir_addr, 5);
 		break;
+	case 13: /* output BAM_TEST_BUS_REG */
+		if (testbus_sel)
+			print_bam_test_bus_reg(vir_addr, testbus_sel);
+		else
+			pr_info("sps:TEST_BUS_SEL should NOT be zero.");
+		break;
 	default:
 		pr_info("sps:no dump option is chosen yet.");
 	}
@@ -367,6 +395,8 @@
 	debug_level_option = 0;
 	print_limit_option = 0;
 	reg_dump_option = 0;
+	testbus_sel = 0;
+	bam_pipe_sel = 0;
 	debugfs_buf_size = 0;
 	debugfs_buf_used = 0;
 	wraparound = false;
@@ -416,6 +446,20 @@
 		goto reg_dump_option_err;
 	}
 
+	dfile_testbus_sel = debugfs_create_u32("testbus_sel", 0666,
+						dent, &testbus_sel);
+	if (!dfile_testbus_sel || IS_ERR(dfile_testbus_sel)) {
+		pr_err("sps:fail to create debug_fs file for testbus_sel.\n");
+		goto testbus_sel_err;
+	}
+
+	dfile_bam_pipe_sel = debugfs_create_u32("bam_pipe_sel", 0666,
+						dent, &bam_pipe_sel);
+	if (!dfile_bam_pipe_sel || IS_ERR(dfile_bam_pipe_sel)) {
+		pr_err("sps:fail to create debug_fs file for bam_pipe_sel.\n");
+		goto bam_pipe_sel_err;
+	}
+
 	dfile_bam_addr = debugfs_create_file("bam_addr", 0666,
 			dent, 0, &sps_bam_addr_ops);
 	if (!dfile_bam_addr || IS_ERR(dfile_bam_addr)) {
@@ -427,6 +471,10 @@
 	return;
 
 bam_addr_err:
+	debugfs_remove(dfile_bam_pipe_sel);
+bam_pipe_sel_err:
+	debugfs_remove(dfile_testbus_sel);
+testbus_sel_err:
 	debugfs_remove(dfile_reg_dump_option);
 reg_dump_option_err:
 	debugfs_remove(dfile_print_limit_option);
@@ -452,6 +500,10 @@
 		debugfs_remove(dfile_print_limit_option);
 	if (dfile_reg_dump_option)
 		debugfs_remove(dfile_reg_dump_option);
+	if (dfile_testbus_sel)
+		debugfs_remove(dfile_testbus_sel);
+	if (dfile_bam_pipe_sel)
+		debugfs_remove(dfile_bam_pipe_sel);
 	if (dfile_bam_addr)
 		debugfs_remove(dfile_bam_addr);
 	if (dent)
@@ -462,7 +514,8 @@
 #endif
 
 /* Get the debug info of BAM registers and descriptor FIFOs */
-int sps_get_bam_debug_info(u32 dev, u32 option, u32 para)
+int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
+		u32 tb_sel, u8 pre_level)
 {
 	int res = 0;
 	struct sps_bam *bam;
@@ -545,6 +598,12 @@
 		print_bam_pipe_selected_reg(vir_addr, 5);
 		print_bam_pipe_desc_fifo(vir_addr, 5);
 		break;
+	case 13: /* output BAM_TEST_BUS_REG */
+		if (tb_sel)
+			print_bam_test_bus_reg(vir_addr, tb_sel);
+		else
+			pr_info("sps:TEST_BUS_SEL should NOT be zero.");
+		break;
 	default:
 		pr_info("sps:no option is chosen yet.");
 	}
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index 43a50bd..8a5deff 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -200,6 +200,9 @@
 /* output descriptor FIFO of a pipe */
 void print_bam_pipe_desc_fifo(void *, u32);
 
+/* output BAM_TEST_BUS_REG */
+void print_bam_test_bus_reg(void *, u32);
+
 /**
  * Translate physical to virtual address
  *
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index a347984..551c0a7 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -539,6 +539,9 @@
 		return NULL;
 	}
 
+	pdata->ignore_core_reset_ack = of_property_read_bool(node,
+					"qcom,ignore-core-reset-ack");
+
 	for_each_child_of_node(pdev->dev.of_node, node)
 		pipe_entry++;
 
@@ -684,6 +687,12 @@
 	usb_props.summing_threshold = USB_SUMMING_THRESHOLD;
 	usb_props.event_threshold = 512;
 	usb_props.num_pipes = pdata->usb_bam_num_pipes;
+	/*
+	 * HSUSB and HSIC Cores don't support RESET ACK signal to BAMs
+	 * Hence, let BAM to ignore acknowledge from USB while resetting PIPE
+	 */
+	if (pdata->ignore_core_reset_ack && pdata->usb_active_bam != SSUSB_BAM)
+		usb_props.options = SPS_BAM_NO_EXT_P_RST;
 
 	ret = sps_register_bam_device(&usb_props, &h_usb);
 	if (ret < 0) {
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 6a4e50c..cfe1efb 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -270,6 +270,7 @@
 	int				rconn_mohm;
 	enum pm8921_chg_led_src_config	led_src_config;
 	bool				host_mode;
+	bool				has_dc_supply;
 	u8				active_path;
 	int				recent_reported_soc;
 };
@@ -1195,6 +1196,12 @@
 	case POWER_SUPPLY_PROP_PRESENT:
 	case POWER_SUPPLY_PROP_ONLINE:
 		val->intval = 0;
+
+		if (the_chip->has_dc_supply) {
+			val->intval = 1;
+			return 0;
+		}
+
 		if (charging_disabled)
 			return 0;
 
@@ -1669,8 +1676,7 @@
 	 */
 	if (!get_prop_batt_present(the_chip)
 		&& !is_dc_chg_plugged_in(the_chip)) {
-		if (get_prop_batt_current(the_chip) <
-				the_chip->min_voltage_mv) {
+		if (!the_chip->has_dc_supply) {
 			pr_err("rejected: no other power source connected\n");
 			return;
 		}
@@ -4037,6 +4043,7 @@
 	chip->hot_thr = pdata->hot_thr;
 	chip->rconn_mohm = pdata->rconn_mohm;
 	chip->led_src_config = pdata->led_src_config;
+	chip->has_dc_supply = pdata->has_dc_supply;
 
 	rc = pm8921_chg_hw_init(chip);
 	if (rc) {
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 40f3803..7e74eca 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -62,11 +62,11 @@
 	config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config),
 								 GFP_KERNEL);
 	if (!config)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	config->init_data = of_get_regulator_init_data(dev, dev->of_node);
 	if (!config->init_data)
-		return NULL;
+		return ERR_PTR(-EINVAL);
 
 	init_data = config->init_data;
 	init_data->constraints.apply_uV = 0;
@@ -77,13 +77,26 @@
 	} else {
 		dev_err(dev,
 			 "Fixed regulator specified with variable voltages\n");
-		return NULL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	if (init_data->constraints.boot_on)
 		config->enabled_at_boot = true;
 
 	config->gpio = of_get_named_gpio(np, "gpio", 0);
+	/*
+	 * of_get_named_gpio() currently returns ENODEV rather than
+	 * EPROBE_DEFER. This code attempts to be compatible with both
+	 * for now; the ENODEV check can be removed once the API is fixed.
+	 * of_get_named_gpio() doesn't differentiate between a missing
+	 * property (which would be fine here, since the GPIO is optional)
+	 * and some other error. Patches have been posted for both issues.
+	 * Once they are check in, we should replace this with:
+	 * if (config->gpio < 0 && config->gpio != -ENOENT)
+	 */
+	if ((config->gpio == -ENODEV) || (config->gpio == -EPROBE_DEFER))
+		return ERR_PTR(-EPROBE_DEFER);
+
 	delay = of_get_property(np, "startup-delay-us", NULL);
 	if (delay)
 		config->startup_delay = be32_to_cpu(*delay);
@@ -168,10 +181,13 @@
 	struct fixed_voltage_data *drvdata;
 	int ret;
 
-	if (pdev->dev.of_node)
+	if (pdev->dev.of_node) {
 		config = of_get_fixed_voltage_config(&pdev->dev);
-	else
+		if (IS_ERR(config))
+			return PTR_ERR(config);
+	} else {
 		config = pdev->dev.platform_data;
+	}
 
 	if (!config)
 		return -ENOMEM;
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 14d554c..f3a0d98 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -25,6 +25,7 @@
 #include <linux/of.h>
 #include <linux/of_slimbus.h>
 #include <mach/sps.h>
+#include <mach/qdsp6v2/apr.h>
 
 /* Per spec.max 40 bytes per received message */
 #define SLIM_RX_MSGQ_BUF_LEN	40
@@ -1846,10 +1847,20 @@
 {
 	struct msm_slim_ctrl *dev;
 	int ret;
+	enum apr_subsys_state q6_state;
 	struct resource		*bam_mem, *bam_io;
 	struct resource		*slim_mem, *slim_io;
 	struct resource		*irq, *bam_irq;
 	bool			rxreg_access = false;
+
+	q6_state = apr_get_q6_state();
+	if (q6_state == APR_SUBSYS_DOWN) {
+		dev_dbg(&pdev->dev, "defering %s, adsp_state %d\n", __func__,
+			q6_state);
+		return -EPROBE_DEFER;
+	} else
+		dev_dbg(&pdev->dev, "adsp is ready\n");
+
 	slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						"slimbus_physical");
 	if (!slim_mem) {
@@ -2075,6 +2086,10 @@
 	 * function
 	 */
 	mb();
+
+	/* Add devices registered with board-info now that controller is up */
+	slim_ctrl_add_boarddevs(&dev->ctrl);
+
 	if (pdev->dev.of_node)
 		of_register_slim_devices(&dev->ctrl);
 
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index d0b5817..e50addb 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -373,6 +373,24 @@
 EXPORT_SYMBOL_GPL(slim_register_board_info);
 
 /*
+ * slim_ctrl_add_boarddevs: Add devices registered by board-info
+ * @ctrl: Controller to which these devices are to be added to.
+ * This API is called by controller when it is up and running.
+ * If devices on a controller were registered before controller,
+ * this will make sure that they get probed when controller is up.
+ */
+void slim_ctrl_add_boarddevs(struct slim_controller *ctrl)
+{
+	struct sbi_boardinfo *bi;
+	mutex_lock(&board_lock);
+	list_add_tail(&ctrl->list, &slim_ctrl_list);
+	list_for_each_entry(bi, &board_list, list)
+		slim_match_ctrl_to_boardinfo(ctrl, &bi->board_info);
+	mutex_unlock(&board_lock);
+}
+EXPORT_SYMBOL_GPL(slim_ctrl_add_boarddevs);
+
+/*
  * slim_busnum_to_ctrl: Map bus number to controller
  * @busnum: Bus number
  * Returns controller representing this bus number
@@ -394,7 +412,6 @@
 static int slim_register_controller(struct slim_controller *ctrl)
 {
 	int ret = 0;
-	struct sbi_boardinfo *bi;
 
 	/* Can't register until after driver model init */
 	if (WARN_ON(!slimbus_type.p)) {
@@ -462,15 +479,6 @@
 	ctrl->wq = create_singlethread_workqueue(dev_name(&ctrl->dev));
 	if (!ctrl->wq)
 		goto err_workq_failed;
-	/*
-	 * If devices on a controller were registered before controller,
-	 * this will make sure that they get probed now that controller is up
-	 */
-	mutex_lock(&board_lock);
-	list_add_tail(&ctrl->list, &slim_ctrl_list);
-	list_for_each_entry(bi, &board_list, list)
-		slim_match_ctrl_to_boardinfo(ctrl, &bi->board_info);
-	mutex_unlock(&board_lock);
 
 	return 0;
 
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 3366bba..b97ea1c 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -71,7 +71,8 @@
 #define TSENS_CAL_SEL_SHIFT		30
 #define TSENS_CAL_SEL_SHIFT_2		28
 #define TSENS_ONE_POINT_CALIB		0x1
-#define TSENS_TWO_POINT_CALIB		0x2
+#define TSENS_ONE_POINT_CALIB_OPTION_2	0x2
+#define TSENS_TWO_POINT_CALIB		0x3
 
 #define TSENS0_POINT1_SHIFT		8
 #define TSENS1_POINT1_SHIFT		14
@@ -574,30 +575,66 @@
 		return -ENODEV;
 	}
 
-	if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB ||
-					TSENS_TWO_POINT_CALIB) {
+	if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
 		tmdev->sensor[0].calib_data_point1 =
-		(((tsens_base1_data + tsens0_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens0_point1;
 		tmdev->sensor[1].calib_data_point1 =
-		(((tsens_base1_data + tsens1_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens1_point1;
 		tmdev->sensor[2].calib_data_point1 =
-		(((tsens_base1_data + tsens2_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens2_point1;
 		tmdev->sensor[3].calib_data_point1 =
-		(((tsens_base1_data + tsens3_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens3_point1;
 		tmdev->sensor[4].calib_data_point1 =
-		(((tsens_base1_data + tsens4_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens4_point1;
 		tmdev->sensor[5].calib_data_point1 =
-		(((tsens_base1_data + tsens5_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens5_point1;
 		tmdev->sensor[6].calib_data_point1 =
-		(((tsens_base1_data + tsens6_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens6_point1;
 		tmdev->sensor[7].calib_data_point1 =
-		(((tsens_base1_data + tsens7_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens7_point1;
 		tmdev->sensor[8].calib_data_point1 =
-		(((tsens_base1_data + tsens8_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens8_point1;
 		tmdev->sensor[9].calib_data_point1 =
-		(((tsens_base1_data + tsens9_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens9_point1;
 		tmdev->sensor[10].calib_data_point1 =
-		(((tsens_base1_data + tsens10_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens10_point1;
+	}
+
+	if (tsens_calibration_mode == (TSENS_ONE_POINT_CALIB_OPTION_2 ||
+					TSENS_TWO_POINT_CALIB)) {
+		tmdev->sensor[0].calib_data_point1 =
+		((((tsens_base1_data) + tsens0_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[1].calib_data_point1 =
+		((((tsens_base1_data) + tsens1_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[2].calib_data_point1 =
+		((((tsens_base1_data) + tsens2_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[3].calib_data_point1 =
+		((((tsens_base1_data) + tsens3_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[4].calib_data_point1 =
+		((((tsens_base1_data) + tsens4_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[5].calib_data_point1 =
+		((((tsens_base1_data) + tsens5_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[6].calib_data_point1 =
+		((((tsens_base1_data) + tsens6_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[7].calib_data_point1 =
+		((((tsens_base1_data) + tsens7_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[8].calib_data_point1 =
+		((((tsens_base1_data) + tsens8_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[9].calib_data_point1 =
+		((((tsens_base1_data) + tsens9_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[10].calib_data_point1 =
+		((((tsens_base1_data) + tsens10_point1) << 2) |
+						TSENS_BIT_APPEND);
 	}
 
 	if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index 9ebb54a..71f6a99 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -6,7 +6,7 @@
 obj-$(CONFIG_MAGIC_SYSRQ)	+= sysrq.o
 obj-$(CONFIG_N_HDLC)		+= n_hdlc.o
 obj-$(CONFIG_N_GSM)		+= n_gsm.o
-obj-$(CONFIG_N_SMUX)		+= n_smux.o
+obj-$(CONFIG_N_SMUX)		+= n_smux.o smux_debug.o
 obj-$(CONFIG_N_SMUX_LOOPBACK)	+= smux_test.o smux_loopback.o
 obj-$(CONFIG_SMUX_CTL)		+= smux_ctl.o
 obj-$(CONFIG_TRACE_ROUTER)	+= n_tracerouter.o
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index 1385e08..14b8ca2 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -28,12 +28,13 @@
 #include <mach/subsystem_notif.h>
 #include <mach/subsystem_restart.h>
 #include <mach/msm_serial_hs.h>
+#include <mach/msm_ipc_logging.h>
 #include "smux_private.h"
 #include "smux_loopback.h"
 
 #define SMUX_NOTIFY_FIFO_SIZE	128
 #define SMUX_TX_QUEUE_SIZE	256
-#define SMUX_PKT_LOG_SIZE 80
+#define SMUX_PKT_LOG_SIZE 128
 
 /* Maximum size we can accept in a single RX buffer */
 #define TTY_RECEIVE_ROOM 65536
@@ -59,10 +60,12 @@
 	MSM_SMUX_PKT = 1U << 3,
 };
 
-static int smux_debug_mask;
+static int smux_debug_mask = MSM_SMUX_DEBUG | MSM_SMUX_POWER_INFO;
 module_param_named(debug_mask, smux_debug_mask,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
 
+static int disable_ipc_logging;
+
 /* Simulated wakeup used for testing */
 int smux_byte_loopback;
 module_param_named(byte_loopback, smux_byte_loopback,
@@ -71,14 +74,24 @@
 module_param_named(simulate_wakeup_delay, smux_simulate_wakeup_delay,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
 
+#define IPC_LOG_STR(x...) do { \
+	if (!disable_ipc_logging && log_ctx) \
+		ipc_log_string(log_ctx, x); \
+} while (0)
+
 #define SMUX_DBG(x...) do {                              \
 	if (smux_debug_mask & MSM_SMUX_DEBUG) \
-			pr_info(x);  \
+			IPC_LOG_STR(x);  \
+} while (0)
+
+#define SMUX_ERR(x...) do {                              \
+	pr_err(x); \
+	IPC_LOG_STR(x);  \
 } while (0)
 
 #define SMUX_PWR(x...) do {                              \
 	if (smux_debug_mask & MSM_SMUX_POWER_INFO) \
-			pr_info(x);  \
+			IPC_LOG_STR(x);  \
 } while (0)
 
 #define SMUX_PWR_PKT_RX(pkt) do { \
@@ -90,10 +103,10 @@
 	if (smux_debug_mask & MSM_SMUX_POWER_INFO) { \
 			if (pkt->hdr.cmd == SMUX_CMD_BYTE && \
 					pkt->hdr.flags == SMUX_WAKEUP_ACK) \
-				pr_info("smux: TX Wakeup ACK\n"); \
+				IPC_LOG_STR("smux: TX Wakeup ACK\n"); \
 			else if (pkt->hdr.cmd == SMUX_CMD_BYTE && \
 					pkt->hdr.flags == SMUX_WAKEUP_REQ) \
-				pr_info("smux: TX Wakeup REQ\n"); \
+				IPC_LOG_STR("smux: TX Wakeup REQ\n"); \
 			else \
 				smux_log_pkt(pkt, 0); \
 	} \
@@ -170,59 +183,6 @@
 	SMUX_PWR_OFF_FLUSH,
 };
 
-/**
- * Logical Channel Structure.  One instance per channel.
- *
- * Locking Hierarchy
- * Each lock has a postfix that describes the locking level.  If multiple locks
- * are required, only increasing lock hierarchy numbers may be locked which
- * ensures avoiding a deadlock.
- *
- * Locking Example
- * If state_lock_lhb1 is currently held and the TX list needs to be
- * manipulated, then tx_lock_lhb2 may be locked since it's locking hierarchy
- * is greater.  However, if tx_lock_lhb2 is held, then state_lock_lhb1 may
- * not be acquired since it would result in a deadlock.
- *
- * Note that the Line Discipline locks (*_lha) should always be acquired
- * before the logical channel locks.
- */
-struct smux_lch_t {
-	/* channel state */
-	spinlock_t state_lock_lhb1;
-	uint8_t lcid;
-	unsigned local_state;
-	unsigned local_mode;
-	uint8_t local_tiocm;
-	unsigned options;
-
-	unsigned remote_state;
-	unsigned remote_mode;
-	uint8_t remote_tiocm;
-
-	int tx_flow_control;
-	int rx_flow_control_auto;
-	int rx_flow_control_client;
-
-	/* client callbacks and private data */
-	void *priv;
-	void (*notify)(void *priv, int event_type, const void *metadata);
-	int (*get_rx_buffer)(void *priv, void **pkt_priv, void **buffer,
-								int size);
-
-	/* RX Info */
-	struct list_head rx_retry_queue;
-	unsigned rx_retry_queue_cnt;
-	struct delayed_work rx_retry_work;
-
-	/* TX Info */
-	spinlock_t tx_lock_lhb2;
-	struct list_head tx_queue;
-	struct list_head tx_ready_list;
-	unsigned tx_pending_data_cnt;
-	unsigned notify_lwm;
-};
-
 union notifier_metadata {
 	struct smux_meta_disconnected disconnected;
 	struct smux_meta_read read;
@@ -276,6 +236,7 @@
 	int is_initialized;
 	int platform_devs_registered;
 	int in_reset;
+	int remote_is_alive;
 	int ld_open_count;
 	struct tty_struct *tty;
 
@@ -302,7 +263,7 @@
 
 
 /* data structures */
-static struct smux_lch_t smux_lch[SMUX_NUM_LOGICAL_CHANNELS];
+struct smux_lch_t smux_lch[SMUX_NUM_LOGICAL_CHANNELS];
 static struct smux_ldisc_t smux;
 static const char *tty_error_type[] = {
 	[TTY_NORMAL] = "normal",
@@ -312,7 +273,7 @@
 	[TTY_FRAME] = "framing",
 };
 
-static const char *smux_cmds[] = {
+static const char * const smux_cmds[] = {
 	[SMUX_CMD_DATA] = "DATA",
 	[SMUX_CMD_OPEN_LCH] = "OPEN",
 	[SMUX_CMD_CLOSE_LCH] = "CLOSE",
@@ -321,6 +282,44 @@
 	[SMUX_CMD_BYTE] = "Raw Byte",
 };
 
+static const char * const smux_events[] = {
+	[SMUX_CONNECTED] = "CONNECTED" ,
+	[SMUX_DISCONNECTED] = "DISCONNECTED",
+	[SMUX_READ_DONE] = "READ_DONE",
+	[SMUX_READ_FAIL] = "READ_FAIL",
+	[SMUX_WRITE_DONE] = "WRITE_DONE",
+	[SMUX_WRITE_FAIL] = "WRITE_FAIL",
+	[SMUX_TIOCM_UPDATE] = "TIOCM_UPDATE",
+	[SMUX_LOW_WM_HIT] = "LOW_WM_HIT",
+	[SMUX_HIGH_WM_HIT] = "HIGH_WM_HIT",
+	[SMUX_RX_RETRY_HIGH_WM_HIT] = "RX_RETRY_HIGH_WM_HIT",
+	[SMUX_RX_RETRY_LOW_WM_HIT] = "RX_RETRY_LOW_WM_HIT",
+};
+
+static const char * const smux_local_state[] = {
+	[SMUX_LCH_LOCAL_CLOSED] = "CLOSED",
+	[SMUX_LCH_LOCAL_OPENING] = "OPENING",
+	[SMUX_LCH_LOCAL_OPENED] = "OPENED",
+	[SMUX_LCH_LOCAL_CLOSING] = "CLOSING",
+};
+
+static const char * const smux_remote_state[] = {
+	[SMUX_LCH_REMOTE_CLOSED] = "CLOSED",
+	[SMUX_LCH_REMOTE_OPENED] = "OPENED",
+};
+
+static const char * const smux_mode[] = {
+	[SMUX_LCH_MODE_NORMAL] = "N",
+	[SMUX_LCH_MODE_LOCAL_LOOPBACK] = "L",
+	[SMUX_LCH_MODE_REMOTE_LOOPBACK] = "R",
+};
+
+static const char * const smux_undef[] = {
+	[SMUX_UNDEF_LONG] = "UNDEF",
+	[SMUX_UNDEF_SHORT] = "U",
+};
+
+static void *log_ctx;
 static void smux_notify_local_fn(struct work_struct *work);
 static DECLARE_WORK(smux_notify_local, smux_notify_local_fn);
 
@@ -346,12 +345,11 @@
 static DECLARE_DELAYED_WORK(smux_delayed_inactivity_work,
 		smux_inactivity_worker);
 
-static long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch);
 static void list_channel(struct smux_lch_t *ch);
 static int smux_send_status_cmd(struct smux_lch_t *ch);
 static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt);
 static void smux_flush_tty(void);
-static void smux_purge_ch_tx_queue(struct smux_lch_t *ch);
+static void smux_purge_ch_tx_queue(struct smux_lch_t *ch, int is_ssr);
 static int schedule_notify(uint8_t lcid, int event,
 			const union notifier_metadata *metadata);
 static int ssr_notifier_cb(struct notifier_block *this,
@@ -363,6 +361,45 @@
 static void smux_pdev_release(struct device *dev);
 
 /**
+ * local_lch_state() - Return human readable form of local logical state.
+ * @state:  Local logical channel state enum.
+ *
+ */
+const char *local_lch_state(unsigned state)
+{
+	if (state < ARRAY_SIZE(smux_local_state))
+		return smux_local_state[state];
+	else
+		return smux_undef[SMUX_UNDEF_LONG];
+}
+
+/**
+ * remote_lch_state() - Return human readable for of remote logical state.
+ * @state:  Remote logical channel state enum.
+ *
+ */
+const char *remote_lch_state(unsigned state)
+{
+	if (state < ARRAY_SIZE(smux_remote_state))
+		return smux_remote_state[state];
+	else
+		return smux_undef[SMUX_UNDEF_LONG];
+}
+
+/**
+ * lch_mode() - Return human readable form of mode.
+ * @mode:  Mode of the logical channel.
+ *
+ */
+const char *lch_mode(unsigned mode)
+{
+	if (mode < ARRAY_SIZE(smux_mode))
+		return smux_mode[mode];
+	else
+		return smux_undef[SMUX_UNDEF_SHORT];
+}
+
+/**
  * Convert TTY Error Flags to string for logging purposes.
  *
  * @flag    TTY_* flag
@@ -389,14 +426,31 @@
 }
 
 /**
+ * Convert SMUX event to string for logging purposes.
+ *
+ * @event    SMUX event
+ * @returns String description or NULL if unknown
+ */
+static const char *event_to_str(unsigned cmd)
+{
+	if (cmd < ARRAY_SIZE(smux_events))
+		return smux_events[cmd];
+	return NULL;
+}
+
+/**
  * Set the reset state due to an unrecoverable failure.
  */
 static void smux_enter_reset(void)
 {
-	pr_err("%s: unrecoverable failure, waiting for ssr\n", __func__);
+	SMUX_ERR("%s: unrecoverable failure, waiting for ssr\n", __func__);
 	smux.in_reset = 1;
+	smux.remote_is_alive = 0;
 }
 
+/**
+ * Initialize the lch_structs.
+ */
 static int lch_init(void)
 {
 	unsigned int id;
@@ -410,7 +464,7 @@
 	smux_rx_wq = create_singlethread_workqueue("smux_rx_wq");
 
 	if (IS_ERR(smux_notify_wq) || IS_ERR(smux_tx_wq)) {
-		SMUX_DBG("%s: create_singlethread_workqueue ENOMEM\n",
+		SMUX_DBG("smux: %s: create_singlethread_workqueue ENOMEM\n",
 							__func__);
 		return -ENOMEM;
 	}
@@ -421,7 +475,7 @@
 	i |= smux_loopback_init();
 
 	if (i) {
-		pr_err("%s: out of memory error\n", __func__);
+		SMUX_ERR("%s: out of memory error\n", __func__);
 		return -ENOMEM;
 	}
 
@@ -471,7 +525,7 @@
 	/* Empty TX ready list */
 	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	while (!list_empty(&smux.lch_tx_ready_list)) {
-		SMUX_DBG("%s: emptying ready list %p\n",
+		SMUX_DBG("smux: %s: emptying ready list %p\n",
 				__func__, smux.lch_tx_ready_list.next);
 		ch = list_first_entry(&smux.lch_tx_ready_list,
 						struct smux_lch_t,
@@ -488,7 +542,7 @@
 						struct smux_pkt_t,
 						list);
 		list_del(&pkt->list);
-		SMUX_DBG("%s: emptying power queue pkt=%p\n",
+		SMUX_DBG("smux: %s: emptying power queue pkt=%p\n",
 				__func__, pkt);
 		smux_free_pkt(pkt);
 	}
@@ -497,13 +551,13 @@
 	/* Close all ports */
 	for (i = 0 ; i < SMUX_NUM_LOGICAL_CHANNELS; i++) {
 		ch = &smux_lch[i];
-		SMUX_DBG("%s: cleaning up lcid %d\n", __func__, i);
+		SMUX_DBG("smux: %s: cleaning up lcid %d\n", __func__, i);
 
 		spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 
 		/* Purge TX queue */
 		spin_lock(&ch->tx_lock_lhb2);
-		smux_purge_ch_tx_queue(ch);
+		smux_purge_ch_tx_queue(ch, 1);
 		spin_unlock(&ch->tx_lock_lhb2);
 
 		/* Notify user of disconnect and reset channel state */
@@ -670,7 +724,7 @@
 		i += snprintf(logbuf + i, SMUX_PKT_LOG_SIZE - i,
 				"%02x ", (unsigned)data[count]);
 
-	pr_info("%s\n", logbuf);
+	IPC_LOG_STR(logbuf);
 }
 
 static void smux_notify_local_fn(struct work_struct *work)
@@ -688,8 +742,9 @@
 				&notify_handle,
 				handle_size);
 		if (i != handle_size) {
-			pr_err("%s: unable to retrieve handle %d expected %d\n",
-					__func__, i, handle_size);
+			SMUX_ERR(
+				"%s: unable to retrieve handle %d expected %d\n",
+				__func__, i, handle_size);
 			spin_unlock_irqrestore(&notify_lock_lhc1, flags);
 			break;
 			}
@@ -735,7 +790,7 @@
 	/* Consider a free list implementation instead of kmalloc */
 	pkt = kmalloc(sizeof(struct smux_pkt_t), GFP_ATOMIC);
 	if (!pkt) {
-		pr_err("%s: out of memory\n", __func__);
+		SMUX_ERR("%s: out of memory\n", __func__);
 		return NULL;
 	}
 	smux_init_pkt(pkt);
@@ -779,7 +834,7 @@
 	pkt->payload = kmalloc(pkt->hdr.payload_len, GFP_ATOMIC);
 	pkt->free_payload = 1;
 	if (!pkt->payload) {
-		pr_err("%s: unable to malloc %d bytes for payload\n",
+		SMUX_ERR("%s: unable to malloc %d bytes for payload\n",
 				__func__, pkt->hdr.payload_len);
 		return -ENOMEM;
 	}
@@ -797,11 +852,12 @@
 	unsigned long flags;
 	int ret = 0;
 
+	IPC_LOG_STR("smux: %s ch:%d\n", event_to_str(event), lcid);
 	ch = &smux_lch[lcid];
 	notify_handle = kzalloc(sizeof(struct smux_notify_handle),
 						GFP_ATOMIC);
 	if (!notify_handle) {
-		pr_err("%s: out of memory\n", __func__);
+		SMUX_ERR("%s: out of memory\n", __func__);
 		ret = -ENOMEM;
 		goto free_out;
 	}
@@ -813,7 +869,7 @@
 		meta_copy = kzalloc(sizeof(union notifier_metadata),
 							GFP_ATOMIC);
 		if (!meta_copy) {
-			pr_err("%s: out of memory\n", __func__);
+			SMUX_ERR("%s: out of memory\n", __func__);
 			ret = -ENOMEM;
 			goto free_out;
 		}
@@ -826,7 +882,7 @@
 	spin_lock_irqsave(&notify_lock_lhc1, flags);
 	i = kfifo_avail(&smux_notify_fifo);
 	if (i < handle_size) {
-		pr_err("%s: fifo full error %d expected %d\n",
+		SMUX_ERR("%s: fifo full error %d expected %d\n",
 					__func__, i, handle_size);
 		ret = -ENOMEM;
 		goto unlock_out;
@@ -834,7 +890,7 @@
 
 	i = kfifo_in(&smux_notify_fifo, &notify_handle, handle_size);
 	if (i < 0 || i != handle_size) {
-		pr_err("%s: fifo not available error %d (expected %d)\n",
+		SMUX_ERR("%s: fifo not available error %d (expected %d)\n",
 				__func__, i, handle_size);
 		ret = -ENOSPC;
 		goto unlock_out;
@@ -886,7 +942,7 @@
 	char *data_start = out;
 
 	if (smux_serialize_size(pkt) > SMUX_MAX_PKT_SIZE) {
-		pr_err("%s: packet size %d too big\n",
+		SMUX_ERR("%s: packet size %d too big\n",
 				__func__, smux_serialize_size(pkt));
 		return -E2BIG;
 	}
@@ -971,7 +1027,7 @@
 			len -= data_written;
 			data += data_written;
 		} else {
-			pr_err("%s: TTY write returned error %d\n",
+			SMUX_ERR("%s: TTY write returned error %d\n",
 					__func__, data_written);
 			return data_written;
 		}
@@ -997,12 +1053,12 @@
 	int ret;
 
 	if (!smux.tty) {
-		pr_err("%s: TTY not initialized", __func__);
+		SMUX_ERR("%s: TTY not initialized", __func__);
 		return -ENOTTY;
 	}
 
 	if (pkt->hdr.cmd == SMUX_CMD_BYTE) {
-		SMUX_DBG("%s: tty send single byte\n", __func__);
+		SMUX_DBG("smux: %s: tty send single byte\n", __func__);
 		ret = write_to_tty(&pkt->hdr.flags, 1);
 		return ret;
 	}
@@ -1010,7 +1066,7 @@
 	smux_serialize_hdr(pkt, &data, &len);
 	ret = write_to_tty(data, len);
 	if (ret) {
-		pr_err("%s: failed %d to write header %d\n",
+		SMUX_ERR("%s: failed %d to write header %d\n",
 				__func__, ret, len);
 		return ret;
 	}
@@ -1018,7 +1074,7 @@
 	smux_serialize_payload(pkt, &data, &len);
 	ret = write_to_tty(data, len);
 	if (ret) {
-		pr_err("%s: failed %d to write payload %d\n",
+		SMUX_ERR("%s: failed %d to write payload %d\n",
 				__func__, ret, len);
 		return ret;
 	}
@@ -1028,7 +1084,7 @@
 		char zero = 0x0;
 		ret = write_to_tty(&zero, 1);
 		if (ret) {
-			pr_err("%s: failed %d to write padding %d\n",
+			SMUX_ERR("%s: failed %d to write padding %d\n",
 					__func__, ret, len);
 			return ret;
 		}
@@ -1048,7 +1104,7 @@
 
 	pkt = smux_alloc_pkt();
 	if (!pkt) {
-		pr_err("%s: alloc failure for byte %x\n", __func__, ch);
+		SMUX_ERR("%s: alloc failure for byte %x\n", __func__, ch);
 		return;
 	}
 	pkt->hdr.cmd = SMUX_CMD_BYTE;
@@ -1091,7 +1147,7 @@
 {
 	unsigned long flags;
 
-	SMUX_DBG("%s: queuing pkt %p\n", __func__, pkt_ptr);
+	SMUX_DBG("smux: %s: queuing pkt %p\n", __func__, pkt_ptr);
 
 	spin_lock_irqsave(&ch->tx_lock_lhb2, flags);
 	list_add_tail(&pkt_ptr->list, &ch->tx_queue);
@@ -1120,7 +1176,7 @@
 
 	spin_lock(&ch->state_lock_lhb1);
 	if (ch->local_state == SMUX_LCH_LOCAL_OPENING) {
-		SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+		SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
 				ch->local_state,
 				SMUX_LCH_LOCAL_OPENED);
 
@@ -1132,10 +1188,10 @@
 			schedule_notify(lcid, SMUX_CONNECTED, NULL);
 		ret = 0;
 	} else if (ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK) {
-		SMUX_DBG("Remote loopback OPEN ACK received\n");
+		SMUX_DBG("smux: Remote loopback OPEN ACK received\n");
 		ret = 0;
 	} else {
-		pr_err("%s: lcid %d state 0x%x open ack invalid\n",
+		SMUX_ERR("%s: lcid %d state 0x%x open ack invalid\n",
 				__func__, lcid, ch->local_state);
 		ret = -EINVAL;
 	}
@@ -1145,7 +1201,7 @@
 		spin_lock(&smux.tx_lock_lha2);
 		if (!smux.powerdown_enabled) {
 			smux.powerdown_enabled = 1;
-			SMUX_DBG("%s: enabling power-collapse support\n",
+			SMUX_DBG("smux: %s: enabling power-collapse support\n",
 					__func__);
 		}
 		spin_unlock(&smux.tx_lock_lha2);
@@ -1169,7 +1225,7 @@
 	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 
 	if (ch->local_state == SMUX_LCH_LOCAL_CLOSING) {
-		SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+		SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
 				SMUX_LCH_LOCAL_CLOSING,
 				SMUX_LCH_LOCAL_CLOSED);
 		ch->local_state = SMUX_LCH_LOCAL_CLOSED;
@@ -1178,10 +1234,10 @@
 				&meta_disconnected);
 		ret = 0;
 	} else if (ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK) {
-		SMUX_DBG("Remote loopback CLOSE ACK received\n");
+		SMUX_DBG("smux: Remote loopback CLOSE ACK received\n");
 		ret = 0;
 	} else {
-		pr_err("%s: lcid %d state 0x%x close ack invalid\n",
+		SMUX_ERR("%s: lcid %d state 0x%x close ack invalid\n",
 				__func__, lcid,	ch->local_state);
 		ret = -EINVAL;
 	}
@@ -1215,7 +1271,7 @@
 	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 
 	if (ch->remote_state == SMUX_LCH_REMOTE_CLOSED) {
-		SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
+		SMUX_DBG("smux: lcid %d remote state 0x%x -> 0x%x\n", lcid,
 				SMUX_LCH_REMOTE_CLOSED,
 				SMUX_LCH_REMOTE_OPENED);
 
@@ -1259,15 +1315,16 @@
 				smux_tx_queue(ack_pkt, ch, 0);
 				tx_ready = 1;
 			} else {
-				pr_err("%s: Remote loopack allocation failure\n",
-						__func__);
+				SMUX_ERR(
+					"%s: Remote loopack allocation failure\n",
+					__func__);
 			}
 		} else if (ch->local_state == SMUX_LCH_LOCAL_OPENED) {
 			schedule_notify(lcid, SMUX_CONNECTED, NULL);
 		}
 		ret = 0;
 	} else {
-		pr_err("%s: lcid %d remote state 0x%x open invalid\n",
+		SMUX_ERR("%s: lcid %d remote state 0x%x open invalid\n",
 			   __func__, lcid, ch->remote_state);
 		ret = -EINVAL;
 	}
@@ -1279,7 +1336,7 @@
 		spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 		if (!smux.powerdown_enabled) {
 			smux.powerdown_enabled = 1;
-			SMUX_DBG("%s: enabling power-collapse support\n",
+			SMUX_DBG("smux: %s: enabling power-collapse support\n",
 					__func__);
 		}
 		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -1317,7 +1374,7 @@
 
 	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 	if (ch->remote_state == SMUX_LCH_REMOTE_OPENED) {
-		SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
+		SMUX_DBG("smux: lcid %d remote state 0x%x -> 0x%x\n", lcid,
 				SMUX_LCH_REMOTE_OPENED,
 				SMUX_LCH_REMOTE_CLOSED);
 
@@ -1351,8 +1408,9 @@
 				smux_tx_queue(ack_pkt, ch, 0);
 				tx_ready = 1;
 			} else {
-				pr_err("%s: Remote loopack allocation failure\n",
-						__func__);
+				SMUX_ERR(
+					"%s: Remote loopack allocation failure\n",
+					__func__);
 			}
 		}
 
@@ -1361,7 +1419,7 @@
 				&meta_disconnected);
 		ret = 0;
 	} else {
-		pr_err("%s: lcid %d remote state 0x%x close invalid\n",
+		SMUX_ERR("%s: lcid %d remote state 0x%x close invalid\n",
 				__func__, lcid, ch->remote_state);
 		ret = -EINVAL;
 	}
@@ -1412,7 +1470,7 @@
 
 	if (ch->local_state != SMUX_LCH_LOCAL_OPENED
 		&& !remote_loopback) {
-		pr_err("smux: ch %d error data on local state 0x%x",
+		SMUX_ERR("smux: ch %d error data on local state 0x%x",
 					lcid, ch->local_state);
 		ret = -EIO;
 		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
@@ -1420,7 +1478,7 @@
 	}
 
 	if (ch->remote_state != SMUX_LCH_REMOTE_OPENED) {
-		pr_err("smux: ch %d error data on remote state 0x%x",
+		SMUX_ERR("smux: ch %d error data on remote state 0x%x",
 					lcid, ch->remote_state);
 		ret = -EIO;
 		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
@@ -1441,8 +1499,9 @@
 		}
 		if ((ch->rx_retry_queue_cnt + 1) > SMUX_RX_RETRY_MAX_PKTS) {
 			/* retry queue full */
-			pr_err("%s: ch %d RX retry queue full\n",
-					__func__, lcid);
+			SMUX_ERR(
+				"%s: ch %d RX retry queue full; rx flow=%d\n",
+				__func__, lcid, ch->rx_flow_control_auto);
 			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
 			ret = -ENOMEM;
 			spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
@@ -1468,7 +1527,7 @@
 			smux_tx_queue(ack_pkt, ch, 0);
 			tx_ready = 1;
 		} else {
-			pr_err("%s: Remote loopack allocation failure\n",
+			SMUX_ERR("%s: Remote loopack allocation failure\n",
 					__func__);
 		}
 	} else if (!do_retry) {
@@ -1492,7 +1551,7 @@
 			/* buffer allocation failed - add to retry queue */
 			do_retry = 1;
 		} else if (tmp < 0) {
-			pr_err("%s: ch %d Client RX buffer alloc failed %d\n",
+			SMUX_ERR("%s: ch %d Client RX buffer alloc failed %d\n",
 					__func__, lcid, tmp);
 			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
 			ret = -ENOMEM;
@@ -1504,7 +1563,7 @@
 
 		retry = kmalloc(sizeof(struct smux_rx_pkt_retry), GFP_KERNEL);
 		if (!retry) {
-			pr_err("%s: retry alloc failure\n", __func__);
+			SMUX_ERR("%s: retry alloc failure\n", __func__);
 			ret = -ENOMEM;
 			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
 			goto out;
@@ -1516,7 +1575,7 @@
 		retry->pkt = smux_alloc_pkt();
 		if (!retry->pkt) {
 			kfree(retry);
-			pr_err("%s: pkt alloc failure\n", __func__);
+			SMUX_ERR("%s: pkt alloc failure\n", __func__);
 			ret = -ENOMEM;
 			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
 			goto out;
@@ -1562,7 +1621,7 @@
 	unsigned long flags;
 
 	if (!pkt || smux_assert_lch_id(pkt->hdr.lcid)) {
-		pr_err("%s: invalid packet or channel id\n", __func__);
+		SMUX_ERR("%s: invalid packet or channel id\n", __func__);
 		return -ENXIO;
 	}
 
@@ -1571,14 +1630,14 @@
 	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 
 	if (ch->local_state != SMUX_LCH_LOCAL_OPENED) {
-		pr_err("smux: ch %d error data on local state 0x%x",
+		SMUX_ERR("smux: ch %d error data on local state 0x%x",
 					lcid, ch->local_state);
 		ret = -EIO;
 		goto out;
 	}
 
 	if (ch->remote_state != SMUX_LCH_REMOTE_OPENED) {
-		pr_err("smux: ch %d error data on remote state 0x%x",
+		SMUX_ERR("smux: ch %d error data on remote state 0x%x",
 					lcid, ch->remote_state);
 		ret = -EIO;
 		goto out;
@@ -1623,11 +1682,11 @@
 		/* logical channel flow control changed */
 		if (pkt->hdr.flags & SMUX_CMD_STATUS_FLOW_CNTL) {
 			/* disabled TX */
-			SMUX_DBG("TX Flow control enabled\n");
+			SMUX_DBG("smux: TX Flow control enabled\n");
 			ch->tx_flow_control = 1;
 		} else {
 			/* re-enable channel */
-			SMUX_DBG("TX Flow control disabled\n");
+			SMUX_DBG("smux: TX Flow control disabled\n");
 			ch->tx_flow_control = 0;
 			tx_ready = 1;
 		}
@@ -1671,7 +1730,7 @@
 			/* Power-down complete, turn off UART */
 			power_down = 1;
 		else
-			pr_err("%s: sleep request ack invalid in state %d\n",
+			SMUX_ERR("%s: sleep request ack invalid in state %d\n",
 					__func__, smux.power_state);
 	} else {
 		/*
@@ -1690,7 +1749,7 @@
 		if (smux.power_state == SMUX_PWR_ON) {
 			ack_pkt = smux_alloc_pkt();
 			if (ack_pkt) {
-				SMUX_PWR("%s: Power %d->%d\n", __func__,
+				SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
 						smux.power_state,
 						SMUX_PWR_TURNING_OFF_FLUSH);
 
@@ -1706,7 +1765,7 @@
 			}
 		} else if (smux.power_state == SMUX_PWR_TURNING_OFF_FLUSH) {
 			/* Local power-down request still in TX queue */
-			SMUX_PWR("%s: Power-down shortcut - no ack\n",
+			SMUX_PWR("smux: %s: Power-down shortcut - no ack\n",
 					__func__);
 			smux.power_ctl_remote_req_received = 1;
 		} else if (smux.power_state == SMUX_PWR_TURNING_OFF) {
@@ -1714,17 +1773,17 @@
 			 * Local power-down request already sent to remote
 			 * side, so this request gets treated as an ACK.
 			 */
-			SMUX_PWR("%s: Power-down shortcut - no ack\n",
+			SMUX_PWR("smux: %s: Power-down shortcut - no ack\n",
 					__func__);
 			power_down = 1;
 		} else {
-			pr_err("%s: sleep request invalid in state %d\n",
+			SMUX_ERR("%s: sleep request invalid in state %d\n",
 					__func__, smux.power_state);
 		}
 	}
 
 	if (power_down) {
-		SMUX_PWR("%s: Power %d->%d\n", __func__,
+		SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_OFF_FLUSH);
 		smux.power_state = SMUX_PWR_OFF_FLUSH;
 		queue_work(smux_tx_wq, &smux_inactivity_work);
@@ -1749,7 +1808,7 @@
 	case SMUX_CMD_OPEN_LCH:
 		SMUX_LOG_PKT_RX(pkt);
 		if (smux_assert_lch_id(pkt->hdr.lcid)) {
-			pr_err("%s: invalid channel id %d\n",
+			SMUX_ERR("%s: invalid channel id %d\n",
 					__func__, pkt->hdr.lcid);
 			break;
 		}
@@ -1759,7 +1818,7 @@
 	case SMUX_CMD_DATA:
 		SMUX_LOG_PKT_RX(pkt);
 		if (smux_assert_lch_id(pkt->hdr.lcid)) {
-			pr_err("%s: invalid channel id %d\n",
+			SMUX_ERR("%s: invalid channel id %d\n",
 					__func__, pkt->hdr.lcid);
 			break;
 		}
@@ -1769,7 +1828,7 @@
 	case SMUX_CMD_CLOSE_LCH:
 		SMUX_LOG_PKT_RX(pkt);
 		if (smux_assert_lch_id(pkt->hdr.lcid)) {
-			pr_err("%s: invalid channel id %d\n",
+			SMUX_ERR("%s: invalid channel id %d\n",
 					__func__, pkt->hdr.lcid);
 			break;
 		}
@@ -1779,7 +1838,7 @@
 	case SMUX_CMD_STATUS:
 		SMUX_LOG_PKT_RX(pkt);
 		if (smux_assert_lch_id(pkt->hdr.lcid)) {
-			pr_err("%s: invalid channel id %d\n",
+			SMUX_ERR("%s: invalid channel id %d\n",
 					__func__, pkt->hdr.lcid);
 			break;
 		}
@@ -1797,7 +1856,7 @@
 
 	default:
 		SMUX_LOG_PKT_RX(pkt);
-		pr_err("%s: command %d unknown\n", __func__, pkt->hdr.cmd);
+		SMUX_ERR("%s: command %d unknown\n", __func__, pkt->hdr.cmd);
 		ret = -EINVAL;
 	}
 	return ret;
@@ -1824,7 +1883,7 @@
 	memcpy(&recv.hdr, data, sizeof(struct smux_hdr_t));
 
 	if (recv.hdr.magic != SMUX_MAGIC) {
-		pr_err("%s: invalid header magic\n", __func__);
+		SMUX_ERR("%s: invalid header magic\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1845,7 +1904,7 @@
 	if (smux.power_state == SMUX_PWR_OFF
 		|| smux.power_state == SMUX_PWR_TURNING_ON) {
 		/* wakeup system */
-		SMUX_PWR("%s: Power %d->%d\n", __func__,
+		SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_ON);
 		smux.power_state = SMUX_PWR_ON;
 		queue_work(smux_tx_wq, &smux_wakeup_work);
@@ -1857,7 +1916,7 @@
 		smux_send_byte(SMUX_WAKEUP_ACK);
 	} else {
 		/* stale wakeup request from previous wakeup */
-		SMUX_PWR("%s: stale Wakeup REQ in state %d\n",
+		SMUX_PWR("smux: %s: stale Wakeup REQ in state %d\n",
 				__func__, smux.power_state);
 	}
 	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -1873,7 +1932,7 @@
 	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	if (smux.power_state == SMUX_PWR_TURNING_ON) {
 		/* received response to wakeup request */
-		SMUX_PWR("%s: Power %d->%d\n", __func__,
+		SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_ON);
 		smux.power_state = SMUX_PWR_ON;
 		queue_work(smux_tx_wq, &smux_tx_work);
@@ -1882,7 +1941,7 @@
 
 	} else if (smux.power_state != SMUX_PWR_ON) {
 		/* invalid message */
-		SMUX_PWR("%s: stale Wakeup REQ ACK in state %d\n",
+		SMUX_PWR("smux: %s: stale Wakeup REQ ACK in state %d\n",
 				__func__, smux.power_state);
 	}
 	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -1905,7 +1964,7 @@
 		if (smux_byte_loopback)
 			smux_receive_byte(SMUX_UT_ECHO_ACK_FAIL,
 					smux_byte_loopback);
-		pr_err("%s: TTY error 0x%x - ignoring\n", __func__, flag);
+		SMUX_ERR("%s: TTY error 0x%x - ignoring\n", __func__, flag);
 		++*used;
 		return;
 	}
@@ -1916,11 +1975,21 @@
 			smux.rx_state = SMUX_RX_MAGIC;
 			break;
 		case SMUX_WAKEUP_REQ:
-			SMUX_PWR("smux: RX Wakeup REQ\n");
+			SMUX_PWR("smux: smux: RX Wakeup REQ\n");
+			if (unlikely(!smux.remote_is_alive)) {
+				mutex_lock(&smux.mutex_lha0);
+				smux.remote_is_alive = 1;
+				mutex_unlock(&smux.mutex_lha0);
+			}
 			smux_handle_wakeup_req();
 			break;
 		case SMUX_WAKEUP_ACK:
-			SMUX_PWR("smux: RX Wakeup ACK\n");
+			SMUX_PWR("smux: smux: RX Wakeup ACK\n");
+			if (unlikely(!smux.remote_is_alive)) {
+				mutex_lock(&smux.mutex_lha0);
+				smux.remote_is_alive = 1;
+				mutex_unlock(&smux.mutex_lha0);
+			}
 			smux_handle_wakeup_ack();
 			break;
 		default:
@@ -1928,8 +1997,8 @@
 			if (smux_byte_loopback && data[i] == SMUX_UT_ECHO_REQ)
 				smux_receive_byte(SMUX_UT_ECHO_ACK_OK,
 						smux_byte_loopback);
-			pr_err("%s: parse error 0x%02x - ignoring\n", __func__,
-					(unsigned)data[i]);
+			SMUX_ERR("%s: parse error 0x%02x - ignoring\n",
+				__func__, (unsigned)data[i]);
 			break;
 		}
 	}
@@ -1951,7 +2020,7 @@
 	int i;
 
 	if (flag) {
-		pr_err("%s: TTY RX error %d\n", __func__, flag);
+		SMUX_ERR("%s: TTY RX error %d\n", __func__, flag);
 		smux_enter_reset();
 		smux.rx_state = SMUX_RX_FAILURE;
 		++*used;
@@ -1967,8 +2036,9 @@
 			smux.rx_state = SMUX_RX_HDR;
 		} else {
 			/* unexpected / trash character */
-			pr_err("%s: rx parse error for char %c; *used=%d, len=%d\n",
-					__func__, data[i], *used, len);
+			SMUX_ERR(
+				"%s: rx parse error for char %c; *used=%d, len=%d\n",
+				__func__, data[i], *used, len);
 			smux.rx_state = SMUX_RX_IDLE;
 		}
 	}
@@ -1991,7 +2061,7 @@
 	struct smux_hdr_t *hdr;
 
 	if (flag) {
-		pr_err("%s: TTY RX error %d\n", __func__, flag);
+		SMUX_ERR("%s: TTY RX error %d\n", __func__, flag);
 		smux_enter_reset();
 		smux.rx_state = SMUX_RX_FAILURE;
 		++*used;
@@ -2025,7 +2095,7 @@
 	int remaining;
 
 	if (flag) {
-		pr_err("%s: TTY RX error %d\n", __func__, flag);
+		SMUX_ERR("%s: TTY RX error %d\n", __func__, flag);
 		smux_enter_reset();
 		smux.rx_state = SMUX_RX_FAILURE;
 		++*used;
@@ -2073,6 +2143,24 @@
 }
 
 /**
+ * Returns true if the remote side has acknowledged a wakeup
+ * request previously, so we know that the link is alive and active.
+ *
+ * @returns true for is alive, false for not alive
+ */
+bool smux_remote_is_active(void)
+{
+	bool is_active = false;
+
+	mutex_lock(&smux.mutex_lha0);
+	if (smux.remote_is_alive)
+		is_active = true;
+	mutex_unlock(&smux.mutex_lha0);
+
+	return is_active;
+}
+
+/**
  * Add channel to transmit-ready list and trigger transmit worker.
  *
  * @ch Channel to add
@@ -2081,7 +2169,7 @@
 {
 	unsigned long flags;
 
-	SMUX_DBG("%s: listing channel %d\n",
+	SMUX_DBG("smux: %s: listing channel %d\n",
 			__func__, ch->lcid);
 
 	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
@@ -2120,11 +2208,11 @@
 			meta_write.write.buffer = pkt->payload;
 			meta_write.write.len = pkt->hdr.payload_len;
 			if (ret >= 0) {
-				SMUX_DBG("%s: PKT write done", __func__);
+				SMUX_DBG("smux: %s: PKT write done", __func__);
 				schedule_notify(ch->lcid, SMUX_WRITE_DONE,
 						&meta_write);
 			} else {
-				pr_err("%s: failed to write pkt %d\n",
+				SMUX_ERR("%s: failed to write pkt %d\n",
 						__func__, ret);
 				schedule_notify(ch->lcid, SMUX_WRITE_FAIL,
 						&meta_write);
@@ -2140,7 +2228,7 @@
 {
 	mutex_lock(&smux.mutex_lha0);
 	if (!smux.tty) {
-		pr_err("%s: ldisc not loaded\n", __func__);
+		SMUX_ERR("%s: ldisc not loaded\n", __func__);
 		mutex_unlock(&smux.mutex_lha0);
 		return;
 	}
@@ -2149,7 +2237,7 @@
 			msecs_to_jiffies(TTY_BUFFER_FULL_WAIT_MS));
 
 	if (tty_chars_in_buffer(smux.tty) > 0)
-		pr_err("%s: unable to flush UART queue\n", __func__);
+		SMUX_ERR("%s: unable to flush UART queue\n", __func__);
 
 	mutex_unlock(&smux.mutex_lha0);
 }
@@ -2158,25 +2246,35 @@
  * Purge TX queue for logical channel.
  *
  * @ch     Logical channel pointer
+ * @is_ssr 1 = this is a subsystem restart purge
  *
  * Must be called with the following spinlocks locked:
  *  state_lock_lhb1
  *  tx_lock_lhb2
  */
-static void smux_purge_ch_tx_queue(struct smux_lch_t *ch)
+static void smux_purge_ch_tx_queue(struct smux_lch_t *ch, int is_ssr)
 {
 	struct smux_pkt_t *pkt;
 	int send_disconnect = 0;
+	struct smux_pkt_t *pkt_tmp;
+	int is_state_pkt;
 
-	while (!list_empty(&ch->tx_queue)) {
-		pkt = list_first_entry(&ch->tx_queue, struct smux_pkt_t,
-							list);
-		list_del(&pkt->list);
-
+	list_for_each_entry_safe(pkt, pkt_tmp, &ch->tx_queue, list) {
+		is_state_pkt = 0;
 		if (pkt->hdr.cmd == SMUX_CMD_OPEN_LCH) {
-			/* Open was never sent, just force to closed state */
-			ch->local_state = SMUX_LCH_LOCAL_CLOSED;
-			send_disconnect = 1;
+			if (pkt->hdr.flags & SMUX_CMD_OPEN_ACK) {
+				/* Open ACK must still be sent */
+				is_state_pkt = 1;
+			} else {
+				/* Open never sent -- force to closed state */
+				ch->local_state = SMUX_LCH_LOCAL_CLOSED;
+				send_disconnect = 1;
+			}
+		} else if (pkt->hdr.cmd == SMUX_CMD_CLOSE_LCH) {
+			if (pkt->hdr.flags & SMUX_CMD_CLOSE_ACK)
+				is_state_pkt = 1;
+			if (!send_disconnect)
+				is_state_pkt = 1;
 		} else if (pkt->hdr.cmd == SMUX_CMD_DATA) {
 			/* Notify client of failed write */
 			union notifier_metadata meta_write;
@@ -2186,7 +2284,11 @@
 			meta_write.write.len = pkt->hdr.payload_len;
 			schedule_notify(ch->lcid, SMUX_WRITE_FAIL, &meta_write);
 		}
-		smux_free_pkt(pkt);
+
+		if (!is_state_pkt || is_ssr) {
+			list_del(&pkt->list);
+			smux_free_pkt(pkt);
+		}
 	}
 
 	if (send_disconnect) {
@@ -2208,7 +2310,7 @@
 	struct uart_state *state;
 
 	if (!smux.tty || !smux.tty->driver_data) {
-		pr_err("%s: unable to find UART port for tty %p\n",
+		SMUX_ERR("%s: unable to find UART port for tty %p\n",
 				__func__, smux.tty);
 		return;
 	}
@@ -2236,7 +2338,7 @@
 	struct uart_state *state;
 
 	if (!smux.tty || !smux.tty->driver_data) {
-		pr_err("%s: unable to find UART port for tty %p\n",
+		SMUX_ERR("%s: unable to find UART port for tty %p\n",
 				__func__, smux.tty);
 		mutex_unlock(&smux.mutex_lha0);
 		return;
@@ -2276,7 +2378,7 @@
 		/* wakeup complete */
 		smux.pwr_wakeup_delay_us = 1;
 		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
-		SMUX_DBG("%s: wakeup complete\n", __func__);
+		SMUX_DBG("smux: %s: wakeup complete\n", __func__);
 
 		/*
 		 * Cancel any pending retry.  This avoids a race condition with
@@ -2296,17 +2398,18 @@
 				SMUX_WAKEUP_DELAY_MAX;
 
 		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
-		SMUX_PWR("%s: triggering wakeup\n", __func__);
+		SMUX_PWR("smux: %s: triggering wakeup\n", __func__);
 		smux_send_byte(SMUX_WAKEUP_REQ);
 
 		if (wakeup_delay < SMUX_WAKEUP_DELAY_MIN) {
-			SMUX_DBG("%s: sleeping for %u us\n", __func__,
+			SMUX_DBG("smux: %s: sleeping for %u us\n", __func__,
 					wakeup_delay);
 			usleep_range(wakeup_delay, 2*wakeup_delay);
 			queue_work(smux_tx_wq, &smux_wakeup_work);
 		} else {
 			/* schedule delayed work */
-			SMUX_DBG("%s: scheduling delayed wakeup in %u ms\n",
+			SMUX_DBG(
+			"smux: %s: scheduling delayed wakeup in %u ms\n",
 					__func__, wakeup_delay / 1000);
 			queue_delayed_work(smux_tx_wq,
 					&smux_wakeup_delayed_work,
@@ -2316,7 +2419,7 @@
 		/* wakeup aborted */
 		smux.pwr_wakeup_delay_us = 1;
 		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
-		SMUX_PWR("%s: wakeup aborted\n", __func__);
+		SMUX_PWR("smux: %s: wakeup aborted\n", __func__);
 		cancel_delayed_work(&smux_wakeup_delayed_work);
 	}
 }
@@ -2346,7 +2449,8 @@
 				/* start power-down sequence */
 				pkt = smux_alloc_pkt();
 				if (pkt) {
-					SMUX_PWR("%s: Power %d->%d\n", __func__,
+					SMUX_PWR(
+					"smux: %s: Power %d->%d\n", __func__,
 						smux.power_state,
 						SMUX_PWR_TURNING_OFF_FLUSH);
 					smux.power_state =
@@ -2360,7 +2464,7 @@
 							&smux.power_queue);
 					queue_work(smux_tx_wq, &smux_tx_work);
 				} else {
-					pr_err("%s: packet alloc failed\n",
+					SMUX_ERR("%s: packet alloc failed\n",
 							__func__);
 				}
 			}
@@ -2371,7 +2475,7 @@
 
 	if (smux.power_state == SMUX_PWR_OFF_FLUSH) {
 		/* ready to power-down the UART */
-		SMUX_PWR("%s: Power %d->%d\n", __func__,
+		SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_OFF);
 		smux.power_state = SMUX_PWR_OFF;
 
@@ -2452,16 +2556,16 @@
 	smux.rx_activity_flag = 1;
 	spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
 
-	SMUX_DBG("%s: %p, len=%d, flag=%d\n", __func__, data, len, flag);
+	SMUX_DBG("smux: %s: %p, len=%d, flag=%d\n", __func__, data, len, flag);
 	used = 0;
 	do {
 		if (smux.in_reset) {
-			SMUX_DBG("%s: abort RX due to reset\n", __func__);
+			SMUX_DBG("smux: %s: abort RX due to reset\n", __func__);
 			smux.rx_state = SMUX_RX_IDLE;
 			break;
 		}
 
-		SMUX_DBG("%s: state %d; %d of %d\n",
+		SMUX_DBG("smux: %s: state %d; %d of %d\n",
 				__func__, smux.rx_state, used, len);
 		initial_rx_state = smux.rx_state;
 
@@ -2479,7 +2583,7 @@
 			smux_rx_handle_pkt_payload(data, len, &used, flag);
 			break;
 		default:
-			SMUX_DBG("%s: invalid state %d\n",
+			SMUX_DBG("smux: %s: invalid state %d\n",
 					__func__, smux.rx_state);
 			smux.rx_state = SMUX_RX_IDLE;
 			break;
@@ -2520,7 +2624,7 @@
 	}
 
 	if (list_empty(&ch->rx_retry_queue)) {
-		SMUX_DBG("%s: retry list empty for channel %d\n",
+		SMUX_DBG("smux: %s: retry list empty for channel %d\n",
 				__func__, ch->lcid);
 		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
 		return;
@@ -2530,7 +2634,7 @@
 					rx_retry_list);
 	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
 
-	SMUX_DBG("%s: ch %d retrying rx pkt %p\n",
+	SMUX_DBG("smux: %s: ch %d retrying rx pkt %p\n",
 			__func__, ch->lcid, retry);
 	metadata.read.pkt_priv = 0;
 	metadata.read.buffer = 0;
@@ -2559,7 +2663,7 @@
 		retry->timeout_in_ms <<= 1;
 		if (retry->timeout_in_ms > SMUX_RX_RETRY_MAX_MS) {
 			/* timed out */
-			pr_err("%s: ch %d RX retry client timeout\n",
+			SMUX_ERR("%s: ch %d RX retry client timeout\n",
 					__func__, ch->lcid);
 			spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 			tx_ready = smux_remove_rx_retry(ch, retry);
@@ -2570,7 +2674,7 @@
 		}
 	} else {
 		/* client error - drop packet */
-		pr_err("%s: ch %d RX retry client failed (%d)\n",
+		SMUX_ERR("%s: ch %d RX retry client failed (%d)\n",
 				__func__, ch->lcid, tmp);
 		spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 		tx_ready = smux_remove_rx_retry(ch, retry);
@@ -2635,7 +2739,7 @@
 			if (!list_empty(&smux.lch_tx_ready_list) ||
 			   !list_empty(&smux.power_queue)) {
 				/* data to transmit, do wakeup */
-				SMUX_PWR("%s: Power %d->%d\n", __func__,
+				SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
 						smux.power_state,
 						SMUX_PWR_TURNING_ON);
 				smux.power_state = SMUX_PWR_TURNING_ON;
@@ -2669,7 +2773,8 @@
 					 * and we already received a remote
 					 * power-down request.
 					 */
-					SMUX_PWR("%s: Power %d->%d\n", __func__,
+					SMUX_PWR(
+					"smux: %s: Power %d->%d\n", __func__,
 							smux.power_state,
 							SMUX_PWR_OFF_FLUSH);
 					smux.power_state = SMUX_PWR_OFF_FLUSH;
@@ -2678,7 +2783,8 @@
 							&smux_inactivity_work);
 				} else {
 					/* sending local power-down request */
-					SMUX_PWR("%s: Power %d->%d\n", __func__,
+					SMUX_PWR(
+					"smux: %s: Power %d->%d\n", __func__,
 							smux.power_state,
 							SMUX_PWR_TURNING_OFF);
 					smux.power_state = SMUX_PWR_TURNING_OFF;
@@ -2704,7 +2810,7 @@
 		/* get the next ready channel */
 		if (list_empty(&smux.lch_tx_ready_list)) {
 			/* no ready channels */
-			SMUX_DBG("%s: no more ready channels, exiting\n",
+			SMUX_DBG("smux: %s: no more ready channels, exiting\n",
 					__func__);
 			spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
 			break;
@@ -2713,7 +2819,7 @@
 
 		if (smux.power_state != SMUX_PWR_ON) {
 			/* channel not ready to transmit */
-			SMUX_DBG("%s: waiting for link up (state %d)\n",
+			SMUX_DBG("smux: %s: waiting for link up (state %d)\n",
 					__func__,
 					smux.power_state);
 			spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -2824,11 +2930,11 @@
 {
 	smux.in_reset = 1;
 
-	SMUX_DBG("%s: flushing tx wq\n", __func__);
+	SMUX_DBG("smux: %s: flushing tx wq\n", __func__);
 	flush_workqueue(smux_tx_wq);
-	SMUX_DBG("%s: flushing rx wq\n", __func__);
+	SMUX_DBG("smux: %s: flushing rx wq\n", __func__);
 	flush_workqueue(smux_rx_wq);
-	SMUX_DBG("%s: flushing notify wq\n", __func__);
+	SMUX_DBG("smux: %s: flushing notify wq\n", __func__);
 	flush_workqueue(smux_notify_wq);
 }
 
@@ -2886,13 +2992,13 @@
 
 	/* Auto RX Flow Control */
 	if (set & SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP) {
-		SMUX_DBG("%s: auto rx flow control option enabled\n",
+		SMUX_DBG("smux: %s: auto rx flow control option enabled\n",
 			__func__);
 		ch->options |= SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP;
 	}
 
 	if (clear & SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP) {
-		SMUX_DBG("%s: auto rx flow control option disabled\n",
+		SMUX_DBG("smux: %s: auto rx flow control option disabled\n",
 			__func__);
 		ch->options &= ~SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP;
 		ch->rx_flow_control_auto = 0;
@@ -2947,13 +3053,13 @@
 	}
 
 	if (ch->local_state != SMUX_LCH_LOCAL_CLOSED) {
-		pr_err("%s: open lcid %d local state %x invalid\n",
+		SMUX_ERR("%s: open lcid %d local state %x invalid\n",
 				__func__, lcid, ch->local_state);
 		ret = -EINVAL;
 		goto out;
 	}
 
-	SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+	SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
 			ch->local_state,
 			SMUX_LCH_LOCAL_OPENING);
 
@@ -3017,16 +3123,17 @@
 	ch->remote_tiocm = 0x0;
 	ch->tx_pending_data_cnt = 0;
 	ch->notify_lwm = 0;
+	ch->tx_flow_control = 0;
 
 	/* Purge TX queue */
 	spin_lock(&ch->tx_lock_lhb2);
-	smux_purge_ch_tx_queue(ch);
+	smux_purge_ch_tx_queue(ch, 0);
 	spin_unlock(&ch->tx_lock_lhb2);
 
 	/* Send Close Command */
 	if (ch->local_state == SMUX_LCH_LOCAL_OPENED ||
 		ch->local_state == SMUX_LCH_LOCAL_OPENING) {
-		SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+		SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
 				ch->local_state,
 				SMUX_LCH_LOCAL_CLOSING);
 
@@ -3041,7 +3148,7 @@
 			smux_tx_queue(pkt, ch, 0);
 			tx_ready = 1;
 		} else {
-			pr_err("%s: pkt allocation failed\n", __func__);
+			SMUX_ERR("%s: pkt allocation failed\n", __func__);
 			ret = -ENOMEM;
 		}
 
@@ -3091,14 +3198,14 @@
 
 	if (ch->local_state != SMUX_LCH_LOCAL_OPENED &&
 		ch->local_state != SMUX_LCH_LOCAL_OPENING) {
-		pr_err("%s: hdr.invalid local state %d channel %d\n",
+		SMUX_ERR("%s: hdr.invalid local state %d channel %d\n",
 					__func__, ch->local_state, lcid);
 		ret = -EINVAL;
 		goto out;
 	}
 
 	if (len > SMUX_MAX_PKT_SIZE - sizeof(struct smux_hdr_t)) {
-		pr_err("%s: payload %d too large\n",
+		SMUX_ERR("%s: payload %d too large\n",
 				__func__, len);
 		ret = -E2BIG;
 		goto out;
@@ -3120,10 +3227,10 @@
 
 	spin_lock(&ch->tx_lock_lhb2);
 	/* verify high watermark */
-	SMUX_DBG("%s: pending %d", __func__, ch->tx_pending_data_cnt);
+	SMUX_DBG("smux: %s: pending %d", __func__, ch->tx_pending_data_cnt);
 
 	if (ch->tx_pending_data_cnt >= SMUX_TX_WM_HIGH) {
-		pr_err("%s: ch %d high watermark %d exceeded %d\n",
+		SMUX_ERR("%s: ch %d high watermark %d exceeded %d\n",
 				__func__, lcid, SMUX_TX_WM_HIGH,
 				ch->tx_pending_data_cnt);
 		ret = -EAGAIN;
@@ -3133,7 +3240,7 @@
 	/* queue packet for transmit */
 	if (++ch->tx_pending_data_cnt == SMUX_TX_WM_HIGH) {
 		ch->notify_lwm = 1;
-		pr_err("%s: high watermark hit\n", __func__);
+		SMUX_ERR("%s: high watermark hit\n", __func__);
 		schedule_notify(lcid, SMUX_HIGH_WM_HIT, NULL);
 	}
 	list_add_tail(&pkt->list, &ch->tx_queue);
@@ -3251,7 +3358,7 @@
  *
  * @returns TIOCM status
  */
-static long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch)
+long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch)
 {
 	long status = 0x0;
 
@@ -3369,24 +3476,26 @@
 	int power_off_uart = 0;
 
 	if (code == SUBSYS_BEFORE_SHUTDOWN) {
-		SMUX_DBG("%s: ssr - before shutdown\n", __func__);
+		SMUX_DBG("smux: %s: ssr - before shutdown\n", __func__);
 		mutex_lock(&smux.mutex_lha0);
 		smux.in_reset = 1;
+		smux.remote_is_alive = 0;
 		mutex_unlock(&smux.mutex_lha0);
 		return NOTIFY_DONE;
 	} else if (code == SUBSYS_AFTER_POWERUP) {
 		/* re-register platform devices */
-		SMUX_DBG("%s: ssr - after power-up\n", __func__);
+		SMUX_DBG("smux: %s: ssr - after power-up\n", __func__);
 		mutex_lock(&smux.mutex_lha0);
 		if (smux.ld_open_count > 0
 				&& !smux.platform_devs_registered) {
 			for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
-				SMUX_DBG("%s: register pdev '%s'\n",
+				SMUX_DBG("smux: %s: register pdev '%s'\n",
 					__func__, smux_devs[i].name);
 				smux_devs[i].dev.release = smux_pdev_release;
 				tmp = platform_device_register(&smux_devs[i]);
 				if (tmp)
-					pr_err("%s: error %d registering device %s\n",
+					SMUX_ERR(
+						"%s: error %d registering device %s\n",
 					   __func__, tmp, smux_devs[i].name);
 			}
 			smux.platform_devs_registered = 1;
@@ -3396,7 +3505,7 @@
 	} else if (code != SUBSYS_AFTER_SHUTDOWN) {
 		return NOTIFY_DONE;
 	}
-	SMUX_DBG("%s: ssr - after shutdown\n", __func__);
+	SMUX_DBG("smux: %s: ssr - after shutdown\n", __func__);
 
 	/* Cleanup channels */
 	smux_flush_workqueues();
@@ -3409,7 +3518,7 @@
 		/* Unregister platform devices */
 		if (smux.platform_devs_registered) {
 			for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
-				SMUX_DBG("%s: unregister pdev '%s'\n",
+				SMUX_DBG("smux: %s: unregister pdev '%s'\n",
 						__func__, smux_devs[i].name);
 				platform_device_unregister(&smux_devs[i]);
 			}
@@ -3419,7 +3528,8 @@
 		/* Power-down UART */
 		spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 		if (smux.power_state != SMUX_PWR_OFF) {
-			SMUX_PWR("%s: SSR - turning off UART\n", __func__);
+			SMUX_PWR("smux: %s: SSR - turning off UART\n",
+							__func__);
 			smux.power_state = SMUX_PWR_OFF;
 			power_off_uart = 1;
 		}
@@ -3433,6 +3543,7 @@
 	smux.rx_activity_flag = 0;
 	smux.rx_state = SMUX_RX_IDLE;
 	smux.in_reset = 0;
+	smux.remote_is_alive = 0;
 	mutex_unlock(&smux.mutex_lha0);
 
 	return NOTIFY_DONE;
@@ -3446,7 +3557,8 @@
 	struct platform_device *pdev;
 
 	pdev = container_of(dev, struct platform_device, dev);
-	SMUX_DBG("%s: releasing pdev %p '%s'\n", __func__, pdev, pdev->name);
+	SMUX_DBG("smux: %s: releasing pdev %p '%s'\n",
+			__func__, pdev, pdev->name);
 	memset(&pdev->dev, 0x0, sizeof(pdev->dev));
 }
 
@@ -3461,14 +3573,14 @@
 
 	mutex_lock(&smux.mutex_lha0);
 	if (smux.ld_open_count) {
-		pr_err("%s: %p multiple instances not supported\n",
+		SMUX_ERR("%s: %p multiple instances not supported\n",
 			__func__, tty);
 		mutex_unlock(&smux.mutex_lha0);
 		return -EEXIST;
 	}
 
 	if (tty->ops->write == NULL) {
-		pr_err("%s: tty->ops->write already NULL\n", __func__);
+		SMUX_ERR("%s: tty->ops->write already NULL\n", __func__);
 		mutex_unlock(&smux.mutex_lha0);
 		return -EINVAL;
 	}
@@ -3484,7 +3596,7 @@
 	/* power-down the UART if we are idle */
 	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	if (smux.power_state == SMUX_PWR_OFF) {
-		SMUX_PWR("%s: powering off uart\n", __func__);
+		SMUX_PWR("smux: %s: powering off uart\n", __func__);
 		smux.power_state = SMUX_PWR_OFF_FLUSH;
 		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
 		queue_work(smux_tx_wq, &smux_inactivity_work);
@@ -3494,12 +3606,12 @@
 
 	/* register platform devices */
 	for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
-		SMUX_DBG("%s: register pdev '%s'\n",
+		SMUX_DBG("smux: %s: register pdev '%s'\n",
 				__func__, smux_devs[i].name);
 		smux_devs[i].dev.release = smux_pdev_release;
 		tmp = platform_device_register(&smux_devs[i]);
 		if (tmp)
-			pr_err("%s: error %d registering device %s\n",
+			SMUX_ERR("%s: error %d registering device %s\n",
 				   __func__, tmp, smux_devs[i].name);
 	}
 	smux.platform_devs_registered = 1;
@@ -3513,12 +3625,12 @@
 	int power_up_uart = 0;
 	int i;
 
-	SMUX_DBG("%s: ldisc unload\n", __func__);
+	SMUX_DBG("smux: %s: ldisc unload\n", __func__);
 	smux_flush_workqueues();
 
 	mutex_lock(&smux.mutex_lha0);
 	if (smux.ld_open_count <= 0) {
-		pr_err("%s: invalid ld count %d\n", __func__,
+		SMUX_ERR("%s: invalid ld count %d\n", __func__,
 			smux.ld_open_count);
 		mutex_unlock(&smux.mutex_lha0);
 		return;
@@ -3531,7 +3643,7 @@
 	/* Unregister platform devices */
 	if (smux.platform_devs_registered) {
 		for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
-			SMUX_DBG("%s: unregister pdev '%s'\n",
+			SMUX_DBG("smux: %s: unregister pdev '%s'\n",
 					__func__, smux_devs[i].name);
 			platform_device_unregister(&smux_devs[i]);
 		}
@@ -3555,8 +3667,9 @@
 
 	/* Disconnect from TTY */
 	smux.tty = NULL;
+	smux.remote_is_alive = 0;
 	mutex_unlock(&smux.mutex_lha0);
-	SMUX_DBG("%s: ldisc complete\n", __func__);
+	SMUX_DBG("smux: %s: ldisc complete\n", __func__);
 }
 
 /**
@@ -3575,16 +3688,12 @@
 	const char *tty_name = NULL;
 	char *f;
 
-	if (smux_debug_mask & MSM_SMUX_DEBUG)
-		print_hex_dump(KERN_INFO, "smux tty rx: ", DUMP_PREFIX_OFFSET,
-				     16, 1, cp, count, true);
-
 	/* verify error flags */
 	for (i = 0, f = fp; i < count; ++i, ++f) {
 		if (*f != TTY_NORMAL) {
 			if (tty)
 				tty_name = tty->name;
-			pr_err("%s: TTY %s Error %d (%s)\n", __func__,
+			SMUX_ERR("%s: TTY %s Error %d (%s)\n", __func__,
 				   tty_name, *f, tty_flag_to_str(*f));
 
 			/* feed all previous valid data to the parser */
@@ -3603,46 +3712,46 @@
 
 static void smuxld_flush_buffer(struct tty_struct *tty)
 {
-	pr_err("%s: not supported\n", __func__);
+	SMUX_ERR("%s: not supported\n", __func__);
 }
 
 static ssize_t	smuxld_chars_in_buffer(struct tty_struct *tty)
 {
-	pr_err("%s: not supported\n", __func__);
+	SMUX_ERR("%s: not supported\n", __func__);
 	return -ENODEV;
 }
 
 static ssize_t	smuxld_read(struct tty_struct *tty, struct file *file,
 		unsigned char __user *buf, size_t nr)
 {
-	pr_err("%s: not supported\n", __func__);
+	SMUX_ERR("%s: not supported\n", __func__);
 	return -ENODEV;
 }
 
 static ssize_t	smuxld_write(struct tty_struct *tty, struct file *file,
 		 const unsigned char *buf, size_t nr)
 {
-	pr_err("%s: not supported\n", __func__);
+	SMUX_ERR("%s: not supported\n", __func__);
 	return -ENODEV;
 }
 
 static int	smuxld_ioctl(struct tty_struct *tty, struct file *file,
 		 unsigned int cmd, unsigned long arg)
 {
-	pr_err("%s: not supported\n", __func__);
+	SMUX_ERR("%s: not supported\n", __func__);
 	return -ENODEV;
 }
 
 static unsigned int smuxld_poll(struct tty_struct *tty, struct file *file,
 			 struct poll_table_struct *tbl)
 {
-	pr_err("%s: not supported\n", __func__);
+	SMUX_ERR("%s: not supported\n", __func__);
 	return -ENODEV;
 }
 
 static void smuxld_write_wakeup(struct tty_struct *tty)
 {
-	pr_err("%s: not supported\n", __func__);
+	SMUX_ERR("%s: not supported\n", __func__);
 }
 
 static struct tty_ldisc_ops smux_ldisc_ops = {
@@ -3680,6 +3789,7 @@
 	smux.tty = NULL;
 	smux.ld_open_count = 0;
 	smux.in_reset = 0;
+	smux.remote_is_alive = 0;
 	smux.is_initialized = 1;
 	smux.platform_devs_registered = 0;
 	smux_byte_loopback = 0;
@@ -3689,7 +3799,7 @@
 
 	ret	= tty_register_ldisc(N_SMUX, &smux_ldisc_ops);
 	if (ret != 0) {
-		pr_err("%s: error %d registering line discipline\n",
+		SMUX_ERR("%s: error %d registering line discipline\n",
 				__func__, ret);
 		return ret;
 	}
@@ -3698,10 +3808,16 @@
 
 	ret = lch_init();
 	if (ret != 0) {
-		pr_err("%s: lch_init failed\n", __func__);
+		SMUX_ERR("%s: lch_init failed\n", __func__);
 		return ret;
 	}
 
+	log_ctx = ipc_log_context_create(1, "smux");
+	if (!log_ctx) {
+		SMUX_ERR("%s: unable to create log context\n", __func__);
+		disable_ipc_logging = 1;
+	}
+
 	return 0;
 }
 
@@ -3711,7 +3827,7 @@
 
 	ret	= tty_unregister_ldisc(N_SMUX);
 	if (ret != 0) {
-		pr_err("%s error %d unregistering line discipline\n",
+		SMUX_ERR("%s error %d unregistering line discipline\n",
 				__func__, ret);
 		return;
 	}
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index a5235ba..e6f5bf5 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -503,7 +503,7 @@
 
 	if (msm_port->uim) {
 		msm_write(port,
-			UART_SIM_CFG_STOP_BIT_LEN_N(1) |
+			UART_SIM_CFG_STOP_BIT_LEN_N(2) |
 			UART_SIM_CFG_SIM_CLK_ON |
 			UART_SIM_CFG_SIM_CLK_STOP_HIGH |
 			UART_SIM_CFG_MASK_RX |
diff --git a/drivers/tty/smux_debug.c b/drivers/tty/smux_debug.c
new file mode 100644
index 0000000..86377d6
--- /dev/null
+++ b/drivers/tty/smux_debug.c
@@ -0,0 +1,170 @@
+/* drivers/tty/smux_debug.c
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/termios.h>
+#include <linux/smux.h>
+#include "smux_private.h"
+
+#define DEBUG_BUFMAX 4096
+
+
+
+/**
+ * smux_dump_ch() - Dumps the information of a channel to the screen.
+ * @buf:  Buffer for status message.
+ * @max: Size of status queue.
+ * @lch_number:  Number of the logical channel.
+ * @lch:  Pointer to the lch_number'th instance of struct smux_lch_t.
+ *
+ */
+static int smux_dump_ch(char *buf, int max, struct smux_lch_t *lch)
+{
+	int bytes_written;
+	long tiocm_bits;
+	unsigned long flags;
+
+	spin_lock_irqsave(&lch->state_lock_lhb1, flags);
+	spin_lock(&lch->tx_lock_lhb2);
+
+	tiocm_bits = msm_smux_tiocm_get_atomic(lch);
+
+	bytes_written = scnprintf(
+		buf, max,
+		"ch%02d: "
+		"%s(%s) "
+		"%c%c%c%c%c  "
+		"%d  "
+		"%s(%s) "
+		"%c%c\n",
+		lch->lcid,
+		local_lch_state(lch->local_state), lch_mode(lch->local_mode),
+		(tiocm_bits & TIOCM_DSR) ? 'D' : 'd',
+		(tiocm_bits & TIOCM_CTS) ? 'T' : 't',
+		(tiocm_bits & TIOCM_RI) ? 'I' : 'i',
+		(tiocm_bits & TIOCM_CD) ? 'C' : 'c',
+		lch->tx_flow_control ? 'F' : 'f',
+		lch->tx_pending_data_cnt,
+		remote_lch_state(lch->remote_state), lch_mode(lch->remote_mode),
+		(tiocm_bits & TIOCM_DTR) ? 'R' : 'r',
+		(tiocm_bits & TIOCM_RTS) ? 'S' : 's'
+		);
+
+	spin_unlock(&lch->tx_lock_lhb2);
+	spin_unlock_irqrestore(&lch->state_lock_lhb1, flags);
+
+	return bytes_written;
+}
+
+/**
+ * smux_dump_format_ch() - Informs user of format for channel dump
+ * @buf:  Buffer for status message.
+ * @max:  Size of status queue.
+ *
+ */
+static int smux_dump_format_ch(char *buf, int max)
+{
+	return scnprintf(
+		buf, max,
+		"ch_id "
+		"local state(mode) tiocm  "
+		"tx_queue  "
+		"remote state(mode) tiocm\n"
+		"local tiocm: DSR(D) CTS(T) RI(I) DCD(C) FLOW_CONTROL(F)\n"
+		"remote tiocm: DTR(R) RTS(S)\n"
+		"A capital letter indicates set, otherwise, it is not set.\n\n"
+		);
+}
+
+/**
+ * smux_debug_ch() - Log following information about each channel
+ * local open, local mode, remote open, remote mode,
+ * tiocm bits, flow control state and transmit queue size.
+ * Returns the number of bytes written to buf.
+ * @buf Buffer for status message
+ * @max Size of status queue
+ *
+ */
+static int smux_debug_ch(char *buf, int max)
+{
+	int ch_id;
+
+	int bytes_written = smux_dump_format_ch(buf, max);
+
+	for (ch_id = 0; ch_id < SMUX_NUM_LOGICAL_CHANNELS; ch_id++) {
+		bytes_written += smux_dump_ch(buf + bytes_written,
+					max - bytes_written,
+					&smux_lch[ch_id]);
+	}
+
+	return bytes_written;
+
+}
+
+static char debug_buffer[DEBUG_BUFMAX];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	int (*fill)(char *buf, int max) = file->private_data;
+	int bsize;
+
+	if (*ppos != 0)
+		return 0;
+
+	bsize = fill(debug_buffer, DEBUG_BUFMAX);
+	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations debug_ops = {
+	.read = debug_read,
+	.open = debug_open,
+};
+
+
+static void debug_create(const char *name, mode_t mode,
+			struct dentry *dent,
+			int (*fill)(char *buf, int max))
+{
+	debugfs_create_file(name, mode, dent, fill, &debug_ops);
+}
+
+
+static int __init smux_debugfs_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("n_smux", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debug_create("ch", 0444, dent, smux_debug_ch);
+
+
+	return 0;
+}
+
+late_initcall(smux_debugfs_init);
diff --git a/drivers/tty/smux_private.h b/drivers/tty/smux_private.h
index 353c762..195ee0f 100644
--- a/drivers/tty/smux_private.h
+++ b/drivers/tty/smux_private.h
@@ -31,14 +31,70 @@
 #define SMUX_UT_ECHO_ACK_FAIL 0xF2
 
 /* Maximum number of packets in retry queue */
-#define SMUX_RX_RETRY_MAX_PKTS 32
-#define SMUX_RX_WM_HIGH        16
-#define SMUX_RX_WM_LOW          4
-#define SMUX_TX_WM_LOW          2
-#define SMUX_TX_WM_HIGH         4
+#define SMUX_RX_RETRY_MAX_PKTS 128
+#define SMUX_RX_WM_HIGH          4
+#define SMUX_RX_WM_LOW           0
+#define SMUX_TX_WM_LOW           2
+#define SMUX_TX_WM_HIGH          4
 
 struct tty_struct;
 
+/**
+ * Logical Channel Structure.  One instance per channel.
+ *
+ * Locking Hierarchy
+ * Each lock has a postfix that describes the locking level.  If multiple locks
+ * are required, only increasing lock hierarchy numbers may be locked which
+ * ensures avoiding a deadlock.
+ *
+ * Locking Example
+ * If state_lock_lhb1 is currently held and the TX list needs to be
+ * manipulated, then tx_lock_lhb2 may be locked since it's locking hierarchy
+ * is greater.  However, if tx_lock_lhb2 is held, then state_lock_lhb1 may
+ * not be acquired since it would result in a deadlock.
+ *
+ * Note that the Line Discipline locks (*_lha) should always be acquired
+ * before the logical channel locks.
+ */
+struct smux_lch_t {
+	/* channel state */
+	spinlock_t state_lock_lhb1;
+	uint8_t lcid;
+	unsigned local_state;
+	unsigned local_mode;
+	uint8_t local_tiocm;
+	unsigned options;
+
+	unsigned remote_state;
+	unsigned remote_mode;
+	uint8_t remote_tiocm;
+
+	int tx_flow_control;
+	int rx_flow_control_auto;
+	int rx_flow_control_client;
+
+	/* client callbacks and private data */
+	void *priv;
+	void (*notify)(void *priv, int event_type, const void *metadata);
+	int (*get_rx_buffer)(void *priv, void **pkt_priv, void **buffer,
+								int size);
+
+	/* RX Info */
+	struct list_head rx_retry_queue;
+	unsigned rx_retry_queue_cnt;
+	struct delayed_work rx_retry_work;
+
+	/* TX Info */
+	spinlock_t tx_lock_lhb2;
+	struct list_head tx_queue;
+	struct list_head tx_ready_list;
+	unsigned tx_pending_data_cnt;
+	unsigned notify_lwm;
+};
+
+/* Each instance of smux_lch_t */
+extern struct smux_lch_t smux_lch[SMUX_NUM_LOGICAL_CHANNELS];
+
 /* Packet header. */
 struct smux_hdr_t {
 	uint16_t magic;
@@ -102,6 +158,16 @@
 	SMUX_LCH_REMOTE_OPENED,
 };
 
+/* Enum used to report various undefined actions */
+enum {
+	SMUX_UNDEF_LONG,
+	SMUX_UNDEF_SHORT,
+};
+
+long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch);
+const char *local_lch_state(unsigned state);
+const char *remote_lch_state(unsigned state);
+const char *lch_mode(unsigned mode);
 
 int smux_assert_lch_id(uint32_t lcid);
 void smux_init_pkt(struct smux_pkt_t *pkt);
@@ -114,6 +180,7 @@
 void smux_rx_state_machine(const unsigned char *data, int len, int flag);
 void smuxld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 			   char *fp, int count);
+bool smux_remote_is_active(void);
 
 /* testing parameters */
 extern int smux_byte_loopback;
diff --git a/drivers/tty/smux_test.c b/drivers/tty/smux_test.c
index 4c255a4..81ac04b 100644
--- a/drivers/tty/smux_test.c
+++ b/drivers/tty/smux_test.c
@@ -690,6 +690,7 @@
 	};
 	int i = 0;
 	int failed = 0;
+	int retry_count = 0;
 	int ret;
 
 	i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
@@ -701,7 +702,13 @@
 
 		i += smux_ut_basic_core(buf + i, max - i, test_data, __func__);
 		subsystem_restart("external_modem");
-		msleep(5000);
+
+		do {
+			msleep(500);
+			++retry_count;
+			UT_ASSERT_INT(retry_count, <, 20);
+		} while (!smux_remote_is_active() && !failed);
+
 		i += smux_ut_basic_core(buf + i, max - i, test_data, __func__);
 		break;
 	}
@@ -721,6 +728,7 @@
 	static struct smux_mock_callback cb_data;
 	static int cb_initialized;
 	int ret;
+	int retry_count;
 	int i = 0;
 	int failed = 0;
 
@@ -763,6 +771,14 @@
 		/* close port */
 		ret = msm_smux_close(SMUX_TEST_LCID);
 		UT_ASSERT_INT(ret, ==, 0);
+
+		/* wait for remote side to finish booting */
+		retry_count = 0;
+		do {
+			msleep(500);
+			++retry_count;
+			UT_ASSERT_INT(retry_count, <, 20);
+		} while (!smux_remote_is_active() && !failed);
 		break;
 	}
 
@@ -795,6 +811,7 @@
 	static int cb_initialized;
 	int i = 0;
 	int failed = 0;
+	int retry_count;
 	int ret;
 
 	i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
@@ -841,12 +858,16 @@
 		subsystem_restart("external_modem");
 
 		/* verify SSR completed */
-		UT_ASSERT_INT(ret, ==, 0);
-		UT_ASSERT_INT(
-			(int)wait_for_completion_timeout(
-				&cb_data.cb_completion, 5*HZ),
-			>, 0);
-		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		retry_count = 0;
+		while (cb_data.event_disconnected_ssr == 0) {
+			(void)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ);
+			INIT_COMPLETION(cb_data.cb_completion);
+			++retry_count;
+			UT_ASSERT_INT(retry_count, <, 10);
+		}
+		if (failed)
+			break;
 		UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
 		UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 1);
 		mock_cb_data_reset(&cb_data);
@@ -854,6 +875,14 @@
 		/* close port */
 		ret = msm_smux_close(SMUX_TEST_LCID);
 		UT_ASSERT_INT(ret, ==, 0);
+
+		/* wait for remote side to finish booting */
+		retry_count = 0;
+		do {
+			msleep(500);
+			++retry_count;
+			UT_ASSERT_INT(retry_count, <, 20);
+		} while (!smux_remote_is_active() && !failed);
 		break;
 	}
 
@@ -1924,6 +1953,136 @@
 	return i;
 }
 
+/**
+ * Verify remote flow control (remote TX stop).
+ *
+ * @buf  Buffer for status message
+ * @max  Size of buffer
+ *
+ * @returns Number of bytes written to @buf
+ */
+static int smux_ut_remote_tx_stop(char *buf, int max)
+{
+	static struct smux_mock_callback cb_data;
+	static int cb_initialized;
+	int i = 0;
+	int failed = 0;
+	int ret;
+
+	i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
+	pr_err("%s", buf);
+
+	if (!cb_initialized)
+		mock_cb_data_init(&cb_data);
+
+	mock_cb_data_reset(&cb_data);
+	while (!failed) {
+		/* open port for remote loopback */
+		ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+				SMUX_CH_OPTION_REMOTE_LOOPBACK, 0);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		ret = msm_smux_open(SMUX_TEST_LCID, &cb_data, smux_mock_cb,
+								get_rx_buffer);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ), >, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_connected, ==, 1);
+		mock_cb_data_reset(&cb_data);
+
+		/* send 1 packet and verify response */
+		ret = msm_smux_write(SMUX_TEST_LCID, (void *)1,
+					test_array, sizeof(test_array));
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ),
+			>, 0);
+		UT_ASSERT_INT(cb_data.event_write_done, ==, 1);
+
+		INIT_COMPLETION(cb_data.cb_completion);
+		if (!cb_data.event_read_done) {
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ),
+				>, 0);
+		}
+		UT_ASSERT_INT(cb_data.event_read_done, ==, 1);
+		mock_cb_data_reset(&cb_data);
+
+		/* enable flow control */
+		UT_ASSERT_INT(smux_lch[SMUX_TEST_LCID].tx_flow_control, ==, 0);
+		ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+				SMUX_CH_OPTION_REMOTE_TX_STOP, 0);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		/* wait for remote echo and clear our tx_flow control */
+		msleep(500);
+		UT_ASSERT_INT(smux_lch[SMUX_TEST_LCID].tx_flow_control, ==, 1);
+		smux_lch[SMUX_TEST_LCID].tx_flow_control = 0;
+
+		/* Send 1 packet and verify no response */
+		ret = msm_smux_write(SMUX_TEST_LCID, (void *)2,
+					test_array, sizeof(test_array));
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ),
+				>, 0);
+		INIT_COMPLETION(cb_data.cb_completion);
+		UT_ASSERT_INT(cb_data.event_write_done, ==, 1);
+		UT_ASSERT_INT(cb_data.event_read_done, ==, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, 1*HZ),
+			==, 0);
+		UT_ASSERT_INT(cb_data.event_read_done, ==, 0);
+		mock_cb_data_reset(&cb_data);
+
+		/* disable flow control and verify response is received */
+		UT_ASSERT_INT(cb_data.event_read_done, ==, 0);
+		ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+				0, SMUX_CH_OPTION_REMOTE_TX_STOP);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ),
+			>, 0);
+		UT_ASSERT_INT(cb_data.event_read_done, ==, 1);
+		mock_cb_data_reset(&cb_data);
+
+		/* close port */
+		ret = msm_smux_close(SMUX_TEST_LCID);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ),
+			>, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+		break;
+	}
+
+	if (!failed) {
+		i += scnprintf(buf + i, max - i, "\tOK\n");
+	} else {
+		pr_err("%s: Failed\n", __func__);
+		i += scnprintf(buf + i, max - i, "\tFailed\n");
+		i += mock_cb_data_print(&cb_data, buf + i, max - i);
+		msm_smux_set_ch_option(SMUX_TEST_LCID,
+			0, SMUX_CH_OPTION_REMOTE_TX_STOP);
+		msm_smux_close(SMUX_TEST_LCID);
+	}
+	mock_cb_data_reset(&cb_data);
+	return i;
+}
+
 static char debug_buffer[DEBUG_BUFMAX];
 
 static ssize_t debug_read(struct file *file, char __user *buf,
@@ -1961,7 +2120,7 @@
 {
 	struct dentry *dent;
 
-	dent = debugfs_create_dir("n_smux", 0);
+	dent = debugfs_create_dir("n_smux_test", 0);
 	if (IS_ERR(dent))
 		return PTR_ERR(dent);
 
@@ -1995,6 +2154,8 @@
 			smux_ut_remote_ssr_open);
 	debug_create("ut_remote_ssr_rx_buff_retry", 0444, dent,
 			smux_ut_remote_ssr_rx_buff_retry);
+	debug_create("ut_remote_tx_stop", 0444, dent,
+			smux_ut_remote_tx_stop);
 
 	return 0;
 }
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 54ea85d..f517340 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -559,13 +559,6 @@
 			goto err1;
 		}
 
-		ret = dwc3_host_init(dwc);
-		if (ret) {
-			dev_err(dev, "failed to initialize host\n");
-			dwc3_otg_exit(dwc);
-			goto err1;
-		}
-
 		ret = dwc3_gadget_init(dwc);
 		if (ret) {
 			dev_err(dev, "failed to initialize gadget\n");
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 522e3a4..6917b2d 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -124,7 +124,11 @@
 	u8 ep_num_mapping[DBM_MAX_EPS];
 	const struct usb_ep_ops *original_ep_ops[DWC3_ENDPOINTS_NUM];
 	struct list_head req_complete_list;
+	struct clk		*ref_clk;
 	struct clk		*core_clk;
+	struct clk		*iface_clk;
+	struct clk		*sleep_clk;
+	struct clk		*hsphy_sleep_clk;
 	struct regulator	*hsusb_3p3;
 	struct regulator	*hsusb_1p8;
 	struct regulator	*hsusb_vddcx;
@@ -1227,7 +1231,9 @@
 		return 0;
 	}
 
+	clk_disable_unprepare(mdwc->iface_clk);
 	clk_disable_unprepare(mdwc->core_clk);
+	clk_disable_unprepare(mdwc->ref_clk);
 	dwc3_hsusb_ldo_enable(0);
 	dwc3_ssusb_ldo_enable(0);
 	wake_unlock(&mdwc->wlock);
@@ -1248,7 +1254,9 @@
 	}
 
 	wake_lock(&mdwc->wlock);
+	clk_prepare_enable(mdwc->ref_clk);
 	clk_prepare_enable(mdwc->core_clk);
+	clk_prepare_enable(mdwc->iface_clk);
 	dwc3_hsusb_ldo_enable(1);
 	dwc3_ssusb_ldo_enable(1);
 
@@ -1378,6 +1386,7 @@
 	struct platform_device *dwc3;
 	struct dwc3_msm *msm;
 	struct resource *res;
+	void __iomem *tcsr;
 	int ret = 0;
 
 	msm = devm_kzalloc(&pdev->dev, sizeof(*msm), GFP_KERNEL);
@@ -1406,6 +1415,38 @@
 	clk_set_rate(msm->core_clk, 125000000);
 	clk_prepare_enable(msm->core_clk);
 
+	msm->iface_clk = devm_clk_get(&pdev->dev, "iface_clk");
+	if (IS_ERR(msm->iface_clk)) {
+		dev_err(&pdev->dev, "failed to get iface_clk\n");
+		ret = PTR_ERR(msm->iface_clk);
+		goto disable_core_clk;
+	}
+	clk_prepare_enable(msm->iface_clk);
+
+	msm->sleep_clk = devm_clk_get(&pdev->dev, "sleep_clk");
+	if (IS_ERR(msm->sleep_clk)) {
+		dev_err(&pdev->dev, "failed to get sleep_clk\n");
+		ret = PTR_ERR(msm->sleep_clk);
+		goto disable_iface_clk;
+	}
+	clk_prepare_enable(msm->sleep_clk);
+
+	msm->hsphy_sleep_clk = devm_clk_get(&pdev->dev, "sleep_a_clk");
+	if (IS_ERR(msm->hsphy_sleep_clk)) {
+		dev_err(&pdev->dev, "failed to get sleep_a_clk\n");
+		ret = PTR_ERR(msm->hsphy_sleep_clk);
+		goto disable_sleep_clk;
+	}
+	clk_prepare_enable(msm->hsphy_sleep_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;
+	}
+	clk_prepare_enable(msm->ref_clk);
+
 	/* SS PHY */
 	msm->ss_vdd_type = VDDCX_CORNER;
 	msm->ssusb_vddcx = devm_regulator_get(&pdev->dev, "ssusb_vdd_dig");
@@ -1415,7 +1456,7 @@
 		if (IS_ERR(msm->ssusb_vddcx)) {
 			dev_err(&pdev->dev, "unable to get ssusb vddcx\n");
 			ret = PTR_ERR(msm->ssusb_vddcx);
-			goto disable_core_clk;
+			goto disable_ref_clk;
 		}
 		msm->ss_vdd_type = VDDCX;
 		dev_dbg(&pdev->dev, "ss_vdd_type: VDDCX\n");
@@ -1424,7 +1465,7 @@
 	ret = dwc3_ssusb_config_vddcx(1);
 	if (ret) {
 		dev_err(&pdev->dev, "ssusb vddcx configuration failed\n");
-		goto disable_core_clk;
+		goto disable_ref_clk;
 	}
 
 	ret = regulator_enable(context->ssusb_vddcx);
@@ -1484,6 +1525,25 @@
 		goto free_hs_ldo_init;
 	}
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_dbg(&pdev->dev, "missing TCSR memory resource\n");
+	} else {
+		tcsr = devm_ioremap_nocache(&pdev->dev, res->start,
+			resource_size(res));
+		if (!tcsr) {
+			dev_dbg(&pdev->dev, "tcsr ioremap failed\n");
+		} else {
+			/* Enable USB3 on the primary USB port. */
+			writel_relaxed(0x1, tcsr);
+			/*
+			 * Ensure that TCSR write is completed before
+			 * USB registers initialization.
+			 */
+			mb();
+		}
+	}
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "missing memory base resource\n");
@@ -1514,7 +1574,6 @@
 	msm->dwc3 = dwc3;
 
 	pm_runtime_set_active(msm->dev);
-	pm_runtime_enable(msm->dev);
 
 	if (of_property_read_u32(node, "qcom,dwc-usb3-msm-dbm-eps",
 				 &msm->dbm_num_eps)) {
@@ -1600,6 +1659,14 @@
 	regulator_disable(context->ssusb_vddcx);
 unconfig_ss_vddcx:
 	dwc3_ssusb_config_vddcx(0);
+disable_ref_clk:
+	clk_disable_unprepare(msm->ref_clk);
+disable_sleep_a_clk:
+	clk_disable_unprepare(msm->hsphy_sleep_clk);
+disable_sleep_clk:
+	clk_disable_unprepare(msm->sleep_clk);
+disable_iface_clk:
+	clk_disable_unprepare(msm->iface_clk);
 disable_core_clk:
 	clk_disable_unprepare(msm->core_clk);
 
@@ -1629,6 +1696,10 @@
 	regulator_disable(msm->ssusb_vddcx);
 	dwc3_ssusb_config_vddcx(0);
 	clk_disable_unprepare(msm->core_clk);
+	clk_disable_unprepare(msm->iface_clk);
+	clk_disable_unprepare(msm->sleep_clk);
+	clk_disable_unprepare(msm->hsphy_sleep_clk);
+	clk_disable_unprepare(msm->ref_clk);
 
 	return 0;
 }
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 7b34e60..23f6ea3 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1334,7 +1334,7 @@
 		config->fsg.nluns = 2;
 		config->fsg.luns[1].cdrom = 1;
 		config->fsg.luns[1].ro = 1;
-		config->fsg.luns[1].removable = 1;
+		config->fsg.luns[1].removable = 0;
 		name[1] = "lun0";
 	}
 
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 1ea3982..0514aa8 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2921,7 +2921,7 @@
 			rc = fsg_lun_open(curlun, lcfg->filename);
 			if (rc)
 				goto error_luns;
-		} else if (!curlun->removable) {
+		} else if (!curlun->removable && !curlun->cdrom) {
 			ERROR(common, "no file given for LUN%d\n", i);
 			rc = -EINVAL;
 			goto error_luns;
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index c16ff97..40b79a2 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -348,7 +348,6 @@
 			driver->unbind(udc->gadget);
 			goto err1;
 		}
-		usb_gadget_connect(udc->gadget);
 	} else {
 
 		ret = usb_gadget_start(udc->gadget, driver, bind);
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index b396593..2126ff0 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -27,6 +27,7 @@
 #include <linux/err.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <linux/wakelock.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 
@@ -58,13 +59,14 @@
 	struct clk		*phy_clk;
 	struct clk		*cal_clk;
 	struct regulator	*hsic_vddcx;
+	bool			async_int;
 	atomic_t                in_lpm;
+	struct wake_lock	wlock;
 	int			peripheral_status_irq;
 	int			wakeup_irq;
 	int			wakeup_gpio;
 	bool			wakeup_irq_enabled;
-	bool			irq_enabled;
-	bool			async_int;
+	atomic_t		pm_usage_cnt;
 	uint32_t		bus_perf_client;
 	uint32_t		wakeup_int_cnt;
 	enum usb_vdd_type	vdd_type;
@@ -624,15 +626,13 @@
 
 	disable_irq(hcd->irq);
 
-	/* make sure we don't race against the root hub being resumed */
-	if (HCD_RH_RUNNING(hcd) || HCD_WAKEUP_PENDING(hcd) ||
+	/* make sure we don't race against a remote wakeup */
+	if (test_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags) ||
 	    readl_relaxed(USB_PORTSC) & PORT_RESUME) {
-		dev_warn(mehci->dev, "%s: Root hub is not suspended\n",
-				__func__);
+		dev_dbg(mehci->dev, "wakeup pending, aborting suspend\n");
 		enable_irq(hcd->irq);
 		return -EBUSY;
 	}
-	mehci->irq_enabled = false;
 
 	/*
 	 * PHY may take some time or even fail to enter into low power
@@ -690,13 +690,14 @@
 	}
 
 	atomic_set(&mehci->in_lpm, 1);
-	mehci->irq_enabled = true;
 	enable_irq(hcd->irq);
 
 	mehci->wakeup_irq_enabled = 1;
 	enable_irq_wake(mehci->wakeup_irq);
 	enable_irq(mehci->wakeup_irq);
 
+	wake_unlock(&mehci->wlock);
+
 	dev_info(mehci->dev, "HSIC-USB in low power mode\n");
 
 	return 0;
@@ -720,6 +721,8 @@
 		mehci->wakeup_irq_enabled = 0;
 	}
 
+	wake_lock(&mehci->wlock);
+
 	if (mehci->bus_perf_client && debug_bus_voting_enabled) {
 		mehci->bus_vote = true;
 		queue_work(ehci_wq, &mehci->bus_vote_w);
@@ -775,14 +778,13 @@
 	if (mehci->async_int) {
 		mehci->async_int = false;
 		pm_runtime_put_noidle(mehci->dev);
-	}
-
-	if (!mehci->irq_enabled) {
 		enable_irq(hcd->irq);
-		mehci->irq_enabled = true;
 	}
 
-	pm_relax(mehci->dev);
+	if (atomic_read(&mehci->pm_usage_cnt)) {
+		atomic_set(&mehci->pm_usage_cnt, 0);
+		pm_runtime_put_noidle(mehci->dev);
+	}
 
 	dev_info(mehci->dev, "HSIC-USB exited from low power mode\n");
 
@@ -809,11 +811,9 @@
 
 	if (atomic_read(&mehci->in_lpm)) {
 		disable_irq_nosync(hcd->irq);
-		mehci->irq_enabled = false;
 		dev_dbg(mehci->dev, "phy async intr\n");
 		mehci->async_int = true;
 		pm_runtime_get(mehci->dev);
-		pm_stay_awake(mehci->dev);
 		return IRQ_HANDLED;
 	}
 
@@ -1030,9 +1030,7 @@
 	dev_dbg(mehci->dev, "%s: hsic remote wakeup interrupt cnt: %u\n",
 			__func__, mehci->wakeup_int_cnt);
 
-	mehci->async_int = true;
-	pm_runtime_get(mehci->dev);
-	pm_stay_awake(mehci->dev);
+	wake_lock(&mehci->wlock);
 
 	if (mehci->wakeup_irq_enabled) {
 		mehci->wakeup_irq_enabled = 0;
@@ -1040,6 +1038,11 @@
 		disable_irq_nosync(irq);
 	}
 
+	if (!atomic_read(&mehci->pm_usage_cnt)) {
+		atomic_set(&mehci->pm_usage_cnt, 1);
+		pm_runtime_get(mehci->dev);
+	}
+
 	return IRQ_HANDLED;
 }
 
@@ -1345,8 +1348,9 @@
 		goto unconfig_gpio;
 	}
 
-	mehci->irq_enabled = true;
 	device_init_wakeup(&pdev->dev, 1);
+	wake_lock_init(&mehci->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
+	wake_lock(&mehci->wlock);
 
 	if (mehci->peripheral_status_irq) {
 		ret = request_threaded_irq(mehci->peripheral_status_irq,
@@ -1460,6 +1464,7 @@
 	msm_hsic_init_vddcx(mehci, 0);
 
 	msm_hsic_init_clocks(mehci, 0);
+	wake_lock_destroy(&mehci->wlock);
 	iounmap(hcd->regs);
 	usb_put_hcd(hcd);
 
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 0ef8249..f5bad19 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -760,6 +760,14 @@
 		test_bit(A_BUS_SUSPEND, &motg->inputs) &&
 		motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
 	dcp = motg->chg_type == USB_DCP_CHARGER;
+
+	/* charging detection in progress due to cable plug-in */
+	if (test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
+		!dcp) {
+		enable_irq(motg->irq);
+		return -EBUSY;
+	}
+
 	/*
 	 * Chipidea 45-nm PHY suspend sequence:
 	 *
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 6d14ec1..2272cc1 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -548,7 +548,7 @@
 	}
 
 	/*mask off non LUT select bits*/
-	out = inpdw(MDP_BASE + 0x90070) & ~((0x1 << 10) | 0x7);
+	out = inpdw(MDP_BASE + 0x90070);
 	MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x7 | out);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	mdp_lut_i = (mdp_lut_i + 1)%2;
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 293bd9b..26f5efd 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -44,6 +44,7 @@
 extern int mdp_rev;
 extern int mdp_iommu_split_domain;
 extern struct mdp_csc_cfg mdp_csc_convert[4];
+extern struct mdp_csc_cfg_data csc_cfg_matrix[];
 extern struct workqueue_struct *mdp_hist_wq;
 
 extern uint32 mdp_intr_mask;
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 13a922f..bcbb253 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -193,6 +193,8 @@
 	MDP4_CHROMA_420
 };
 
+#define CSC_MAX_BLOCKS 6
+
 #define MDP4_BLEND_BG_TRANSP_EN		BIT(9)
 #define MDP4_BLEND_FG_TRANSP_EN		BIT(8)
 #define MDP4_BLEND_BG_MOD_ALPHA		BIT(7)
@@ -456,9 +458,6 @@
 void mdp4_clear_lcdc(void);
 void mdp4_mixer_blend_init(int mixer_num);
 void mdp4_vg_qseed_init(int vg_num);
-void mdp4_vg_csc_setup(int vp_num);
-void mdp4_mixer_csc_setup(uint32 mixer);
-void mdp4_dmap_csc_setup(void);
 void mdp4_vg_csc_update(struct mdp_csc *p);
 irqreturn_t mdp4_isr(int irq, void *ptr);
 void mdp4_overlay_format_to_pipe(uint32 format, struct mdp4_overlay_pipe *pipe);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 31e62b2..9d9f250 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -794,7 +794,8 @@
 	uint32 frame_size, src_size, src_xy, dst_size, dst_xy;
 	uint32 format, pattern, luma_offset, chroma_offset;
 	uint32 mask;
-	int pnum, ptype;
+	int pnum, ptype, i;
+	uint32_t block;
 
 	pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; /* start from 0 */
 	vg_base = MDP_BASE + MDP4_VIDEO_BASE;
@@ -822,6 +823,20 @@
 
 			mdp4_csc_write(&pipe->pp_cfg.csc_cfg,
 				(uint32_t) (vg_base + MDP4_VIDEO_CSC_OFF));
+
+			if (pipe->pipe_num == OVERLAY_PIPE_VG1)
+				block = MDP_BLOCK_VG_1;
+			else
+				block = MDP_BLOCK_VG_2;
+
+			for (i = 0; i < CSC_MAX_BLOCKS; i++) {
+				if (block == csc_cfg_matrix[i].block) {
+					memcpy(&csc_cfg_matrix[i].csc_data,
+					&(pipe->pp_cfg.csc_cfg),
+					sizeof(struct mdp_csc_cfg));
+					break;
+				}
+			}
 		}
 		if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_QSEED_CFG) {
 			mdp4_qseed_access_cfg(&pipe->pp_cfg.qseed_cfg[0],
@@ -3222,9 +3237,7 @@
 		return 0;
 	}
 
-	if (pipe->mixer_num == MDP4_MIXER2 ||
-					ctrl->panel_mode & MDP4_PANEL_MDDI)
-		mutex_lock(&mfd->dma->ov_mutex);
+	mutex_lock(&mfd->dma->ov_mutex);
 
 	img = &req->data;
 	get_img(img, info, pipe, 0, &start, &len, &srcp0_file,
@@ -3354,6 +3367,7 @@
 			mdp4_dtv_pipe_queue(0, pipe);/* cndx = 0 */
 	}
 
+	mutex_unlock(&mfd->dma->ov_mutex);
 	return ret;
 
 mddi:
@@ -3385,8 +3399,10 @@
 	if (!(pipe->flags & MDP_OV_PLAY_NOWAIT))
 		mdp4_iommu_unmap(pipe);
 	mdp4_stat.overlay_play[pipe->mixer_num]++;
-	mutex_unlock(&mfd->dma->ov_mutex);
+
 end:
+	mutex_unlock(&mfd->dma->ov_mutex);
+
 #ifdef CONFIG_ANDROID_PMEM
 	if (srcp0_file)
 		put_pmem_file(srcp0_file);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index ca73a70..34ae716 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -35,6 +35,148 @@
 
 struct mdp4_statistic mdp4_stat;
 
+struct mdp_csc_cfg_data csc_cfg_matrix[CSC_MAX_BLOCKS] = {
+	{
+	.block = MDP_BLOCK_VG_1,
+	.csc_data = {
+			(MDP_CSC_FLAG_YUV_OUT),
+			{
+				0x0254, 0x0000, 0x0331,
+				0x0254, 0xff37, 0xfe60,
+				0x0254, 0x0409, 0x0000,
+			},
+			{
+				0xfff0, 0xff80, 0xff80,
+			},
+			{
+				0, 0, 0,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+		},
+	},
+	{
+	.block = MDP_BLOCK_VG_2,
+	.csc_data = {
+			(MDP_CSC_FLAG_YUV_OUT),
+			{
+				0x0254, 0x0000, 0x0331,
+				0x0254, 0xff37, 0xfe60,
+				0x0254, 0x0409, 0x0000,
+			},
+			{
+				0xfff0, 0xff80, 0xff80,
+			},
+			{
+				0, 0, 0,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+		},
+	},
+	{
+	.block = MDP_BLOCK_DMA_P,
+	.csc_data = {
+			(0),
+			{
+				0x0200, 0x0000, 0x0000,
+				0x0000, 0x0200, 0x0000,
+				0x0000, 0x0000, 0x0200,
+			},
+			{
+				0x0, 0x0, 0x0,
+			},
+			{
+				0, 0, 0,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+		},
+	},
+	{
+	.block = MDP_BLOCK_OVERLAY_1,
+	.csc_data = {
+			(0),
+			{
+				0x0200, 0x0000, 0x0000,
+				0x0000, 0x0200, 0x0000,
+				0x0000, 0x0000, 0x0200,
+			},
+			{
+				0x0, 0x0, 0x0,
+			},
+			{
+				0, 0, 0,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+		},
+	},
+	{
+	.block = MDP_BLOCK_OVERLAY_2,
+	.csc_data = {
+			(0),
+			{
+				0x0200, 0x0000, 0x0000,
+				0x0000, 0x0200, 0x0000,
+				0x0000, 0x0000, 0x0200,
+			},
+			{
+				0x0, 0x0, 0x0,
+			},
+			{
+				0, 0, 0,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+		},
+	},
+	{
+	.block = MDP_BLOCK_DMA_S,
+	.csc_data = {
+			(0),
+			{
+				0x0200, 0x0000, 0x0000,
+				0x0000, 0x0200, 0x0000,
+				0x0000, 0x0000, 0x0200,
+			},
+			{
+				0x0, 0x0, 0x0,
+			},
+			{
+				0, 0, 0,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+		},
+	},
+};
+
+
 unsigned is_mdp4_hw_reset(void)
 {
 	unsigned hw_reset = 0;
@@ -245,7 +387,7 @@
 {
 	ulong bits;
 	uint32 clk_rate;
-
+	int i;
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
@@ -273,11 +415,8 @@
 	mdp4_vg_qseed_init(0);
 	mdp4_vg_qseed_init(1);
 
-	mdp4_vg_csc_setup(0);
-	mdp4_vg_csc_setup(1);
-	mdp4_mixer_csc_setup(1);
-	mdp4_mixer_csc_setup(2);
-	mdp4_dmap_csc_setup();
+	for (i = 0; i < CSC_MAX_BLOCKS; i++)
+		mdp4_csc_config(&csc_cfg_matrix[i]);
 
 	if (mdp_rev <= MDP_REV_41) {
 		mdp4_mixer_gc_lut_setup(0);
@@ -1258,422 +1397,46 @@
 	},
 };
 
-struct mdp_csc_cfg csc_matrix[3] = {
-	{
-		(MDP_CSC_FLAG_YUV_OUT),
-		{
-			0x0254, 0x0000, 0x0331,
-			0x0254, 0xff37, 0xfe60,
-			0x0254, 0x0409, 0x0000,
-		},
-		{
-			0xfff0, 0xff80, 0xff80,
-		},
-		{
-			0, 0, 0,
-		},
-		{
-			0, 0xff, 0, 0xff, 0, 0xff,
-		},
-		{
-			0, 0xff, 0, 0xff, 0, 0xff,
-		},
-	},
-	{
-		(MDP_CSC_FLAG_YUV_OUT),
-		{
-			0x0254, 0x0000, 0x0331,
-			0x0254, 0xff37, 0xfe60,
-			0x0254, 0x0409, 0x0000,
-		},
-		{
-			0xfff0, 0xff80, 0xff80,
-		},
-		{
-			0, 0, 0,
-		},
-		{
-			0, 0xff, 0, 0xff, 0, 0xff,
-		},
-		{
-			0, 0xff, 0, 0xff, 0, 0xff,
-		},
-	},
-	{
-		(0),
-		{
-			0x0200, 0x0000, 0x0000,
-			0x0000, 0x0200, 0x0000,
-			0x0000, 0x0000, 0x0200,
-		},
-		{
-			0x0, 0x0, 0x0,
-		},
-		{
-			0, 0, 0,
-		},
-		{
-			0, 0xff, 0, 0xff, 0, 0xff,
-		},
-		{
-			0, 0xff, 0, 0xff, 0, 0xff,
-		},
-	},
-};
 
-
-
-#define MDP4_CSC_MV_OFF 	0x4400
-#define MDP4_CSC_PRE_BV_OFF 	0x4500
-#define MDP4_CSC_POST_BV_OFF 	0x4580
-#define MDP4_CSC_PRE_LV_OFF 	0x4600
-#define MDP4_CSC_POST_LV_OFF 	0x4680
-
-void mdp4_vg_csc_mv_setup(int vp_num)
-{
-	uint32 *off;
-	int i, voff;
-
-	voff = MDP4_VIDEO_OFF * vp_num;
-	off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
-					MDP4_CSC_MV_OFF);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 9; i++) {
-		outpdw(off, csc_matrix[vp_num].csc_mv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_vg_csc_pre_bv_setup(int vp_num)
-{
-	uint32 *off;
-	int i, voff;
-
-	voff = MDP4_VIDEO_OFF * vp_num;
-	off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
-					MDP4_CSC_PRE_BV_OFF);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 3; i++) {
-		outpdw(off, csc_matrix[vp_num].csc_pre_bv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_vg_csc_post_bv_setup(int vp_num)
-{
-	uint32 *off;
-	int i, voff;
-
-	voff = MDP4_VIDEO_OFF * vp_num;
-	off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
-					MDP4_CSC_POST_BV_OFF);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 3; i++) {
-		outpdw(off, csc_matrix[vp_num].csc_post_bv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_vg_csc_pre_lv_setup(int vp_num)
-{
-	uint32 *off;
-	int i, voff;
-
-	voff = MDP4_VIDEO_OFF * vp_num;
-	off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
-					MDP4_CSC_PRE_LV_OFF);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 6; i++) {
-		outpdw(off, csc_matrix[vp_num].csc_pre_lv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_vg_csc_post_lv_setup(int vp_num)
-{
-	uint32 *off;
-	int i, voff;
-
-	voff = MDP4_VIDEO_OFF * vp_num;
-	off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
-					MDP4_CSC_POST_LV_OFF);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 6; i++) {
-		outpdw(off, csc_matrix[vp_num].csc_post_lv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_vg_csc_convert_setup(int vp_num)
-{
-	struct mdp_csc_cfg_data cfg;
-
-	switch (vp_num) {
-	case 0:
-		cfg.block = MDP_BLOCK_VG_1;
-		break;
-	case 1:
-		cfg.block = MDP_BLOCK_VG_2;
-		break;
-	default:
-		pr_err("%s - invalid vp_num = %d", __func__, vp_num);
-		return;
-	}
-	cfg.csc_data = csc_matrix[vp_num];
-	mdp4_csc_enable(&cfg);
-}
-
-void mdp4_vg_csc_setup(int vp_num)
-{
-		/* yuv2rgb */
-		mdp4_vg_csc_mv_setup(vp_num);
-		mdp4_vg_csc_pre_bv_setup(vp_num);
-		mdp4_vg_csc_post_bv_setup(vp_num);
-		mdp4_vg_csc_pre_lv_setup(vp_num);
-		mdp4_vg_csc_post_lv_setup(vp_num);
-		mdp4_vg_csc_convert_setup(vp_num);
-}
 void mdp4_vg_csc_update(struct mdp_csc *p)
 {
 	struct mdp4_overlay_pipe *pipe;
-	int vp_num;
+	uint32_t block = 0;
+	int i = 0;
 
 	pipe = mdp4_overlay_ndx2pipe(p->id);
 	if (pipe == NULL) {
 		pr_err("%s: p->id = %d Error\n", __func__, p->id);
 		return;
 	}
-
-	vp_num = pipe->pipe_num - OVERLAY_PIPE_VG1;
-
-	if (vp_num == 0 || vp_num == 1) {
-		memcpy(csc_matrix[vp_num].csc_mv, p->csc_mv, sizeof(p->csc_mv));
-		memcpy(csc_matrix[vp_num].csc_pre_bv, p->csc_pre_bv,
-			sizeof(p->csc_pre_bv));
-		memcpy(csc_matrix[vp_num].csc_post_bv, p->csc_post_bv,
-			sizeof(p->csc_post_bv));
-		memcpy(csc_matrix[vp_num].csc_pre_lv, p->csc_pre_lv,
-			sizeof(p->csc_pre_lv));
-		memcpy(csc_matrix[vp_num].csc_post_lv, p->csc_post_lv,
-			sizeof(p->csc_post_lv));
-		mdp4_vg_csc_setup(vp_num);
-	}
-}
-static uint32 csc_rgb2yuv_matrix_tab[9] = {
-	0x0083, 0x0102, 0x0032,
-	0x1fb5, 0x1f6c, 0x00e1,
-	0x00e1, 0x1f45, 0x1fdc
-};
-
-static uint32 csc_rgb2yuv_pre_bv_tab[3] = {0, 0, 0};
-
-static uint32 csc_rgb2yuv_post_bv_tab[3] = {0x0010, 0x0080, 0x0080};
-
-static  uint32 csc_rgb2yuv_pre_lv_tab[6] = {
-	0x00, 0xff, 0x00,
-	0xff, 0x00, 0xff
-};
-
-static  uint32 csc_rgb2yuv_post_lv_tab[6] = {
-	0x0010, 0x00eb, 0x0010,
-	0x00f0, 0x0010, 0x00f0
-};
-
-void mdp4_mixer_csc_mv_setup(uint32 mixer)
-{
-	uint32 *off;
-	int i;
-
-	if (mixer == MDP4_MIXER1)
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2400);
+	if (pipe->pipe_num == OVERLAY_PIPE_VG1)
+		block = MDP_BLOCK_VG_1;
+	else if (pipe->pipe_num == OVERLAY_PIPE_VG2)
+		block = MDP_BLOCK_VG_2;
 	else
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2400);
+		return;
 
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 9; i++) {
-		outpdw(off, csc_rgb2yuv_matrix_tab[i]);
-		off++;
+	for (i = 0; i < CSC_MAX_BLOCKS; i++) {
+		if (csc_cfg_matrix[i].block == block)
+			break;
 	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
+	if (i == CSC_MAX_BLOCKS)
+		return;
 
-void mdp4_mixer_csc_pre_bv_setup(uint32 mixer)
-{
-	uint32 *off;
-	int i;
+	memcpy(&csc_cfg_matrix[i].csc_data.csc_mv, p->csc_mv,
+			sizeof(p->csc_mv));
+	memcpy(&csc_cfg_matrix[i].csc_data.csc_pre_bv, p->csc_pre_bv,
+		sizeof(p->csc_pre_bv));
+	memcpy(&csc_cfg_matrix[i].csc_data.csc_post_bv, p->csc_post_bv,
+		sizeof(p->csc_post_bv));
+	memcpy(&csc_cfg_matrix[i].csc_data.csc_pre_lv, p->csc_pre_lv,
+		sizeof(p->csc_pre_lv));
+	memcpy(&csc_cfg_matrix[i].csc_data.csc_post_lv, p->csc_post_lv,
+		sizeof(p->csc_post_lv));
+	csc_cfg_matrix[i].csc_data.flags = MDP_CSC_FLAG_YUV_OUT;
 
-	if (mixer == MDP4_MIXER1)
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2500);
-	else
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2500);
+	mdp4_csc_config(&csc_cfg_matrix[i]);
 
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 3; i++) {
-		outpdw(off, csc_rgb2yuv_pre_bv_tab[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_mixer_csc_post_bv_setup(uint32 mixer)
-{
-	uint32 *off;
-	int i;
-
-	if (mixer == MDP4_MIXER1)
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2580);
-	else
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2580);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 3; i++) {
-		outpdw(off, csc_rgb2yuv_post_bv_tab[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_mixer_csc_pre_lv_setup(uint32 mixer)
-{
-	uint32 *off;
-	int i;
-
-	if (mixer == MDP4_MIXER1)
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2600);
-	else
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2600);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 6; i++) {
-		outpdw(off, csc_rgb2yuv_pre_lv_tab[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_mixer_csc_post_lv_setup(uint32 mixer)
-{
-	uint32 *off;
-	int i;
-
-	if (mixer == MDP4_MIXER1)
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2680);
-	else
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2680);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 6; i++) {
-		outpdw(off, csc_rgb2yuv_post_lv_tab[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_mixer_csc_setup(uint32 mixer)
-{
-	if (mixer >= MDP4_MIXER1) {
-		/* rgb2yuv */
-		mdp4_mixer_csc_mv_setup(mixer);
-		mdp4_mixer_csc_pre_bv_setup(mixer);
-		mdp4_mixer_csc_post_bv_setup(mixer);
-		mdp4_mixer_csc_pre_lv_setup(mixer);
-		mdp4_mixer_csc_post_lv_setup(mixer);
-	}
-}
-
-#define DMA_P_BASE 0x90000
-void mdp4_dmap_csc_mv_setup(void)
-{
-	uint32 *off;
-	int i;
-
-	off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3400);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 9; i++) {
-		outpdw(off, csc_matrix[2].csc_mv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_dmap_csc_pre_bv_setup(void)
-{
-	uint32 *off;
-	int i;
-
-	off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3500);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 3; i++) {
-		outpdw(off, csc_matrix[2].csc_pre_bv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_dmap_csc_post_bv_setup(void)
-{
-	uint32 *off;
-	int i;
-
-	off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3580);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 3; i++) {
-		outpdw(off, csc_matrix[2].csc_post_bv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_dmap_csc_pre_lv_setup(void)
-{
-	uint32 *off;
-	int i;
-
-	off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3600);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 6; i++) {
-		outpdw(off, csc_matrix[2].csc_pre_lv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_dmap_csc_post_lv_setup(void)
-{
-	uint32 *off;
-	int i;
-
-	off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3680);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 6; i++) {
-		outpdw(off, csc_matrix[2].csc_post_lv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_dmap_csc_setup(void)
-{
-	mdp4_dmap_csc_mv_setup();
-	mdp4_dmap_csc_pre_bv_setup();
-	mdp4_dmap_csc_post_bv_setup();
-	mdp4_dmap_csc_pre_lv_setup();
-	mdp4_dmap_csc_post_lv_setup();
 }
 
 char gc_lut[] = {
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 1a1bb07..1f83b2b 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -186,7 +186,7 @@
 	/*
 	 * alloc framebuffer info + par data
 	 */
-	fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), &pdev->dev);
+	fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL);
 	if (fbi == NULL) {
 		pr_err("can't allocate framebuffer info data!\n");
 		return -ENOMEM;
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 17281d5..a282c3a 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -107,6 +107,9 @@
 	MDSS_MDP_MAX_CSC
 };
 
+struct mdss_mdp_ctl;
+typedef void (*mdp_vsync_handler_t)(struct mdss_mdp_ctl *, ktime_t);
+
 struct mdss_mdp_ctl {
 	u32 num;
 	u32 ref_cnt;
@@ -138,6 +141,7 @@
 	int (*stop_fnc) (struct mdss_mdp_ctl *ctl);
 	int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
 	int (*display_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
+	int (*set_vsync_handler) (struct mdss_mdp_ctl *, mdp_vsync_handler_t);
 
 	void *priv_data;
 };
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index d29ecd6..21f4071 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -533,6 +533,11 @@
 		mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_PACK_3D, 0);
 	}
 
+	/* request bus bandwidth for panel commands */
+	ctl->clk_rate = MDP_CLK_DEFAULT_RATE;
+	ctl->bus_ib_quota = SZ_1M;
+	mdss_mdp_ctl_perf_commit(MDSS_MDP_PERF_UPDATE_ALL);
+
 	ret = pdata->on(pdata);
 
 start_fail:
diff --git a/drivers/video/msm/mdss/mdss_mdp_formats.h b/drivers/video/msm/mdss/mdss_mdp_formats.h
index d8ae531..ee3b8e6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_formats.h
+++ b/drivers/video/msm/mdss/mdss_mdp_formats.h
@@ -131,6 +131,8 @@
 	FMT_YUV_PSEUDO(MDP_Y_CBCR_H1V2, MDSS_MDP_CHROMA_H1V2, C1_B_Cb, C2_R_Cr),
 	FMT_YUV_PSEUDO(MDP_Y_CRCB_H2V2, MDSS_MDP_CHROMA_420, C2_R_Cr, C1_B_Cb),
 	FMT_YUV_PSEUDO(MDP_Y_CBCR_H2V2, MDSS_MDP_CHROMA_420, C1_B_Cb, C2_R_Cr),
+	FMT_YUV_PSEUDO(MDP_Y_CBCR_H2V2_VENUS, MDSS_MDP_CHROMA_420,
+		       C1_B_Cb, C2_R_Cr),
 
 	FMT_YUV_PLANR(MDP_Y_CR_CB_H2V2, MDSS_MDP_CHROMA_420, C2_R_Cr, C1_B_Cb),
 	FMT_YUV_PLANR(MDP_Y_CB_CR_H2V2, MDSS_MDP_CHROMA_420, C1_B_Cb, C2_R_Cr),
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index bc64d2e..6f92474 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -13,6 +13,8 @@
 
 #define pr_fmt(fmt)	"%s: " fmt, __func__
 
+#include <linux/workqueue.h>
+
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 
@@ -44,6 +46,12 @@
 	u8 timegen_en;
 	struct completion pp_comp;
 	struct completion vsync_comp;
+
+	struct mutex vsync_lock;
+	struct work_struct vsync_work;
+	mdp_vsync_handler_t vsync_handler;
+	void *vsync_ptr;
+	ktime_t vsync_time;
 };
 
 struct mdss_mdp_video_ctx mdss_mdp_video_ctx_list[MAX_SESSIONS];
@@ -141,6 +149,47 @@
 	return 0;
 }
 
+static void send_vsync_work(struct work_struct *work)
+{
+	struct mdss_mdp_video_ctx *ctx;
+
+	ctx = container_of(work, typeof(*ctx), vsync_work);
+	mutex_lock(&ctx->vsync_lock);
+	if (ctx->vsync_handler)
+		ctx->vsync_handler(ctx->vsync_ptr, ctx->vsync_time);
+	mutex_unlock(&ctx->vsync_lock);
+}
+
+static int mdss_mdp_video_set_vsync_handler(struct mdss_mdp_ctl *ctl,
+		mdp_vsync_handler_t vsync_handler)
+{
+	struct mdss_mdp_video_ctx *ctx;
+
+	ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx for ctl=%d\n", ctl->num);
+		return -ENODEV;
+	}
+	if (mutex_lock_interruptible(&ctx->vsync_lock))
+		return -EINTR;
+
+	if (!ctx->timegen_en) {
+		ctx->vsync_time = ktime_get();
+		schedule_work(&ctx->vsync_work);
+	}
+
+	if (!ctx->vsync_handler && vsync_handler)
+		mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+	else if (ctx->vsync_handler && !vsync_handler)
+		mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+
+	ctx->vsync_handler = vsync_handler;
+	ctx->vsync_ptr = ctl;
+	mutex_unlock(&ctx->vsync_lock);
+
+	return 0;
+}
+
 static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_mdp_video_ctx *ctx;
@@ -161,6 +210,11 @@
 		ctx->timegen_en = false;
 	}
 
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
+				   NULL, NULL);
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
+				   NULL, NULL);
+
 	memset(ctx, 0, sizeof(*ctx));
 
 	return 0;
@@ -190,10 +244,13 @@
 		pr_err("invalid ctx\n");
 		return;
 	}
+	ctx->vsync_time = ktime_get();
 
 	pr_debug("intr ctl=%d\n", ctx->ctl_num);
 
 	complete(&ctx->vsync_comp);
+	if (ctx->vsync_handler)
+		schedule_work(&ctx->vsync_work);
 }
 
 static int mdss_mdp_video_prepare(struct mdss_mdp_ctl *ctl, void *arg)
@@ -207,15 +264,10 @@
 	}
 
 	if (ctx->timegen_en) {
-		u32 intr_type = MDSS_MDP_IRQ_PING_PONG_COMP;
-
 		pr_debug("waiting for ping pong %d done\n", ctx->pp_num);
-		mdss_mdp_set_intr_callback(intr_type, ctx->pp_num,
-					   mdss_mdp_video_pp_intr_done, ctx);
-		mdss_mdp_irq_enable(intr_type, ctx->pp_num);
-
+		mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
 		wait_for_completion_interruptible(&ctx->pp_comp);
-		mdss_mdp_irq_disable(intr_type, ctx->pp_num);
+		mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
 	}
 
 	return 0;
@@ -224,7 +276,6 @@
 static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
 {
 	struct mdss_mdp_video_ctx *ctx;
-	u32 intr_type = MDSS_MDP_IRQ_INTF_VSYNC;
 
 	pr_debug("kickoff ctl=%d\n", ctl->num);
 
@@ -233,9 +284,12 @@
 		pr_err("invalid ctx\n");
 		return -ENODEV;
 	}
-	mdss_mdp_set_intr_callback(intr_type, ctl->intf_num,
-				   mdss_mdp_video_vsync_intr_done, ctx);
-	mdss_mdp_irq_enable(intr_type, ctl->intf_num);
+	INIT_COMPLETION(ctx->vsync_comp);
+
+	if (mutex_lock_interruptible(&ctx->vsync_lock))
+		return -EINTR;
+	if (!ctx->vsync_handler)
+		mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
 
 	if (!ctx->timegen_en) {
 		int off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
@@ -249,7 +303,9 @@
 	}
 
 	wait_for_completion_interruptible(&ctx->vsync_comp);
-	mdss_mdp_irq_disable(intr_type, ctl->intf_num);
+	if (!ctx->vsync_handler)
+		mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+	mutex_unlock(&ctx->vsync_lock);
 
 	return 0;
 }
@@ -293,6 +349,13 @@
 	init_completion(&ctx->pp_comp);
 	init_completion(&ctx->vsync_comp);
 
+	INIT_WORK(&ctx->vsync_work, send_vsync_work);
+	mutex_init(&ctx->vsync_lock);
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
+				   mdss_mdp_video_vsync_intr_done, ctx);
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
+				   mdss_mdp_video_pp_intr_done, ctx);
+
 	itp.width = pinfo->xres + pinfo->lcdc.xres_pad;
 	itp.height = pinfo->yres + pinfo->lcdc.yres_pad;
 	itp.border_clr = pinfo->lcdc.border_clr;
@@ -316,6 +379,7 @@
 	ctl->stop_fnc = mdss_mdp_video_stop;
 	ctl->prepare_fnc = mdss_mdp_video_prepare;
 	ctl->display_fnc = mdss_mdp_video_display;
+	ctl->set_vsync_handler = mdss_mdp_video_set_vsync_handler;
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index d4d889b..1cb474d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -615,6 +615,49 @@
 		mfd->kickoff_fnc(mfd->ctl);
 }
 
+static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t)
+{
+	struct device *dev;
+	char buf[64];
+	char *envp[2];
+
+	if (!ctl || !ctl->mfd || !ctl->mfd->fbi) {
+		pr_warn("Invalid handle for vsync\n");
+		return;
+	}
+
+	dev = ctl->mfd->fbi->dev;
+
+	snprintf(buf, sizeof(buf), "VSYNC=%llu", ktime_to_ns(t));
+	envp[0] = buf;
+	envp[1] = NULL;
+	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
+
+	pr_debug("sent vsync on ctl=%d ts=%llu\n", ctl->num, ktime_to_ns(t));
+}
+
+static int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
+{
+	struct mdss_mdp_ctl *ctl = mfd->ctl;
+	int rc;
+
+	if (!ctl)
+		return -ENODEV;
+	if (!ctl->set_vsync_handler)
+		return -ENOTSUPP;
+
+	pr_debug("vsync en=%d\n", en);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	if (en)
+		rc = ctl->set_vsync_handler(ctl, mdss_mdp_overlay_handle_vsync);
+	else
+		rc = ctl->set_vsync_handler(ctl, NULL);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	return rc;
+}
+
 static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
 				     struct fb_cursor *cursor)
 {
@@ -822,6 +865,16 @@
 		}
 		break;
 
+	case MSMFB_VSYNC_CTRL:
+	case MSMFB_OVERLAY_VSYNC_CTRL:
+		if (!copy_from_user(&val, argp, sizeof(val))) {
+			ret = mdss_mdp_overlay_vsync_ctrl(mfd, val);
+		} else {
+			pr_err("MSMFB_OVERLAY_VSYNC_CTRL failed (%d)\n", ret);
+			ret = -EFAULT;
+		}
+		break;
+
 	default:
 		if (mfd->panel_info.type == WRITEBACK_PANEL)
 			ret = mdss_mdp_wb_ioctl_handler(mfd, cmd, argp);
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 7f61a14..53cd378 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -102,8 +102,6 @@
 	spin_lock(&mdss_mdp_intr_lock);
 	fnc = mdp_intr_cb[index].func;
 	arg = mdp_intr_cb[index].arg;
-	if (fnc != NULL)
-		mdp_intr_cb[index].func = NULL;
 	spin_unlock(&mdss_mdp_intr_lock);
 	if (fnc)
 		fnc(arg);
@@ -202,18 +200,25 @@
 	} else {
 		u8 hmap[] = { 1, 2, 1, 2 };
 		u8 vmap[] = { 1, 1, 2, 2 };
-		u8 horiz, vert;
+		u8 horiz, vert, stride_align;
 
 		horiz = hmap[fmt->chroma_sample];
 		vert = vmap[fmt->chroma_sample];
 
-		if (format == MDP_Y_CR_CB_GH2V2) {
-			ps->ystride[0] = ALIGN(w, 16);
-			ps->ystride[1] = ALIGN(w / horiz, 16);
-		} else {
-			ps->ystride[0] = w;
-			ps->ystride[1] = (w / horiz);
+		switch (format) {
+		case MDP_Y_CR_CB_GH2V2:
+			stride_align = 16;
+			break;
+		case MDP_Y_CBCR_H2V2_VENUS:
+			stride_align = 32;
+			break;
+		default:
+			stride_align = 1;
+			break;
 		}
+
+		ps->ystride[0] = ALIGN(w, stride_align);
+		ps->ystride[1] = ALIGN(w / horiz, stride_align);
 		ps->plane_size[0] = ps->ystride[0] * h;
 		ps->plane_size[1] = ps->ystride[1] * (h / vert);
 
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index f08a4e4..e6e8aca 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -101,7 +101,6 @@
 	mdp_bus_scale_update_request(0);
 #endif
 
-	spin_lock_bh(&dsi_clk_lock);
 	mipi_dsi_clk_disable();
 
 	/* disbale dsi engine */
@@ -110,7 +109,6 @@
 	mipi_dsi_phy_ctrl(0);
 
 	mipi_dsi_ahb_ctrl(0);
-	spin_unlock_bh(&dsi_clk_lock);
 
 	mipi_dsi_unprepare_clocks();
 	if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save)
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 2c1f5b7..827a951 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -3255,7 +3255,9 @@
 						struct msmfb_mdp_pp *pp_ptr)
 {
 	int ret = -1;
-
+#ifdef CONFIG_FB_MSM_MDP40
+	int i = 0;
+#endif
 	if (!pp_ptr)
 		return ret;
 
@@ -3263,6 +3265,15 @@
 #ifdef CONFIG_FB_MSM_MDP40
 	case mdp_op_csc_cfg:
 		ret = mdp4_csc_config(&(pp_ptr->data.csc_cfg_data));
+		for (i = 0; i < CSC_MAX_BLOCKS; i++) {
+			if (pp_ptr->data.csc_cfg_data.block ==
+					csc_cfg_matrix[i].block) {
+				memcpy(&csc_cfg_matrix[i].csc_data,
+				&(pp_ptr->data.csc_cfg_data.csc_data),
+				sizeof(struct mdp_csc_cfg));
+				break;
+			}
+		}
 		break;
 
 	case mdp_op_pcc_cfg:
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 84f148f..400a3a7 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -289,6 +289,7 @@
 	u32  ext_enc_control_val;
 	u32  num_references_for_p_frame;
 	u32  closed_gop;
+	u32  num_slices_comp;
 	struct vcd_property_slice_delivery_info slice_delivery_info;
 	struct ddl_batch_frame_data batch_frame;
 };
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index c3d20cf..c1e460f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -32,7 +32,7 @@
 static void ddl_handle_enc_frame_done(struct ddl_client_context *ddl,
 	u32 eos_present);
 static void ddl_handle_slice_done_slice_batch(struct ddl_client_context *ddl);
-static void ddl_handle_enc_frame_done_slice_mode(
+static u32 ddl_handle_enc_frame_done_slice_mode(
 		struct ddl_client_context *ddl, u32 eos_present);
 static void ddl_handle_enc_skipframe_slice_mode(
 		struct ddl_client_context *ddl, u32 eos_present);
@@ -491,7 +491,7 @@
 	return ret_status;
 }
 
-static void ddl_encoder_frame_run_callback(
+static u32 ddl_encoder_frame_run_callback(
 	struct ddl_client_context *ddl)
 {
 	struct ddl_context *ddl_context = ddl->ddl_context;
@@ -500,6 +500,7 @@
 	struct vcd_frame_data *output_frame =
 		&(ddl->output_frame.vcd_frm);
 	u32 eos_present = false;
+	u32 status = true;
 
 	DDL_MSG_MED("ddl_encoder_frame_run_callback\n");
 	if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME_DONE) &&
@@ -532,6 +533,7 @@
 					ddl_handle_enc_skipframe_slice_mode(
 							ddl, eos_present);
 				else
+					status =
 					ddl_handle_enc_frame_done_slice_mode(
 							ddl, eos_present);
 			} else {
@@ -605,6 +607,8 @@
 			ddl->command_channel);
 		}
 	}
+
+	return status;
 }
 
 static void get_dec_status(struct ddl_client_context *ddl,
@@ -821,7 +825,7 @@
 		if (ddl->cmd_state == DDL_CMD_DECODE_FRAME)
 			return_status = ddl_decoder_frame_run_callback(ddl);
 		else if (ddl->cmd_state == DDL_CMD_ENCODE_FRAME)
-			ddl_encoder_frame_run_callback(ddl);
+			return_status = ddl_encoder_frame_run_callback(ddl);
 		else if (ddl->cmd_state == DDL_CMD_EOS)
 			return_status = ddl_eos_frame_done_callback(ddl);
 		else {
@@ -1028,6 +1032,9 @@
 				VIDC_1080P_RISC2HOST_CMD_SLICE_DONE_RET)
 			|| (ddl_hw_response->cmd ==
 				VIDC_1080P_RISC2HOST_CMD_FRAME_DONE_RET))) {
+				vidc_sm_get_num_slices_comp(
+				&ddl->shared_mem[ddl->command_channel],
+				&encoder->num_slices_comp);
 				vidc_sm_set_encoder_slice_batch_int_ctrl(
 				&ddl->shared_mem[ddl->command_channel],
 				1);
@@ -1828,7 +1835,7 @@
 			0);
 }
 
-static void ddl_handle_enc_frame_done_slice_mode(
+static u32 ddl_handle_enc_frame_done_slice_mode(
 		struct ddl_client_context *ddl, u32 eos_present)
 {
 	struct ddl_context       *ddl_context = ddl->ddl_context;
@@ -1842,6 +1849,7 @@
 	u32 start_bfr_idx = 0;
 	u32 actual_idx = 0;
 	struct vcd_transc *transc;
+	u32 status = true;
 
 	DDL_MSG_LOW("%s\n", __func__);
 	vidc_sm_get_num_slices_comp(
@@ -1867,6 +1875,7 @@
 		DDL_MSG_ERROR("ERROR : %d %d\n",
 		encoder->slice_delivery_info.num_slices_enc,
 		encoder->batch_frame.num_output_frames);
+		status = false;
 	}
 	for (index = 0; index < num_slices_comp; index++) {
 		actual_idx =
@@ -1934,6 +1943,8 @@
 				sizeof(struct ddl_frame_data_tag),
 				(u32 *) ddl, ddl->client_data);
 	}
+
+	return status;
 }
 
 static void ddl_handle_enc_skipframe_slice_mode(
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 4072b02..04bb160 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -959,6 +959,7 @@
 		ddl_update_core_start_time(__func__, ENC_SLICE_OP_TIME);
 		ddl_set_core_start_time(__func__, ENC_OP_TIME);
 	}
+	encoder->num_slices_comp = 0;
 	ddl_vidc_encode_set_batch_slice_info(ddl);
 	ddl_context->vidc_encode_slice_batch_start[ddl->command_channel] (
 			&enc_param);
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
index 7c0d9fe..8f52f83 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -213,11 +213,11 @@
 	return vcd_handle_input_frame(cctxt, input_frame);
 }
 
-static u32 vcd_pause_in_run(struct vcd_clnt_ctxt *cctxt)
+static u32 vcd_pause_cmn(struct vcd_clnt_ctxt *cctxt)
 {
 	u32 rc = VCD_S_SUCCESS;
 
-	VCD_MSG_LOW("vcd_pause_in_run:");
+	VCD_MSG_LOW("vcd_pause_cmn:");
 
 	if (cctxt->sched_clnt_hdl) {
 		rc = vcd_sched_suspend_resume_clnt(cctxt, false);
@@ -1709,7 +1709,7 @@
 	 vcd_encode_frame_cmn,
 	 vcd_decode_start_in_run,
 	 vcd_decode_frame_cmn,
-	 vcd_pause_in_run,
+	 vcd_pause_cmn,
 	 NULL,
 	 vcd_flush_cmn,
 	 vcd_stop_in_run,
@@ -1784,7 +1784,7 @@
 	 vcd_encode_frame_cmn,
 	 NULL,
 	 vcd_decode_frame_cmn,
-	 NULL,
+	 vcd_pause_cmn,
 	 NULL,
 	 vcd_flush_in_eos,
 	 vcd_stop_in_eos,
diff --git a/include/linux/dvb/video.h b/include/linux/dvb/video.h
index 1d750c0..81475c2 100644
--- a/include/linux/dvb/video.h
+++ b/include/linux/dvb/video.h
@@ -57,6 +57,19 @@
 	VIDEO_CENTER_CUT_OUT  /* use center cut out format */
 } video_displayformat_t;
 
+enum video_codec_t {
+	VIDEO_CODECTYPE_NONE,
+	VIDEO_CODECTYPE_MPEG2,
+	VIDEO_CODECTYPE_MPEG4,
+	VIDEO_CODECTYPE_H264,
+	VIDEO_CODECTYPE_VC1
+};
+
+enum video_out_format_t {
+	VIDEO_YUV_FORMAT_NV12,
+	VIDEO_YUV_FORMAT_TILE_4x2
+};
+
 typedef struct {
 	int w;
 	int h;
@@ -84,12 +97,29 @@
 #define VIDEO_CMD_FREEZE      (2)
 #define VIDEO_CMD_CONTINUE    (3)
 
+#define VIDEO_CMD_SET_CODEC           (4)
+#define VIDEO_CMD_GET_CODEC           (5)
+#define VIDEO_CMD_SET_OUTPUT_FORMAT   (6)
+#define VIDEO_CMD_GET_OUTPUT_FORMAT   (7)
+#define VIDEO_CMD_GET_BUFFER_REQ      (8)
+#define VIDEO_CMD_SET_INPUT_BUFFERS   (9)
+#define VIDEO_CMD_SET_OUTPUT_BUFFERS  (10)
+#define VIDEO_CMD_READ_RAW_OUTPUT     (11)
+#define VIDEO_CMD_GET_PIC_RES         (12)
+#define VIDEO_CMD_FREE_INPUT_BUFFERS  (13)
+#define VIDEO_CMD_FREE_OUTPUT_BUFFERS (14)
+#define VIDEO_CMD_GET_H264_MV_BUFFER  (15)
+#define VIDEO_CMD_SET_H264_MV_BUFFER  (16)
+#define VIDEO_CMD_FREE_H264_MV_BUFFER (17)
+#define VIDEO_CMD_CLEAR_INPUT_BUFFER  (18)
+#define VIDEO_CMD_CLEAR_OUTPUT_BUFFER (19)
+
 /* Flags for VIDEO_CMD_FREEZE */
-#define VIDEO_CMD_FREEZE_TO_BLACK     	(1 << 0)
+#define VIDEO_CMD_FREEZE_TO_BLACK	(1 << 0)
 
 /* Flags for VIDEO_CMD_STOP */
-#define VIDEO_CMD_STOP_TO_BLACK      	(1 << 0)
-#define VIDEO_CMD_STOP_IMMEDIATELY     	(1 << 1)
+#define VIDEO_CMD_STOP_TO_BLACK		(1 << 0)
+#define VIDEO_CMD_STOP_IMMEDIATELY	(1 << 1)
 
 /* Play input formats: */
 /* The decoder has no special format requirements */
@@ -97,6 +127,56 @@
 /* The decoder requires full GOPs */
 #define VIDEO_PLAY_FMT_GOP          (1)
 
+/* Picture Resolution for Video Data */
+struct video_pic_res {
+	unsigned int width;
+	unsigned int height;
+	unsigned int stride;
+	unsigned int scan_lines;
+};
+
+/* Video Buffer Properties */
+struct video_buffer_prop {
+	unsigned int alignment;
+	unsigned int buf_poolid;
+	size_t buf_size;
+};
+
+/* Buffer Requirements from Video Decoder */
+struct video_buffer_req {
+	unsigned int num_input_buffers;  /* Number of Input Buffers */
+	unsigned int num_output_buffers; /* Number of Output Buffers */
+	struct video_buffer_prop input_buf_prop; /* Input Buffer Properties */
+	struct video_buffer_prop output_buf_prop; /* Output Buffer Prop */
+};
+
+/* Video Data Buffer Structure for Input and Output */
+struct video_data_buffer {
+	void __user *bufferaddr; /* Pointer to Buffer */
+	size_t buffer_len;       /* Length of Buffer */
+	int ion_fd;             /* file Descriptor */
+	size_t offset;
+	size_t mmaped_size;
+	void *client_data;
+	void *ip_buffer_tag;
+	__u64 pts;
+};
+
+struct video_h264_mv {
+	size_t size;
+	int count;
+	int ion_fd;
+	int offset;
+};
+
+struct video_mv_buff_size {
+	int width;
+	int height;
+	int size;
+	int alignment;
+};
+
+
 /* The structure must be zeroed before use by the application
    This ensures it can be extended safely in the future. */
 struct video_command {
@@ -112,11 +192,23 @@
 			   1 specifies forward single stepping,
 			   -1 specifies backward single stepping,
 			   >1: playback at speed/1000 of the normal speed,
-			   <-1: reverse playback at (-speed/1000) of the normal speed. */
+			   <-1: reverse playback at (-speed/1000) of
+				the normal speed. */
 			__s32 speed;
 			__u32 format;
 		} play;
 
+		union {
+			enum video_codec_t codec; /* Video Codec Type */
+			enum video_out_format_t format; /* YUV Format */
+			struct video_pic_res frame_res; /* Frame Resolution */
+			/* Buffer Requirements for Video Decoder */
+			struct video_buffer_req buf_req;
+			struct video_data_buffer buffer; /* Buffer Details */
+			struct video_mv_buff_size mv_buffer_req;
+			struct video_h264_mv mv_buffer_prop;
+		};
+
 		struct {
 			__u32 data[16];
 		} raw;
@@ -126,22 +218,47 @@
 /* FIELD_UNKNOWN can be used if the hardware does not know whether
    the Vsync is for an odd, even or progressive (i.e. non-interlaced)
    field. */
-#define VIDEO_VSYNC_FIELD_UNKNOWN  	(0)
-#define VIDEO_VSYNC_FIELD_ODD 		(1)
+#define VIDEO_VSYNC_FIELD_UNKNOWN	(0)
+#define VIDEO_VSYNC_FIELD_ODD		(1)
 #define VIDEO_VSYNC_FIELD_EVEN		(2)
 #define VIDEO_VSYNC_FIELD_PROGRESSIVE	(3)
 
 struct video_event {
 	__s32 type;
-#define VIDEO_EVENT_SIZE_CHANGED	1
-#define VIDEO_EVENT_FRAME_RATE_CHANGED	2
-#define VIDEO_EVENT_DECODER_STOPPED 	3
-#define VIDEO_EVENT_VSYNC 		4
+#define VIDEO_EVENT_SIZE_CHANGED	(1)
+#define VIDEO_EVENT_FRAME_RATE_CHANGED	(2)
+#define VIDEO_EVENT_DECODER_STOPPED	(3)
+#define VIDEO_EVENT_VSYNC		(4)
+#define VIDEO_EVENT_DECODER_PLAYING     (5)
+#define VIDEO_EVENT_DECODER_FREEZED     (6)
+#define VIDEO_EVENT_DECODER_RESUMED     (7)
+#define VIDEO_EVENT_INPUT_BUFFER_DONE   (8)
+#define VIDEO_EVENT_SEQ_HDR_FOUND       (9)
+#define VIDEO_EVENT_OUTPUT_BUFFER_DONE  (10)
+#define VIDEO_EVENT_OUTPUT_FLUSH_DONE   (11)
+#define VIDEO_EVENT_INPUT_FLUSH_DONE    (12)
+#define VIDEO_EVENT_INPUT_FLUSHED       (13)
+#define VIDEO_EVENT_OUTPUT_FLUSHED      (14)
+
+
+	unsigned int    status;
+#define VIDEO_STATUS_SUCESS             0
+#define VIDEO_STATUS_BITSTREAM_ERROR    1
+#define VIDEO_STATUS_FAILED             2
+#define VIDEO_STATUS_NORESOURCE         3
+#define VIDEO_STATUS_INVALID_CMD        4
+#define VIDEO_STATUS_INVALID_PARAM      5
+#define VIDEO_STATUS_INVALID_STATE      6
+#define VIDEO_STATUS_BUSY               7
+#define VIDEO_STATUS_INVALID_HANDLE     8
+#define VIDEO_STATUS_NO_SUPPORT         9
 	__kernel_time_t timestamp;
+
 	union {
 		video_size_t size;
 		unsigned int frame_rate;	/* in frames per 1000sec */
-		unsigned char vsync_field;	/* unknown/odd/even/progressive */
+		unsigned char vsync_field; /* unknown/odd/even/progressive */
+		struct video_data_buffer buffer; /* Output Buffer Details */
 	} u;
 };
 
@@ -149,8 +266,8 @@
 struct video_status {
 	int                   video_blank;   /* blank video on freeze? */
 	video_play_state_t    play_state;    /* current state of playback */
-	video_stream_source_t stream_source; /* current source (demux/memory) */
-	video_format_t        video_format;  /* current aspect ratio of stream*/
+	video_stream_source_t stream_source;/* current source (demux/memory) */
+	video_format_t        video_format; /* current aspect ratio of stream*/
 	video_displayformat_t display_format;/* selected cropping mode */
 };
 
@@ -160,7 +277,6 @@
 	__s32 size;
 };
 
-
 typedef
 struct video_highlight {
 	int     active;      /*    1=show highlight, 0=hide highlight */
@@ -268,9 +384,9 @@
 #define VIDEO_GET_PTS              _IOR('o', 57, __u64)
 
 /* Read the number of displayed frames since the decoder was started */
-#define VIDEO_GET_FRAME_COUNT  	   _IOR('o', 58, __u64)
+#define VIDEO_GET_FRAME_COUNT	   _IOR('o', 58, __u64)
 
-#define VIDEO_COMMAND     	   _IOWR('o', 59, struct video_command)
-#define VIDEO_TRY_COMMAND 	   _IOWR('o', 60, struct video_command)
+#define VIDEO_COMMAND		   _IOWR('o', 59, struct video_command)
+#define VIDEO_TRY_COMMAND	   _IOWR('o', 60, struct video_command)
 
 #endif /*_DVBVIDEO_H_*/
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 6bd4cb2..7b389c5 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -93,6 +93,7 @@
  *			however, this should only be enabled for devices which
  *			control the DC OVP FETs otherwise this option should
  *			remain disabled
+ * @has_dc_supply:	report DC online if this bit is set in board file
  * @trkl_voltage:	the trkl voltage in (mV) below which hw controlled
  *			 trkl charging happens with linear charger
  * @weak_voltage:	the weak voltage (mV) below which hw controlled
@@ -142,6 +143,7 @@
 	int64_t				batt_id_max;
 	bool				keep_btm_on_suspend;
 	bool				dc_unplug_check;
+	bool				has_dc_supply;
 	int				trkl_voltage;
 	int				weak_voltage;
 	int				trkl_current;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 4dd6907..e7cbb79 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -106,6 +106,7 @@
 	MDP_YCBCR_H1V1,   /* YCbCr interleave */
 	MDP_BGR_565,      /* BGR 565 planer */
 	MDP_BGR_888,      /* BGR 888 */
+	MDP_Y_CBCR_H2V2_VENUS,
 	MDP_IMGTYPE_LIMIT,
 	MDP_RGB_BORDERFILL,	/* border fill pipe */
 	MDP_FB_FORMAT = MDP_IMGTYPE2_START,    /* framebuffer format */
diff --git a/include/linux/msm_rmnet.h b/include/linux/msm_rmnet.h
index 9f52464..063a8f1 100644
--- a/include/linux/msm_rmnet.h
+++ b/include/linux/msm_rmnet.h
@@ -40,6 +40,8 @@
 	RMNET_IOCTL_GET_OPMODE       = 0x000089F7, /* Get operation mode     */
 	RMNET_IOCTL_OPEN             = 0x000089F8, /* Open transport port    */
 	RMNET_IOCTL_CLOSE            = 0x000089F9, /* Close transport port   */
+	RMNET_IOCTL_FLOW_ENABLE	     = 0x000089FA, /* Flow enable	     */
+	RMNET_IOCTL_FLOW_DISABLE     = 0x000089FB, /* Flow disable	     */
 	RMNET_IOCTL_MAX
 };
 
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index a088b9c..d365b15 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -1011,6 +1011,15 @@
 extern struct slim_controller *slim_busnum_to_ctrl(u32 busnum);
 
 /*
+ * slim_ctrl_add_boarddevs: Add devices registered by board-info
+ * @ctrl: Controller to which these devices are to be added to.
+ * This API is called by controller when it is up and running.
+ * If devices on a controller were registered before controller,
+ * this will make sure that they get probed when controller is up
+ */
+extern void slim_ctrl_add_boarddevs(struct slim_controller *ctrl);
+
+/*
  * slim_register_board_info: Board-initialization routine.
  * @info: List of all devices on all controllers present on the board.
  * @n: number of entries.
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 468a410..59ba64b 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -438,6 +438,7 @@
  * @usb_bam_num_pipes: max number of pipes to use.
  * @active_conn_num: number of active pipe connections.
  * @usb_base_address: BAM physical address.
+ * @ignore_core_reset_ack: BAM can ignore ACK from USB core during PIPE RESET
  */
 struct msm_usb_bam_platform_data {
 	struct usb_bam_pipe_connect *connections;
@@ -445,6 +446,7 @@
 	int usb_bam_num_pipes;
 	u32 total_bam_num;
 	u32 usb_base_address;
+	bool ignore_core_reset_ack;
 };
 
 enum usb_bam {
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index cf99435..d56e534 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -38,6 +38,12 @@
 		writel_relaxed(val, addr);	\
 	} while (0)
 
+#define VCAP_BASE (dev->vcapbase)
+#define VCAP_OFFSET(off) (VCAP_BASE + off)
+
+#define VCAP_SW_RESET_REQ (VCAP_BASE + 0x024)
+#define VCAP_SW_RESET_STATUS (VCAP_BASE + 0x028)
+
 struct vcap_client_data;
 
 enum rdy_buf {
@@ -167,6 +173,7 @@
 	bool					vp_resource;
 	bool					vp_dummy_event;
 	bool					vp_dummy_complete;
+	bool					vp_shutdown;
 	wait_queue_head_t		vp_dummy_waitq;
 
 	struct workqueue_struct	*vcap_wq;
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index fffdc60..95ec28b 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -103,7 +103,8 @@
 			      struct tcf_result *res);
 extern int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
 		       struct tcf_result *res);
-
+extern void tc_qdisc_flow_control(struct net_device *dev, u32 tcm_handle,
+				  int flow_enable);
 /* Calculate maximal size of packet seen by hard_start_xmit
    routine of this device.
  */
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index f504921..5ac5c52 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -56,6 +56,9 @@
 #include "bnep.h"
 
 #define VERSION "1.3"
+/* As this feature is dummy for BNEP net device
+** disabling support */
+#undef CONFIG_BT_BNEP_MC_FILTER
 
 static bool compress_src = 1;
 static bool compress_dst = 1;
diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c
index 155ff74..a8e5449 100644
--- a/net/bluetooth/bnep/netdev.c
+++ b/net/bluetooth/bnep/netdev.c
@@ -44,6 +44,9 @@
 #include "bnep.h"
 
 #define BNEP_TX_QUEUE_LEN 20
+/* As this feature is dummy for BNEP net device
+** disabling support */
+#undef CONFIG_BT_BNEP_MC_FILTER
 
 static int bnep_net_open(struct net_device *dev)
 {
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 3d8981f..60e2fa9 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1030,6 +1030,35 @@
 }
 
 /*
+ * enable/disable flow on qdisc.
+ */
+void
+tc_qdisc_flow_control(struct net_device *dev, u32 tcm_handle, int enable_flow)
+{
+	struct Qdisc *q;
+	struct __qdisc_change_req {
+		struct nlattr attr;
+		struct tc_prio_qopt data;
+	} req =	{
+		.attr = {sizeof(struct __qdisc_change_req), TCA_OPTIONS},
+		.data = {3, {1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}, 1}
+		};
+
+	/* override flow bit */
+	req.data.enable_flow = enable_flow;
+
+	/* look up using tcm handle */
+	q = qdisc_lookup(dev, tcm_handle);
+
+	/* call registered change function */
+	if (q) {
+		if (q->ops->change(q, &(req.attr)) != 0)
+			pr_err("tc_qdisc_flow_control: qdisc change failed");
+	}
+}
+EXPORT_SYMBOL(tc_qdisc_flow_control);
+
+/*
  * Create/change qdisc.
  */
 
diff --git a/sound/soc/codecs/cs8427.c b/sound/soc/codecs/cs8427.c
index e406a32..dc7f23b 100644
--- a/sound/soc/codecs/cs8427.c
+++ b/sound/soc/codecs/cs8427.c
@@ -740,7 +740,7 @@
 	unsigned char buf[CHANNEL_STATUS_SIZE];
 	unsigned char val = 0;
 	char addr = 0;
-	unsigned int reset_timeout = 100;
+	unsigned int reset_timeout = 1;
 	int ret = 0;
 	struct cs8427 *chip;
 
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 390c314..99302eb 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -62,7 +62,7 @@
 snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
 obj-$(CONFIG_SND_SOC_QDSP6) += snd-soc-qdsp6.o
 
-snd-soc-msm8960-objs := msm8960.o apq8064.o msm8930.o mpq8064.o
+snd-soc-msm8960-objs := msm8960.o apq8064.o msm8930.o mpq8064.o apq8064-i2s.o
 obj-$(CONFIG_SND_SOC_MSM8960) += snd-soc-msm8960.o
 
 # Generic MSM drivers
diff --git a/sound/soc/msm/apq8064-i2s.c b/sound/soc/msm/apq8064-i2s.c
new file mode 100644
index 0000000..162f39d
--- /dev/null
+++ b/sound/soc/msm/apq8064-i2s.c
@@ -0,0 +1,2808 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/slimbus/slimbus.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/socinfo.h>
+#include "msm-pcm-routing.h"
+#include "../codecs/wcd9310.h"
+
+/* 8064 machine driver */
+
+#define PM8921_GPIO_BASE		NR_GPIO_IRQS
+#define PM8921_GPIO_PM_TO_SYS(pm_gpio)  (pm_gpio - 1 + PM8921_GPIO_BASE)
+
+#define MSM8064_SPK_ON 1
+#define MSM8064_SPK_OFF 0
+
+#define MSM_SLIM_0_RX_MAX_CHANNELS		2
+#define MSM_SLIM_0_TX_MAX_CHANNELS		4
+
+#define BTSCO_RATE_8KHZ 8000
+#define BTSCO_RATE_16KHZ 16000
+
+#define BOTTOM_SPK_AMP_POS	0x1
+#define BOTTOM_SPK_AMP_NEG	0x2
+#define TOP_SPK_AMP_POS		0x4
+#define TOP_SPK_AMP_NEG		0x8
+#define TOP_SPK_AMP		0x10
+
+
+#define GPIO_AUX_PCM_DOUT 43
+#define GPIO_AUX_PCM_DIN 44
+#define GPIO_AUX_PCM_SYNC 45
+#define GPIO_AUX_PCM_CLK 46
+
+#define TABLA_EXT_CLK_RATE 12288000
+
+#define TABLA_MBHC_DEF_BUTTONS 8
+#define TABLA_MBHC_DEF_RLOADS 5
+
+#define JACK_DETECT_GPIO 38
+
+#define APQ_I2S_SLAVE_CONFIG	0
+/* MCLK selection GPIOs from PMIC */
+#define PM_GPIO_MCLK_MDM	10
+#define PM_GPIO_MCLK_APQ	41
+
+/* SPKR I2S Configuration */
+#define GPIO_SPKR_I2S_MCLK  39
+#define GPIO_SPKR_I2S_SCK   40
+#define GPIO_SPKR_I2S_DOUT  41
+#define GPIO_SPKR_I2S_WS    42
+
+/* MIC I2S Configuration */
+#define GPIO_MIC_I2S_MCLK	34
+#define GPIO_MIC_I2S_SCK	35
+#define GPIO_MIC_I2S_WS		36
+#define GPIO_MIC_I2S_DIN0	37
+#define GPIO_MIC_I2S_DIN1   38
+
+/* MI2S Configuration */
+#define GPIO_MI2S_WS    27
+#define GPIO_MI2S_SCK   28
+#define GPIO_MI2S_SD3   29
+#define GPIO_MI2S_SD2   30
+#define GPIO_MI2S_SD1   31
+#define GPIO_MI2S_SD0   32
+#define GPIO_MI2S_MCLK  33
+
+struct request_gpio {
+	unsigned gpio_no;
+	char *gpio_name;
+};
+/* SD0 as RX and SD3 as TX. SD1 and SD2 are unused */
+static struct request_gpio mi2s_gpio[] = {
+	{
+		.gpio_no = GPIO_MI2S_WS,
+		.gpio_name = "MI2S_WS",
+	},
+	{
+		.gpio_no = GPIO_MI2S_SCK,
+		.gpio_name = "MI2S_SCK",
+	},
+	{
+		.gpio_no = GPIO_MI2S_SD3,
+		.gpio_name = "MI2S_SD3",
+	},
+	{
+		.gpio_no = GPIO_MI2S_SD0,
+		.gpio_name = "MI2S_SD0",
+	},
+	{
+		.gpio_no = GPIO_MI2S_MCLK,
+		.gpio_name = "MI2S_MCLK",
+	},
+};
+
+/* I2S RX is slave so MCLK is not needed */
+static struct request_gpio spkr_i2s_gpio[] = {
+	{
+		.gpio_no = GPIO_SPKR_I2S_WS,
+		.gpio_name = "SPKR_I2S_WS",
+	},
+	{
+		.gpio_no = GPIO_SPKR_I2S_SCK,
+		.gpio_name = "SPKR_I2S_SCK",
+	},
+	{
+		.gpio_no = GPIO_SPKR_I2S_DOUT,
+		.gpio_name = "SPKR_I2S_DOUT",
+	},
+};
+
+
+/* I2S TX is slave so MCLK is not needed. DIN1 is not used */
+static struct request_gpio mic_i2s_gpio[] = {
+	{
+		.gpio_no = GPIO_MIC_I2S_WS,
+		.gpio_name = "MIC_I2S_WS",
+	},
+	{
+		.gpio_no = GPIO_MIC_I2S_SCK,
+		.gpio_name = "MIC_I2S_SCK",
+	},
+	{
+		.gpio_no = GPIO_MIC_I2S_DIN0,
+		.gpio_name = "MIC_I2S_DIN",
+	},
+};
+
+/* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
+enum {
+	SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
+	SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
+	SLIM_3_RX_1 = 151, /* External echo-cancellation ref */
+	SLIM_3_RX_2 = 152, /* External echo-cancellation ref */
+	SLIM_3_TX_1 = 153, /* HDMI RX */
+	SLIM_3_TX_2 = 154, /* HDMI RX */
+	SLIM_4_TX_1 = 148, /* In-call recording RX */
+	SLIM_4_TX_2 = 149, /* In-call recording RX */
+	SLIM_4_RX_1 = 150, /* In-call music delivery TX */
+};
+
+enum {
+	INCALL_REC_MONO,
+	INCALL_REC_STEREO,
+};
+
+
+#if APQ_I2S_SLAVE_CONFIG
+static u32 mdm_mclk_gpio = PM8921_GPIO_PM_TO_SYS(PM_GPIO_MCLK_MDM);
+static u32 apq_mclk_gpio = PM8921_GPIO_PM_TO_SYS(PM_GPIO_MCLK_APQ);
+#endif
+static u32 top_spk_pamp_gpio  = PM8921_GPIO_PM_TO_SYS(18);
+static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
+static int msm_spk_control;
+static int msm_ext_bottom_spk_pamp;
+static int msm_ext_top_spk_pamp;
+static int msm_slim_0_rx_ch = 1;
+static int msm_slim_0_tx_ch = 1;
+static int msm_slim_3_rx_ch = 1;
+
+static struct clk *i2s_rx_bit_clk;
+static struct clk *i2s_tx_bit_clk;
+
+#if (!APQ_I2S_SLAVE_CONFIG)
+static struct clk *mi2s_osr_clk;
+#endif
+static struct clk *mi2s_bit_clk;
+
+static int msm_i2s_rx_ch = 1;
+static int msm_i2s_tx_ch = 1;
+static int msm_mi2s_rx_ch = 1;
+static int msm_mi2s_tx_ch = 1;
+/* MI2S TX and RX share the same control block*/
+static atomic_t mi2s_rsc_ref;
+
+static int msm_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm_btsco_ch = 1;
+
+static int rec_mode = INCALL_REC_MONO;
+
+static struct clk *codec_clk;
+static int clk_users;
+
+static struct snd_soc_jack hs_jack;
+static struct snd_soc_jack button_jack;
+
+static int apq8064_i2s_hs_detect_use_gpio = -1;
+module_param(apq8064_i2s_hs_detect_use_gpio, int, 0444);
+MODULE_PARM_DESC(apq8064_i2s_hs_detect_use_gpio, "Use GPIO for headset detection");
+
+static bool apq8064_i2s_hs_detect_use_firmware;
+module_param(apq8064_i2s_hs_detect_use_firmware, bool, 0444);
+MODULE_PARM_DESC(apq8064_i2s_hs_detect_use_firmware,
+			"Use firmware for headset detection");
+
+static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+				    bool dapm);
+
+static struct tabla_mbhc_config mbhc_cfg = {
+	.headset_jack = &hs_jack,
+	.button_jack = &button_jack,
+	.read_fw_bin = false,
+	.calibration = NULL,
+	.micbias = TABLA_MICBIAS2,
+	.mclk_cb_fn = msm_enable_codec_ext_clk,
+	.mclk_rate = TABLA_EXT_CLK_RATE,
+	.gpio = 0,
+	.gpio_irq = 0,
+	.gpio_level_insert = 1,
+};
+
+static struct mutex cdc_mclk_mutex;
+
+static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
+{
+	int ret = 0;
+
+	struct pm_gpio param = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 1,
+		.pull      = PM_GPIO_PULL_NO,
+		.vin_sel	= PM_GPIO_VIN_S4,
+		.out_strength   = PM_GPIO_STRENGTH_MED,
+		.
+			function       = PM_GPIO_FUNC_NORMAL,
+	};
+
+	if (spk_amp_gpio == bottom_spk_pamp_gpio) {
+
+		ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
+		if (ret) {
+			pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
+				__func__, bottom_spk_pamp_gpio);
+			return;
+		}
+		ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
+		if (ret)
+			pr_err("%s: Failed to configure Bottom Spk Ampl gpio %u\n",
+			__func__, bottom_spk_pamp_gpio);
+		else {
+			pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
+			gpio_direction_output(bottom_spk_pamp_gpio, 1);
+		}
+
+	} else if (spk_amp_gpio == top_spk_pamp_gpio) {
+
+		ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
+		if (ret) {
+			pr_err("%s: Error requesting GPIO %d\n", __func__,
+				top_spk_pamp_gpio);
+			return;
+		}
+		ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
+		if (ret)
+			pr_err("%s: Failed to configure Top Spk Ampl gpio %u\n",
+			__func__, top_spk_pamp_gpio);
+		else {
+			pr_debug("%s: enable Top spkr amp gpio\n", __func__);
+			gpio_direction_output(top_spk_pamp_gpio, 1);
+		}
+	} else {
+		pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO gpio = %u\n",
+		__func__, spk_amp_gpio);
+		return;
+	}
+}
+
+static void msm_ext_spk_power_amp_on(u32 spk)
+{
+	if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+
+		if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
+			(msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+
+			pr_debug("%s() External Bottom Speaker Ampl already	turned on\n"
+			"spk = 0x%08x\n", __func__, spk);
+			return;
+		}
+
+		msm_ext_bottom_spk_pamp |= spk;
+
+		if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
+			(msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+
+			msm_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
+			pr_debug("%s: slepping 4 ms after turning on external\n"
+			"Bottom Speaker Ampl\n", __func__);
+			usleep_range(4000, 4000);
+		}
+
+	} else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG | TOP_SPK_AMP)) {
+
+		pr_debug("%s():top_spk_amp_state = 0x%x spk_event = 0x%x\n",
+		__func__, msm_ext_top_spk_pamp, spk);
+
+		if (((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+			(msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) ||
+				(msm_ext_top_spk_pamp & TOP_SPK_AMP)) {
+
+			pr_debug("%s() External Top Speaker Ampl already turned on\n"
+			"spk = 0x%08x\n", __func__, spk);
+			return;
+		}
+
+		msm_ext_top_spk_pamp |= spk;
+
+		if (((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+			(msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) ||
+				(msm_ext_top_spk_pamp & TOP_SPK_AMP)) {
+
+			msm_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
+			pr_debug("%s: sleeping 4 ms after turning on\n"
+			"external Top Speaker Ampl\n", __func__);
+			usleep_range(4000, 4000);
+		}
+	} else  {
+
+		pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+			__func__, spk);
+		return;
+	}
+}
+
+static void msm_ext_spk_power_amp_off(u32 spk)
+{
+	if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+
+		if (!msm_ext_bottom_spk_pamp)
+			return;
+
+		gpio_direction_output(bottom_spk_pamp_gpio, 0);
+		gpio_free(bottom_spk_pamp_gpio);
+		msm_ext_bottom_spk_pamp = 0;
+
+		pr_debug("%s: sleeping 4 ms after turning off external Bottom\n"
+		"Speaker Ampl\n", __func__);
+
+		usleep_range(4000, 4000);
+
+	} else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG | TOP_SPK_AMP)) {
+
+		pr_debug("%s: top_spk_amp_state = 0x%x spk_event = 0x%x\n",
+				__func__, msm_ext_top_spk_pamp, spk);
+
+		if (!msm_ext_top_spk_pamp)
+			return;
+
+		if ((spk & TOP_SPK_AMP_POS) || (spk & TOP_SPK_AMP_NEG)) {
+
+			msm_ext_top_spk_pamp &= (~(TOP_SPK_AMP_POS |
+							TOP_SPK_AMP_NEG));
+		} else if (spk & TOP_SPK_AMP) {
+			msm_ext_top_spk_pamp &=  ~TOP_SPK_AMP;
+		}
+
+		if (msm_ext_top_spk_pamp)
+			return;
+
+		gpio_direction_output(top_spk_pamp_gpio, 0);
+		gpio_free(top_spk_pamp_gpio);
+		msm_ext_top_spk_pamp = 0;
+
+		pr_debug("%s: sleeping 4 ms after ext Top Spek Ampl is off\n",
+				__func__);
+
+		usleep_range(4000, 4000);
+	} else  {
+
+		pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
+			__func__, spk);
+		return;
+	}
+}
+
+static void msm_ext_control(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
+	if (msm_spk_control == MSM8064_SPK_ON) {
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+	} else {
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
+	}
+
+	snd_soc_dapm_sync(dapm);
+}
+
+static int msm_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
+	ucontrol->value.integer.value[0] = msm_spk_control;
+	return 0;
+}
+static int msm_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	pr_debug("%s()\n", __func__);
+	if (msm_spk_control == ucontrol->value.integer.value[0])
+		return 0;
+
+	msm_spk_control = ucontrol->value.integer.value[0];
+	msm_ext_control(codec);
+	return 1;
+}
+static int msm_spkramp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *k, int event)
+{
+	pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
+			msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
+		else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
+			msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
+		else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
+			msm_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
+		else if  (!strncmp(w->name, "Ext Spk Top Neg", 15))
+			msm_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
+		else if  (!strncmp(w->name, "Ext Spk Top", 12))
+			msm_ext_spk_power_amp_on(TOP_SPK_AMP);
+		else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+		}
+
+	} else {
+		if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
+			msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
+		else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
+			msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
+		else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
+			msm_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
+		else if  (!strncmp(w->name, "Ext Spk Top Neg", 15))
+			msm_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
+		else if  (!strncmp(w->name, "Ext Spk Top", 12))
+			msm_ext_spk_power_amp_off(TOP_SPK_AMP);
+		else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+				    bool dapm)
+{
+	int r = 0;
+	pr_debug("%s: enable = %d\n", __func__, enable);
+
+	mutex_lock(&cdc_mclk_mutex);
+	if (enable) {
+		clk_users++;
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+		if (clk_users == 1) {
+			if (codec_clk) {
+				/*
+				* For MBHC calc, the MCLK is from APQ side
+				* so APQ has control of the MCLK at this point
+				*/
+				clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+				clk_prepare_enable(codec_clk);
+				tabla_mclk_enable(codec, 1, dapm);
+			} else {
+				pr_err("%s: Error setting Tabla MCLK\n",
+				       __func__);
+				clk_users--;
+				r = -EINVAL;
+			}
+		}
+	} else {
+		if (clk_users > 0) {
+			clk_users--;
+			pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+			if (clk_users == 0) {
+				pr_debug("%s: disabling MCLK. clk_users = %d\n",
+					 __func__, clk_users);
+				tabla_mclk_enable(codec, 0, dapm);
+				/*
+				* For MBHC calc, the MCLK is from APQ side
+				* so APQ has control of the MCLK at this point
+				*/
+				clk_disable_unprepare(codec_clk);
+			}
+		} else {
+			pr_err("%s: Error releasing Tabla MCLK\n", __func__);
+			r = -EINVAL;
+		}
+	}
+	mutex_unlock(&cdc_mclk_mutex);
+	return r;
+}
+
+static int msm_mclk_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	pr_debug("%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+
+		clk_users++;
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+
+		if (clk_users != 1)
+			return 0;
+
+		if (codec_clk) {
+			/*
+			* Since the MCLK is from MDM side so APQ side
+			* has no control of the MCLK at this point
+			*/
+			/*clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+			clk_prepare_enable(codec_clk); */
+			tabla_mclk_enable(w->codec, 1, true);
+
+		} else {
+			pr_err("%s: Error setting Tabla MCLK\n", __func__);
+			clk_users--;
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+
+		if (clk_users == 0)
+			return 0;
+
+		clk_users--;
+
+		if (!clk_users) {
+			pr_debug("%s: disabling MCLK. clk_users = %d\n",
+					__func__, clk_users);
+
+			tabla_mclk_enable(w->codec, 0, true);
+			/*
+			* Since the MCLK is from MDM side so APQ side
+			* has no control of the MCLK at this point
+			*/
+			/* clk_disable_unprepare(codec_clk); */
+		}
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget apq8064_dapm_widgets[] = {
+
+	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
+	msm_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm_spkramp_event),
+
+	SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Top", msm_spkramp_event),
+
+	/************ Analog MICs ************/
+	/**
+	 * Analog mic7 (Front Top) on Liquid.
+	 * Used as Handset mic on CDP.
+	 */
+	SND_SOC_DAPM_MIC("Analog mic7", NULL),
+
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+
+	/*********** Digital Mics ***************/
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic5", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+};
+
+static const struct snd_soc_dapm_route apq8064_common_audio_map[] = {
+
+	{"RX_BIAS", NULL, "MCLK"},
+	{"LDO_H", NULL, "MCLK"},
+
+	{"HEADPHONE", NULL, "LDO_H"},
+
+	/* Speaker path */
+	{"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
+	{"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
+
+	{"Ext Spk Top Pos", NULL, "LINEOUT2"},
+	{"Ext Spk Top Neg", NULL, "LINEOUT4"},
+	{"Ext Spk Top", NULL, "LINEOUT5"},
+
+	/************   Analog MIC Paths  ************/
+
+	/* Headset Mic */
+	{"AMIC2", NULL, "MIC BIAS2 External"},
+	{"MIC BIAS2 External", NULL, "Headset Mic"},
+
+	/* Headset ANC microphones */
+	{"AMIC3", NULL, "MIC BIAS3 Internal1"},
+	{"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
+
+	{"AMIC4", NULL, "MIC BIAS1 Internal2"},
+	{"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
+};
+
+static const struct snd_soc_dapm_route apq8064_mtp_audio_map[] = {
+
+	/************   Digital MIC Paths  ************/
+
+	/*
+	 * Digital Mic1 (Front bottom Left) on MTP.
+	 * Conncted to DMIC1 Input on Tabla codec.
+	 */
+	{"DMIC1", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic1"},
+
+	/**
+	 * Digital Mic2 (Front bottom right) on MTP.
+	 * Conncted to DMIC2 Input on Tabla codec.
+	 */
+	{"DMIC2", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic2"},
+
+	/**
+	 * Digital Mic3 (Back bottom) on MTP.
+	 * Conncted to DMIC3 Input on Tabla codec.
+	 */
+	{"DMIC3", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic3"},
+
+	/**
+	 * Digital Mic4 (Back top) on MTP.
+	 * Conncted to DMIC4 Input on Tabla codec.
+	 */
+	{"DMIC4", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic4"},
+
+	/**
+	 * Digital Mic5 (Top front Mic) on MTP.
+	 * Conncted to DMIC6 Input on Tabla codec.
+	 */
+	{"DMIC6", NULL, "MIC BIAS4 External"},
+	{"MIC BIAS4 External", NULL, "Digital Mic5"},
+
+};
+
+static const struct snd_soc_dapm_route apq8064_liquid_cdp_audio_map[] = {
+
+	/************   Analog MIC Paths  ************/
+	/**
+	 * Analog mic7 (Front Top Mic) on Liquid.
+	 * Used as Handset mic on CDP.
+	 * Not there on MTP.
+	 */
+	{"AMIC1", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Analog mic7"},
+
+
+	/************   Digital MIC Paths  ************/
+	/**
+	 * The digital Mic routes are setup considering
+	 * Liquid as default device.
+	 */
+
+	/**
+	 * Digital Mic1 (Front bottom left corner) on Liquid.
+	 * Digital Mic2 (Front bottom right) on MTP.
+	 * Digital Mic GM1 on CDP mainboard.
+	 * Conncted to DMIC2 Input on Tabla codec.
+	 */
+	{"DMIC2", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic1"},
+
+	/**
+	 * Digital Mic2 (Front left side) on Liquid.
+	 * Digital Mic GM2 on CDP mainboard.
+	 * Not there on MTP.
+	 * Conncted to DMIC3 Input on Tabla codec.
+	 */
+	{"DMIC3", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic2"},
+
+	/**
+	 * Digital Mic3. Front bottom left of middle on Liquid.
+	 * Digital Mic5 (Top front Mic) on MTP.
+	 * Digital Mic GM5 on CDP mainboard.
+	 * Conncted to DMIC6 Input on Tabla codec.
+	 */
+	{"DMIC6", NULL, "MIC BIAS4 External"},
+	{"MIC BIAS4 External", NULL, "Digital Mic3"},
+
+	/**
+	 * Digital Mic4. Back bottom on Liquid.
+	 * Digital Mic GM3 on CDP mainboard.
+	 * Top Front Mic on MTP.
+	 * Conncted to DMIC5 Input on Tabla codec.
+	 */
+	{"DMIC5", NULL, "MIC BIAS4 External"},
+	{"MIC BIAS4 External", NULL, "Digital Mic4"},
+
+	/**
+	 * Digital Mic5. Front bottom right of middle on Liquid.
+	 * Digital Mic GM6 on CDP mainboard.
+	 * Not there on MTP.
+	 * Conncted to DMIC4 Input on Tabla codec.
+	 */
+	{"DMIC4", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic5"},
+
+	/* Digital Mic6 (Front bottom right corner) on Liquid.
+	 * Digital Mic1 (Front bottom Left) on MTP.
+	 * Digital Mic GM4 on CDP.
+	 * Conncted to DMIC1 Input on Tabla codec.
+	 */
+	{"DMIC1", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic6"},
+};
+
+static const char * const spk_function[] = {"Off", "On"};
+static const char * const rx_ch_text[] = {"One", "Two"};
+static const char * const tx_ch_text[] = {"One", "Two", "Three", "Four"};
+
+static const struct soc_enum msm_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+	SOC_ENUM_SINGLE_EXT(2, rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(4, tx_ch_text),
+};
+
+static const char * const btsco_rate_text[] = {"8000", "16000"};
+static const struct soc_enum msm_btsco_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
+};
+
+static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_slim_0_rx_ch  = %d\n", __func__,
+			msm_slim_0_rx_ch);
+	ucontrol->value.integer.value[0] = msm_slim_0_rx_ch - 1;
+	return 0;
+}
+
+static int msm_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
+			msm_slim_0_rx_ch);
+	return 1;
+}
+
+static int msm_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_slim_0_tx_ch  = %d\n", __func__,
+			msm_slim_0_tx_ch);
+	ucontrol->value.integer.value[0] = msm_slim_0_tx_ch - 1;
+	return 0;
+}
+
+static int msm_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__,
+			msm_slim_0_tx_ch);
+	return 1;
+}
+
+static int msm_slim_3_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_slim_3_rx_ch  = %d\n", __func__,
+			msm_slim_3_rx_ch);
+	ucontrol->value.integer.value[0] = msm_slim_3_rx_ch - 1;
+	return 0;
+}
+
+static int msm_slim_3_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_slim_3_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_slim_3_rx_ch = %d\n", __func__,
+			msm_slim_3_rx_ch);
+	return 1;
+}
+
+static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_btsco_rate  = %d", __func__,
+					msm_btsco_rate);
+	ucontrol->value.integer.value[0] = msm_btsco_rate;
+	return 0;
+}
+
+static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 8000:
+		msm_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	case 16000:
+		msm_btsco_rate = BTSCO_RATE_16KHZ;
+		break;
+	default:
+		msm_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	}
+	pr_debug("%s: msm_btsco_rate = %d\n", __func__,
+					msm_btsco_rate);
+	return 0;
+}
+
+static int msm_incall_rec_mode_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = rec_mode;
+	return 0;
+}
+
+static int msm_incall_rec_mode_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+
+	rec_mode = ucontrol->value.integer.value[0];
+	pr_debug("%s: rec_mode:%d\n", __func__, rec_mode);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new tabla_msm_controls[] = {
+	SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_get_spk,
+		msm_set_spk),
+	SOC_ENUM_EXT("SLIM_0_RX Channels", msm_enum[1],
+		msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
+	SOC_ENUM_EXT("SLIM_0_TX Channels", msm_enum[2],
+		msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+		msm_btsco_rate_get, msm_btsco_rate_put),
+	SOC_SINGLE_EXT("Incall Rec Mode", SND_SOC_NOPM, 0, 1, 0,
+			msm_incall_rec_mode_get, msm_incall_rec_mode_put),
+	SOC_ENUM_EXT("SLIM_3_RX Channels", msm_enum[1],
+		msm_slim_3_rx_ch_get, msm_slim_3_rx_ch_put),
+};
+
+
+static int msm_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_mi2s_rx_ch  = %d\n", __func__,
+			msm_mi2s_rx_ch);
+	ucontrol->value.integer.value[0] = msm_mi2s_rx_ch - 1;
+	return 0;
+}
+
+static int msm_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_mi2s_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_mi2s_rx_ch = %d\n", __func__,
+			msm_mi2s_rx_ch);
+	return 1;
+}
+
+static int msm_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_mi2s_tx_ch  = %d\n", __func__,
+			msm_mi2s_tx_ch);
+	ucontrol->value.integer.value[0] = msm_mi2s_tx_ch - 1;
+	return 0;
+}
+
+static int msm_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_mi2s_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_mi2s_tx_ch = %d\n", __func__,
+			msm_mi2s_tx_ch);
+	return 1;
+}
+
+static int msm_mi2s_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
+	ucontrol->value.integer.value[0] = msm_spk_control;
+	return 0;
+}
+static int msm_mi2s_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	pr_debug("%s()\n", __func__);
+	if (msm_spk_control == ucontrol->value.integer.value[0])
+		return 0;
+
+	msm_spk_control = ucontrol->value.integer.value[0];
+	msm_ext_control(codec);
+	return 1;
+}
+
+static int msm_mi2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_mi2s_rx_ch;
+
+	return 0;
+}
+
+static int msm_mi2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+
+	channels->min = channels->max = msm_mi2s_tx_ch;
+
+	return 0;
+}
+
+
+static int msm_i2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_i2s_rx_ch;
+
+	return 0;
+}
+
+static int msm_i2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+
+	channels->min = channels->max = msm_i2s_tx_ch;
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new tabla_msm_mi2s_controls[] = {
+	SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_mi2s_get_spk,
+		msm_mi2s_set_spk),
+	SOC_ENUM_EXT("MI2S_RX Channels", msm_enum[1],
+		msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+	SOC_ENUM_EXT("MI2S_TX Channels", msm_enum[2],
+		msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+		msm_btsco_rate_get, msm_btsco_rate_put),
+	SOC_SINGLE_EXT("Incall Rec Mode", SND_SOC_NOPM, 0, 1, 0,
+		msm_incall_rec_mode_get, msm_incall_rec_mode_put),
+};
+
+static int msm_mi2s_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int ret;
+	uint32_t revision;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+#if APQ_I2S_SLAVE_CONFIG
+	struct pm_gpio param = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 1,
+		.pull      = PM_GPIO_PULL_NO,
+		.vin_sel	= PM_GPIO_VIN_S4,
+		.out_strength   = PM_GPIO_STRENGTH_MED,
+		.function       = PM_GPIO_FUNC_NORMAL,
+	};
+#endif
+	pr_debug("%s(), dev_name(%s)\n", __func__, dev_name(cpu_dai->dev));
+	ret = gpio_request(GPIO_MI2S_MCLK, "MI2S_MCLK");
+	if (ret)
+		pr_err("%s: Failed to request gpio %d\n", __func__,
+			   GPIO_MI2S_MCLK);
+
+#if APQ_I2S_SLAVE_CONFIG
+	/* APQ provides the mclk to codec */
+	ret = gpio_request(mdm_mclk_gpio, "MDM_MCLK_SWITCH");
+	if (ret) {
+		pr_err("%s: Failed to request gpio %d\n", __func__,
+			mdm_mclk_gpio);
+		return ret;
+	}
+	ret = pm8xxx_gpio_config(mdm_mclk_gpio, &param);
+	if (ret)
+		pr_err("%s: Failed to configure gpio %d\n", __func__,
+			mdm_mclk_gpio);
+	else
+		gpio_direction_output(mdm_mclk_gpio, 0);
+
+	ret = gpio_request(apq_mclk_gpio, "APQ_MCLK_SWITCH");
+	if (ret) {
+		pr_err("%s: Failed to request gpio %d\n", __func__,
+			apq_mclk_gpio);
+		return ret;
+	}
+	ret = pm8xxx_gpio_config(apq_mclk_gpio, &param);
+	if (ret)
+		pr_err("%s: Failed to configure gpio %d\n", __func__,
+			apq_mclk_gpio);
+	else
+		gpio_direction_output(apq_mclk_gpio, 1);
+	pr_debug("%s: Config mdm_mclk_gpio and apq_mclk_gpio\n",
+	__func__);
+#else
+	pr_debug("%s: Not config mdm_mclk_gpio and apq_mclk_gpio\n",
+	__func__);
+#endif
+	snd_soc_dapm_new_controls(dapm, apq8064_dapm_widgets,
+				ARRAY_SIZE(apq8064_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, apq8064_common_audio_map,
+		ARRAY_SIZE(apq8064_common_audio_map));
+
+	if (machine_is_apq8064_mtp()) {
+		snd_soc_dapm_add_routes(dapm, apq8064_mtp_audio_map,
+			ARRAY_SIZE(apq8064_mtp_audio_map));
+	} else  {
+		snd_soc_dapm_add_routes(dapm, apq8064_liquid_cdp_audio_map,
+			ARRAY_SIZE(apq8064_liquid_cdp_audio_map));
+	}
+
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+
+	snd_soc_dapm_sync(dapm);
+
+	ret = snd_soc_jack_new(codec, "Headset Jack",
+			       (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
+				SND_JACK_OC_HPHR | SND_JACK_UNSUPPORTED),
+		&hs_jack);
+	if (ret) {
+		pr_err("failed to create new jack\n");
+		return ret;
+	}
+
+	ret = snd_soc_jack_new(codec, "Button Jack",
+			       TABLA_JACK_BUTTON_MASK, &button_jack);
+	if (ret) {
+		pr_err("failed to create new jack\n");
+		return ret;
+	}
+	/* Get the MCLK from MI2S block for MBHC calibration */
+	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+	pr_debug("%s: Device name is %s\n", __func__, dev_name(cpu_dai->dev));
+
+	/* APQ8064 Rev 1.1 CDP and Liquid have mechanical switch */
+	revision = socinfo_get_version();
+	if (apq8064_i2s_hs_detect_use_gpio != -1) {
+		if (apq8064_i2s_hs_detect_use_gpio == 1)
+			pr_debug("%s: MBHC mechanical is enabled by request\n",
+				 __func__);
+		else if (apq8064_i2s_hs_detect_use_gpio == 0)
+			pr_debug("%s: MBHC mechanical is disabled by request\n",
+				 __func__);
+		else
+			pr_warn("%s: Invalid hs_detect_use_gpio %d\n", __func__,
+				apq8064_i2s_hs_detect_use_gpio);
+	} else if (SOCINFO_VERSION_MAJOR(revision) == 0) {
+		pr_warn("%s: Unknown HW revision detected %d.%d\n", __func__,
+			SOCINFO_VERSION_MAJOR(revision),
+			SOCINFO_VERSION_MINOR(revision));
+	} else if ((SOCINFO_VERSION_MAJOR(revision) == 1 &&
+		    SOCINFO_VERSION_MINOR(revision) >= 1 &&
+		    (machine_is_apq8064_cdp() ||
+		     machine_is_apq8064_liquid())) ||
+		   SOCINFO_VERSION_MAJOR(revision) > 1) {
+		pr_debug("%s: MBHC mechanical switch available APQ8064 detected\n",
+		__func__);
+		apq8064_i2s_hs_detect_use_gpio = 1;
+	}
+
+	if (apq8064_i2s_hs_detect_use_gpio == 1) {
+		pr_debug("%s: Using MBHC mechanical switch\n", __func__);
+		mbhc_cfg.gpio = JACK_DETECT_GPIO;
+		mbhc_cfg.gpio_irq = gpio_to_irq(JACK_DETECT_GPIO);
+		ret = gpio_request(mbhc_cfg.gpio, "MBHC_HS_DETECT");
+		if (ret < 0) {
+			pr_err("%s: gpio_request %d failed %d\n", __func__,
+			       mbhc_cfg.gpio, ret);
+			return ret;
+		}
+		gpio_direction_input(JACK_DETECT_GPIO);
+	} else
+		pr_debug("%s: Not using MBHC mechanical switch\n", __func__);
+
+	mbhc_cfg.read_fw_bin = apq8064_i2s_hs_detect_use_firmware;
+
+	ret = tabla_hs_detect(codec, &mbhc_cfg);
+
+#if APQ_I2S_SLAVE_CONFIG
+	/* MDM provides the mclk to codec */
+	gpio_direction_output(apq_mclk_gpio, 0);
+	gpio_direction_output(mdm_mclk_gpio, 1);
+	pr_debug("%s: Should not running here if no clock switch\n", __func__);
+#endif
+	/* Should we add code to put back codec clock?*/
+	gpio_free(GPIO_MI2S_MCLK);
+	pr_debug("%s: Free MCLK GPIO\n", __func__);
+	return ret;
+}
+
+static int msm_mi2s_free_gpios(void)
+{
+	int	i;
+	for (i = 0; i < ARRAY_SIZE(mi2s_gpio); i++)
+		gpio_free(mi2s_gpio[i].gpio_no);
+	return 0;
+}
+
+static void msm_mi2s_shutdown(struct snd_pcm_substream *substream)
+{
+
+	if (atomic_dec_return(&mi2s_rsc_ref) == 0) {
+		pr_debug("%s: free mi2s resources\n", __func__);
+		if (mi2s_bit_clk) {
+			clk_disable_unprepare(mi2s_bit_clk);
+			clk_put(mi2s_bit_clk);
+			mi2s_bit_clk = NULL;
+		}
+#if (!APQ_I2S_SLAVE_CONFIG)
+		if (mi2s_osr_clk) {
+			clk_disable_unprepare(mi2s_osr_clk);
+			clk_put(mi2s_osr_clk);
+			mi2s_osr_clk = NULL;
+		}
+#endif
+		msm_mi2s_free_gpios();
+	}
+}
+
+static int msm_configure_mi2s_gpio(void)
+{
+	int	rtn;
+	int	i;
+	int	j;
+	for (i = 0; i < ARRAY_SIZE(mi2s_gpio); i++) {
+		rtn = gpio_request(mi2s_gpio[i].gpio_no,
+						   mi2s_gpio[i].gpio_name);
+		pr_debug("%s: gpio = %d, gpio name = %s, rtn = %d\n",
+				 __func__,
+				 mi2s_gpio[i].gpio_no,
+				 mi2s_gpio[i].gpio_name,
+				 rtn);
+		if (rtn) {
+			pr_err("%s: Failed to request gpio %d\n",
+				   __func__,
+				   mi2s_gpio[i].gpio_no);
+			for (j = i; j >= 0; j--)
+				gpio_free(mi2s_gpio[j].gpio_no);
+			goto err;
+		}
+	}
+err:
+	return rtn;
+}
+
+static int msm_mi2s_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+	pr_debug("%s: dai name %s %p\n", __func__, cpu_dai->name, cpu_dai->dev);
+
+	if (atomic_inc_return(&mi2s_rsc_ref) == 1) {
+		pr_debug("%s: acquire mi2s resources\n", __func__);
+		msm_configure_mi2s_gpio();
+
+#if APQ_I2S_SLAVE_CONFIG
+		pr_debug("%s: APQ is MI2S slave\n", __func__);
+		mi2s_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+		if (IS_ERR(mi2s_bit_clk))
+			return PTR_ERR(mi2s_bit_clk);
+		clk_set_rate(mi2s_bit_clk, 0);
+		ret = clk_prepare_enable(mi2s_bit_clk);
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("Unable to enable mi2s_bit_clk\n");
+			clk_put(mi2s_bit_clk);
+			return ret;
+		}
+		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM);
+		if (IS_ERR_VALUE(ret))
+			pr_err("set format for CPU dai failed\n");
+#else
+		pr_debug("%s: APQ is MI2S master\n", __func__);
+		mi2s_osr_clk = clk_get(cpu_dai->dev, "osr_clk");
+		if (IS_ERR(mi2s_osr_clk))
+			return PTR_ERR(mi2s_osr_clk);
+		clk_set_rate(mi2s_osr_clk, TABLA_EXT_CLK_RATE);
+		ret = clk_prepare_enable(mi2s_osr_clk);
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("Unable to enable mi2s_osr_clk\n");
+			clk_put(mi2s_osr_clk);
+			return ret;
+		}
+		mi2s_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+		if (IS_ERR(mi2s_bit_clk)) {
+			pr_err("Unable to get mi2s_bit_clk\n");
+			clk_disable_unprepare(mi2s_osr_clk);
+			clk_put(mi2s_osr_clk);
+			return PTR_ERR(mi2s_bit_clk);
+		}
+		clk_set_rate(mi2s_bit_clk, 8);
+		ret = clk_prepare_enable(mi2s_bit_clk);
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("Unable to enable mi2s_bit_clk\n");
+			clk_disable_unprepare(mi2s_osr_clk);
+			clk_put(mi2s_osr_clk);
+			clk_put(mi2s_bit_clk);
+			return ret;
+		}
+		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+		if (IS_ERR_VALUE(ret))
+			pr_err("set format for CPU dai failed\n");
+#endif
+	}
+
+	return ret;
+}
+
+
+static int msm_i2s_rx_free_gpios(void)
+{
+	int	i;
+	for (i = 0; i < ARRAY_SIZE(spkr_i2s_gpio); i++)
+		gpio_free(spkr_i2s_gpio[i].gpio_no);
+	return 0;
+}
+
+
+static int msm_i2s_tx_free_gpios(void)
+{
+	int	i;
+	for (i = 0; i < ARRAY_SIZE(mic_i2s_gpio); i++)
+		gpio_free(mic_i2s_gpio[i].gpio_no);
+	return 0;
+}
+
+static void msm_i2s_shutdown(struct snd_pcm_substream *substream)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_debug("%s: free i2s rx resources\n", __func__);
+		if (i2s_rx_bit_clk) {
+			clk_disable_unprepare(i2s_rx_bit_clk);
+			clk_put(i2s_rx_bit_clk);
+			i2s_rx_bit_clk = NULL;
+		}
+		msm_i2s_rx_free_gpios();
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		pr_debug("%s: free i2s tx resources\n", __func__);
+		if (i2s_tx_bit_clk) {
+			clk_disable_unprepare(i2s_tx_bit_clk);
+			clk_put(i2s_tx_bit_clk);
+			i2s_tx_bit_clk = NULL;
+		}
+		msm_i2s_tx_free_gpios();
+	}
+}
+
+static int msm_configure_i2s_rx_gpio(void)
+{
+	int	rtn;
+	int	i;
+	int	j;
+	for (i = 0; i < ARRAY_SIZE(spkr_i2s_gpio); i++) {
+		rtn = gpio_request(spkr_i2s_gpio[i].gpio_no,
+						   spkr_i2s_gpio[i].gpio_name);
+		pr_debug("%s: gpio = %d, gpio name = %s, rtn = %d\n",
+				 __func__,
+				 spkr_i2s_gpio[i].gpio_no,
+				 spkr_i2s_gpio[i].gpio_name,
+				 rtn);
+		if (rtn) {
+			pr_err("%s: Failed to request gpio %d\n",
+				   __func__,
+				   spkr_i2s_gpio[i].gpio_no);
+			for (j = i; j >= 0; j--)
+				gpio_free(spkr_i2s_gpio[j].gpio_no);
+			goto err;
+		}
+	}
+err:
+	return rtn;
+}
+
+static int msm_configure_i2s_tx_gpio(void)
+{
+	int	rtn;
+	int	i;
+	int	j;
+	for (i = 0; i < ARRAY_SIZE(mic_i2s_gpio); i++) {
+		rtn = gpio_request(mic_i2s_gpio[i].gpio_no,
+						   mic_i2s_gpio[i].gpio_name);
+		pr_debug("%s: gpio = %d, gpio name = %s, rtn = %d\n",
+				 __func__,
+				 mic_i2s_gpio[i].gpio_no,
+				 mic_i2s_gpio[i].gpio_name,
+				 rtn);
+		if (rtn) {
+			pr_err("%s: Failed to request gpio %d\n",
+				   __func__,
+				   mic_i2s_gpio[i].gpio_no);
+			for (j = i; j >= 0; j--)
+				gpio_free(mic_i2s_gpio[j].gpio_no);
+			goto err;
+		}
+	}
+err:
+	return rtn;
+}
+
+static int msm_i2s_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		msm_configure_i2s_rx_gpio();
+		i2s_rx_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+		if (IS_ERR(i2s_rx_bit_clk)) {
+			pr_err("Failed to get i2s bit_clk\n");
+			return PTR_ERR(i2s_rx_bit_clk);
+		}
+		clk_set_rate(i2s_rx_bit_clk, 0);
+		ret = clk_prepare_enable(i2s_rx_bit_clk);
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("Unable to enable i2s_rx_bit_clk\n");
+			clk_put(i2s_rx_bit_clk);
+			return ret;
+		}
+		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM);
+		if (IS_ERR_VALUE(ret))
+			pr_err("set format for CPU dai failed\n");
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		msm_configure_i2s_tx_gpio();
+		i2s_tx_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+		if (IS_ERR(i2s_tx_bit_clk)) {
+			pr_err("Failed to get i2s_tx_bit_clk\n");
+			return PTR_ERR(i2s_tx_bit_clk);
+		}
+		clk_set_rate(i2s_tx_bit_clk, 0);
+		ret = clk_prepare_enable(i2s_tx_bit_clk);
+		if (ret != 0) {
+			pr_err("Unable to enable i2s_tx_bit_clk\n");
+			clk_put(i2s_tx_bit_clk);
+			return ret;
+		}
+		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM);
+		if (IS_ERR_VALUE(ret))
+			pr_err("set format for CPU dai failed\n");
+	}
+
+	pr_debug("%s: ret = %d\n", __func__, ret);
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+			substream->name, substream->stream);
+	return ret;
+}
+
+static void *def_tabla_mbhc_cal(void)
+{
+	void *tabla_cal;
+	struct tabla_mbhc_btn_detect_cfg *btn_cfg;
+	u16 *btn_low, *btn_high;
+	u8 *n_ready, *n_cic, *gain;
+
+	tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
+						TABLA_MBHC_DEF_RLOADS),
+			    GFP_KERNEL);
+	if (!tabla_cal) {
+		pr_err("%s: out of memory\n", __func__);
+		return NULL;
+	}
+
+#define S(X, Y) ((TABLA_MBHC_CAL_GENERAL_PTR(tabla_cal)->X) = (Y))
+	S(t_ldoh, 100);
+	S(t_bg_fast_settle, 100);
+	S(t_shutdown_plug_rem, 255);
+	S(mbhc_nsa, 4);
+	S(mbhc_navg, 4);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_DET_PTR(tabla_cal)->X) = (Y))
+	S(mic_current, TABLA_PID_MIC_5_UA);
+	S(hph_current, TABLA_PID_MIC_5_UA);
+	S(t_mic_pid, 100);
+	S(t_ins_complete, 250);
+	S(t_ins_retry, 200);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
+	S(v_no_mic, 30);
+	S(v_hs_max, 1550);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
+	S(c[0], 62);
+	S(c[1], 124);
+	S(nc, 1);
+	S(n_meas, 3);
+	S(mbhc_nsc, 11);
+	S(n_btn_meas, 1);
+	S(n_btn_con, 2);
+	S(num_btn, TABLA_MBHC_DEF_BUTTONS);
+	S(v_btn_press_delta_sta, 100);
+	S(v_btn_press_delta_cic, 50);
+#undef S
+	btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
+	btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
+	btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
+	btn_low[0] = -50;
+	btn_high[0] = 10;
+	btn_low[1] = 11;
+	btn_high[1] = 38;
+	btn_low[2] = 39;
+	btn_high[2] = 64;
+	btn_low[3] = 65;
+	btn_high[3] = 91;
+	btn_low[4] = 92;
+	btn_high[4] = 115;
+	btn_low[5] = 116;
+	btn_high[5] = 141;
+	btn_low[6] = 142;
+	btn_high[6] = 163;
+	btn_low[7] = 164;
+	btn_high[7] = 250;
+	n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
+	n_ready[0] = 48;
+	n_ready[1] = 38;
+	n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
+	n_cic[0] = 60;
+	n_cic[1] = 47;
+	gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
+	gain[0] = 11;
+	gain[1] = 9;
+
+	return tabla_cal;
+}
+
+static int msm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+	unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+	unsigned int num_tx_ch = 0;
+
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+		pr_debug("%s: rx_0_ch=%d\n", __func__, msm_slim_0_rx_ch);
+
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+				msm_slim_0_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+				msm_slim_0_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set codec channel map\n",
+								__func__);
+			goto end;
+		}
+	} else {
+
+		if (codec_dai->id  == 2)
+			num_tx_ch =  msm_slim_0_tx_ch;
+		else if (codec_dai->id == 5) {
+			/* DAI 5 is used for external EC reference from codec.
+			 * Since Rx is fed as reference for EC, the config of
+			 * this DAI is based on that of the Rx path.
+			 */
+			num_tx_ch =  msm_slim_0_rx_ch;
+		}
+
+		pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
+			codec_dai->name, codec_dai->id, num_tx_ch);
+
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai,
+				num_tx_ch, tx_ch, 0 , 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(codec_dai,
+				num_tx_ch, tx_ch, 0, 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set codec channel map\n",
+								__func__);
+			goto end;
+		}
+
+
+	}
+end:
+	return ret;
+}
+
+static int msm_stubrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	rtd->pmdown_time = 0;
+
+	return 0;
+}
+
+static int msm_slimbus_2_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+	unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+	unsigned int num_tx_ch = 0;
+	unsigned int num_rx_ch = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+		num_rx_ch =  params_channels(params);
+
+		pr_debug("%s: %s rx_dai_id = %d  num_ch = %d\n", __func__,
+			codec_dai->name, codec_dai->id, num_rx_ch);
+
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+				num_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+				num_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set codec channel map\n",
+								__func__);
+			goto end;
+		}
+	} else {
+
+		num_tx_ch =  params_channels(params);
+
+		pr_debug("%s: %s  tx_dai_id = %d  num_ch = %d\n", __func__,
+			codec_dai->name, codec_dai->id, num_tx_ch);
+
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai,
+				num_tx_ch, tx_ch, 0 , 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(codec_dai,
+				num_tx_ch, tx_ch, 0, 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set codec channel map\n",
+								__func__);
+			goto end;
+		}
+	}
+end:
+	return ret;
+}
+
+static int msm_slimbus_1_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch = SLIM_1_RX_1, tx_ch = SLIM_1_TX_1;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_debug("%s: APQ BT/USB TX -> SLIMBUS_1_RX -> MDM TX shared ch %d\n",
+			__func__, rx_ch);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, 1, &rx_ch);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_1 RX channel map\n",
+				__func__, ret);
+
+			goto end;
+		}
+	} else {
+		pr_debug("%s: MDM RX -> SLIMBUS_1_TX -> APQ BT/USB Rx shared ch %d\n",
+			__func__, tx_ch);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 1, &tx_ch, 0, 0);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_1 TX channel map\n",
+				__func__, ret);
+
+			goto end;
+		}
+	}
+
+end:
+	return ret;
+}
+
+static int msm_slimbus_3_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch[2] = {SLIM_3_RX_1, SLIM_3_RX_2};
+	unsigned int tx_ch[2] = {SLIM_3_TX_1, SLIM_3_TX_2};
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_debug("%s: slim_3_rx_ch %d, sch %d %d\n",
+			 __func__, msm_slim_3_rx_ch,
+				 rx_ch[0], rx_ch[1]);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+				msm_slim_3_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_3 RX channel map\n",
+				__func__, ret);
+
+			goto end;
+		}
+	} else {
+		pr_debug("%s: MDM RX -> SLIMBUS_3_TX -> APQ HDMI ch: %d, %d\n",
+			__func__, tx_ch[0], tx_ch[1]);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 2, tx_ch, 0, 0);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_3 TX channel map\n",
+				__func__, ret);
+
+			goto end;
+		}
+	}
+
+end:
+	return ret;
+}
+
+static int msm_slimbus_4_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch = SLIM_4_RX_1, tx_ch[2];
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_debug("%s: APQ Incall Playback SLIMBUS_4_RX -> MDM TX shared ch %d\n",
+			__func__, rx_ch);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, 1, &rx_ch);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_4 RX channel map\n",
+				__func__, ret);
+
+		}
+	} else {
+		if (rec_mode == INCALL_REC_STEREO) {
+			tx_ch[0] = SLIM_4_TX_1;
+			tx_ch[1] = SLIM_4_TX_2;
+			ret = snd_soc_dai_set_channel_map(cpu_dai, 2,
+							tx_ch, 0, 0);
+		} else {
+			tx_ch[0] = SLIM_4_TX_1;
+			ret = snd_soc_dai_set_channel_map(cpu_dai, 1,
+							tx_ch, 0, 0);
+		}
+		pr_debug("%s: Incall Record shared tx_ch[0]:%d, tx_ch[1]:%d\n",
+			__func__, tx_ch[0], tx_ch[1]);
+
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_4 TX channel map\n",
+				__func__, ret);
+
+		}
+	}
+
+	return ret;
+}
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err;
+	uint32_t revision;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+	pr_debug("%s(), dev_name(%s)\n", __func__, dev_name(cpu_dai->dev));
+
+	/*if (machine_is_msm_liquid()) {
+		top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(19));
+		bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(18));
+	}*/
+
+	snd_soc_dapm_new_controls(dapm, apq8064_dapm_widgets,
+				ARRAY_SIZE(apq8064_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, apq8064_common_audio_map,
+		ARRAY_SIZE(apq8064_common_audio_map));
+
+	if (machine_is_apq8064_mtp()) {
+		snd_soc_dapm_add_routes(dapm, apq8064_mtp_audio_map,
+			ARRAY_SIZE(apq8064_mtp_audio_map));
+	} else  {
+		snd_soc_dapm_add_routes(dapm, apq8064_liquid_cdp_audio_map,
+			ARRAY_SIZE(apq8064_liquid_cdp_audio_map));
+	}
+
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+
+	snd_soc_dapm_sync(dapm);
+
+	err = snd_soc_jack_new(codec, "Headset Jack",
+			       (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
+				SND_JACK_OC_HPHR | SND_JACK_UNSUPPORTED),
+			       &hs_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+
+	err = snd_soc_jack_new(codec, "Button Jack",
+			       TABLA_JACK_BUTTON_MASK, &button_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+
+	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+
+	/* APQ8064 Rev 1.1 CDP and Liquid have mechanical switch */
+	revision = socinfo_get_version();
+	if (apq8064_i2s_hs_detect_use_gpio != -1) {
+		if (apq8064_i2s_hs_detect_use_gpio == 1)
+			pr_debug("%s: MBHC mechanical is enabled by request\n",
+				 __func__);
+		else if (apq8064_i2s_hs_detect_use_gpio == 0)
+			pr_debug("%s: MBHC mechanical is disabled by request\n",
+				 __func__);
+		else
+			pr_warn("%s: Invalid hs_detect_use_gpio %d\n", __func__,
+				apq8064_i2s_hs_detect_use_gpio);
+	} else if (SOCINFO_VERSION_MAJOR(revision) == 0) {
+		pr_warn("%s: Unknown HW revision detected %d.%d\n", __func__,
+			SOCINFO_VERSION_MAJOR(revision),
+			SOCINFO_VERSION_MINOR(revision));
+	} else if ((SOCINFO_VERSION_MAJOR(revision) == 1 &&
+		    SOCINFO_VERSION_MINOR(revision) >= 1 &&
+		    (machine_is_apq8064_cdp() ||
+		     machine_is_apq8064_liquid())) ||
+		   SOCINFO_VERSION_MAJOR(revision) > 1) {
+		pr_debug("%s: MBHC mechanical switch available APQ8064 detected\n",
+		__func__);
+		apq8064_i2s_hs_detect_use_gpio = 1;
+	}
+
+	if (apq8064_i2s_hs_detect_use_gpio == 1) {
+		pr_debug("%s: Using MBHC mechanical switch\n", __func__);
+		mbhc_cfg.gpio = JACK_DETECT_GPIO;
+		mbhc_cfg.gpio_irq = gpio_to_irq(JACK_DETECT_GPIO);
+		err = gpio_request(mbhc_cfg.gpio, "MBHC_HS_DETECT");
+		if (err < 0) {
+			pr_err("%s: gpio_request %d failed %d\n", __func__,
+			       mbhc_cfg.gpio, err);
+			return err;
+		}
+		gpio_direction_input(JACK_DETECT_GPIO);
+	} else
+		pr_debug("%s: Not using MBHC mechanical switch\n", __func__);
+
+	mbhc_cfg.read_fw_bin = apq8064_i2s_hs_detect_use_firmware;
+
+	err = tabla_hs_detect(codec, &mbhc_cfg);
+
+	return err;
+}
+
+static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_slim_0_rx_ch;
+
+	return 0;
+}
+
+static int msm_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_slim_0_tx_ch;
+
+	return 0;
+}
+
+static int msm_slim_3_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_slim_3_rx_ch;
+
+	return 0;
+}
+
+static int msm_slim_3_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	return 0;
+}
+
+static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+
+	return 0;
+}
+
+static int msm_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
+			channels->min, channels->max);
+
+	rate->min = rate->max = 48000;
+
+	return 0;
+}
+
+static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	rate->min = rate->max = msm_btsco_rate;
+	channels->min = channels->max = msm_btsco_ch;
+
+	return 0;
+}
+static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	/* PCM only supports mono output with 8khz sample rate */
+	rate->min = rate->max = 8000;
+	channels->min = channels->max = 1;
+
+	return 0;
+}
+static int msm_proxy_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+
+	return 0;
+}
+
+static int msm_aux_pcm_get_gpios(void)
+{
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
+				__func__, GPIO_AUX_PCM_DOUT);
+		goto fail_dout;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
+				__func__, GPIO_AUX_PCM_DIN);
+		goto fail_din;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
+				__func__, GPIO_AUX_PCM_SYNC);
+		goto fail_sync;
+	}
+	ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
+				__func__, GPIO_AUX_PCM_CLK);
+		goto fail_clk;
+	}
+
+	return 0;
+
+fail_clk:
+	gpio_free(GPIO_AUX_PCM_SYNC);
+fail_sync:
+	gpio_free(GPIO_AUX_PCM_DIN);
+fail_din:
+	gpio_free(GPIO_AUX_PCM_DOUT);
+fail_dout:
+
+	return ret;
+}
+
+static int msm_aux_pcm_free_gpios(void)
+{
+	gpio_free(GPIO_AUX_PCM_DIN);
+	gpio_free(GPIO_AUX_PCM_DOUT);
+	gpio_free(GPIO_AUX_PCM_SYNC);
+	gpio_free(GPIO_AUX_PCM_CLK);
+
+	return 0;
+}
+static int msm_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	pr_debug("%s(): dai_link_str_name = %s cpu_dai = %s codec_dai = %s\n",
+		__func__, rtd->dai_link->stream_name,
+		rtd->dai_link->cpu_dai_name,
+		 rtd->dai_link->codec_dai_name);
+	return 0;
+}
+
+static int msm_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	ret = msm_aux_pcm_get_gpios();
+	if (ret < 0) {
+		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int msm_slimbus_1_startup(struct snd_pcm_substream *substream)
+{
+	struct slim_controller *slim = slim_busnum_to_ctrl(1);
+
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+
+	if (slim != NULL)
+		pm_runtime_get_sync(slim->dev.parent);
+
+	return 0;
+}
+
+static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	msm_aux_pcm_free_gpios();
+}
+
+static void msm_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	pr_debug("%s(): dai_link_str_name = %s cpu_dai = %s codec_dai = %s\n",
+		__func__, rtd->dai_link->stream_name,
+		rtd->dai_link->cpu_dai_name, rtd->dai_link->codec_dai_name);
+}
+
+static void msm_slimbus_1_shutdown(struct snd_pcm_substream *substream)
+{
+	struct slim_controller *slim = slim_busnum_to_ctrl(1);
+
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+
+	if (slim != NULL) {
+		pm_runtime_mark_last_busy(slim->dev.parent);
+		pm_runtime_put(slim->dev.parent);
+	}
+}
+
+static struct snd_soc_ops msm_be_ops = {
+	.startup = msm_startup,
+	.hw_params = msm_hw_params,
+	.shutdown = msm_shutdown,
+};
+
+static struct snd_soc_ops msm_auxpcm_be_ops = {
+	.startup = msm_auxpcm_startup,
+	.shutdown = msm_auxpcm_shutdown,
+};
+
+static struct snd_soc_ops msm_slimbus_1_be_ops = {
+	.startup = msm_slimbus_1_startup,
+	.hw_params = msm_slimbus_1_hw_params,
+	.shutdown = msm_slimbus_1_shutdown,
+};
+
+static struct snd_soc_ops msm_slimbus_3_be_ops = {
+	.startup = msm_startup,
+	.hw_params = msm_slimbus_3_hw_params,
+	.shutdown = msm_shutdown,
+};
+
+static struct snd_soc_ops msm_slimbus_4_be_ops = {
+	.startup = msm_startup,
+	.hw_params = msm_slimbus_4_hw_params,
+	.shutdown = msm_shutdown,
+};
+
+static struct snd_soc_ops msm_slimbus_2_be_ops = {
+	.startup = msm_startup,
+	.hw_params = msm_slimbus_2_hw_params,
+	.shutdown = msm_shutdown,
+};
+
+static struct snd_soc_ops msm_mi2s_be_ops = {
+	.startup = msm_mi2s_startup,
+	.shutdown = msm_mi2s_shutdown,
+};
+
+
+static struct snd_soc_ops msm_i2s_be_ops = {
+	.startup = msm_i2s_startup,
+	.shutdown = msm_i2s_shutdown,
+};
+
+static struct snd_soc_dai_link msm_dai_delta_mi2s[] = {
+	/* Backend DAI Links */
+	{
+		.name = LPASS_BE_MI2S_RX,
+		.stream_name = "MI2S Playback",
+		.cpu_dai_name = "msm-dai-q6-mi2s",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_i2s_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_MI2S_RX,
+		.init = &msm_mi2s_audrx_init,
+		.be_hw_params_fixup = msm_mi2s_rx_be_hw_params_fixup,
+		.ops = &msm_mi2s_be_ops,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_MI2S_TX,
+		.stream_name = "MI2S Capture",
+		.cpu_dai_name = "msm-dai-q6-mi2s",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_i2s_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_MI2S_TX,
+		.be_hw_params_fixup = msm_mi2s_tx_be_hw_params_fixup,
+		.ops = &msm_mi2s_be_ops,
+	},
+	{
+		.name = LPASS_BE_PRI_I2S_RX,
+		.stream_name = "Primary I2S Playback",
+		.cpu_dai_name = "msm-dai-q6.0",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_PRI_I2S_RX,
+		.be_hw_params_fixup = msm_i2s_rx_be_hw_params_fixup,
+		.ops = &msm_i2s_be_ops,
+	},
+	{
+		.name = LPASS_BE_PRI_I2S_TX,
+		.stream_name = "Primary I2S Capture",
+		.cpu_dai_name = "msm-dai-q6.1",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_PRI_I2S_TX,
+		.be_hw_params_fixup = msm_i2s_tx_be_hw_params_fixup,
+		.ops = &msm_i2s_be_ops,
+	},
+};
+
+
+static struct snd_soc_dai_link msm_dai_delta_slim[] = {
+	/* Hostless PMC purpose */
+	{
+		.name = "SLIMBUS_0 Hostless",
+		.stream_name = "SLIMBUS_0 Hostless",
+		.cpu_dai_name	= "SLIMBUS0_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		/* .be_id = do not care */
+	},
+	/* Backend DAI Links */
+	{
+		.name = LPASS_BE_SLIMBUS_0_RX,
+		.stream_name = "Slimbus Playback",
+		.cpu_dai_name = "msm-dai-q6.16384",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+		.init = &msm_audrx_init,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_0_TX,
+		.stream_name = "Slimbus Capture",
+		.cpu_dai_name = "msm-dai-q6.16385",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+	},
+	{
+		.name = LPASS_BE_STUB_RX,
+		.stream_name = "Stub Playback",
+		.cpu_dai_name = "msm-dai-stub",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tabla_codec",
+		.codec_dai_name = "tabla_rx2",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_EXTPROC_RX,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.init = &msm_stubrx_init,
+		.ops = &msm_be_ops,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_STUB_TX,
+		.stream_name = "Stub Capture",
+		.cpu_dai_name = "msm-dai-stub",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tabla_codec",
+		.codec_dai_name = "tabla_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_EXTPROC_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_RX,
+		.stream_name = "Slimbus1 Playback",
+		.cpu_dai_name = "msm-dai-q6.16386",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+		.ops = &msm_slimbus_1_be_ops,
+		.ignore_pmdown_time = 1, /* Playback support */
+
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_TX,
+		.stream_name = "Slimbus1 Capture",
+		.cpu_dai_name = "msm-dai-q6.16387",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		.be_hw_params_fixup =  msm_btsco_be_hw_params_fixup,
+		.ops = &msm_slimbus_1_be_ops,
+	},
+	/* Ultrasound TX Back End DAI Link */
+	{
+		.name = "SLIMBUS_2 Hostless Capture",
+		.stream_name = "SLIMBUS_2 Hostless Capture",
+		.cpu_dai_name = "msm-dai-q6.16389",
+		.platform_name = "msm-pcm-hostless",
+		.codec_name = "tabla_codec",
+		.codec_dai_name = "tabla_tx2",
+		.ignore_suspend = 1,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ops = &msm_slimbus_2_be_ops,
+	},
+	/* Ultrasound RX Back End DAI Link */
+	{
+		.name = "SLIMBUS_2 Hostless Playback",
+		.stream_name = "SLIMBUS_2 Hostless Playback",
+		.cpu_dai_name = "msm-dai-q6.16388",
+		.platform_name = "msm-pcm-hostless",
+		.codec_name = "tabla_codec",
+		.codec_dai_name = "tabla_rx3",
+		.ignore_suspend = 1,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ops = &msm_slimbus_2_be_ops,
+	},
+	/* Incall Music Back End DAI Link */
+	{
+		.name = LPASS_BE_SLIMBUS_4_RX,
+		.stream_name = "Slimbus4 Playback",
+		.cpu_dai_name = "msm-dai-q6.16392",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_slimbus_4_be_ops,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	/* Incall Record Back End DAI Link */
+	{
+		.name = LPASS_BE_SLIMBUS_4_TX,
+		.stream_name = "Slimbus4 Capture",
+		.cpu_dai_name = "msm-dai-q6.16393",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_slimbus_4_be_ops,
+	},
+	{
+		.name = LPASS_BE_STUB_1_TX,
+		.stream_name = "Stub1 Capture",
+		.cpu_dai_name = "msm-dai-stub",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_tx3",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_EXTPROC_EC_TX,
+		/* This BE is used for external EC reference from codec. Since
+		 * Rx is fed as reference for EC, the config of this DAI is
+		 * based on that of the Rx path.
+		 */
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_3_RX,
+		.stream_name = "Slimbus3 Playback",
+		.cpu_dai_name = "msm-dai-q6.16390",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+		.be_hw_params_fixup = msm_slim_3_rx_be_hw_params_fixup,
+		.ops = &msm_slimbus_3_be_ops,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_3_TX,
+		.stream_name = "Slimbus3 Capture",
+		.cpu_dai_name = "msm-dai-q6.16391",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		.be_hw_params_fixup = msm_slim_3_tx_be_hw_params_fixup,
+		.ops = &msm_slimbus_3_be_ops,
+	},
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm_dai[] = {
+	/* FrontEnd DAI Links */
+	{
+		.name = "MSM8960 Media1",
+		.stream_name = "MultiMedia1",
+		.cpu_dai_name	= "MultiMedia1",
+		.platform_name  = "msm-pcm-dsp",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+	},
+	{
+		.name = "MSM8960 Media2",
+		.stream_name = "MultiMedia2",
+		.cpu_dai_name	= "MultiMedia2",
+		.platform_name  = "msm-multi-ch-pcm-dsp",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+	},
+	{
+		.name = "Circuit-Switch Voice",
+		.stream_name = "CS-Voice",
+		.cpu_dai_name   = "CS-VOICE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.be_id = MSM_FRONTEND_DAI_CS_VOICE,
+	},
+	{
+		.name = "MSM VoIP",
+		.stream_name = "VoIP",
+		.cpu_dai_name	= "VoIP",
+		.platform_name  = "msm-voip-dsp",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.be_id = MSM_FRONTEND_DAI_VOIP,
+	},
+	{
+		.name = "MSM8960 LPA",
+		.stream_name = "LPA",
+		.cpu_dai_name	= "MultiMedia3",
+		.platform_name  = "msm-pcm-lpa",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+	},
+	{
+		.name = "INT_FM Hostless",
+		.stream_name = "INT_FM Hostless",
+		.cpu_dai_name	= "INT_FM_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		/* .be_id = do not care */
+	},
+	{
+		.name = "MSM AFE-PCM RX",
+		.stream_name = "AFE-PROXY RX",
+		.cpu_dai_name = "msm-dai-q6.241",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = "MSM AFE-PCM TX",
+		.stream_name = "AFE-PROXY TX",
+		.cpu_dai_name = "msm-dai-q6.240",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "MSM8960 Compr",
+		.stream_name = "COMPR",
+		.cpu_dai_name	= "MultiMedia4",
+		.platform_name  = "msm-compr-dsp",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+	},
+	{
+		.name = "AUXPCM Hostless",
+		.stream_name = "AUXPCM Hostless",
+		.cpu_dai_name	= "AUXPCM_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	/* HDMI Hostless */
+	{
+		.name = "HDMI_RX_HOSTLESS",
+		.stream_name = "HDMI_RX_HOSTLESS",
+		.cpu_dai_name = "HDMI_HOSTLESS",
+		.platform_name = "msm-pcm-hostless",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = "Voice Stub",
+		.stream_name = "Voice Stub",
+		.cpu_dai_name = "VOICE_STUB",
+		.platform_name = "msm-pcm-hostless",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	/* Backend BT/FM DAI Links */
+	{
+		.name = LPASS_BE_INT_BT_SCO_RX,
+		.stream_name = "Internal BT-SCO Playback",
+		.cpu_dai_name = "msm-dai-q6.12288",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name	= "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
+		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_INT_BT_SCO_TX,
+		.stream_name = "Internal BT-SCO Capture",
+		.cpu_dai_name = "msm-dai-q6.12289",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name	= "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
+		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+	},
+	{
+		.name = LPASS_BE_INT_FM_RX,
+		.stream_name = "Internal FM Playback",
+		.cpu_dai_name = "msm-dai-q6.12292",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_FM_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_INT_FM_TX,
+		.stream_name = "Internal FM Capture",
+		.cpu_dai_name = "msm-dai-q6.12293",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_FM_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+	},
+	/* HDMI BACK END DAI Link */
+	{
+		.name = LPASS_BE_HDMI,
+		.stream_name = "HDMI Playback",
+		.cpu_dai_name = "msm-dai-q6-hdmi.8",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_HDMI_RX,
+		.be_hw_params_fixup = msm_hdmi_be_hw_params_fixup,
+	},
+	/* Backend AFE DAI Links */
+	{
+		.name = LPASS_BE_AFE_PCM_RX,
+		.stream_name = "AFE Playback",
+		.cpu_dai_name = "msm-dai-q6.224",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+		.be_hw_params_fixup = msm_proxy_be_hw_params_fixup,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_AFE_PCM_TX,
+		.stream_name = "AFE Capture",
+		.cpu_dai_name = "msm-dai-q6.225",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+		.be_hw_params_fixup = msm_proxy_be_hw_params_fixup,
+	},
+	/* AUX PCM Backend DAI Links */
+	{
+		.name = LPASS_BE_AUXPCM_RX,
+		.stream_name = "AUX PCM Playback",
+		.cpu_dai_name = "msm-dai-q6.2",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+		.ops = &msm_auxpcm_be_ops,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_AUXPCM_TX,
+		.stream_name = "AUX PCM Capture",
+		.cpu_dai_name = "msm-dai-q6.3",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+	},
+};
+
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm_mi2s_dai[
+					 ARRAY_SIZE(msm_dai) +
+					 ARRAY_SIZE(msm_dai_delta_mi2s)];
+
+static struct snd_soc_dai_link msm_slim_dai[
+					 ARRAY_SIZE(msm_dai) +
+					 ARRAY_SIZE(msm_dai_delta_slim)];
+
+static struct snd_soc_card snd_soc_card_msm = {
+	.name		= "apq8064-tabla-snd-card",
+};
+
+static struct platform_device *msm_snd_device;
+
+static int __init msm_audio_init(void)
+{
+
+	int ret;
+	u32	version = socinfo_get_platform_version();
+	if (!machine_is_apq8064_mtp() ||
+	(SOCINFO_VERSION_MINOR(version) != 1)) {
+		pr_info("%s: Not APQ8064 in I2S mode\n", __func__);
+		return -ENODEV;
+	}
+	pr_debug("%s: APQ8064 is in I2S mode\n", __func__);
+	mbhc_cfg.calibration = def_tabla_mbhc_cal();
+	if (!mbhc_cfg.calibration) {
+		pr_err("Calibration data allocation failed\n");
+		return -ENOMEM;
+	}
+
+	msm_snd_device = platform_device_alloc("soc-audio", 0);
+	if (!msm_snd_device) {
+		pr_err("Platform device allocation failed\n");
+		kfree(mbhc_cfg.calibration);
+		return -ENOMEM;
+	}
+
+	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		memcpy(msm_slim_dai, msm_dai, sizeof(msm_dai));
+		memcpy(msm_slim_dai + ARRAY_SIZE(msm_dai),
+			   msm_dai_delta_slim, sizeof(msm_dai_delta_slim));
+		snd_soc_card_msm.dai_link = msm_slim_dai;
+		snd_soc_card_msm.num_links = ARRAY_SIZE(msm_slim_dai);
+		snd_soc_card_msm.controls = tabla_msm_controls;
+		snd_soc_card_msm.num_controls =
+			ARRAY_SIZE(tabla_msm_controls);
+		pr_info("%s: Load Slimbus Dai\n", __func__);
+	} else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) {
+			memcpy(msm_mi2s_dai, msm_dai, sizeof(msm_dai));
+			memcpy(msm_mi2s_dai + ARRAY_SIZE(msm_dai),
+			msm_dai_delta_mi2s, sizeof(msm_dai_delta_mi2s));
+			snd_soc_card_msm.dai_link = msm_mi2s_dai;
+			snd_soc_card_msm.num_links = ARRAY_SIZE(msm_mi2s_dai);
+			snd_soc_card_msm.controls = tabla_msm_mi2s_controls;
+			snd_soc_card_msm.num_controls =
+				ARRAY_SIZE(tabla_msm_mi2s_controls);
+			pr_info("%s: Load MI2S\n", __func__);
+	}
+
+	platform_set_drvdata(msm_snd_device, &snd_soc_card_msm);
+	ret = platform_device_add(msm_snd_device);
+	if (ret) {
+		platform_device_put(msm_snd_device);
+		kfree(mbhc_cfg.calibration);
+		return ret;
+	}
+
+	mutex_init(&cdc_mclk_mutex);
+	atomic_set(&mi2s_rsc_ref, 0);
+	return ret;
+
+}
+module_init(msm_audio_init);
+
+static void __exit msm_audio_exit(void)
+{
+	if (!cpu_is_apq8064() || (socinfo_get_id() == 130)) {
+		pr_err("%s: Not the right machine type\n", __func__);
+		return ;
+	}
+	platform_device_unregister(msm_snd_device);
+	if (mbhc_cfg.gpio)
+		gpio_free(mbhc_cfg.gpio);
+	kfree(mbhc_cfg.calibration);
+	mutex_destroy(&cdc_mclk_mutex);
+}
+module_exit(msm_audio_exit);
+
+MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 4b86f2b..ece0a15 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -2013,7 +2013,7 @@
 	},
 };
 
-struct snd_soc_card snd_soc_card_msm = {
+static struct snd_soc_card snd_soc_card_msm = {
 	.name		= "apq8064-tabla-snd-card",
 	.dai_link	= msm_dai,
 	.num_links	= ARRAY_SIZE(msm_dai),
@@ -2026,9 +2026,10 @@
 static int __init msm_audio_init(void)
 {
 	int ret;
-
-	if (!cpu_is_apq8064() || (socinfo_get_id() == 130)) {
-		pr_err("%s: Not the right machine type\n", __func__);
+	u32	version = socinfo_get_platform_version();
+	if (!cpu_is_apq8064() || (socinfo_get_id() == 130) ||
+		SOCINFO_VERSION_MINOR(version) == 1) {
+		pr_info("%s: Not APQ8064 in SLIMBUS mode\n", __func__);
 		return -ENODEV;
 	}
 
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 3b880ed..be0395b 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -133,7 +133,7 @@
 static int msm_ext_top_spk_pamp;
 static int msm_slim_0_rx_ch = 1;
 static int msm_slim_0_tx_ch = 1;
-static int msm_hdmi_rx_ch = 2;
+static int msm_hdmi_rx_ch = 8;
 
 static struct clk *codec_clk;
 static int clk_users;
@@ -515,14 +515,15 @@
 static const char *spk_function[] = {"Off", "On"};
 static const char *slim0_rx_ch_text[] = {"One", "Two"};
 static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
-static const char *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five", "Six"};
+static const char * const hdmi_rx_ch_text[] = {"Two", "Three", "Four",
+					"Five", "Six", "Seven", "Eight"};
 
 
 static const struct soc_enum msm_enum[] = {
 	SOC_ENUM_SINGLE_EXT(2, spk_function),
 	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
 	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
-	SOC_ENUM_SINGLE_EXT(5, hdmi_rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
 
 };
 
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 5df132b..bb138d3 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -26,6 +26,7 @@
 #include <sound/initval.h>
 #include <sound/control.h>
 #include <sound/q6asm.h>
+#include <sound/pcm_params.h>
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
 #include <linux/android_pmem.h>
@@ -82,7 +83,7 @@
 	.rate_min =	     8000,
 	.rate_max =	     48000,
 	.channels_min =	 1,
-	.channels_max =	 2,
+	.channels_max =	 8,
 	.buffer_bytes_max =     1200 * 1024 * 2,
 	.period_bytes_min =	2400,
 	.period_bytes_max =     1200 * 1024,
@@ -134,8 +135,6 @@
 			break;
 		} else
 			atomic_set(&prtd->pending_buffer, 0);
-		if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
-			break;
 		buf = prtd->audio_client->port[IN].buf;
 		pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
 				__func__, prtd->pcm_count, prtd->out_head);
@@ -197,7 +196,7 @@
 		buf = prtd->audio_client->port[OUT].buf;
 		pr_debug("pcm_irq_pos=%d, buf[0].phys = 0x%X\n",
 				prtd->pcm_irq_pos, (uint32_t)buf[0].phys);
-		read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE ;
+		read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE;
 		read_param.paddr = (unsigned long)(buf[0].phys) +
 			prtd->pcm_irq_pos + COMPRE_CAPTURE_HEADER_SIZE;
 		prtd->pcm_irq_pos += prtd->pcm_count;
@@ -427,6 +426,7 @@
 	struct compr_audio *compr = runtime->private_data;
 	struct msm_audio *prtd = &compr->prtd;
 	struct audio_buffer *buf = prtd->audio_client->port[OUT].buf;
+	struct snd_codec *codec = &compr->info.codec_param.codec;
 	struct audio_aio_read_param read_param;
 	int ret = 0;
 	int i;
@@ -441,6 +441,21 @@
 	if (prtd->enabled)
 		return ret;
 	read_param.len = prtd->pcm_count;
+
+	switch (codec->id) {
+	case SND_AUDIOCODEC_AMRWB:
+		pr_debug("SND_AUDIOCODEC_AMRWB\n");
+		ret = q6asm_enc_cfg_blk_amrwb(prtd->audio_client,
+			MAX_NUM_FRAMES_PER_BUFFER,
+			codec->options.generic.reserved[0] /*bitrate 0-8*/,
+			codec->options.generic.reserved[1] /*dtx mode 0/1*/);
+		if (ret < 0)
+			pr_err("%s: CMD Format block" \
+				"failed: %d\n", __func__, ret);
+		break;
+	default:
+		pr_debug("No config for codec %d\n", codec->id);
+	}
 	pr_debug("%s: Samp_rate = %d, Channel = %d, pcm_size = %d,\n"
 			 "pcm_count = %d, periods = %d\n",
 			 __func__, prtd->samp_rate, prtd->channel_mode,
@@ -448,8 +463,24 @@
 
 	for (i = 0; i < runtime->periods; i++) {
 		read_param.uid = i;
-		read_param.paddr = (unsigned long)(buf[i].phys);
-		q6asm_async_read_compressed(prtd->audio_client, &read_param);
+		switch (codec->id) {
+		case SND_AUDIOCODEC_AMRWB:
+			read_param.len = prtd->pcm_count
+					- COMPRE_CAPTURE_HEADER_SIZE;
+			read_param.paddr = (unsigned long)(buf[i].phys)
+					+ COMPRE_CAPTURE_HEADER_SIZE;
+			pr_debug("Push buffer [%d] to DSP, "\
+					"paddr: %p, vaddr: %p\n",
+					i, (void *) read_param.paddr,
+					buf[i].data);
+			q6asm_async_read(prtd->audio_client, &read_param);
+			break;
+		default:
+			read_param.paddr = (unsigned long)(buf[i].phys);
+			q6asm_async_read_compressed(prtd->audio_client,
+				&read_param);
+			break;
+		}
 	}
 	prtd->periods = runtime->periods;
 
@@ -481,9 +512,16 @@
 					1);
 			}
 		} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			msm_pcm_routing_reg_psthr_stream(
-				soc_prtd->dai_link->be_id,
-				prtd->session_id, substream->stream, 1);
+			switch (compr->info.codec_param.codec.id) {
+			case SND_AUDIOCODEC_AMRWB:
+				break;
+			default:
+				msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream,
+					1);
+				break;
+			}
 		}
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -502,10 +540,16 @@
 					0);
 			}
 		} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			msm_pcm_routing_reg_psthr_stream(
-				soc_prtd->dai_link->be_id,
-				prtd->session_id, substream->stream,
-				0);
+			switch (compr->info.codec_param.codec.id) {
+			case SND_AUDIOCODEC_AMRWB:
+				break;
+			default:
+				msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream,
+					0);
+				break;
+			}
 		}
 		atomic_set(&prtd->start, 0);
 		break;
@@ -543,7 +587,7 @@
 	compr->info.compr_cap.codecs[7] = SND_AUDIOCODEC_DTS_PASS_THROUGH;
 	compr->info.compr_cap.codecs[8] = SND_AUDIOCODEC_AMRWB;
 	compr->info.compr_cap.codecs[9] = SND_AUDIOCODEC_AMRWBPLUS;
-	/* Add new codecs here */
+	/* Add new codecs here and update num_codecs*/
 }
 
 static int msm_compr_open(struct snd_pcm_substream *substream)
@@ -799,9 +843,29 @@
 			break;
 		}
 	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-		ret = q6asm_open_read_compressed(prtd->audio_client,
-					MAX_NUM_FRAMES_PER_BUFFER,
-					COMPRESSED_META_DATA_MODE);
+		switch (compr->info.codec_param.codec.id) {
+		case SND_AUDIOCODEC_AMRWB:
+			pr_debug("q6asm_open_read(FORMAT_AMRWB)\n");
+			ret = q6asm_open_read(prtd->audio_client,
+				FORMAT_AMRWB);
+			if (ret < 0) {
+				pr_err("%s: compressed Session out open failed\n",
+					__func__);
+				return -ENOMEM;
+			}
+			pr_debug("msm_pcm_routing_reg_phy_stream\n");
+			msm_pcm_routing_reg_phy_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->audio_client->perf_mode,
+					prtd->session_id, substream->stream);
+			break;
+		default:
+			pr_debug("q6asm_open_read_compressed(COMPRESSED_META_DATA_MODE)\n");
+			ret = q6asm_open_read_compressed(prtd->audio_client,
+				MAX_NUM_FRAMES_PER_BUFFER,
+				COMPRESSED_META_DATA_MODE);
+			break;
+		}
 
 		if (ret < 0) {
 			pr_err("%s: compressed Session out open failed\n",
@@ -809,12 +873,23 @@
 			return -ENOMEM;
 		}
 	}
+
 	ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
 	if (ret < 0) {
 		pr_err("%s: Set IO mode failed\n", __func__);
 		return -ENOMEM;
 	}
-
+	/* Modifying kernel hardware params based on userspace config */
+	if (params_periods(params) > 0 &&
+		(params_periods(params) != runtime->hw.periods_max)) {
+		runtime->hw.periods_max = params_periods(params);
+	}
+	if (params_period_bytes(params) > 0 &&
+		(params_period_bytes(params) != runtime->hw.period_bytes_min)) {
+		runtime->hw.period_bytes_min = params_period_bytes(params);
+	}
+	runtime->hw.buffer_bytes_max =
+			runtime->hw.period_bytes_min * runtime->hw.periods_max;
 	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
 			prtd->audio_client,
 			runtime->hw.period_bytes_min,
@@ -944,15 +1019,23 @@
 		}
 		return 0;
 	case SNDRV_PCM_IOCTL1_RESET:
-		prtd->cmd_ack = 0;
-		rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
-		if (rc < 0)
-			pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
-		rc = wait_event_timeout(the_locks.eos_wait,
-			prtd->cmd_ack, 5 * HZ);
-		if (rc < 0)
-			pr_err("Flush cmd timeout\n");
-		prtd->pcm_irq_pos = 0;
+		pr_debug("SNDRV_PCM_IOCTL1_RESET\n");
+		/* Flush only when session is started during CAPTURE,
+		   while PLAYBACK has no such restriction. */
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+			  (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
+						atomic_read(&prtd->start))) {
+			prtd->cmd_ack = 0;
+			rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+			if (rc < 0)
+				pr_err("%s: flush cmd failed rc=%d\n",
+						__func__, rc);
+			rc = wait_event_timeout(the_locks.eos_wait,
+					prtd->cmd_ack, 5 * HZ);
+			if (rc < 0)
+				pr_err("Flush cmd timeout\n");
+			prtd->pcm_irq_pos = 0;
+		}
 		break;
 	default:
 		break;
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 011ff29..011912e 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -82,7 +82,7 @@
 					SNDRV_PCM_RATE_KNOT),
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
-			.channels_max = 6,
+			.channels_max = 8,
 			.rate_min =     8000,
 			.rate_max =	48000,
 		},
@@ -173,7 +173,7 @@
 					SNDRV_PCM_RATE_KNOT),
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
-			.channels_max = 6,
+			.channels_max = 8,
 			.rate_min =	8000,
 			.rate_max = 48000,
 		},
diff --git a/sound/soc/msm/msm-dai-q6-hdmi.c b/sound/soc/msm/msm-dai-q6-hdmi.c
index c082ed7..2b3dd5f 100644
--- a/sound/soc/msm/msm-dai-q6-hdmi.c
+++ b/sound/soc/msm/msm-dai-q6-hdmi.c
@@ -111,6 +111,13 @@
 		dai_data->port_config.hdmi_multi_ch.channel_allocation =
 				channel_allocation;
 		break;
+	case 8:
+		channel_allocation  = 0x1F;
+		hdmi_msm_audio_info_setup(1, MSM_HDMI_AUDIO_CHANNEL_8,
+				channel_allocation, level_shift, down_mix);
+		dai_data->port_config.hdmi_multi_ch.channel_allocation =
+				channel_allocation;
+		break;
 	default:
 		dev_err(dai->dev, "invalid Channels = %u\n",
 				dai_data->channels);
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index 89b709f..ee1ab79 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -465,6 +465,9 @@
 	dai_data->channels = params_channels(params);
 	switch (dai_data->channels) {
 	case 2:
+	case 4:
+	case 6:
+	case 8:
 		dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
 		break;
 	case 1:
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index a13d4da..10b8f7a 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -83,7 +83,7 @@
 	.rate_min =             8000,
 	.rate_max =             48000,
 	.channels_min =         1,
-	.channels_max =         6,
+	.channels_max =         8,
 	.buffer_bytes_max =     PLAYBACK_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
 	.period_bytes_min =     PLAYBACK_MIN_PERIOD_SIZE,
 	.period_bytes_max =     PLAYBACK_MAX_PERIOD_SIZE,
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 374357d..6456b2a 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1302,6 +1302,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[] = {
@@ -1317,6 +1320,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[] = {
@@ -1332,6 +1338,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[] = {
@@ -1347,6 +1356,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 sec_auxpcm_rx_mixer_controls[] = {
@@ -1407,6 +1419,18 @@
 	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),
 };
 
 
@@ -1414,6 +1438,9 @@
 	SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer)
 };
 
 static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
@@ -2322,12 +2349,14 @@
 	{"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"},
 
 	{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
 	{"MultiMedia1 Mixer", "MI2S_TX", "MI2S_TX"},
 	{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
 	{"MultiMedia4 Mixer", "MI2S_TX", "MI2S_TX"},
+	{"MultiMedia4 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
 	{"MultiMedia1 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
@@ -2336,24 +2365,30 @@
 	{"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"},
@@ -2364,6 +2399,7 @@
 	{"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"},
 
 	{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index a577b6a..c8d4b02 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -38,6 +38,7 @@
 #define SPK_AMP_POS	0x1
 #define SPK_AMP_NEG	0x2
 #define SPKR_BOOST_GPIO 15
+#define LEFT_SPKR_AMPL_GPIO 15
 #define DEFAULT_PMIC_SPK_GAIN 0x0D
 #define SITAR_EXT_CLK_RATE 12288000
 
@@ -121,6 +122,24 @@
 	return 1;
 }
 
+static int msm8930_cfg_spkr_gpio(int gpio,
+		int enable, const char *gpio_label)
+{
+	int ret = 0;
+
+	pr_debug("%s: Configure %s GPIO %u",
+		__func__, gpio_label, gpio);
+	ret = gpio_request(gpio, gpio_label);
+	if (ret)
+		return ret;
+
+	pr_debug("%s: Enable %s gpio %u\n",
+		__func__, gpio_label, gpio);
+	gpio_direction_output(gpio, enable);
+
+	return ret;
+}
+
 static void msm8960_ext_spk_power_amp_on(u32 spk)
 {
 	int ret = 0;
@@ -139,24 +158,30 @@
 		if ((msm8930_ext_spk_pamp & SPK_AMP_POS) &&
 			(msm8930_ext_spk_pamp & SPK_AMP_NEG)) {
 
-			if (machine_is_msm8930_mtp()
-				|| machine_is_msm8930_fluid()) {
-				pr_debug("%s: Configure Speaker Boost GPIO %u",
-						__func__, SPKR_BOOST_GPIO);
-				ret = gpio_request(SPKR_BOOST_GPIO,
-								   "SPKR_BOOST_EN");
+			if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917) {
+				ret = msm8930_cfg_spkr_gpio(
+						LEFT_SPKR_AMPL_GPIO,
+						1, "LEFT_SPKR_AMPL");
 				if (ret) {
-					pr_err("%s: Failed to configure speaker boost "
-					"gpio %u\n", __func__, SPKR_BOOST_GPIO);
+					pr_err("%s: Failed to config ampl gpio %u\n",
+						__func__, LEFT_SPKR_AMPL_GPIO);
 					return;
 				}
+			} else {
 
-				pr_debug("%s: Enable Speaker boost gpio %u\n",
-					__func__, SPKR_BOOST_GPIO);
-				gpio_direction_output(SPKR_BOOST_GPIO, 1);
+				if (machine_is_msm8930_mtp()
+					|| machine_is_msm8930_fluid()) {
+					ret = msm8930_cfg_spkr_gpio(
+					  SPKR_BOOST_GPIO, 1, "SPKR_BOOST");
+					if (ret) {
+						pr_err("%s: Failure: spkr boost gpio %u\n",
+						  __func__, SPKR_BOOST_GPIO);
+						return;
+					}
+				}
+				pm8xxx_spk_enable(MSM8930_SPK_ON);
 			}
 
-			pm8xxx_spk_enable(MSM8930_SPK_ON);
 			pr_debug("%s: slepping 4 ms after turning on external "
 				" Left Speaker Ampl\n", __func__);
 			usleep_range(4000, 4000);
@@ -175,6 +200,13 @@
 	if (spk & (SPK_AMP_POS | SPK_AMP_NEG)) {
 		if (!msm8930_ext_spk_pamp)
 			return;
+
+		if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917) {
+			gpio_free(LEFT_SPKR_AMPL_GPIO);
+			msm8930_ext_spk_pamp = 0;
+			return;
+		}
+
 		if (machine_is_msm8930_mtp()
 			|| machine_is_msm8930_fluid()) {
 			pr_debug("%s: Free speaker boost gpio %u\n",
@@ -463,7 +495,8 @@
 {
 	int ret = 0;
 	msm8930_pmic_spk_gain = ucontrol->value.integer.value[0];
-	ret = pm8xxx_spk_gain(msm8930_pmic_spk_gain);
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+		ret = pm8xxx_spk_gain(msm8930_pmic_spk_gain);
 	pr_debug("%s: msm8930_pmic_spk_gain = %d"
 			 " ucontrol->value.integer.value[0] = %d\n", __func__,
 			 msm8930_pmic_spk_gain,
@@ -660,8 +693,10 @@
 	mbhc_cfg.gpio_irq = gpio_to_irq(mbhc_cfg.gpio);
 	sitar_hs_detect(codec, &mbhc_cfg);
 
-	/* Initialize default PMIC speaker gain */
-	pm8xxx_spk_gain(DEFAULT_PMIC_SPK_GAIN);
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
+		/* Initialize default PMIC speaker gain */
+		pm8xxx_spk_gain(DEFAULT_PMIC_SPK_GAIN);
+	}
 
 	return 0;
 }
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 545a5b9..45b69ea 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -954,7 +954,7 @@
 	},
 };
 
-struct snd_soc_card snd_soc_card_msm = {
+static struct snd_soc_card snd_soc_card_msm = {
 	.name		= "msm8974-taiko-snd-card",
 	.dai_link	= msm_dai,
 	.num_links	= ARRAY_SIZE(msm_dai),
@@ -976,7 +976,7 @@
 
 	mutex_init(&cdc_mclk_mutex);
 	if (!machine_is_msm8974_sim()) {
-		pr_err("%s: Not the right machine type\n", __func__);
+		pr_info("%s: Not msm8974 machine type\n", __func__);
 		return -ENODEV;
 	}
 	msm_snd_device = platform_device_alloc("soc-audio", 0);