Merge "radio-iris: Configure repeat count for PS string"
diff --git a/Documentation/devicetree/bindings/pil/pil-pronto.txt b/Documentation/devicetree/bindings/pil/pil-pronto.txt
index 199862f..85ccc5d 100644
--- a/Documentation/devicetree/bindings/pil/pil-pronto.txt
+++ b/Documentation/devicetree/bindings/pil/pil-pronto.txt
@@ -14,6 +14,7 @@
 - vdd_pronto_pll-supply: regulator to supply pronto pll.
 - qcom,firmware-name: Base name of the firmware image. Ex. "wcnss"
 - qcom,gpio-err-fatal: GPIO used by the wcnss to indicate error fatal to the Apps.
+- qcom,gpio-err-ready: GPIO used by the wcnss to indicate error ready to the Apps.
 - qcom,gpio-proxy-unvote: GPIO used by the wcnss to trigger proxy unvoting in
   the Apps
 - qcom,gpio-force-stop: GPIO used by the Apps to force the wcnss to shutdown.
@@ -32,6 +33,7 @@
 
 		/* GPIO input from wcnss */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+		qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
 		qcom,proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
 
 		/* GPIO output to wcnss */
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 2d20794..c3d929c 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -17,6 +17,7 @@
 - vdd_mx-supply:      Reference to the regulator that supplies the memory rail.
 - qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
 - qcom,gpio-err-fatal: GPIO used by the modem to indicate error fatal to the apps.
+- qcom,gpio-err-ready: GPIO used by the modem to indicate error ready to the apps.
 - qcom,gpio-proxy-unvote: GPIO used by the modem to trigger proxy unvoting in
   the apps.
 - qcom,gpio-force-stop: GPIO used by the apps to force the modem to shutdown.
@@ -49,6 +50,7 @@
 
 		/* GPIO inputs from mss */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+		qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
 		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
 
 		/* GPIO output to mss */
diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
index eb62ea1..f2cfe34 100644
--- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
@@ -11,9 +11,10 @@
 
 Optional properties:
  - parent-supply:   phandle to the parent supply/regulator node
- - qcom,retain-mems: For Oxili GDSCs only: Presence currently denotes a hardware
-		     requirement to assert the forced memory retention signals
-		     in the core's clock branch control register.
+ - qcom,clock-names: List of string names for core clocks
+ - qcom,retain-mems: Presence denotes a hardware requirement to leave the
+		     forced memory retention signals in the core's clock
+		     branch control register asserted.
 
 Example:
 	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
@@ -21,4 +22,5 @@
 		regulator-name = "gdsc_oxili_gx";
 		parent-supply = <&pm8841_s4>;
 		reg = <0xfd8c4024 0x4>;
+		qcom,clock-names = "core_clk";
 	};
diff --git a/arch/arm/boot/dts/apq8084-sim.dts b/arch/arm/boot/dts/apq8084-sim.dts
index 93803dbe..ebcca1b 100644
--- a/arch/arm/boot/dts/apq8084-sim.dts
+++ b/arch/arm/boot/dts/apq8084-sim.dts
@@ -165,3 +165,7 @@
 	mpp@a700 { /* MPP 8 */
 	};
 };
+
+&usb3 {
+	qcom,skip-charger-detection;
+};
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index bc6f030..95b1c8f 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -126,6 +126,37 @@
 		interrupt-controller;
 		#interrupt-cells = <3>;
 	};
+
+	usb3: qcom,ssusb@f9200000 {
+		compatible = "qcom,dwc-usb3-msm";
+		reg = <0xf9200000 0xfc000>,
+			 <0xfd4ab000 0x4>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		interrupts = <0 133 0>;
+		interrupt-names = "hs_phy_irq";
+		ssusb_vdd_dig-supply = <&pma8084_s1>;
+		SSUSB_1p8-supply = <&pma8084_l6>;
+		hsusb_vdd_dig-supply = <&pma8084_s1>;
+		HSUSB_1p8-supply = <&pma8084_l6>;
+		HSUSB_3p3-supply = <&pma8084_l24>;
+		qcom,dwc-usb3-msm-dbm-eps = <4>;
+		qcom,vdd-voltage-level = <0 900000 1050000>;
+
+		dwc3@f9200000 {
+			compatible = "synopsys,dwc3";
+			reg = <0xf9200000 0xfc000>;
+			interrupt-parent = <&intc>;
+			interrupts = <0 131 0>, <0 179 0>;
+			interrupt-names = "irq", "otg_irq";
+			tx-fifo-resize;
+		};
+	};
+
+	android_usb {
+		compatible = "qcom,android-usb";
+	};
 };
 
 /include/ "msm-pma8084.dtsi"
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
new file mode 100644
index 0000000..7942567
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
@@ -0,0 +1,530 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	qcom,mdss_dsi_nt35590_720p_cmd {
+		compatible = "qcom,mdss-dsi-panel";
+		label = "nt35590 720p command mode dsi panel";
+		status = "disable";
+		qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+		qcom,rst-gpio = <&msmgpio 25 0>;
+		qcom,te-gpio = <&msmgpio 24 0>;
+		qcom,mdss-pan-res = <720 1280>;
+		qcom,mdss-pan-bpp = <24>;
+		qcom,mdss-pan-dest = "display_1";
+		qcom,mdss-pan-porch-values = <164 8 140 1 1 6>;
+		qcom,mdss-pan-underflow-clr = <0xff>;
+		qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+		qcom,mdss-pan-bl-levels = <1 4095>;
+		qcom,mdss-pan-dsi-mode = <1>;
+		qcom,mdss-vsync-enable = <1>;
+		qcom,mdss-hw-vsync-mode = <1>;
+		qcom,mdss-pan-dsi-h-pulse-mode = <1>;
+		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 = <2>;
+		qcom,mdss-pan-dsi-dst-format = <8>;
+		qcom,mdss-pan-insert-dcs-cmd = <1>;
+		qcom,mdss-pan-wr-mem-continue = <0x3c>;
+		qcom,mdss-pan-wr-mem-start = <0x2c>;
+		qcom,mdss-pan-te-sel = <1>;
+		qcom,mdss-pan-dsi-vc = <0>;
+		qcom,mdss-pan-dsi-rgb-swap = <0>;
+		qcom,mdss-pan-dsi-data-lanes = <1 1 1 1>; /* 4 lanes */
+		qcom,mdss-pan-dsi-dlane-swap = <0>;
+		qcom,mdss-pan-dsi-t-clk = <0x2c 0x20>;
+		qcom,mdss-pan-dsi-stream = <0>;
+		qcom,mdss-pan-dsi-mdp-tr = <0x0>;
+		qcom,mdss-pan-dsi-dma-tr = <0x04>;
+		qcom,mdss-pan-dsi-frame-rate = <60>;
+		qcom,panel-phy-regulatorSettings = [07 09 03 00  /* Regualotor settings */
+						    20 00 01];
+		qcom,panel-phy-timingSettings = [7d 25 1d 00 37 33
+						    22 27 1e 03 04 00];
+		qcom,panel-phy-strengthCtrl = [ff 06];
+		qcom,panel-phy-bistCtrl = [00 00 b1 ff           /* BIST Ctrl settings */
+					   00 00];
+		qcom,panel-phy-laneConfig = [00 00 00 00 00 00 00 01 97 /* lane0 config */
+					     00 00 00 00 05 00 00 01 97 /* lane1 config */
+					     00 00 00 00 0a 00 00 01 97 /* lane2 config */
+					     00 00 00 00 0f 00 00 01 97 /* lane3 config */
+					     00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
+		qcom,panel-on-cmds = [29 01 00 00 00 02 FF EE
+					29 01 00 00 00 02 26 08
+					29 01 00 00 00 02 26 00
+					29 01 00 00 10 02 FF 00
+					29 01 00 00 00 02 BA 03
+					29 01 00 00 00 02 C2 08
+					29 01 00 00 00 02 FF 01
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 00 4A
+					29 01 00 00 00 02 01 33
+					29 01 00 00 00 02 02 53
+					29 01 00 00 00 02 03 55
+					29 01 00 00 00 02 04 55
+					29 01 00 00 00 02 05 33
+					29 01 00 00 00 02 06 22
+					29 01 00 00 00 02 08 56
+					29 01 00 00 00 02 09 8F
+					29 01 00 00 00 02 36 73
+					29 01 00 00 00 02 0B 9F
+					29 01 00 00 00 02 0C 9F
+					29 01 00 00 00 02 0D 2F
+					29 01 00 00 00 02 0E 24
+					29 01 00 00 00 02 11 83
+					29 01 00 00 00 02 12 03
+					29 01 00 00 00 02 71 2C
+					29 01 00 00 00 02 6F 03
+					29 01 00 00 00 02 0F 0A
+					29 01 00 00 00 02 FF 05
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 01 00
+					29 01 00 00 00 02 02 8B
+					29 01 00 00 00 02 03 82
+					29 01 00 00 00 02 04 82
+					29 01 00 00 00 02 05 30
+					29 01 00 00 00 02 06 33
+					29 01 00 00 00 02 07 01
+					29 01 00 00 00 02 08 00
+					29 01 00 00 00 02 09 46
+					29 01 00 00 00 02 0A 46
+					29 01 00 00 00 02 0D 0B
+					29 01 00 00 00 02 0E 1D
+					29 01 00 00 00 02 0F 08
+					29 01 00 00 00 02 10 53
+					29 01 00 00 00 02 11 00
+					29 01 00 00 00 02 12 00
+					29 01 00 00 00 02 14 01
+					29 01 00 00 00 02 15 00
+					29 01 00 00 00 02 16 05
+					29 01 00 00 00 02 17 00
+					29 01 00 00 00 02 19 7F
+					29 01 00 00 00 02 1A FF
+					29 01 00 00 00 02 1B 0F
+					29 01 00 00 00 02 1C 00
+					29 01 00 00 00 02 1D 00
+					29 01 00 00 00 02 1E 00
+					29 01 00 00 00 02 1F 07
+					29 01 00 00 00 02 20 00
+					29 01 00 00 00 02 21 06
+					29 01 00 00 00 02 22 55
+					29 01 00 00 00 02 23 4D
+					29 01 00 00 00 02 2D 02
+					29 01 00 00 00 02 28 01
+					29 01 00 00 00 02 2F 02
+					29 01 00 00 00 02 83 01
+					29 01 00 00 00 02 9E 58
+					29 01 00 00 00 02 9F 6A
+					29 01 00 00 00 02 A0 01
+					29 01 00 00 00 02 A2 10
+					29 01 00 00 00 02 BB 0A
+					29 01 00 00 00 02 BC 0A
+					29 01 00 00 00 02 32 08
+					29 01 00 00 00 02 33 B8
+					29 01 00 00 00 02 36 01
+					29 01 00 00 00 02 37 00
+					29 01 00 00 00 02 43 00
+					29 01 00 00 00 02 4B 21
+					29 01 00 00 00 02 4C 03
+					29 01 00 00 00 02 50 21
+					29 01 00 00 00 02 51 03
+					29 01 00 00 00 02 58 21
+					29 01 00 00 00 02 59 03
+					29 01 00 00 00 02 5D 21
+					29 01 00 00 00 02 5E 03
+					29 01 00 00 00 02 6C 00
+					29 01 00 00 00 02 6D 00
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 FF 01
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 75 00
+					29 01 00 00 00 02 76 7D
+					29 01 00 00 00 02 77 00
+					29 01 00 00 00 02 78 8A
+					29 01 00 00 00 02 79 00
+					29 01 00 00 00 02 7A 9C
+					29 01 00 00 00 02 7B 00
+					29 01 00 00 00 02 7C B1
+					29 01 00 00 00 02 7D 00
+					29 01 00 00 00 02 7E BF
+					29 01 00 00 00 02 7F 00
+					29 01 00 00 00 02 80 CF
+					29 01 00 00 00 02 81 00
+					29 01 00 00 00 02 82 DD
+					29 01 00 00 00 02 83 00
+					29 01 00 00 00 02 84 E8
+					29 01 00 00 00 02 85 00
+					29 01 00 00 00 02 86 F2
+					29 01 00 00 00 02 87 01
+					29 01 00 00 00 02 88 1F
+					29 01 00 00 00 02 89 01
+					29 01 00 00 00 02 8A 41
+					29 01 00 00 00 02 8B 01
+					29 01 00 00 00 02 8C 78
+					29 01 00 00 00 02 8D 01
+					29 01 00 00 00 02 8E A5
+					29 01 00 00 00 02 8F 01
+					29 01 00 00 00 02 90 EE
+					29 01 00 00 00 02 91 02
+					29 01 00 00 00 02 92 29
+					29 01 00 00 00 02 93 02
+					29 01 00 00 00 02 94 2A
+					29 01 00 00 00 02 95 02
+					29 01 00 00 00 02 96 5D
+					29 01 00 00 00 02 97 02
+					29 01 00 00 00 02 98 93
+					29 01 00 00 00 02 99 02
+					29 01 00 00 00 02 9A B8
+					29 01 00 00 00 02 9B 02
+					29 01 00 00 00 02 9C E7
+					29 01 00 00 00 02 9D 03
+					29 01 00 00 00 02 9E 07
+					29 01 00 00 00 02 9F 03
+					29 01 00 00 00 02 A0 37
+					29 01 00 00 00 02 A2 03
+					29 01 00 00 00 02 A3 46
+					29 01 00 00 00 02 A4 03
+					29 01 00 00 00 02 A5 56
+					29 01 00 00 00 02 A6 03
+					29 01 00 00 00 02 A7 66
+					29 01 00 00 00 02 A9 03
+					29 01 00 00 00 02 AA 7A
+					29 01 00 00 00 02 AB 03
+					29 01 00 00 00 02 AC 93
+					29 01 00 00 00 02 AD 03
+					29 01 00 00 00 02 AE A3
+					29 01 00 00 00 02 AF 03
+					29 01 00 00 00 02 B0 B4
+					29 01 00 00 00 02 B1 03
+					29 01 00 00 00 02 B2 CB
+					29 01 00 00 00 02 B3 00
+					29 01 00 00 00 02 B4 7D
+					29 01 00 00 00 02 B5 00
+					29 01 00 00 00 02 B6 8A
+					29 01 00 00 00 02 B7 00
+					29 01 00 00 00 02 B8 9C
+					29 01 00 00 00 02 B9 00
+					29 01 00 00 00 02 BA B1
+					29 01 00 00 00 02 BB 00
+					29 01 00 00 00 02 BC BF
+					29 01 00 00 00 02 BD 00
+					29 01 00 00 00 02 BE CF
+					29 01 00 00 00 02 BF 00
+					29 01 00 00 00 02 C0 DD
+					29 01 00 00 00 02 C1 00
+					29 01 00 00 00 02 C2 E8
+					29 01 00 00 00 02 C3 00
+					29 01 00 00 00 02 C4 F2
+					29 01 00 00 00 02 C5 01
+					29 01 00 00 00 02 C6 1F
+					29 01 00 00 00 02 C7 01
+					29 01 00 00 00 02 C8 41
+					29 01 00 00 00 02 C9 01
+					29 01 00 00 00 02 CA 78
+					29 01 00 00 00 02 CB 01
+					29 01 00 00 00 02 CC A5
+					29 01 00 00 00 02 CD 01
+					29 01 00 00 00 02 CE EE
+					29 01 00 00 00 02 CF 02
+					29 01 00 00 00 02 D0 29
+					29 01 00 00 00 02 D1 02
+					29 01 00 00 00 02 D2 2A
+					29 01 00 00 00 02 D3 02
+					29 01 00 00 00 02 D4 5D
+					29 01 00 00 00 02 D5 02
+					29 01 00 00 00 02 D6 93
+					29 01 00 00 00 02 D7 02
+					29 01 00 00 00 02 D8 B8
+					29 01 00 00 00 02 D9 02
+					29 01 00 00 00 02 DA E7
+					29 01 00 00 00 02 DB 03
+					29 01 00 00 00 02 DC 07
+					29 01 00 00 00 02 DD 03
+					29 01 00 00 00 02 DE 37
+					29 01 00 00 00 02 DF 03
+					29 01 00 00 00 02 E0 46
+					29 01 00 00 00 02 E1 03
+					29 01 00 00 00 02 E2 56
+					29 01 00 00 00 02 E3 03
+					29 01 00 00 00 02 E4 66
+					29 01 00 00 00 02 E5 03
+					29 01 00 00 00 02 E6 7A
+					29 01 00 00 00 02 E7 03
+					29 01 00 00 00 02 E8 93
+					29 01 00 00 00 02 E9 03
+					29 01 00 00 00 02 EA A3
+					29 01 00 00 00 02 EB 03
+					29 01 00 00 00 02 EC B4
+					29 01 00 00 00 02 ED 03
+					29 01 00 00 00 02 EE CB
+					29 01 00 00 00 02 EF 00
+					29 01 00 00 00 02 F0 ED
+					29 01 00 00 00 02 F1 00
+					29 01 00 00 00 02 F2 F3
+					29 01 00 00 00 02 F3 00
+					29 01 00 00 00 02 F4 FE
+					29 01 00 00 00 02 F5 01
+					29 01 00 00 00 02 F6 09
+					29 01 00 00 00 02 F7 01
+					29 01 00 00 00 02 F8 13
+					29 01 00 00 00 02 F9 01
+					29 01 00 00 00 02 FA 1D
+					29 01 00 00 00 02 FF 02
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 00 01
+					29 01 00 00 00 02 01 26
+					29 01 00 00 00 02 02 01
+					29 01 00 00 00 02 03 2F
+					29 01 00 00 00 02 04 01
+					29 01 00 00 00 02 05 37
+					29 01 00 00 00 02 06 01
+					29 01 00 00 00 02 07 56
+					29 01 00 00 00 02 08 01
+					29 01 00 00 00 02 09 70
+					29 01 00 00 00 02 0A 01
+					29 01 00 00 00 02 0B 9D
+					29 01 00 00 00 02 0C 01
+					29 01 00 00 00 02 0D C2
+					29 01 00 00 00 02 0E 01
+					29 01 00 00 00 02 0F FF
+					29 01 00 00 00 02 10 02
+					29 01 00 00 00 02 11 31
+					29 01 00 00 00 02 12 02
+					29 01 00 00 00 02 13 32
+					29 01 00 00 00 02 14 02
+					29 01 00 00 00 02 15 60
+					29 01 00 00 00 02 16 02
+					29 01 00 00 00 02 17 94
+					29 01 00 00 00 02 18 02
+					29 01 00 00 00 02 19 B5
+					29 01 00 00 00 02 1A 02
+					29 01 00 00 00 02 1B E3
+					29 01 00 00 00 02 1C 03
+					29 01 00 00 00 02 1D 03
+					29 01 00 00 00 02 1E 03
+					29 01 00 00 00 02 1F 2D
+					29 01 00 00 00 02 20 03
+					29 01 00 00 00 02 21 3A
+					29 01 00 00 00 02 22 03
+					29 01 00 00 00 02 23 48
+					29 01 00 00 00 02 24 03
+					29 01 00 00 00 02 25 57
+					29 01 00 00 00 02 26 03
+					29 01 00 00 00 02 27 68
+					29 01 00 00 00 02 28 03
+					29 01 00 00 00 02 29 7B
+					29 01 00 00 00 02 2A 03
+					29 01 00 00 00 02 2B 90
+					29 01 00 00 00 02 2D 03
+					29 01 00 00 00 02 2F A0
+					29 01 00 00 00 02 30 03
+					29 01 00 00 00 02 31 CB
+					29 01 00 00 00 02 32 00
+					29 01 00 00 00 02 33 ED
+					29 01 00 00 00 02 34 00
+					29 01 00 00 00 02 35 F3
+					29 01 00 00 00 02 36 00
+					29 01 00 00 00 02 37 FE
+					29 01 00 00 00 02 38 01
+					29 01 00 00 00 02 39 09
+					29 01 00 00 00 02 3A 01
+					29 01 00 00 00 02 3B 13
+					29 01 00 00 00 02 3D 01
+					29 01 00 00 00 02 3F 1D
+					29 01 00 00 00 02 40 01
+					29 01 00 00 00 02 41 26
+					29 01 00 00 00 02 42 01
+					29 01 00 00 00 02 43 2F
+					29 01 00 00 00 02 44 01
+					29 01 00 00 00 02 45 37
+					29 01 00 00 00 02 46 01
+					29 01 00 00 00 02 47 56
+					29 01 00 00 00 02 48 01
+					29 01 00 00 00 02 49 70
+					29 01 00 00 00 02 4A 01
+					29 01 00 00 00 02 4B 9D
+					29 01 00 00 00 02 4C 01
+					29 01 00 00 00 02 4D C2
+					29 01 00 00 00 02 4E 01
+					29 01 00 00 00 02 4F FF
+					29 01 00 00 00 02 50 02
+					29 01 00 00 00 02 51 31
+					29 01 00 00 00 02 52 02
+					29 01 00 00 00 02 53 32
+					29 01 00 00 00 02 54 02
+					29 01 00 00 00 02 55 60
+					29 01 00 00 00 02 56 02
+					29 01 00 00 00 02 58 94
+					29 01 00 00 00 02 59 02
+					29 01 00 00 00 02 5A B5
+					29 01 00 00 00 02 5B 02
+					29 01 00 00 00 02 5C E3
+					29 01 00 00 00 02 5D 03
+					29 01 00 00 00 02 5E 03
+					29 01 00 00 00 02 5F 03
+					29 01 00 00 00 02 60 2D
+					29 01 00 00 00 02 61 03
+					29 01 00 00 00 02 62 3A
+					29 01 00 00 00 02 63 03
+					29 01 00 00 00 02 64 48
+					29 01 00 00 00 02 65 03
+					29 01 00 00 00 02 66 57
+					29 01 00 00 00 02 67 03
+					29 01 00 00 00 02 68 68
+					29 01 00 00 00 02 69 03
+					29 01 00 00 00 02 6A 7B
+					29 01 00 00 00 02 6B 03
+					29 01 00 00 00 02 6C 90
+					29 01 00 00 00 02 6D 03
+					29 01 00 00 00 02 6E A0
+					29 01 00 00 00 02 6F 03
+					29 01 00 00 00 02 70 CB
+					29 01 00 00 00 02 71 00
+					29 01 00 00 00 02 72 19
+					29 01 00 00 00 02 73 00
+					29 01 00 00 00 02 74 36
+					29 01 00 00 00 02 75 00
+					29 01 00 00 00 02 76 55
+					29 01 00 00 00 02 77 00
+					29 01 00 00 00 02 78 70
+					29 01 00 00 00 02 79 00
+					29 01 00 00 00 02 7A 83
+					29 01 00 00 00 02 7B 00
+					29 01 00 00 00 02 7C 99
+					29 01 00 00 00 02 7D 00
+					29 01 00 00 00 02 7E A8
+					29 01 00 00 00 02 7F 00
+					29 01 00 00 00 02 80 B7
+					29 01 00 00 00 02 81 00
+					29 01 00 00 00 02 82 C5
+					29 01 00 00 00 02 83 00
+					29 01 00 00 00 02 84 F7
+					29 01 00 00 00 02 85 01
+					29 01 00 00 00 02 86 1E
+					29 01 00 00 00 02 87 01
+					29 01 00 00 00 02 88 60
+					29 01 00 00 00 02 89 01
+					29 01 00 00 00 02 8A 95
+					29 01 00 00 00 02 8B 01
+					29 01 00 00 00 02 8C E1
+					29 01 00 00 00 02 8D 02
+					29 01 00 00 00 02 8E 20
+					29 01 00 00 00 02 8F 02
+					29 01 00 00 00 02 90 23
+					29 01 00 00 00 02 91 02
+					29 01 00 00 00 02 92 59
+					29 01 00 00 00 02 93 02
+					29 01 00 00 00 02 94 94
+					29 01 00 00 00 02 95 02
+					29 01 00 00 00 02 96 B4
+					29 01 00 00 00 02 97 02
+					29 01 00 00 00 02 98 E1
+					29 01 00 00 00 02 99 03
+					29 01 00 00 00 02 9A 01
+					29 01 00 00 00 02 9B 03
+					29 01 00 00 00 02 9C 28
+					29 01 00 00 00 02 9D 03
+					29 01 00 00 00 02 9E 30
+					29 01 00 00 00 02 9F 03
+					29 01 00 00 00 02 A0 37
+					29 01 00 00 00 02 A2 03
+					29 01 00 00 00 02 A3 3B
+					29 01 00 00 00 02 A4 03
+					29 01 00 00 00 02 A5 40
+					29 01 00 00 00 02 A6 03
+					29 01 00 00 00 02 A7 50
+					29 01 00 00 00 02 A9 03
+					29 01 00 00 00 02 AA 6D
+					29 01 00 00 00 02 AB 03
+					29 01 00 00 00 02 AC 80
+					29 01 00 00 00 02 AD 03
+					29 01 00 00 00 02 AE CB
+					29 01 00 00 00 02 AF 00
+					29 01 00 00 00 02 B0 19
+					29 01 00 00 00 02 B1 00
+					29 01 00 00 00 02 B2 36
+					29 01 00 00 00 02 B3 00
+					29 01 00 00 00 02 B4 55
+					29 01 00 00 00 02 B5 00
+					29 01 00 00 00 02 B6 70
+					29 01 00 00 00 02 B7 00
+					29 01 00 00 00 02 B8 83
+					29 01 00 00 00 02 B9 00
+					29 01 00 00 00 02 BA 99
+					29 01 00 00 00 02 BB 00
+					29 01 00 00 00 02 BC A8
+					29 01 00 00 00 02 BD 00
+					29 01 00 00 00 02 BE B7
+					29 01 00 00 00 02 BF 00
+					29 01 00 00 00 02 C0 C5
+					29 01 00 00 00 02 C1 00
+					29 01 00 00 00 02 C2 F7
+					29 01 00 00 00 02 C3 01
+					29 01 00 00 00 02 C4 1E
+					29 01 00 00 00 02 C5 01
+					29 01 00 00 00 02 C6 60
+					29 01 00 00 00 02 C7 01
+					29 01 00 00 00 02 C8 95
+					29 01 00 00 00 02 C9 01
+					29 01 00 00 00 02 CA E1
+					29 01 00 00 00 02 CB 02
+					29 01 00 00 00 02 CC 20
+					29 01 00 00 00 02 CD 02
+					29 01 00 00 00 02 CE 23
+					29 01 00 00 00 02 CF 02
+					29 01 00 00 00 02 D0 59
+					29 01 00 00 00 02 D1 02
+					29 01 00 00 00 02 D2 94
+					29 01 00 00 00 02 D3 02
+					29 01 00 00 00 02 D4 B4
+					29 01 00 00 00 02 D5 02
+					29 01 00 00 00 02 D6 E1
+					29 01 00 00 00 02 D7 03
+					29 01 00 00 00 02 D8 01
+					29 01 00 00 00 02 D9 03
+					29 01 00 00 00 02 DA 28
+					29 01 00 00 00 02 DB 03
+					29 01 00 00 00 02 DC 30
+					29 01 00 00 00 02 DD 03
+					29 01 00 00 00 02 DE 37
+					29 01 00 00 00 02 DF 03
+					29 01 00 00 00 02 E0 3B
+					29 01 00 00 00 02 E1 03
+					29 01 00 00 00 02 E2 40
+					29 01 00 00 00 02 E3 03
+					29 01 00 00 00 02 E4 50
+					29 01 00 00 00 02 E5 03
+					29 01 00 00 00 02 E6 6D
+					29 01 00 00 00 02 E7 03
+					29 01 00 00 00 02 E8 80
+					29 01 00 00 00 02 E9 03
+					29 01 00 00 00 02 EA CB
+					29 01 00 00 00 02 FF 01
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 FF 02
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 FF 04
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 FF 00
+					29 01 00 00 64 02 11 00
+					29 01 00 00 00 02 FF EE
+					29 01 00 00 00 02 12 50
+					29 01 00 00 00 02 13 02
+					29 01 00 00 00 02 6A 60
+					29 01 00 00 00 02 FF 00
+					29 01 00 00 78 02 29 00];
+		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+		qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+					05 01 00 00 78 02 10 00];
+		qcom,off-cmds-dsi-state = "DSI_HS_MODE";
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
new file mode 100644
index 0000000..a3718aa
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
@@ -0,0 +1,120 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	qcom,dsi_v2_truly_wvga_video {
+		compatible = "qcom,dsi-panel-v2";
+		label = "Truly WVGA video mode dsi panel";
+		qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+		qcom,rst-gpio = <&msmgpio 41 0>;
+		qcom,mode-selection-gpio = <&msmgpio 7 0>;
+		vdda-supply = <&pm8110_l19>;
+		vddio-supply=<&pm8110_l14>;
+		qcom,mdss-pan-res = <480 800>;
+		qcom,mdss-pan-bpp = <24>;
+		qcom,mdss-pan-dest = "display_1";
+		qcom,mdss-pan-porch-values = <40 8 160 10 2 12>;
+		qcom,mdss-pan-underflow-clr = <0xff>;
+		qcom,mdss-pan-bl-levels = <1 255>;
+		qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+		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 0 0>;
+		qcom,mdss-pan-dsi-dlane-swap = <0>;
+		qcom,mdss-pan-dsi-t-clk = <0x1b 0x04>;
+		qcom,mdss-pan-dsi-stream = <0>;
+		qcom,mdss-pan-dsi-mdp-tr = <0x0>;/*todo*/
+		qcom,mdss-pan-dsi-dma-tr = <0x04>;
+		qcom,mdss-pan-dsi-frame-rate = <60>;
+		qcom,panel-phy-regulatorSettings =[09 08 05 00 20 03];
+		qcom,panel-phy-timingSettings = [5D 12 0C  00 33 38
+						 10 16 1E 03 04 00];
+		qcom,panel-phy-strengthCtrl = [ff 06];
+		qcom,panel-phy-bistCtrl = [03 03 00 00 0f 00];
+		qcom,panel-phy-laneConfig =
+					[80 45 00 00 01 66 /*lane0**/
+					80 45 00 00 01 66 /*lane1*/
+					80 45 00 00 01 66 /*lane2*/
+					80 45 00 00 01 66 /*lane3*/
+					40 67 00 00 01 88]; /*Clk*/
+
+		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+		qcom,panel-on-cmds = [
+					05 01 00 00 01 02
+						01 00
+					23 01 00 00 01 02
+						b0 04
+					29 01 00 00 01 03
+						b3 02 00
+					23 01 00 00 01 02
+						bd 00
+					29 01 00 00 01 03
+						c0 18 66
+					29 01 00 00 01 10
+						c1 23 31 99 21 20 00 30 28 0c 0c
+						00 00 00 21 01
+					29 01 00 00 01 07
+						c2 10 06 06 01 03 00
+					29 01 00 00 01 19
+						c8 04 10 18 20 2e 46 3c 28 1f 18
+						10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+					29 01 00 00 01 19
+						c9 04 10 18 20 2e 46 3c 28 1f 18
+						10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+					29 01 00 00 01 19
+						ca 04 10 18 20 2e 46 3c 28 1f 18
+						10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+					29 01 00 00 01 11
+						d0 29 03 ce a6 00 43 20 10 01 00
+						01 01 00 03 01 00
+					29 01 00 00 01 08
+						d1 18 0C 23 03 75 02 50
+					23 01 00 00 01 02
+						d3 11
+					29 01 00 00 01 03
+						d5 2a 2a
+					29 01 00 00 01 03
+						de 01 41
+					23 01 00 00 01 02
+						e6 51
+					23 01 00 00 01 02
+						fa 03
+					23 01 00 00 64 02
+						d6 28
+					39 01 00 00 01 05
+						2a 00 00 01 df
+					39 01 00 00 01 05
+						2b 00 00 03 1f
+					15 01 00 00 01 02
+						35 00
+					39 01 00 00 01 03
+						44 00 50
+					15 01 00 00 01 02
+						36 c1
+					15 01 00 00 01 02
+						3a 77
+					05 01 00 00 96 02
+						11 00
+					05 01 00 00 64 02
+						29 00
+					];
+		qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+					05 01 00 00 78 02 10 00];
+		qcom,off-cmds-dsi-state = "DSI_LP_MODE";
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 79760c1..391c564 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -260,6 +260,12 @@
 			};
 		};
 
+		qcom,leds@a100 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xa100 0x100>;
+			label = "mpp";
+		};
+
 		qcom,leds@a200 {
 			compatible = "qcom,leds-qpnp";
 			reg = <0xa200 0x100>;
@@ -492,5 +498,12 @@
 			reg = <0x5500 0x100>;
 			status = "disabled";
 		};
+
+		qcom,vibrator@c000 {
+			compatible = "qcom,qpnp-vibrator";
+			reg = <0xc000 0x100>;
+			label = "vibrator";
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226-ion.dtsi b/arch/arm/boot/dts/msm8226-ion.dtsi
index f433a49..9ada271 100644
--- a/arch/arm/boot/dts/msm8226-ion.dtsi
+++ b/arch/arm/boot/dts/msm8226-ion.dtsi
@@ -38,9 +38,7 @@
 		qcom,ion-heap@27 { /* QSECOM HEAP */
 			compatible = "qcom,msm-ion-reserve";
 			reg = <27>;
-			qcom,heap-align = <0x1000>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x780000>;
+			linux,contiguous-region = <&qsecom_mem>;
 		};
 
 		qcom,ion-heap@28 { /* AUDIO HEAP */
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index c62fb3e..b6fbd5b 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -114,7 +114,7 @@
 			qcom,type = <0x61706d73>;	/* "smpa" */
 			qcom,id = <0x01>;
 			qcom,key = <0x6e726f63>;	/* "corn" */
-			qcom,init-value = <5>;		/* Super Turbo */
+			qcom,init-value = <3>;		/* SVS SOC */
 		};
 
 		qcom,lpm-resources@1 {
@@ -123,7 +123,7 @@
 			qcom,type = <0x616F646C>;	/* "ldoa" */
 			qcom,id = <0x03>;
 			qcom,key = <0x6e726f63>;	/* "corn" */
-			qcom,init-value = <3>;		/* Active */
+			qcom,init-value = <3>;		/* SVS SOC */
 		};
 
 		qcom,lpm-resources@2 {
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 70731d2..4551f03 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -67,7 +67,7 @@
 			regulator-min-microvolt = <1>;
 			regulator-max-microvolt = <7>;
 			qcom,use-voltage-corner;
-			qcom,consumer-supplies = "vdd_dig", "", "vdd_sr2_dig", "";
+			qcom,consumer-supplies = "vdd_dig", "";
 		};
 		pm8226_s1_corner_ao: regulator-s1-corner-ao {
 			compatible = "qcom,rpm-regulator-smd";
@@ -76,6 +76,7 @@
 			regulator-min-microvolt = <1>;
 			regulator-max-microvolt = <7>;
 			qcom,use-voltage-corner;
+			qcom,consumer-supplies = "vdd_sr2_dig", "";
 		};
 	};
 
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index c392428..cdb79d6 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -59,6 +59,19 @@
 			reg = <0 0x3800000>;
 			label = "secure_mem";
 		};
+
+		qsecom_mem: qsecom_region {
+			linux,contiguous-region;
+			reg = <0 0x780000>;
+			label = "qsecom_mem";
+		};
+
+	};
+
+	qcom,mpm2-sleep-counter@fc4a3000 {
+		compatible = "qcom,mpm2-sleep-counter";
+		reg = <0xfc4a3000 0x1000>;
+		clock-frequency = <32768>;
 	};
 
 	timer {
@@ -680,7 +693,7 @@
 		reg = <0xf9927000 0x1000>;
 		interrupt-names = "qup_err_intr";
 		interrupts = <0 99 0>;
-		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-bus-freq = <384000>;
 		qcom,i2c-src-freq = <19200000>;
 	};
 
@@ -737,6 +750,7 @@
 
 		/* GPIO inputs from wcnss */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+		qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
 		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
 
 		/* GPIO output to wcnss */
@@ -789,6 +803,7 @@
 
 		/* GPIO inputs from mss */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+		qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
 		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
 
 		/* GPIO output to mss */
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index 84eebbf..d6d41cc 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 /include/ "msm8610.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8610 CDP";
@@ -23,10 +24,131 @@
 	serial@f991e000 {
 		status = "ok";
 	};
+
+	i2c@f9923000{
+		atmel_mxt_ts@4a {
+		compatible = "atmel,mxt-ts";
+		reg = <0x4a>;
+		interrupt-parent = <&msmgpio>;
+		interrupts = <1 0x2>;
+		vdd_ana-supply = <&pm8110_l19>;
+		vcc_i2c-supply = <&pm8110_l14>;
+		atmel,reset-gpio = <&msmgpio 0 0x00>;
+		atmel,irq-gpio = <&msmgpio 1 0x00>;
+		atmel,panel-coords = <0 0 508 880>;
+		atmel,display-coords = <0 0 480 800>;
+		atmel,i2c-pull-up;
+		atmel,no-force-update;
+		atmel,cfg_1 {
+			atmel,family-id = <0x81>;
+			atmel,variant-id = <0x15>;
+			atmel,version = <0x11>;
+			atmel,build = <0xaa>;
+			atmel,config = [
+				/* Object 6, Instance = 0 */
+				00 00 00 00 00 00
+				/* Object 38, Instance = 0 */
+				1D 01 00 0C 04 0D 00 00
+				/* Object 7, Instance = 0 */
+				20 08 32
+				/* Object 8, Instance = 0 */
+				19 00 14 14 FF 00 FF 00 00 00
+				/* Object 9, Instance = 0 */
+				83 00 00 13 0B 00 20 32 01 03
+				00 32 05 30 0A 05 0A 00 70 03
+				FC 01 00 36 2F 2C 00 00 40 00
+				00 0A 00 00 02
+				/* Object 18, Instance = 0 */
+				00 00
+				/* Object 19, Instance = 0 */
+				00 00 00 00 00 00
+				/* Object 25, Instance = 0 */
+				03 00 18 79 A8 61
+				/* Object 58, Instance = 0 */
+				00 00 00 00 00 00 00 00 00 00
+				00
+				/* Object 42, Instance = 0 */
+				00 00 00 00 00 00 00 00
+				/* Object 46, Instance = 0 */
+				04 03 08 10 00 00 00 00 00
+				/* Object 47, Instance = 0 */
+				00 00 00 00 00 00 00 00 00 00
+				/* Object 48, Instance = 0 */
+				00 00 00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 00 00
+				/* Object 55, Instance = 0 */
+				00 00 00 00
+				];
+			};
+		};
+	};
+};
+
+&i2c_cdc  {
+	msm8x10_wcd_codec@0d{
+		compatible = "qcom,msm8x10-wcd-i2c";
+		reg = <0x0d>;
+		cdc-vdda-cp-supply = <&pm8110_s4>;
+		qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
+		qcom,cdc-vdda-cp-current = <650000>;
+
+		cdc-vdda-h-supply = <&pm8110_l6>;
+		qcom,cdc-vdda-h-voltage = <1800000 1800000>;
+		qcom,cdc-vdda-h-current = <250000>;
+
+		cdc-vdd-px-supply = <&pm8110_l6>;
+		qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-px-current = <10000>;
+
+		cdc-vdd-1p2v-supply = <&pm8110_l4>;
+		qcom,cdc-vdd-1p2v-voltage = <1200000 1200000>;
+		qcom,cdc-vdd-1p2v-current = <5000>;
+
+		cdc-vdd-mic-bias-supply = <&pm8110_l20>;
+		qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+		qcom,cdc-vdd-mic-bias-current = <25000>;
+
+		qcom,cdc-micbias-cfilt-sel = <0x0>;
+		qcom,cdc-micbias-cfilt-mv = <1800000>;
+		qcom,cdc-mclk-clk-rate = <12288000>;
+	};
+
+	msm8x10_wcd_codec@77{
+		compatible = "qcom,msm8x10-wcd-i2c";
+		reg = <0x77>;
+	};
+
+	msm8x10_wcd_codec@66{
+		compatible = "qcom,msm8x10-wcd-i2c";
+		reg = <0x66>;
+	};
+
+	msm8x10_wcd_codec@55{
+		compatible = "qcom,msm8x10-wcd-i2c";
+		reg = <0x55>;
+	};
 };
 
 &spmi_bus {
 	qcom,pm8110@0 {
+		qcom,leds@a100 {
+			status = "okay";
+			qcom,led_mpp_2 {
+				label = "mpp";
+				linux,name = "button-backlight";
+				linux-default-trigger = "hr-trigger";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,id = <6>;
+				qcom,source-sel = <1>;
+				qcom,mode-ctrl = <0x60>;
+			};
+		};
+
 		qcom,leds@a200 {
 			status = "okay";
 			qcom,led_mpp_3 {
@@ -75,6 +197,16 @@
 	};
 };
 
+&spmi_bus {
+	qcom,pm8110@1 {
+		qcom,vibrator@c000 {
+			status = "okay";
+			qcom,vib-timeout-ms = <15000>;
+			qcom,vib-vtg-level-mV = <3100>;
+		};
+	};
+};
+
 &sdhc_1 {
 	vdd-supply = <&pm8110_l17>;
 	qcom,vdd-always-on;
@@ -152,3 +284,33 @@
 		status = "ok";
 	};
 };
+
+&pm8110_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+};
+
+&pm8110_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+		status = "disabled";
+	};
+
+	mpp@a200 { /* MPP 3 */
+		status = "disabled";
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm8610-ion.dtsi b/arch/arm/boot/dts/msm8610-ion.dtsi
index 41b58da..7d7d8fd 100644
--- a/arch/arm/boot/dts/msm8610-ion.dtsi
+++ b/arch/arm/boot/dts/msm8610-ion.dtsi
@@ -31,9 +31,7 @@
 		qcom,ion-heap@27 { /* QSECOM HEAP */
 			compatible = "qcom,msm-ion-reserve";
 			reg = <27>;
-			qcom,heap-align = <0x1000>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x100000>;
+			linux,contiguous-region = <&qsecom_mem>;
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8610-mdss.dtsi b/arch/arm/boot/dts/msm8610-mdss.dtsi
new file mode 100644
index 0000000..42fa149
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-mdss.dtsi
@@ -0,0 +1,37 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+/ {
+	qcom,mdss_mdp@fd900000 {
+		compatible = "qcom,mdss_mdp3";
+		reg = <0xfd900000 0x100000>;
+		reg-names = "mdp_phys";
+		interrupts = <0 72 0>;
+
+		mdss_fb0: qcom,mdss_fb_primary {
+			cell-index = <0>;
+			compatible = "qcom,mdss-fb";
+			qcom,memory-reservation-type = "EBI1";
+			qcom,memory-reservation-size = <0x800000>;
+		};
+	};
+
+	mdss_dsi0: qcom,mdss_dsi@fdd00000 {
+		compatible = "qcom,msm-dsi-v2";
+		label = "MDSS DSI CTRL->0";
+		cell-index = <0>;
+		reg = <0xfdd00000 0x100000>;
+		interrupts = <0 30 0>;
+		vdda-supply = <&pm8110_l4>;
+		qcom,mdss-fb-map = <&mdss_fb0>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index 90d4a0e..06a2321 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 /include/ "msm8610.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8610 MTP";
@@ -23,10 +24,131 @@
 	serial@f991e000 {
 		status = "ok";
 	};
+
+	i2c@f9923000{
+		atmel_mxt_ts@4a {
+		compatible = "atmel,mxt-ts";
+		reg = <0x4a>;
+		interrupt-parent = <&msmgpio>;
+		interrupts = <1 0x2>;
+		vdd_ana-supply = <&pm8110_l19>;
+		vcc_i2c-supply = <&pm8110_l14>;
+		atmel,reset-gpio = <&msmgpio 0 0x00>;
+		atmel,irq-gpio = <&msmgpio 1 0x00>;
+		atmel,panel-coords = <0 0 508 880>;
+		atmel,display-coords = <0 0 480 800>;
+		atmel,i2c-pull-up;
+		atmel,no-force-update;
+		atmel,cfg_1 {
+			atmel,family-id = <0x81>;
+			atmel,variant-id = <0x15>;
+			atmel,version = <0x11>;
+			atmel,build = <0xaa>;
+			atmel,config = [
+				/* Object 6, Instance = 0 */
+				00 00 00 00 00 00
+				/* Object 38, Instance = 0 */
+				1D 01 00 0C 04 0D 00 00
+				/* Object 7, Instance = 0 */
+				20 08 32
+				/* Object 8, Instance = 0 */
+				19 00 14 14 FF 00 FF 00 00 00
+				/* Object 9, Instance = 0 */
+				83 00 00 13 0B 00 20 32 01 03
+				00 32 05 30 0A 05 0A 00 70 03
+				FC 01 00 36 2F 2C 00 00 40 00
+				00 0A 00 00 02
+				/* Object 18, Instance = 0 */
+				00 00
+				/* Object 19, Instance = 0 */
+				00 00 00 00 00 00
+				/* Object 25, Instance = 0 */
+				03 00 18 79 A8 61
+				/* Object 58, Instance = 0 */
+				00 00 00 00 00 00 00 00 00 00
+				00
+				/* Object 42, Instance = 0 */
+				00 00 00 00 00 00 00 00
+				/* Object 46, Instance = 0 */
+				04 03 08 10 00 00 00 00 00
+				/* Object 47, Instance = 0 */
+				00 00 00 00 00 00 00 00 00 00
+				/* Object 48, Instance = 0 */
+				00 00 00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 00 00
+				/* Object 55, Instance = 0 */
+				00 00 00 00
+				];
+			};
+		};
+	};
+};
+
+&i2c_cdc  {
+	msm8x10_wcd_codec@0d{
+		compatible = "qcom,msm8x10-wcd-i2c";
+		reg = <0x0d>;
+		cdc-vdda-cp-supply = <&pm8110_s4>;
+		qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
+		qcom,cdc-vdda-cp-current = <650000>;
+
+		cdc-vdda-h-supply = <&pm8110_l6>;
+		qcom,cdc-vdda-h-voltage = <1800000 1800000>;
+		qcom,cdc-vdda-h-current = <250000>;
+
+		cdc-vdd-px-supply = <&pm8110_l6>;
+		qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-px-current = <10000>;
+
+		cdc-vdd-1p2v-supply = <&pm8110_l4>;
+		qcom,cdc-vdd-1p2v-voltage = <1200000 1200000>;
+		qcom,cdc-vdd-1p2v-current = <5000>;
+
+		cdc-vdd-mic-bias-supply = <&pm8110_l20>;
+		qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+		qcom,cdc-vdd-mic-bias-current = <25000>;
+
+		qcom,cdc-micbias-cfilt-sel = <0x0>;
+		qcom,cdc-micbias-cfilt-mv = <1800000>;
+		qcom,cdc-mclk-clk-rate = <12288000>;
+	};
+
+	msm8x10_wcd_codec@77{
+		compatible = "qcom,msm8x10-wcd-i2c";
+		reg = <0x77>;
+	};
+
+	msm8x10_wcd_codec@66{
+		compatible = "qcom,msm8x10-wcd-i2c";
+		reg = <0x66>;
+	};
+
+	msm8x10_wcd_codec@55{
+		compatible = "qcom,msm8x10-wcd-i2c";
+		reg = <0x55>;
+	};
 };
 
 &spmi_bus {
 	qcom,pm8110@0 {
+		qcom,leds@a100 {
+			status = "okay";
+			qcom,led_mpp_2 {
+				label = "mpp";
+				linux,name = "button-backlight";
+				linux-default-trigger = "hr-trigger";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,id = <6>;
+				qcom,source-sel = <1>;
+				qcom,mode-ctrl = <0x60>;
+			};
+		};
+
 		qcom,leds@a200 {
 			status = "okay";
 			qcom,led_mpp_3 {
@@ -75,6 +197,16 @@
 	};
 };
 
+&spmi_bus {
+	qcom,pm8110@1 {
+		qcom,vibrator@c000 {
+			status = "okay";
+			qcom,vib-timeout-ms = <15000>;
+			qcom,vib-vtg-level-mV = <3100>;
+		};
+	};
+};
+
 &sdhc_1 {
 	vdd-supply = <&pm8110_l17>;
 	qcom,vdd-always-on;
@@ -155,3 +287,33 @@
 		status = "ok";
 	};
 };
+
+&pm8110_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+};
+
+&pm8110_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+		status = "disabled";
+	};
+
+	mpp@a200 { /* MPP 3 */
+		status = "disabled";
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 67eee5c..f5d01e0 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -66,7 +66,7 @@
 			regulator-min-microvolt = <1>;
 			regulator-max-microvolt = <7>;
 			qcom,use-voltage-corner;
-			qcom,consumer-supplies = "vdd_dig", "", "vdd_sr2_dig", "";
+			qcom,consumer-supplies = "vdd_dig", "";
 		};
 
 		pm8110_s1_corner_ao: regulator-s1-corner-ao {
@@ -76,6 +76,7 @@
 			regulator-min-microvolt = <1>;
 			regulator-max-microvolt = <7>;
 			qcom,use-voltage-corner;
+			qcom,consumer-supplies = "vdd_sr2_dig", "";
 		};
 	};
 
diff --git a/arch/arm/boot/dts/msm8610-sim.dts b/arch/arm/boot/dts/msm8610-sim.dts
index 1838b94..fc94cc9 100644
--- a/arch/arm/boot/dts/msm8610-sim.dts
+++ b/arch/arm/boot/dts/msm8610-sim.dts
@@ -23,3 +23,48 @@
 		status = "ok";
 	};
 };
+
+&i2c_cdc  {
+	msm8x10_wcd_codec@0d{
+		compatible = "qcom,msm8x10-wcd-i2c";
+		reg = <0x0d>;
+		cdc-vdda-cp-supply = <&pm8110_s4>;
+		qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
+		qcom,cdc-vdda-cp-current = <650000>;
+
+		cdc-vdda-h-supply = <&pm8110_l6>;
+		qcom,cdc-vdda-h-voltage = <1800000 1800000>;
+		qcom,cdc-vdda-h-current = <250000>;
+
+		cdc-vdd-px-supply = <&pm8110_l6>;
+		qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-px-current = <10000>;
+
+		cdc-vdd-1p2v-supply = <&pm8110_l4>;
+		qcom,cdc-vdd-1p2v-voltage = <1200000 1200000>;
+		qcom,cdc-vdd-1p2v-current = <5000>;
+
+		cdc-vdd-mic-bias-supply = <&pm8110_l20>;
+		qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+		qcom,cdc-vdd-mic-bias-current = <25000>;
+
+		qcom,cdc-micbias-cfilt-sel = <0x0>;
+		qcom,cdc-micbias-cfilt-mv = <1800000>;
+		qcom,cdc-mclk-clk-rate = <12288000>;
+	};
+
+	msm8x10_wcd_codec@77{
+		compatible = "qcom,msm8x10-wcd-i2c";
+		reg = <0x77>;
+	};
+
+	msm8x10_wcd_codec@66{
+		compatible = "qcom,msm8x10-wcd-i2c";
+		reg = <0x66>;
+	};
+
+	msm8x10_wcd_codec@55{
+		compatible = "qcom,msm8x10-wcd-i2c";
+		reg = <0x55>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 822c792..2cbd76e 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -19,6 +19,7 @@
 /include/ "msm8610-pm.dtsi"
 /include/ "msm8610-smp2p.dtsi"
 /include/ "msm8610-bus.dtsi"
+/include/ "msm8610-mdss.dtsi"
 
 / {
 	model = "Qualcomm MSM 8610";
@@ -45,12 +46,27 @@
 		qcom,direct-connect-irqs = <8>;
 	};
 
+	memory {
+
+		qsecom_mem: qsecom_region {
+			linux,contiguous-region;
+			reg = <0 0x100000>;
+			label = "qsecom_mem";
+		};
+
+	};
+
 	aliases {
-		spi0 = &spi_0;
 		sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
 		sdhc2 = &sdhc_2; /* SDC2 SD card slot */
 	};
 
+	qcom,mpm2-sleep-counter@fc4a3000 {
+		compatible = "qcom,mpm2-sleep-counter";
+		reg = <0xfc4a3000 0x1000>;
+		clock-frequency = <32768>;
+	};
+
 	timer {
 		compatible = "arm,armv7-timer";
 		interrupts = <1 2 0 1 3 0>;
@@ -148,7 +164,7 @@
 		qcom,buffer-type-tz-usage-map = <0x1 0x1>,
 						<0x1fe 0x2>;
 		qcom,hfi = "q6";
-		qcom,max-hw-load = <97200>; /* FWVGA @ 30 * 2 */
+		qcom,max-hw-load = <108000>; /* 720p @ 30 * 1 */
 	};
 
 	qcom,usbbam@f9a44000 {
@@ -417,18 +433,33 @@
 		qcom,pmic-arb-channel = <0>;
 	};
 
-	i2c@f9925000 { /* BLSP-1 QUP-3 */
-		cell-index = <0>;
+	i2c@f9923000 { /* BLSP-1 QUP-1 */
+		cell-index = <1>;
 		compatible = "qcom,i2c-qup";
 		#address-cells = <1>;
 		#size-cells = <0>;
 		reg-names = "qup_phys_addr";
-		reg = <0xf9925000 0x1000>;
+		reg = <0xf9923000 0x1000>;
 		interrupt-names = "qup_err_intr";
-		interrupts = <0 97 0>;
+		interrupts = <0 95 0>;
 		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <19200000>;
+		qcom,sda-gpio = <&msmgpio 2 0>;
+		qcom,scl-gpio = <&msmgpio 3 0>;
 	};
 
+	i2c_cdc: i2c@f9927000 { /* BLSP1 QUP5 */
+                cell-index = <5>;
+                compatible = "qcom,i2c-qup";
+                #address-cells = <1>;
+                #size-cells = <0>;
+                reg-names = "qup_phys_addr";
+                reg = <0xf9927000 0x1000>;
+                interrupt-names = "qup_err_intr";
+                interrupts = <0 99 0>;
+                qcom,i2c-bus-freq = <100000>;
+        };
+
 	i2c@f9928000 { /* BLSP1 QUP6 */
 		cell-index = <6>;
 		compatible = "qcom,i2c-qup";
@@ -444,27 +475,16 @@
 		qcom,scl-gpio = <&msmgpio 17 0>;
 	};
 
-	spi_0: spi@f9923000 { /* BLSP1 QUP1 */
-		compatible = "qcom,spi-qup-v2";
+	i2c@f9925000 { /* BLSP-1 QUP-3 */
+		cell-index = <0>;
+		compatible = "qcom,i2c-qup";
 		#address-cells = <1>;
 		#size-cells = <0>;
-		reg-names = "spi_physical", "spi_bam_physical";
-		reg = <0xf9923000 0x1000>,
-		      <0xf9904000 0xF000>;
-		interrupt-names = "spi_irq", "spi_bam_irq";
-		interrupts = <0 95 0>, <0 238 0>;
-		spi-max-frequency = <19200000>;
-
-		gpios = <&msmgpio 3 0>, /* CLK  */
-			<&msmgpio 1 0>, /* MISO */
-			<&msmgpio 0 0>; /* MOSI */
-		cs-gpios = <&msmgpio 2 0>;
-
-		qcom,infinite-mode = <0>;
-		qcom,use-bam;
-		qcom,ver-reg-exists;
-		qcom,bam-consumer-pipe-index = <12>;
-		qcom,bam-producer-pipe-index = <13>;
+		reg-names = "qup_phys_addr";
+		reg = <0xf9925000 0x1000>;
+		interrupt-names = "qup_err_intr";
+		interrupts = <0 97 0>;
+		qcom,i2c-bus-freq = <100000>;
 	};
 
 	qcom,pronto@fb21b000 {
@@ -480,6 +500,7 @@
 
 		/* GPIO inputs from wcnss */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+		qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
 		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
 
 		/* GPIO output to wcnss */
@@ -497,6 +518,13 @@
 
 	qcom,msm-pcm {
 		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <0>;
+	};
+
+	qcom,msm-pcm-low-latency {
+		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <1>;
+		qcom,msm-pcm-low-latency;
 	};
 
 	qcom,msm-pcm-routing {
@@ -536,15 +564,15 @@
 		qcom,msm-dai-q6-mi2s-prim {
 			compatible = "qcom,msm-dai-q6-mi2s";
 			qcom,msm-dai-q6-mi2s-dev-id = <0>;
-			qcom,msm-mi2s-rx-lines = <1>;
-			qcom,msm-mi2s-tx-lines = <0>;
+			qcom,msm-mi2s-rx-lines = <0>;
+			qcom,msm-mi2s-tx-lines = <3>;
 		};
 
 		qcom,msm-dai-q6-mi2s-sec {
 			compatible = "qcom,msm-dai-q6-mi2s";
 			qcom,msm-dai-q6-mi2s-dev-id = <1>;
-			qcom,msm-mi2s-rx-lines = <0>;
-			qcom,msm-mi2s-tx-lines = <3>;
+			qcom,msm-mi2s-rx-lines = <3>;
+			qcom,msm-mi2s-tx-lines = <0>;
 		};
 	};
 
@@ -589,6 +617,21 @@
 			compatible = "qcom,msm-dai-q6-dev";
 			qcom,msm-dai-q6-dev-id = <240>;
 		};
+
+		qcom,msm-dai-q6-incall-record-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32771>;
+		};
+
+		qcom,msm-dai-q6-incall-record-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32772>;
+		};
+
+		qcom,msm-dai-q6-incall-music-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32773>;
+		};
 	};
 
 	qcom,msm-pcm-hostless {
@@ -637,6 +680,7 @@
 
 		/* GPIO inputs from mss */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+		qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
 		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
 
 		/* GPIO output to mss */
@@ -720,6 +764,12 @@
                 qcom,msm-rng-iface-clk;
         };
 
+	qcom,msm-rtb {
+		compatible = "qcom,msm-rtb";
+		qcom,memory-reservation-type = "EBI1";
+		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+	};
+
 	jtag_mm0: jtagmm@fc34c000 {
 		compatible = "qcom,jtag-mm";
 		reg = <0xfc34c000 0x1000>,
@@ -808,7 +858,7 @@
 		label = "vchg_sns";
 		reg = <2>;
 		qcom,decimation = <0>;
-		qcom,pre-div-channel-scaling = <3>;
+		qcom,pre-div-channel-scaling = <2>;
 		qcom,calibration-type = "absolute";
 		qcom,scale-function = <0>;
 		qcom,hw-settle-time = <0>;
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 31afd9c..cfe39fc 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -45,9 +45,7 @@
 		qcom,ion-heap@27 { /* QSECOM HEAP */
 			compatible = "qcom,msm-ion-reserve";
 			reg = <27>;
-			qcom,heap-align = <0x1000>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x1100000>;
+			linux,contiguous-region = <&qsecom_mem>;
 		};
 
 		qcom,ion-heap@28 { /* AUDIO HEAP */
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index f787cf5..a0a7cbe 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -47,6 +47,13 @@
 			reg = <0 0x2000000>;
 			label = "adsp_mem";
 		};
+
+		qsecom_mem: qsecom_region {
+			linux,contiguous-region;
+			reg = <0 0x1100000>;
+			label = "qseecom_mem";
+		};
+
 	};
 
 	intc: interrupt-controller@F9000000 {
@@ -725,6 +732,22 @@
 		qcom,i2c-src-freq = <50000000>;
 	};
 
+	i2c_1: i2c@f9923000 {
+		cell-index = <1>;
+		compatible = "qcom,i2c-qup";
+		reg = <0xf9923000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		interrupts = <0 95 0>;
+		interrupt-names = "qup_err_intr";
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <19200000>;
+		qcom,scl-gpio = <&msmgpio 3 0>;
+		qcom,sda-gpio = <&msmgpio 2 0>;
+		status = "disabled";
+	};
+
 	i2c_2: i2c@f9924000 {
 		cell-index = <2>;
 		compatible = "qcom,i2c-qup";
@@ -1102,6 +1125,7 @@
 
 		/* GPIO inputs from mss */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+		qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
 		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
 
 		/* GPIO output to mss */
@@ -1121,6 +1145,7 @@
 
 		/* GPIO inputs from wcnss */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+		qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
 		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
 
 		/* GPIO output to wcnss */
@@ -1544,22 +1569,28 @@
 };
 
 &gdsc_venus {
+	qcom,clock-names = "core_clk";
 	status = "ok";
 };
 
 &gdsc_mdss {
+	qcom,clock-names = "core_clk", "lut_clk";
 	status = "ok";
 };
 
 &gdsc_jpeg {
+	qcom,clock-names = "core0_clk", "core1_clk", "core2_clk";
 	status = "ok";
 };
 
 &gdsc_vfe {
+	qcom,clock-names = "core0_clk", "core1_clk", "csi0_clk", "csi1_clk",
+			   "cpp_clk";
 	status = "ok";
 };
 
 &gdsc_oxili_gx {
+	qcom,clock-names = "core_clk";
 	qcom,retain-mems;
 	status = "ok";
 };
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index abfd7ec..3e2eab3 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -757,6 +757,7 @@
 
 		/* GPIO inputs from mss */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+		qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
 		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
 
 		/* GPIO output to mss */
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 5ba76b6..a1fa53c 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -74,8 +74,6 @@
 CONFIG_MSM_L2_ERP_PORT_PANIC=y
 CONFIG_MSM_L2_ERP_1BIT_PANIC=y
 CONFIG_MSM_L2_ERP_2BIT_PANIC=y
-CONFIG_MSM_CACHE_DUMP=y
-CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_ARM_LPAE=y
 CONFIG_NO_HZ=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 03ac944..5660dec 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -25,6 +25,7 @@
 CONFIG_PANIC_TIMEOUT=5
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=m
 CONFIG_MODULES=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 3322896..09b038c 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -59,7 +59,6 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_MSM_ADSP_LOADER=m
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
@@ -69,6 +68,7 @@
 CONFIG_SENSORS_ADSP=y
 CONFIG_MSM_RTB=y
 CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
@@ -214,6 +214,7 @@
 CONFIG_INPUT_EVBUG=m
 CONFIG_KEYBOARD_GPIO=y
 CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
@@ -278,7 +279,6 @@
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
 CONFIG_FB=y
-CONFIG_FB_VIRTUAL=y
 CONFIG_FB_MSM=y
 # CONFIG_FB_MSM_BACKLIGHT is not set
 CONFIG_FB_MSM_MDSS=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index a70e6c6..0eecffd 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -418,6 +418,7 @@
 	select MAY_HAVE_SPARSE_IRQ
 	select SPARSE_IRQ
 	select MULTI_IRQ_HANDLER
+	select ARM_TICKET_LOCKS
 	select GPIO_MSM_V3
 	select MSM_GPIOMUX
 	select MSM_NATIVE_RESTART
@@ -459,6 +460,7 @@
 	select MAY_HAVE_SPARSE_IRQ
 	select SPARSE_IRQ
 	select MULTI_IRQ_HANDLER
+	select ARM_TICKET_LOCKS
 	select GPIO_MSM_V3
 	select MSM_GPIOMUX
 	select MSM_NATIVE_RESTART
@@ -1113,14 +1115,14 @@
 config KERNEL_PMEM_SMI_REGION
 	bool "Enable in-kernel PMEM region for SMI"
 	default y if ARCH_MSM8X60
-	depends on ANDROID_PMEM && ((ARCH_QSD8X50 && !PMEM_GPU0) || (ARCH_MSM8X60 && !VCM))
+	depends on (ARCH_QSD8X50 && !PMEM_GPU0) || (ARCH_MSM8X60 && !VCM)
 	help
 	   Enable the in-kernel PMEM allocator to use SMI memory.
 
 config PMEM_GPU0
 	bool "Enable PMEM GPU0 region"
 	default y
-	depends on ARCH_QSD8X50 && ANDROID_PMEM
+	depends on ARCH_QSD8X50
 	help
 	  Enable the PMEM GPU0 device on SMI Memory.
 
@@ -1856,7 +1858,6 @@
 
 config MSM_HW3D
 	tristate "MSM Hardware 3D Register Driver"
-	depends on ANDROID_PMEM
 	help
 	  Provides access to registers needed by the userspace OpenGL|ES
 	  library.
@@ -1864,7 +1865,6 @@
 config MSM_ADSP
 	depends on (ARCH_MSM7X01A || ARCH_MSM7X25 || ARCH_MSM7X27)
 	tristate "MSM ADSP driver"
-	depends on ANDROID_PMEM
 	default y
 	help
 	  Provides access to registers needed by the userspace aDSP library.
@@ -1890,7 +1890,7 @@
 
 config MSM7KV2_AUDIO
 	bool "MSM7K v2 audio"
-	depends on (ARCH_MSM7X30 && ANDROID_PMEM)
+	depends on ARCH_MSM7X30
 	default y
 	help
 	  Enables QDSP5V2-based audio drivers for audio playbacks and
@@ -1906,14 +1906,14 @@
 
 config MSM_QDSP6
 	tristate "QDSP6 support"
-	depends on ARCH_QSD8X50 && ANDROID_PMEM
+	depends on ARCH_QSD8X50
 	default y
 	help
 	  Enable support for qdsp6. This provides audio and video functionality.
 
 config MSM8X60_AUDIO
 	tristate "MSM8X60 audio support"
-	depends on ARCH_MSM8X60 && ANDROID_PMEM
+	depends on ARCH_MSM8X60
 	default y
 	help
 	  Enable support for qdsp6v2. This provides audio functionality.
@@ -1972,7 +1972,7 @@
 
 config QSD_AUDIO
 	bool "QSD audio"
-	depends on ARCH_MSM_SCORPION && MSM_DALRPC && ANDROID_PMEM && !MSM_SMP
+	depends on ARCH_MSM_SCORPION && MSM_DALRPC && !MSM_SMP
 	default y
 	help
 	  Provides PCM, MP3, and AAC audio playback.
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index d5f880a..8efc000 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -4,10 +4,9 @@
 ifndef CONFIG_ARM_ARCH_TIMER
 obj-y += timer.o
 endif
-obj-y += clock.o clock-voter.o clock-dummy.o
+obj-y += clock.o clock-voter.o clock-dummy.o clock-generic.o
 obj-y += modem_notifier.o
 obj-$(CONFIG_USE_OF) += board-dt.o
-obj-$(CONFIG_CPU_FREQ_MSM) += cpufreq.o
 obj-$(CONFIG_DEBUG_FS) += nohlt.o clock-debug.o
 obj-$(CONFIG_KEXEC) += msm_kexec.o
 
@@ -429,3 +428,4 @@
 
 obj-$(CONFIG_ARCH_MSM8974) += msm_mpmctr.o
 obj-$(CONFIG_MSM_CPR_REGULATOR) += cpr-regulator.o
+obj-$(CONFIG_CPU_FREQ_MSM) += cpufreq.o
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 153be21..a6f772d 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -65,7 +65,6 @@
  * 3) Depending on Frodo version, may need minimum of LVL_NOM
  */
 static struct clkctl_acpu_speed acpu_freq_tbl_8226[] = {
-	{ 0,   19200, CXO,     0, 0,   CPR_CORNER_SVS,    0, 0 },
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  384000, ACPUPLL, 5, 0,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
@@ -77,7 +76,6 @@
 };
 
 static struct clkctl_acpu_speed acpu_freq_tbl_8610[] = {
-	{ 0,   19200, CXO,     0, 0,   CPR_CORNER_SVS,    0, 0 },
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 3 },
 	{ 1,  384000, ACPUPLL, 5, 0,   CPR_CORNER_SVS,    0, 3 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 4 },
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 0f88287..ede53bc 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -968,7 +968,6 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
-
 static struct gpiomux_setting ap2mdm_soft_reset_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_4MA,
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index eada62c..593e2b1 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -29,14 +29,26 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
-static struct gpiomux_setting gpio_spi_config = {
-	.func = GPIOMUX_FUNC_1,
-	.drv = GPIOMUX_DRV_6MA,
-	.pull = GPIOMUX_PULL_NONE,
+static struct gpiomux_setting atmel_int_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
 };
 
-static struct gpiomux_setting gpio_spi_cs_config = {
-	.func = GPIOMUX_FUNC_1,
+static struct gpiomux_setting atmel_int_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting atmel_reset_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting atmel_reset_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_6MA,
 	.pull = GPIOMUX_PULL_DOWN,
 };
@@ -97,6 +109,18 @@
 
 static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
 	{
+		.gpio      = 2,		/* BLSP1 QUP1 I2C_SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{
+		.gpio      = 3,		/* BLSP1 QUP1 I2C_SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{
 		.gpio      = 10,	/* BLSP1 QUP3 I2C_SDA */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
@@ -120,28 +144,21 @@
 			[GPIOMUX_SUSPENDED] = &gpio_cam_i2c_config,
 		},
 	},
+};
+
+static struct msm_gpiomux_config msm_atmel_configs[] __initdata = {
 	{
-		.gpio      = 0,		/* BLSP1 QUP1 SPI_DATA_MOSI */
+		.gpio      = 0,		/* TOUCH RESET */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &atmel_reset_act_cfg,
+			[GPIOMUX_SUSPENDED] = &atmel_reset_sus_cfg,
 		},
 	},
 	{
-		.gpio      = 1,		/* BLSP1 QUP1 SPI_DATA_MISO */
+		.gpio      = 1,		/* TOUCH INT */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
-		},
-	},
-	{
-		.gpio      = 3,		/* BLSP1 QUP1 SPI_CLK */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
-		},
-	},
-	{
-		.gpio      = 2,		/* BLSP1 QUP1 SPI_CS1 */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+			[GPIOMUX_ACTIVE] = &atmel_int_act_cfg,
+			[GPIOMUX_SUSPENDED] = &atmel_int_sus_cfg,
 		},
 	},
 };
@@ -208,6 +225,30 @@
 	},
 };
 
+static struct gpiomux_setting sd_card_det_active_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting sd_card_det_suspend_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+	.dir = GPIOMUX_IN,
+};
+
+static struct msm_gpiomux_config sd_card_det[] __initdata = {
+	{
+		.gpio = 42,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sd_card_det_active_config,
+			[GPIOMUX_SUSPENDED] = &sd_card_det_suspend_config,
+		},
+	},
+};
+
 void __init msm8610_init_gpiomux(void)
 {
 	int rc;
@@ -219,9 +260,12 @@
 	}
 
 	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+	msm_gpiomux_install(msm_atmel_configs,
+			ARRAY_SIZE(msm_atmel_configs));
 	msm_gpiomux_install(wcnss_5wire_interface,
 			ARRAY_SIZE(wcnss_5wire_interface));
 	msm_gpiomux_install(msm_lcd_configs, ARRAY_SIZE(msm_lcd_configs));
 	msm_gpiomux_install(msm_keypad_configs,
 				ARRAY_SIZE(msm_keypad_configs));
+	msm_gpiomux_install(sd_card_det, ARRAY_SIZE(sd_card_det));
 }
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8038.c b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
index c34394e..8ed93ea 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8038.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -95,7 +95,7 @@
 	REGULATOR_SUPPLY("VDDIO_CDC",		"sitar1p1-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_TX",		"sitar1p1-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_RX",		"sitar1p1-slim"),
-	REGULATOR_SUPPLY("vddp",		"0-0048"),
+	REGULATOR_SUPPLY("vcc_i2c",		"0-0048"),
 	REGULATOR_SUPPLY("mhl_iovcc18",		"0-0039"),
 	REGULATOR_SUPPLY("vdd-io",		"spi0.0"),
 	REGULATOR_SUPPLY("vdd-phy",		"spi0.0"),
@@ -209,7 +209,6 @@
 	REGULATOR_SUPPLY("8038_lvs2",		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"),
 };
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8917.c b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
index 8f853a4..cdc419f 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8917.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -194,7 +194,7 @@
 	REGULATOR_SUPPLY("VDDIO_CDC",		"sitar1p1-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_TX",		"sitar1p1-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_RX",		"sitar1p1-slim"),
-	REGULATOR_SUPPLY("vddp",		"0-0048"),
+	REGULATOR_SUPPLY("vcc_i2c",		"0-0048"),
 	REGULATOR_SUPPLY("mhl_iovcc18",		"0-0039"),
 	REGULATOR_SUPPLY("CDC_VDD_CP",		"sitar-slim"),
 	REGULATOR_SUPPLY("CDC_VDD_CP",		"sitar1p1-slim"),
@@ -233,7 +233,6 @@
 	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"),
 };
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 6ccaba6..ccea956 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -1718,12 +1718,6 @@
 
 static struct isa1200_regulator isa1200_reg_data[] = {
 	{
-		.name = "vddp",
-		.min_uV = ISA_I2C_VTG_MIN_UV,
-		.max_uV = ISA_I2C_VTG_MAX_UV,
-		.load_uA = ISA_I2C_CURR_UA,
-	},
-	{
 		.name = "vcc_i2c",
 		.min_uV = ISA_I2C_VTG_MIN_UV,
 		.max_uV = ISA_I2C_VTG_MAX_UV,
@@ -2356,6 +2350,7 @@
 	&msm_pcm_hostless,
 	&msm_multi_ch_pcm,
 	&msm_lowlatency_pcm,
+	&msm_fm_loopback,
 };
 
 static void __init msm8930_i2c_init(void)
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 705275c..f5b76da 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -20,6 +20,98 @@
 
 #define KS8851_IRQ_GPIO 94
 
+static struct gpiomux_setting ap2mdm_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdm2ap_status_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting mdm2ap_errfatal_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting mdm2ap_pblrdy = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_IN,
+};
+
+
+static struct gpiomux_setting ap2mdm_soft_reset_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting ap2mdm_wakeup = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config mdm_configs[] __initdata = {
+	/* AP2MDM_STATUS */
+	{
+		.gpio = 105,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* MDM2AP_STATUS */
+	{
+		.gpio = 46,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg,
+		}
+	},
+	/* MDM2AP_ERRFATAL */
+	{
+		.gpio = 82,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg,
+		}
+	},
+	/* AP2MDM_ERRFATAL */
+	{
+		.gpio = 106,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* AP2MDM_SOFT_RESET, aka AP2MDM_PON_RESET_N */
+	{
+		.gpio = 24,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_soft_reset_cfg,
+		}
+	},
+	/* AP2MDM_WAKEUP */
+	{
+		.gpio = 104,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_wakeup,
+		}
+	},
+	/* MDM2AP_PBL_READY*/
+	{
+		.gpio = 80,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_pblrdy,
+		}
+	},
+};
+
 static struct gpiomux_setting gpio_uart_config = {
 	.func = GPIOMUX_FUNC_2,
 	.drv = GPIOMUX_DRV_16MA,
@@ -1140,4 +1232,8 @@
 	if (of_board_is_rumi())
 		msm_gpiomux_install(msm_rumi_blsp_configs,
 				    ARRAY_SIZE(msm_rumi_blsp_configs));
+
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_MDM)
+		msm_gpiomux_install(mdm_configs,
+			ARRAY_SIZE(mdm_configs));
 }
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 1090d89..486842f 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -169,7 +169,7 @@
 	VDD_DIG_NUM
 };
 
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
 	[VDD_DIG_NONE]	  = VDD_UV(RPM_REGULATOR_CORNER_NONE),
 	[VDD_DIG_LOW]	  = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
 	[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
@@ -2753,7 +2753,7 @@
 	VDD_SR2_PLL_NUM
 };
 
-static const int *vdd_sr2_levels[] = {
+static int *vdd_sr2_levels[] = {
 	[VDD_SR2_PLL_OFF] = VDD_UV(0,       RPM_REGULATOR_CORNER_NONE),
 	[VDD_SR2_PLL_SVS] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SVS_SOC),
 	[VDD_SR2_PLL_NOM] = VDD_UV(1800000, RPM_REGULATOR_CORNER_NORMAL),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index c13e595..2683d19 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -30,6 +30,7 @@
 #include "clock-rpm.h"
 #include "clock-voter.h"
 #include "clock.h"
+#include "clock-dsi-8610.h"
 
 enum {
 	GCC_BASE,
@@ -433,7 +434,7 @@
 	VDD_DIG_NUM
 };
 
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
 	[VDD_DIG_NONE]	  = VDD_UV(RPM_REGULATOR_CORNER_NONE),
 	[VDD_DIG_LOW]	  = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
 	[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
@@ -532,7 +533,7 @@
 	VDD_SR2_PLL_NUM
 };
 
-static const int *vdd_sr2_levels[] = {
+static int *vdd_sr2_levels[] = {
 	[VDD_SR2_PLL_OFF] = VDD_UV(0,       RPM_REGULATOR_CORNER_NONE),
 	[VDD_SR2_PLL_SVS] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SVS_SOC),
 	[VDD_SR2_PLL_NOM] = VDD_UV(1800000, RPM_REGULATOR_CORNER_NORMAL),
@@ -1561,21 +1562,85 @@
 static DEFINE_CLK_VOTER(mdp_axi_clk_src, &axi_clk_src.c, 200000000);
 static DEFINE_CLK_VOTER(mmssnoc_axi_clk_src, &axi_clk_src.c, 200000000);
 
-static struct clk_freq_tbl ftbl_dsi_pclk_clk[] = {
-	F_MDSS( 50000000, dsipll, 10, 0, 0),
-	F_MDSS(103330000, dsipll,  9, 0, 0),
-	F_END,
+static struct clk_ops dsi_byte_clk_src_ops;
+static struct clk_ops dsi_pixel_clk_src_ops;
+static struct clk_ops dsi_dsi_clk_src_ops;
+
+static struct dsi_pll_vco_clk dsi_vco  = {
+	.vco_clk_min =  600000000,
+	.vco_clk_max = 1200000000,
+	.pref_div_ratio = 26,
+	.c = {
+		.parent = &gcc_xo_clk_src.c,
+		.dbg_name = "dsi_vco",
+		.ops = &clk_ops_dsi_vco,
+		CLK_INIT(dsi_vco.c),
+	},
 };
 
+static struct clk dsi_pll_byte = {
+	.parent = &dsi_vco.c,
+	.dbg_name = "dsi_pll_byte",
+	.ops = &clk_ops_dsi_byteclk,
+	CLK_INIT(dsi_pll_byte),
+};
+
+static struct clk dsi_pll_pixel = {
+	.parent = &dsi_vco.c,
+	.dbg_name = "dsi_pll_pixel",
+	.ops = &clk_ops_dsi_dsiclk,
+	CLK_INIT(dsi_pll_pixel),
+};
+
+static struct clk_freq_tbl pixel_freq_tbl[] = {
+	{
+		.src_clk = &dsi_pll_pixel,
+		.div_src_val = BVAL(10, 8, dsipll_mm_source_val),
+	},
+	F_END
+};
+
+#define CFG_RCGR_DIV_MASK		BM(4, 0)
+
+static int set_rate_pixel_byte_clk(struct clk *clk, unsigned long rate)
+{
+	struct rcg_clk *rcg = to_rcg_clk(clk);
+	struct clk *pll = clk->parent;
+	unsigned long source_rate, div;
+	struct clk_freq_tbl *cur_freq = rcg->current_freq;
+	int rc;
+
+	if (rate == 0)
+		return clk_set_rate(pll, 0);
+
+	source_rate = clk_round_rate(pll, rate);
+	if (!source_rate || ((2 * source_rate) % rate))
+		return -EINVAL;
+
+	div = ((2 * source_rate)/rate) - 1;
+	if (div > CFG_RCGR_DIV_MASK)
+		return -EINVAL;
+
+	rc = clk_set_rate(pll, source_rate);
+	if (rc)
+		return rc;
+
+	cur_freq->div_src_val &= ~CFG_RCGR_DIV_MASK;
+	cur_freq->div_src_val |= BVAL(4, 0, div);
+	rcg->set_rate(rcg, cur_freq);
+
+	return 0;
+}
+
 static struct rcg_clk dsi_pclk_clk_src = {
 	.cmd_rcgr_reg =  DSI_PCLK_CMD_RCGR,
 	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_dsi_pclk_clk,
-	.current_freq = &rcg_dummy_freq,
+	.current_freq = pixel_freq_tbl,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
+		.parent = &dsi_pll_pixel,
 		.dbg_name = "dsi_pclk_clk_src",
-		.ops = &clk_ops_rcg_mnd,
+		.ops = &dsi_pixel_clk_src_ops,
 		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 103330000),
 		CLK_INIT(dsi_pclk_clk_src.c),
 	},
@@ -1687,41 +1752,60 @@
 	},
 };
 
-static struct clk_freq_tbl ftbl_dsi_clk[] = {
-	F_MDSS(155000000,  dsipll, 6, 0, 0),
-	F_MDSS(310000000,  dsipll, 3, 0, 0),
-	F_END,
+/*
+ * The DSI clock will always use a divider of 1. However, we still
+ * need to set the right voltage and source.
+ */
+static int set_rate_dsi_clk(struct clk *clk, unsigned long rate)
+{
+	struct rcg_clk *rcg = to_rcg_clk(clk);
+	struct clk_freq_tbl *cur_freq = rcg->current_freq;
+
+	rcg->set_rate(rcg, cur_freq);
+
+	return 0;
+}
+
+static struct clk_freq_tbl dsi_freq_tbl[] = {
+	{
+		.src_clk = &dsi_pll_pixel,
+		.div_src_val =  BVAL(4, 0, 0) |
+			BVAL(10, 8, dsipll_mm_source_val),
+	},
+	F_END
 };
 
 static struct rcg_clk dsi_clk_src = {
 	.cmd_rcgr_reg =  DSI_CMD_RCGR,
 	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_dsi_clk,
-	.current_freq = &rcg_dummy_freq,
+	.current_freq = dsi_freq_tbl,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
+		.parent = &dsi_pll_pixel,
 		.dbg_name = "dsi_clk_src",
-		.ops = &clk_ops_rcg_mnd,
+		.ops = &dsi_dsi_clk_src_ops,
 		VDD_DIG_FMAX_MAP2(LOW, 155000000, NOMINAL, 310000000),
 		CLK_INIT(dsi_clk_src.c),
 	},
 };
 
-static struct clk_freq_tbl ftbl_dsi_byte_clk[] = {
-	F_MDSS( 62500000, dsipll, 12, 0, 0),
-	F_MDSS(125000000, dsipll,  6, 0, 0),
-	F_END,
+static struct clk_freq_tbl byte_freq_tbl[] = {
+	{
+		.src_clk = &dsi_pll_byte,
+		.div_src_val = BVAL(10, 8, dsipll_mm_source_val),
+	},
+	F_END
 };
 
 static struct rcg_clk dsi_byte_clk_src = {
 	.cmd_rcgr_reg = DSI_BYTE_CMD_RCGR,
 	.set_rate = set_rate_hid,
-	.freq_tbl = ftbl_dsi_byte_clk,
-	.current_freq = &rcg_dummy_freq,
+	.current_freq = byte_freq_tbl,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
+		.parent = &dsi_pll_byte,
 		.dbg_name = "dsi_byte_clk_src",
-		.ops = &clk_ops_rcg,
+		.ops = &dsi_byte_clk_src_ops,
 		VDD_DIG_FMAX_MAP2(LOW, 62500000, NOMINAL, 125000000),
 		CLK_INIT(dsi_byte_clk_src.c),
 	},
@@ -1933,7 +2017,7 @@
 	},
 };
 
-static struct mux_clk csi0phy_mux_clk = {
+static struct cam_mux_clk csi0phy_cam_mux_clk = {
 	.enable_reg = MMSS_CAMSS_MISC,
 	.enable_mask = BIT(11),
 	.select_reg = MMSS_CAMSS_MISC,
@@ -1945,13 +2029,13 @@
 	},
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
-		.dbg_name = "csi0phy_mux_clk",
-		.ops = &clk_ops_mux,
-		CLK_INIT(csi0phy_mux_clk.c),
+		.dbg_name = "csi0phy_cam_mux_clk",
+		.ops = &clk_ops_cam_mux,
+		CLK_INIT(csi0phy_cam_mux_clk.c),
 	},
 };
 
-static struct mux_clk csi1phy_mux_clk = {
+static struct cam_mux_clk csi1phy_cam_mux_clk = {
 	.enable_reg = MMSS_CAMSS_MISC,
 	.enable_mask = BIT(10),
 	.select_reg = MMSS_CAMSS_MISC,
@@ -1963,13 +2047,13 @@
 	},
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
-		.dbg_name = "csi1phy_mux_clk",
-		.ops = &clk_ops_mux,
-		CLK_INIT(csi1phy_mux_clk.c),
+		.dbg_name = "csi1phy_cam_mux_clk",
+		.ops = &clk_ops_cam_mux,
+		CLK_INIT(csi1phy_cam_mux_clk.c),
 	},
 };
 
-static struct mux_clk csi0pix_mux_clk = {
+static struct cam_mux_clk csi0pix_cam_mux_clk = {
 	.enable_reg = MMSS_CAMSS_MISC,
 	.enable_mask = BIT(7),
 	.select_reg = MMSS_CAMSS_MISC,
@@ -1981,14 +2065,14 @@
 	},
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
-		.dbg_name = "csi0pix_mux_clk",
-		.ops = &clk_ops_mux,
-		CLK_INIT(csi0pix_mux_clk.c),
+		.dbg_name = "csi0pix_cam_mux_clk",
+		.ops = &clk_ops_cam_mux,
+		CLK_INIT(csi0pix_cam_mux_clk.c),
 	},
 };
 
 
-static struct mux_clk rdi2_mux_clk = {
+static struct cam_mux_clk rdi2_cam_mux_clk = {
 	.enable_reg = MMSS_CAMSS_MISC,
 	.enable_mask = BIT(6),
 	.select_reg = MMSS_CAMSS_MISC,
@@ -2000,13 +2084,13 @@
 	},
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
-		.dbg_name = "rdi2_mux_clk",
-		.ops = &clk_ops_mux,
-		CLK_INIT(rdi2_mux_clk.c),
+		.dbg_name = "rdi2_cam_mux_clk",
+		.ops = &clk_ops_cam_mux,
+		CLK_INIT(rdi2_cam_mux_clk.c),
 	},
 };
 
-static struct mux_clk rdi1_mux_clk = {
+static struct cam_mux_clk rdi1_cam_mux_clk = {
 	.enable_reg = MMSS_CAMSS_MISC,
 	.enable_mask = BIT(5),
 	.select_reg = MMSS_CAMSS_MISC,
@@ -2018,13 +2102,13 @@
 	},
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
-		.dbg_name = "rdi1_mux_clk",
-		.ops = &clk_ops_mux,
-		CLK_INIT(rdi1_mux_clk.c),
+		.dbg_name = "rdi1_cam_mux_clk",
+		.ops = &clk_ops_cam_mux,
+		CLK_INIT(rdi1_cam_mux_clk.c),
 	},
 };
 
-static struct mux_clk rdi0_mux_clk = {
+static struct cam_mux_clk rdi0_cam_mux_clk = {
 	.enable_reg = MMSS_CAMSS_MISC,
 	.enable_mask = BIT(4),
 	.select_reg = MMSS_CAMSS_MISC,
@@ -2036,9 +2120,9 @@
 	},
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
-		.dbg_name = "rdi0_mux_clk",
-		.ops = &clk_ops_mux,
-		CLK_INIT(rdi0_mux_clk.c),
+		.dbg_name = "rdi0_cam_mux_clk",
+		.ops = &clk_ops_cam_mux,
+		CLK_INIT(rdi0_cam_mux_clk.c),
 	},
 };
 
@@ -2114,7 +2198,6 @@
 
 static struct branch_clk dsi_pclk_clk = {
 	.cbcr_reg = DSI_PCLK_CBCR,
-	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.parent = &dsi_pclk_clk_src.c,
@@ -2789,17 +2872,18 @@
 	CLK_LOOKUP("core_clk_src",          sdcc1_apps_clk_src.c, ""),
 	CLK_LOOKUP("core_clk_src",          sdcc2_apps_clk_src.c, ""),
 	CLK_LOOKUP("core_clk_src",       usb_hs_system_clk_src.c, ""),
+	CLK_LOOKUP("iface_clk",           gcc_blsp1_ahb_clk.c, "f9923000.i2c"),
 	CLK_LOOKUP("iface_clk",           gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
-	CLK_LOOKUP("iface_clk",           gcc_blsp1_ahb_clk.c, "f9923000.spi"),
-	CLK_LOOKUP("core_clk",  gcc_blsp1_qup1_i2c_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk",  gcc_blsp1_qup1_spi_apps_clk.c, "f9923000.spi"),
+	CLK_LOOKUP("iface_clk",           gcc_blsp1_ahb_clk.c, "f9927000.i2c"),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup1_i2c_apps_clk.c, "f9923000.i2c"),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup1_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup2_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup2_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c"),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup3_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup4_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup4_spi_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk",  gcc_blsp1_qup5_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup5_i2c_apps_clk.c, "f9927000.i2c"),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup5_spi_apps_clk.c, ""),
 	CLK_LOOKUP("iface_clk",           gcc_blsp1_ahb_clk.c, "f9928000.i2c"),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup6_i2c_apps_clk.c, "f9928000.i2c"),
@@ -2884,12 +2968,12 @@
 	CLK_LOOKUP("core_clk",                  vfe_ahb_clk.c, ""),
 	CLK_LOOKUP("core_clk",                  vfe_axi_clk.c, ""),
 
-	CLK_LOOKUP("core_clk",              csi0pix_mux_clk.c, ""),
-	CLK_LOOKUP("core_clk",              csi0phy_mux_clk.c, ""),
-	CLK_LOOKUP("core_clk",              csi1phy_mux_clk.c, ""),
-	CLK_LOOKUP("core_clk",                 rdi2_mux_clk.c, ""),
-	CLK_LOOKUP("core_clk",                 rdi1_mux_clk.c, ""),
-	CLK_LOOKUP("core_clk",                 rdi0_mux_clk.c, ""),
+	CLK_LOOKUP("core_clk",              csi0pix_cam_mux_clk.c, ""),
+	CLK_LOOKUP("core_clk",              csi0phy_cam_mux_clk.c, ""),
+	CLK_LOOKUP("core_clk",              csi1phy_cam_mux_clk.c, ""),
+	CLK_LOOKUP("core_clk",                 rdi2_cam_mux_clk.c, ""),
+	CLK_LOOKUP("core_clk",                 rdi1_cam_mux_clk.c, ""),
+	CLK_LOOKUP("core_clk",                 rdi0_cam_mux_clk.c, ""),
 
 	CLK_LOOKUP("core_clk",   oxili_gfx3d_clk.c, "fdc00000.qcom,kgsl-3d0"),
 	CLK_LOOKUP("iface_clk",    oxili_ahb_clk.c, "fdc00000.qcom,kgsl-3d0"),
@@ -3075,6 +3159,26 @@
 	clk_set_rate(&mclk1_clk_src.c, mclk1_clk_src.freq_tbl[0].freq_hz);
 }
 
+static void dsi_init(void)
+{
+	dsi_byte_clk_src_ops = clk_ops_rcg;
+	dsi_byte_clk_src_ops.set_rate = set_rate_pixel_byte_clk;
+	dsi_byte_clk_src_ops.handoff = byte_rcg_handoff;
+	dsi_byte_clk_src_ops.get_parent = NULL;
+
+	dsi_dsi_clk_src_ops = clk_ops_rcg_mnd;
+	dsi_dsi_clk_src_ops.set_rate = set_rate_dsi_clk;
+	dsi_dsi_clk_src_ops.handoff = pixel_rcg_handoff;
+	dsi_dsi_clk_src_ops.get_parent = NULL;
+
+	dsi_pixel_clk_src_ops = clk_ops_rcg_mnd;
+	dsi_pixel_clk_src_ops.set_rate = set_rate_pixel_byte_clk;
+	dsi_pixel_clk_src_ops.handoff = pixel_rcg_handoff;
+	dsi_pixel_clk_src_ops.get_parent = NULL;
+
+	dsi_clk_ctrl_init(&dsi_ahb_clk.c);
+}
+
 #define GCC_CC_PHYS		0xFC400000
 #define GCC_CC_SIZE		SZ_16K
 
@@ -3134,6 +3238,8 @@
 
 	reg_init();
 
+	dsi_init();
+
 	/* Maintain the max nominal frequency on the MMSSNOC AHB bus. */
 	clk_set_rate(&mmssnoc_ahb_a_clk.c,  40000000);
 	clk_prepare_enable(&mmssnoc_ahb_a_clk.c);
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index be6d965..9ee4476 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -6406,79 +6406,14 @@
 	.main_output_mask = BIT(23),
 };
 
-static void __init reg_init(void)
+
+static void __init init_mm_cc(void)
 {
-	void __iomem *imem_reg;
-
-	/* Deassert MM SW_RESET_ALL signal. */
-	writel_relaxed(0, SW_RESET_ALL_REG);
-
 	/*
-	 * Some bits are only used on 8960 or 8064 or 8930 and are marked as
-	 * reserved bits on the other SoCs. Writing to these reserved bits
-	 * should have no effect.
-	 */
-	/*
-	 * Initialize MM AHB registers: Enable the FPB clock and disable HW
-	 * gating on 8627 and 8930ab for all clocks. Also set VFE_AHB's
-	 * FORCE_CORE_ON bit to prevent its memory from being collapsed when
-	 * the clock is halted. The sleep and wake-up delays are set to safe
-	 * values.
-	 */
-	if (cpu_is_msm8627() || cpu_is_msm8930ab()) {
-		rmwreg(0x00000003, AHB_EN_REG,  0x6C000103);
-		writel_relaxed(0x000007F9, AHB_EN2_REG);
-	} else {
-		rmwreg(0x40000000, AHB_EN_REG,  0x6C000103);
-		writel_relaxed(0x3C7097F9, AHB_EN2_REG);
-	}
-
-	if (soc_class_is_apq8064())
-		rmwreg(0x00000000, AHB_EN3_REG, 0x00000001);
-
-	/* Deassert all locally-owned MM AHB resets. */
-	rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
-	rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
-
-	/* Initialize MM AXI registers: Enable HW gating for all clocks that
-	 * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
-	 * delays to safe values. */
-	if ((cpu_is_msm8960() &&
-			SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 3) ||
-			cpu_is_msm8627() || cpu_is_msm8930ab()) {
-		rmwreg(0x000007F9, MAXI_EN_REG,  0x0803FFFF);
-		rmwreg(0x3027FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
-	} else {
-		rmwreg(0x0003AFF9, MAXI_EN_REG,  0x0803FFFF);
-		rmwreg(0x3A27FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
-	}
-
-	rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
-	rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
-
-	if (soc_class_is_apq8064())
-		rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
-	if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627() ||
-	    cpu_is_msm8930ab())
-		rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
-	if (cpu_is_msm8960ab())
-		rmwreg(0x009FE000, MAXI_EN5_REG, 0x01FFE000);
-
-	if (cpu_is_msm8627() || cpu_is_msm8930ab())
-		rmwreg(0x000003C7, SAXI_EN_REG,  0x00003FFF);
-	else
-		rmwreg(0x00003C38, SAXI_EN_REG,  0x00003FFF);
-
-	/* Enable IMEM's clk_on signal */
-	imem_reg = ioremap(0x04b00040, 4);
-	if (imem_reg) {
-		writel_relaxed(0x3, imem_reg);
-		iounmap(imem_reg);
-	}
-
-	/* Initialize MM CC registers: Set MM FORCE_CORE_ON bits so that core
+	 * Initialize MM CC registers: Set MM FORCE_CORE_ON bits so that core
 	 * memories retain state even when not clocked. Also, set sleep and
-	 * wake-up delays to safe values. */
+	 * wake-up delays to safe values.
+	 */
 	rmwreg(0x00000000, CSI0_CC_REG,       0x00000410);
 	rmwreg(0x00000000, CSI1_CC_REG,       0x00000410);
 	rmwreg(0x80FF0000, DSI1_BYTE_CC_REG,  0xE0FF0010);
@@ -6493,28 +6428,72 @@
 	rmwreg(0x80FF0000, VFE_CC_REG,        0xE0FF4010);
 	rmwreg(0x800000FF, VFE_CC2_REG,       0xE00000FF);
 	rmwreg(0x80FF0000, VPE_CC_REG,        0xE0FF0010);
-	if (cpu_is_msm8960ab() || cpu_is_msm8960() || soc_class_is_apq8064()) {
-		rmwreg(0x80FF0000, DSI2_BYTE_CC_REG,  0xE0FF0010);
-		rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
-		rmwreg(0x80FF0000, JPEGD_CC_REG,      0xE0FF0010);
-	}
-	if (cpu_is_msm8960ab())
-		rmwreg(0x00000001, DSI2_PIXEL_CC2_REG, 0x00000001);
+}
 
-	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
-	    cpu_is_msm8627() || cpu_is_msm8930ab())
-		rmwreg(0x80FF0000, TV_CC_REG,        0xE1FFC010);
-	if (cpu_is_msm8960ab())
-		rmwreg(0x00000000, TV_CC_REG,        0x00004010);
+static void __init enable_imem_clk(unsigned long phys)
+{
+	void __iomem *imem_reg;
 
-	if (cpu_is_msm8960()) {
-		rmwreg(0x80FF0000, GFX2D0_CC_REG,     0xE0FF0010);
-		rmwreg(0x80FF0000, GFX2D1_CC_REG,     0xE0FF0010);
+	/* Enable IMEM's clk_on signal */
+	imem_reg = ioremap(phys, SZ_4);
+	if (imem_reg) {
+		writel_relaxed(0x3, imem_reg);
+		iounmap(imem_reg);
 	}
-	if (soc_class_is_apq8064()) {
-		rmwreg(0x00000000, TV_CC_REG,         0x00004010);
-		rmwreg(0x80FF0000, VCAP_CC_REG,       0xE0FF1010);
+}
+
+static void __init reg_init_8930(void)
+{
+	/* MM-AHB default values */
+	u32 en_reg = 0x40000000, en2_reg = 0x3C7097F9;
+	/* MM-AXI default values */
+	u32 aen_reg = 0x0003AFF9, aen2_reg = 0x3A27FCFF,
+		 saen_reg = 0x00003C38;
+
+
+	/* Deassert MM SW_RESET_ALL signal. */
+	writel_relaxed(0, SW_RESET_ALL_REG);
+
+	/*
+	 * Initialize MM AHB registers: Enable the FPB clock and disable HW
+	 * gating on 8627 and 8930ab for all clocks. Also set VFE_AHB's
+	 * FORCE_CORE_ON bit to prevent its memory from being collapsed when
+	 * the clock is halted. The sleep and wake-up delays are set to safe
+	 * values.
+	 */
+	if (cpu_is_msm8627() || cpu_is_msm8930ab()) {
+		en_reg  = 0x00000003;
+		en2_reg = 0x000007F9;
 	}
+	rmwreg(en_reg, AHB_EN_REG, 0x6C000103);
+	writel_relaxed(en2_reg, AHB_EN2_REG);
+
+	/* Deassert all locally-owned MM AHB resets. */
+	rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
+	rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
+
+	/*
+	 * Initialize MM AXI registers: Enable HW gating for all clocks that
+	 * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
+	 * delays to safe values.
+	 */
+	if (cpu_is_msm8627() || cpu_is_msm8930ab()) {
+		aen_reg = 0x000007F9;
+		aen2_reg = 0x3027FCFF;
+	}
+	rmwreg(aen_reg, MAXI_EN_REG,  0x0803FFFF);
+	rmwreg(aen2_reg, MAXI_EN2_REG, 0x3A3FFFFF);
+	rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
+	rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+	rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
+	if (cpu_is_msm8627() || cpu_is_msm8930ab())
+		saen_reg = 0x000003C7;
+	rmwreg(saen_reg, SAXI_EN_REG,  0x00003FFF);
+
+	enable_imem_clk(0x04b00040);
+
+	init_mm_cc();
+	rmwreg(0x80FF0000, TV_CC_REG,        0xE1FFC010);
 
 	/*
 	 * Initialize USB_HS_HCLK_FS registers: Set FORCE_C_ON bits so that
@@ -6522,10 +6501,6 @@
 	 * and wake-up value to max.
 	 */
 	rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
-	if (soc_class_is_apq8064()) {
-		rmwreg(0x0000004F, USB_HS3_HCLK_FS_REG, 0x0000007F);
-		rmwreg(0x0000004F, USB_HS4_HCLK_FS_REG, 0x0000007F);
-	}
 
 	/* De-assert MM AXI resets to all hardware blocks. */
 	writel_relaxed(0, SW_RESET_AXI_REG);
@@ -6538,88 +6513,231 @@
 	writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
 	writel_relaxed(BIT(15), PDM_CLK_NS_REG);
 
-	/* Source SLIMBus xo src from slimbus reference clock */
-	if (cpu_is_msm8960ab() || cpu_is_msm8960())
-		writel_relaxed(0x3, SLIMBUS_XO_SRC_CLK_CTL_REG);
-
-	/* Source the dsi_byte_clks from the DSI PHY PLLs */
+	/* Source the dsi1_byte_clks/dsi1_esc_clk from the DSI PHY PLLs */
 	rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
-	if (cpu_is_msm8960ab() || cpu_is_msm8960() || soc_class_is_apq8064())
-		rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
-
-	/* Source the dsi1_esc_clk from the DSI1 PHY PLLs */
 	rmwreg(0x1, DSI1_ESC_NS_REG, 0x7);
 
 	/*
+	 * Change PLL15 configuration based on the SoC we're running on.
+	 *
+	 * Default pll15 l, m, n values for 8930/8930aa/8627()
+	 */
+	pll15_config.l = 0x21 | BVAL(31, 7, 0x600);
+	pll15_config.m = 0x1;
+	pll15_config.n = 0x3;
+
+	if (cpu_is_msm8930ab()) {
+		pll15_config.l = 0x25 | BVAL(31, 7, 0x600);
+		pll15_config.m = 0x25;
+		pll15_config.n = 0x3E7;
+	}
+	configure_sr_pll(&pll15_config, &pll15_regs, 0);
+
+	/* Disable AUX and BIST outputs */
+	writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
+}
+
+static void __init reg_init_8064(void)
+{
+	u32 is_pll_enabled;
+
+	/* Deassert MM SW_RESET_ALL signal. */
+	writel_relaxed(0, SW_RESET_ALL_REG);
+
+	/*
+	 * Initialize MM AHB registers:
+	 * Also set VFE_AHB's FORCE_CORE_ON bit to prevent its memory
+	 * from being collapsed when the clock is halted. The sleep and
+	 * wake-up delays are set to safe values.
+	 */
+	rmwreg(0x40000000, AHB_EN_REG, 0x6C000103);
+	writel_relaxed(0x3C7097F9, AHB_EN2_REG);
+	rmwreg(0x00000000, AHB_EN3_REG, 0x00000001);
+
+	/* Deassert all locally-owned MM AHB resets. */
+	rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
+	rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
+
+	/*
+	 * Initialize MM AXI registers: Enable HW gating for all clocks that
+	 * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
+	 * delays to safe values.
+	 */
+	rmwreg(0x0003AFF9, MAXI_EN_REG,  0x0803FFFF);
+	rmwreg(0x3A27FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
+	rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
+	rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+	rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
+	rmwreg(0x00003C38, SAXI_EN_REG,  0x00003FFF);
+
+	enable_imem_clk(0x04b00040);
+
+	init_mm_cc();
+	rmwreg(0x80FF0000, DSI2_BYTE_CC_REG,  0xE0FF0010);
+	rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
+	rmwreg(0x80FF0000, JPEGD_CC_REG,      0xE0FF0010);
+	rmwreg(0x00000000, TV_CC_REG,         0x00004010);
+	rmwreg(0x80FF0000, VCAP_CC_REG,       0xE0FF1010);
+
+	/*
+	 * Initialize USB_HS_HCLK_FS registers: Set FORCE_C_ON bits so that
+	 * core remain active during halt state of the clk. Also, set sleep
+	 * and wake-up value to max.
+	 */
+	rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
+	rmwreg(0x0000004F, USB_HS3_HCLK_FS_REG, 0x0000007F);
+	rmwreg(0x0000004F, USB_HS4_HCLK_FS_REG, 0x0000007F);
+
+	/* De-assert MM AXI resets to all hardware blocks. */
+	writel_relaxed(0, SW_RESET_AXI_REG);
+
+	/* Deassert all MM core resets. */
+	writel_relaxed(0, SW_RESET_CORE_REG);
+	writel_relaxed(0, SW_RESET_CORE2_REG);
+
+	/* Enable TSSC and PDM PXO sources. */
+	writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
+	writel_relaxed(BIT(15), PDM_CLK_NS_REG);
+
+	/* Source the dsi1_byte_clks/dsi1_esc_clk from the DSI PHY PLLs */
+	rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
+	rmwreg(0x1, DSI1_ESC_NS_REG, 0x7);
+
+	/* Source the dsi2_byte_clks from the DSI PHY PLLs */
+	rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
+
+	/*
 	 * Source the sata_phy_ref_clk from PXO and set predivider of
 	 * sata_pmalive_clk to 1.
 	 */
-	if (soc_class_is_apq8064()) {
-		rmwreg(0, SATA_PHY_REF_CLK_CTL_REG, 0x1);
-		rmwreg(0, SATA_PMALIVE_CLK_CTL_REG, 0x3);
-	}
+	rmwreg(0, SATA_PHY_REF_CLK_CTL_REG, 0x1);
+	rmwreg(0, SATA_PMALIVE_CLK_CTL_REG, 0x3);
 
 	/*
 	 * TODO: Programming below PLLs and prng_clk is temporary and
 	 *	 needs to be removed after bootloaders program them.
 	 */
-	if (soc_class_is_apq8064()) {
-		u32 is_pll_enabled;
 
-		/* Program pxo_src_clk to source from PXO */
-		rmwreg(0x1, PXO_SRC_CLK_CTL_REG, 0x7);
+	/* Program pxo_src_clk to source from PXO */
+	rmwreg(0x1, PXO_SRC_CLK_CTL_REG, 0x7);
 
-		/* Check if PLL14 is active */
-		is_pll_enabled = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
-		if (!is_pll_enabled)
-			/* Ref clk = 27MHz and program pll14 to 480MHz */
-			configure_sr_pll(&pll14_config, &pll14_regs, 1);
+	/* Check if PLL14 is active */
+	is_pll_enabled = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
+	if (!is_pll_enabled)
+		/* Ref clk = 27MHz and program pll14 to 480MHz */
+		configure_sr_pll(&pll14_config, &pll14_regs, 1);
 
-		/* Check if PLL4 is active */
-		is_pll_enabled = readl_relaxed(LCC_PLL0_STATUS_REG) & BIT(16);
-		if (!is_pll_enabled)
-			/* Ref clk = 27MHz and program pll4 to 393.2160MHz */
-			configure_sr_pll(&pll4_config_393, &pll4_regs, 1);
+	/* Check if PLL4 is active */
+	is_pll_enabled = readl_relaxed(LCC_PLL0_STATUS_REG) & BIT(16);
+	if (!is_pll_enabled)
+		/* Ref clk = 27MHz and program pll4 to 393.2160MHz */
+		configure_sr_pll(&pll4_config_393, &pll4_regs, 1);
 
-		/* Enable PLL4 source on the LPASS Primary PLL Mux */
-		writel_relaxed(0x1, LCC_PRI_PLL_CLK_CTL_REG);
+	/* Enable PLL4 source on the LPASS Primary PLL Mux */
+	writel_relaxed(0x1, LCC_PRI_PLL_CLK_CTL_REG);
 
-		/* Program prng_clk to 64MHz if it isn't configured */
-		if (!readl_relaxed(PRNG_CLK_NS_REG))
-			writel_relaxed(0x2B, PRNG_CLK_NS_REG);
-	}
+	/* Program prng_clk to 64MHz if it isn't configured */
+	if (!readl_relaxed(PRNG_CLK_NS_REG))
+		writel_relaxed(0x2B, PRNG_CLK_NS_REG);
 
-	if (cpu_is_apq8064() || cpu_is_apq8064aa()) {
-		/* Program PLL15 to 975MHz with ref clk = 27MHz */
-		configure_sr_pll(&pll15_config, &pll15_regs, 0);
-	} else if (cpu_is_apq8064ab()) {
+	if (cpu_is_apq8064ab()) {
 		/* Program PLL15 to 900MHZ */
 		pll15_config.l = 0x21 | BVAL(31, 7, 0x620);
 		pll15_config.m = 0x1;
 		pll15_config.n = 0x3;
-		configure_sr_pll(&pll15_config, &pll15_regs, 0);
-	} else if (cpu_is_msm8960ab()) {
-		pll3_clk.c.rate = 880000000;
-		configure_sr_pll(&pll3_config, &pll3_regs, 0);
+	}
+	/*
+	 * Default Program PLL15 to 975MHz with ref clk = 27MHz
+	 * In case of apq8064ab PLL15 is set to 900MHZ
+	 */
+	configure_sr_pll(&pll15_config, &pll15_regs, 0);
+}
+
+static void __init reg_init_8960(void)
+{
+	u32 aen_reg = 0x0003AFF9, aen2_reg = 0x3A27FCFF;
+
+	/* Deassert MM SW_RESET_ALL signal. */
+	writel_relaxed(0, SW_RESET_ALL_REG);
+
+	/*
+	 * Initialize MM AHB registers:
+	 * Also set VFE_AHB's FORCE_CORE_ON bit to prevent its memory
+	 * from being collapsed when the clock is halted. The sleep and
+	 * wake-up delays are set to safe values.
+	 */
+	rmwreg(0x40000000, AHB_EN_REG, 0x6C000103);
+	writel_relaxed(0x3C7097F9, AHB_EN2_REG);
+
+	/* Deassert all locally-owned MM AHB resets. */
+	rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
+	rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
+
+	/*
+	 * Initialize MM AXI registers: Enable HW gating for all clocks that
+	 * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
+	 * delays to safe values.
+	 */
+	if (cpu_is_msm8960() &&
+		SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 3) {
+		aen_reg = 0x000007F9;
+		aen2_reg = 0x3027FCFF;
+	}
+	rmwreg(aen_reg, MAXI_EN_REG,  0x0803FFFF);
+	rmwreg(aen2_reg, MAXI_EN2_REG, 0x3A3FFFFF);
+	rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
+	rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+	if (cpu_is_msm8960ab())
+		rmwreg(0x009FE000, MAXI_EN5_REG, 0x01FFE000);
+	rmwreg(0x00003C38, SAXI_EN_REG,  0x00003FFF);
+
+	enable_imem_clk(0x04b00040);
+
+	init_mm_cc();
+	rmwreg(0x80FF0000, DSI2_BYTE_CC_REG,  0xE0FF0010);
+	rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
+	rmwreg(0x80FF0000, JPEGD_CC_REG,      0xE0FF0010);
+	if (cpu_is_msm8960ab()) {
+		rmwreg(0x00000001, DSI2_PIXEL_CC2_REG, 0x00000001);
+		rmwreg(0x00000000, TV_CC_REG,        0x00004010);
+	}
+	if (cpu_is_msm8960()) {
+		rmwreg(0x80FF0000, TV_CC_REG,        0xE1FFC010);
+		rmwreg(0x80FF0000, GFX2D0_CC_REG,     0xE0FF0010);
+		rmwreg(0x80FF0000, GFX2D1_CC_REG,     0xE0FF0010);
 	}
 
 	/*
-	 * Change PLL15 configuration based on the SoC we're running on.
+	 * Initialize USB_HS_HCLK_FS registers: Set FORCE_C_ON bits so that
+	 * core remain active during halt state of the clk. Also, set sleep
+	 * and wake-up value to max.
 	 */
-	if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
-		pll15_config.l = 0x21 | BVAL(31, 7, 0x600);
-		pll15_config.m = 0x1;
-		pll15_config.n = 0x3;
-		configure_sr_pll(&pll15_config, &pll15_regs, 0);
-		/* Disable AUX and BIST outputs */
-		writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
-	} else if (cpu_is_msm8930ab()) {
-		pll15_config.l = 0x25 | BVAL(31, 7, 0x600);
-		pll15_config.m = 0x25;
-		pll15_config.n = 0x3E7;
-		configure_sr_pll(&pll15_config, &pll15_regs, 0);
-		/* Disable AUX and BIST outputs */
-		writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
+	rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
+
+	/* De-assert MM AXI resets to all hardware blocks. */
+	writel_relaxed(0, SW_RESET_AXI_REG);
+
+	/* Deassert all MM core resets. */
+	writel_relaxed(0, SW_RESET_CORE_REG);
+	writel_relaxed(0, SW_RESET_CORE2_REG);
+
+	/* Enable TSSC and PDM PXO sources. */
+	writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
+	writel_relaxed(BIT(15), PDM_CLK_NS_REG);
+
+	/* Source the dsi1_byte_clks/dsi1_esc_clk from the DSI PHY PLLs */
+	rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
+	rmwreg(0x1, DSI1_ESC_NS_REG, 0x7);
+
+	/* Source SLIMBus xo src from slimbus reference clock */
+	writel_relaxed(0x3, SLIMBUS_XO_SRC_CLK_CTL_REG);
+
+	/* Source the dsi2_byte_clks from the DSI PHY PLLs */
+	rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
+
+	 if (cpu_is_msm8960ab()) {
+		pll3_clk.c.rate = 880000000;
+		configure_sr_pll(&pll3_config, &pll3_regs, 0);
 	}
 }
 
@@ -6645,13 +6763,15 @@
 }
 
 struct clock_init_data msm8960_clock_init_data __initdata;
+
 static void __init msm8960_clock_pre_init(void)
 {
-	/* Initialize clock registers. */
-	reg_init();
+	struct clk_lookup *clk_lkup;
+	size_t clk_size;
+	struct clk_freq_tbl *tbl;
 
-	if (soc_class_is_apq8064())
-		vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
+	/* Initialize clock registers. */
+	reg_init_8960();
 
 	/* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
 	if (readl_relaxed(LCC_PLL0_L_VAL_REG) == 0x12) {
@@ -6665,73 +6785,120 @@
 		pcm_clk.freq_tbl = clk_tbl_pcm_492;
 	}
 
-	if (cpu_is_msm8960() || cpu_is_msm8960ab())
-		memcpy(msm_clocks_8960, msm_clocks_8960_common,
-			sizeof(msm_clocks_8960_common));
-	if (cpu_is_msm8960ab()) {
-		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8960ab;
-		mdp_clk.c.fmax = fmax_mdp_8960ab;
-
-		gfx3d_clk.c.fmax = select_gfx_fmax_plan(fmax_gfx3d_8960ab,
-						ARRAY_SIZE(fmax_gfx3d_8960ab));
-
-		memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
-			msm_clocks_8960ab_only, sizeof(msm_clocks_8960ab_only));
-		msm8960_clock_init_data.size -=
-			ARRAY_SIZE(msm_clocks_8960_only);
-
-		gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
-	} else if (cpu_is_msm8960()) {
-		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8960;
-		memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
-			 msm_clocks_8960_only, sizeof(msm_clocks_8960_only));
+	if (cpu_is_msm8960()) {
+		tbl = clk_tbl_gfx3d_8960;
+		clk_lkup = msm_clocks_8960_only;
+		clk_size = sizeof(msm_clocks_8960_only);
 		msm8960_clock_init_data.size -=
 			ARRAY_SIZE(msm_clocks_8960ab_only);
 	}
-	/*
-	 * Change the freq tables for and voltage requirements for
-	 * clocks which differ between chips.
-	 */
-	if (cpu_is_apq8064() || cpu_is_apq8064aa())
-		gfx3d_clk.c.fmax = fmax_gfx3d_8064;
+
+	if (cpu_is_msm8960ab()) {
+		mdp_clk.c.fmax = fmax_mdp_8960ab;
+		gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
+		tbl = clk_tbl_gfx3d_8960ab;
+		gfx3d_clk.c.fmax = select_gfx_fmax_plan(fmax_gfx3d_8960ab,
+				ARRAY_SIZE(fmax_gfx3d_8960ab));
+
+		clk_lkup = msm_clocks_8960ab_only;
+		clk_size = sizeof(msm_clocks_8960ab_only);
+		msm8960_clock_init_data.size -=
+			 ARRAY_SIZE(msm_clocks_8960_only);
+	}
+
+	gfx3d_clk.freq_tbl = tbl;
+
+	memcpy(msm_clocks_8960, msm_clocks_8960_common,
+			sizeof(msm_clocks_8960_common));
+	memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
+			clk_lkup, clk_size);
+
+	if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
+		prng_clk.freq_tbl = clk_tbl_prng_64;
+
+	clk_ops_local_pll.enable = sr_pll_clk_enable;
+}
+
+static void __init msm8064_clock_pre_init(void)
+{
+	unsigned long *fmax = fmax_gfx3d_8064;
+
+	/* Initialize clock registers. */
+	reg_init_8064();
+
+	vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
+
+	/* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
+	if (readl_relaxed(LCC_PLL0_L_VAL_REG) == 0x12) {
+		pll4_clk.c.rate = 491520000;
+		audio_slimbus_clk.freq_tbl = clk_tbl_aif_osr_492;
+		mi2s_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+		codec_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+		spare_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+		codec_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+		spare_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+		pcm_clk.freq_tbl = clk_tbl_pcm_492;
+	}
 
 	if (cpu_is_apq8064ab())
-		gfx3d_clk.c.fmax = fmax_gfx3d_8064ab;
+		fmax = fmax_gfx3d_8064ab;
 
 	if ((cpu_is_apq8064() &&
 		SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) ||
 		cpu_is_apq8064ab() || cpu_is_apq8064aa()) {
-
 		vcodec_clk.c.fmax = fmax_vcodec_8064v2;
 		ce3_src_clk.c.fmax = fmax_ce3_8064v2;
 		sdc1_clk.c.fmax = fmax_sdc1_8064v2;
 	}
-	if (soc_class_is_apq8064()) {
-		ijpeg_clk.c.fmax = fmax_ijpeg_8064;
-		mdp_clk.c.fmax = fmax_mdp_8064;
-		tv_src_clk.c.fmax = fmax_tv_src_8064;
-		vfe_clk.c.fmax = fmax_vfe_8064;
-		gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
+
+	gfx3d_clk.c.fmax = fmax;
+	ijpeg_clk.c.fmax = fmax_ijpeg_8064;
+	mdp_clk.c.fmax = fmax_mdp_8064;
+	tv_src_clk.c.fmax = fmax_tv_src_8064;
+	vfe_clk.c.fmax = fmax_vfe_8064;
+
+	gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
+
+	if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
+		prng_clk.freq_tbl = clk_tbl_prng_64;
+
+	clk_ops_local_pll.enable = sr_pll_clk_enable;
+}
+
+static void __init __msm8930_clock_pre_init(void)
+{
+	unsigned long rate = 900000000;
+	unsigned long *fmax = fmax_gfx3d_8930;
+
+	/* Initialize clock registers. */
+	reg_init_8930();
+
+	/* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
+	if (readl_relaxed(LCC_PLL0_L_VAL_REG) == 0x12) {
+		pll4_clk.c.rate = 491520000;
+		audio_slimbus_clk.freq_tbl = clk_tbl_aif_osr_492;
+		mi2s_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+		codec_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+		spare_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+		codec_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+		spare_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+		pcm_clk.freq_tbl = clk_tbl_pcm_492;
 	}
 
-	/*
-	 * Change the freq tables and voltage requirements for
-	 * clocks which differ between 8960 and 8930.
-	 */
-	if (cpu_is_msm8930() || cpu_is_msm8627())
-		gfx3d_clk.c.fmax = fmax_gfx3d_8930;
-	else if (cpu_is_msm8930aa())
-		gfx3d_clk.c.fmax = fmax_gfx3d_8930aa;
-	if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
-		pll15_clk.c.rate = 900000000;
-		gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
-	} else if (cpu_is_msm8930ab()) {
+	if (cpu_is_msm8930aa())
+		fmax = fmax_gfx3d_8930aa;
+
+	if (cpu_is_msm8930ab()) {
+		rate = 1000000000;
+		fmax = fmax_gfx3d_8930ab;
 		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930ab;
-		pll15_clk.c.rate = 1000000000;
-		gfx3d_clk.c.fmax = fmax_gfx3d_8930ab;
-		gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
 		vcodec_clk.c.fmax = fmax_vcodec_8930ab;
 	}
+
+	pll15_clk.c.rate = rate;
+	gfx3d_clk.c.fmax = fmax;
+	gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
+
 	if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
 		prng_clk.freq_tbl = clk_tbl_prng_64;
 
@@ -6746,7 +6913,7 @@
 	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();
+	__msm8930_clock_pre_init();
 }
 
 static void __init msm8930_clock_pre_init(void)
@@ -6754,10 +6921,10 @@
 	vdd_dig.set_vdd = set_vdd_dig_8930;
 	vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930;
 
-	msm8960_clock_pre_init();
+	__msm8930_clock_pre_init();
 }
 
-static void __init msm8960_clock_post_init(void)
+static void __init common_clock_post_init(void)
 {
 	/* Keep PXO on whenever APPS cpu is active */
 	clk_prepare_enable(&pxo_a_clk.c);
@@ -6777,18 +6944,12 @@
 	clk_set_rate(&tsif_ref_clk.c, 105000);
 	clk_set_rate(&tssc_clk.c, 27000000);
 	clk_set_rate(&usb_hs1_xcvr_clk.c, 60000000);
-	if (soc_class_is_apq8064()) {
-		clk_set_rate(&usb_hs3_xcvr_clk.c, 60000000);
-		clk_set_rate(&usb_hs4_xcvr_clk.c, 60000000);
-	}
 	clk_set_rate(&usb_fs1_src_clk.c, 60000000);
-	if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_msm8930() ||
-		cpu_is_msm8930aa() || cpu_is_msm8627() || cpu_is_msm8930ab())
-		clk_set_rate(&usb_fs2_src_clk.c, 60000000);
 	clk_set_rate(&usb_hsic_xcvr_fs_clk.c, 60000000);
 	clk_set_rate(&usb_hsic_hsic_src_clk.c, 480000000);
 	clk_set_rate(&usb_hsic_hsio_cal_clk.c, 9000000);
 	clk_set_rate(&usb_hsic_system_clk.c, 60000000);
+
 	/*
 	 * Set the CSI rates to a safe default to avoid warnings when
 	 * switching csi pix and rdi clocks.
@@ -6817,6 +6978,19 @@
 	clk_prepare_enable(&sfab_tmr_a_clk.c);
 }
 
+static void __init msm8960_clock_post_init(void)
+{
+	common_clock_post_init();
+	clk_set_rate(&usb_fs2_src_clk.c, 60000000);
+}
+
+static void __init msm8064_clock_post_init(void)
+{
+	common_clock_post_init();
+	clk_set_rate(&usb_hs3_xcvr_clk.c, 60000000);
+	clk_set_rate(&usb_hs4_xcvr_clk.c, 60000000);
+}
+
 static int __init msm8960_clock_late_init(void)
 {
 	int rc;
@@ -6859,8 +7033,8 @@
 struct clock_init_data apq8064_clock_init_data __initdata = {
 	.table = msm_clocks_8064,
 	.size = ARRAY_SIZE(msm_clocks_8064),
-	.pre_init = msm8960_clock_pre_init,
-	.post_init = msm8960_clock_post_init,
+	.pre_init = msm8064_clock_pre_init,
+	.post_init = msm8064_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 707e6b6..f5af727 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -638,7 +638,7 @@
 	VDD_DIG_NUM
 };
 
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
 	[VDD_DIG_NONE]	  = VDD_UV(RPM_REGULATOR_CORNER_NONE),
 	[VDD_DIG_LOW]	  = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
 	[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
@@ -920,6 +920,7 @@
 };
 
 static struct clk_freq_tbl ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk[] = {
+	F(19200000,    cxo,   1,   0,   0),
 	F(50000000,  gpll0,  12,   0,   0),
 	F_END
 };
@@ -4894,6 +4895,7 @@
 	CLK_LOOKUP("alt_iface_clk", mdss_hdmi_ahb_clk.c,
 		"fd922100.qcom,hdmi_tx"),
 	CLK_LOOKUP("core_clk", mdss_hdmi_clk.c, "fd922100.qcom,hdmi_tx"),
+	CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922100.qcom,hdmi_tx"),
 	CLK_LOOKUP("extp_clk", mdss_extpclk_clk.c, "fd922100.qcom,hdmi_tx"),
 	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "mdp.0"),
 	CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "mdp.0"),
@@ -5121,6 +5123,17 @@
 	CLK_LOOKUP("bus_clk",  venus0_axi_clk.c, "fdc00000.qcom,vidc"),
 	CLK_LOOKUP("mem_clk",  venus0_ocmemnoc_clk.c, "fdc00000.qcom,vidc"),
 
+	CLK_LOOKUP("core_clk", venus0_vcodec0_clk.c, "fd8c1024.qcom,gdsc"),
+	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd8c2304.qcom,gdsc"),
+	CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd8c2304.qcom,gdsc"),
+	CLK_LOOKUP("core0_clk", camss_jpeg_jpeg0_clk.c, "fd8c35a4.qcom,gdsc"),
+	CLK_LOOKUP("core1_clk", camss_jpeg_jpeg1_clk.c, "fd8c35a4.qcom,gdsc"),
+	CLK_LOOKUP("core2_clk", camss_jpeg_jpeg2_clk.c, "fd8c35a4.qcom,gdsc"),
+	CLK_LOOKUP("core0_clk", camss_vfe_vfe0_clk.c,	"fd8c36a4.qcom,gdsc"),
+	CLK_LOOKUP("core1_clk", camss_vfe_vfe1_clk.c,	"fd8c36a4.qcom,gdsc"),
+	CLK_LOOKUP("csi0_clk", camss_csi_vfe0_clk.c,	"fd8c36a4.qcom,gdsc"),
+	CLK_LOOKUP("csi1_clk", camss_csi_vfe1_clk.c,	"fd8c36a4.qcom,gdsc"),
+	CLK_LOOKUP("cpp_clk", camss_vfe_cpp_clk.c,	"fd8c36a4.qcom,gdsc"),
 	CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fd8c4024.qcom,gdsc"),
 
 	/* LPASS clocks */
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 9a768e5..65176b4 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -280,7 +280,7 @@
 	VDD_DIG_NUM
 };
 
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
 	[VDD_DIG_NONE]	  = VDD_UV(RPM_REGULATOR_CORNER_NONE),
 	[VDD_DIG_LOW]	  = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
 	[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
diff --git a/arch/arm/mach-msm/clock-generic.c b/arch/arm/mach-msm/clock-generic.c
new file mode 100644
index 0000000..4d74533
--- /dev/null
+++ b/arch/arm/mach-msm/clock-generic.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <linux/clk.h>
+#include <mach/clk-provider.h>
+#include <mach/clock-generic.h>
+
+/* ==================== Mux clock ==================== */
+
+static int parent_to_src_sel(struct mux_clk *mux, struct clk *p)
+{
+	int i;
+
+	for (i = 0; i < mux->num_parents; i++) {
+		if (mux->parents[i].src == p)
+			return mux->parents[i].sel;
+	}
+
+	return -EINVAL;
+}
+
+static int mux_set_parent(struct clk *c, struct clk *p)
+{
+	struct mux_clk *mux = to_mux_clk(c);
+	int sel = parent_to_src_sel(mux, p);
+	struct clk *old_parent;
+	int rc = 0;
+	unsigned long flags;
+
+	if (sel < 0)
+		return sel;
+
+	rc = __clk_pre_reparent(c, p, &flags);
+	if (rc)
+		goto out;
+
+	rc = mux->ops->set_mux_sel(mux, sel);
+	if (rc)
+		goto set_fail;
+
+	old_parent = c->parent;
+	c->parent = p;
+	__clk_post_reparent(c, old_parent, &flags);
+
+	return 0;
+
+set_fail:
+	__clk_post_reparent(c, p, &flags);
+out:
+	return rc;
+}
+
+static long mux_round_rate(struct clk *c, unsigned long rate)
+{
+	struct mux_clk *mux = to_mux_clk(c);
+	int i;
+	long prate, max_prate = 0, rrate = LONG_MAX;
+
+	for (i = 0; i < mux->num_parents; i++) {
+		prate = clk_round_rate(mux->parents[i].src, rate);
+		if (prate < rate) {
+			max_prate = max(prate, max_prate);
+			continue;
+		}
+
+		rrate = min(rrate, prate);
+	}
+	if (rrate == LONG_MAX)
+		rrate = max_prate;
+
+	return rrate ? rrate : -EINVAL;
+}
+
+static int mux_set_rate(struct clk *c, unsigned long rate)
+{
+	struct mux_clk *mux = to_mux_clk(c);
+	struct clk *new_parent = NULL;
+	int rc = 0, i;
+	unsigned long new_par_curr_rate;
+
+	for (i = 0; i < mux->num_parents; i++) {
+		if (clk_round_rate(mux->parents[i].src, rate) == rate) {
+			new_parent = mux->parents[i].src;
+			break;
+		}
+	}
+	if (new_parent == NULL)
+		return -EINVAL;
+
+	/*
+	 * Switch to safe parent since the old and new parent might be the
+	 * same and the parent might temporarily turn off while switching
+	 * rates.
+	 */
+	if (mux->safe_sel >= 0)
+		rc = mux->ops->set_mux_sel(mux, mux->safe_sel);
+	if (rc)
+		return rc;
+
+	new_par_curr_rate = clk_get_rate(new_parent);
+	rc = clk_set_rate(new_parent, rate);
+	if (rc)
+		goto set_rate_fail;
+
+	rc = mux_set_parent(c, new_parent);
+	if (rc)
+		goto set_par_fail;
+
+	return 0;
+
+set_par_fail:
+	clk_set_rate(new_parent, new_par_curr_rate);
+set_rate_fail:
+	WARN(mux->ops->set_mux_sel(mux, parent_to_src_sel(mux, c->parent)),
+		"Set rate failed for %s. Also in bad state!\n", c->dbg_name);
+	return rc;
+}
+
+static int mux_enable(struct clk *c)
+{
+	struct mux_clk *mux = to_mux_clk(c);
+	if (mux->ops->enable)
+		return mux->ops->enable(mux);
+	return 0;
+}
+
+static void mux_disable(struct clk *c)
+{
+	struct mux_clk *mux = to_mux_clk(c);
+	if (mux->ops->disable)
+		return mux->ops->disable(mux);
+}
+
+static struct clk *mux_get_parent(struct clk *c)
+{
+	struct mux_clk *mux = to_mux_clk(c);
+	int sel = mux->ops->get_mux_sel(mux);
+	int i;
+
+	for (i = 0; i < mux->num_parents; i++) {
+		if (mux->parents[i].sel == sel)
+			return mux->parents[i].src;
+	}
+
+	/* Unfamiliar parent. */
+	return NULL;
+}
+
+static enum handoff mux_handoff(struct clk *c)
+{
+	struct mux_clk *mux = to_mux_clk(c);
+
+	c->rate = clk_get_rate(c->parent);
+	mux->safe_sel = parent_to_src_sel(mux, mux->safe_parent);
+
+	if (mux->en_mask && mux->ops && mux->ops->is_enabled)
+		return mux->ops->is_enabled(mux)
+			? HANDOFF_ENABLED_CLK
+			: HANDOFF_DISABLED_CLK;
+
+	/*
+	 * If this function returns 'enabled' even when the clock downstream
+	 * of this clock is disabled, then handoff code will unnecessarily
+	 * enable the current parent of this clock. If this function always
+	 * returns 'disabled' and a clock downstream is on, the clock handoff
+	 * code will bump up the ref count for this clock and its current
+	 * parent as necessary. So, clocks without an actual HW gate can
+	 * always return disabled.
+	 */
+	return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_gen_mux = {
+	.enable = mux_enable,
+	.disable = mux_disable,
+	.set_parent = mux_set_parent,
+	.round_rate = mux_round_rate,
+	.set_rate = mux_set_rate,
+	.handoff = mux_handoff,
+	.get_parent = mux_get_parent,
+};
+
+
+/* ==================== Divider clock ==================== */
+
+static long __div_round_rate(struct clk *c, unsigned long rate, int *best_div)
+{
+	struct div_clk *d = to_div_clk(c);
+	unsigned int div, min_div, max_div;
+	long p_rrate, rrate = LONG_MAX;
+
+	rate = max(rate, 1UL);
+
+	if (!d->ops || !d->ops->set_div)
+		min_div = max_div = d->div;
+	else {
+		min_div = max(d->min_div, 1U);
+		max_div = min(d->max_div, (unsigned int) (LONG_MAX / rate));
+	}
+
+	for (div = min_div; div <= max_div; div++) {
+		p_rrate = clk_round_rate(c->parent, rate * div);
+		if (p_rrate < 0)
+			break;
+
+		p_rrate /= div;
+		/*
+		 * Trying higher dividers is only going to ask the parent for
+		 * a higher rate. If it can't even output a rate higher than
+		 * the one we request for this divider, the parent is not
+		 * going to be able to output an even higher rate required
+		 * for a higher divider. So, stop trying higher dividers.
+		 */
+		if (p_rrate < rate) {
+			if (rrate == LONG_MAX) {
+				rrate = p_rrate;
+				if (best_div)
+					*best_div = div;
+			}
+			break;
+		}
+		if (p_rrate < rrate) {
+			rrate = p_rrate;
+			if (best_div)
+				*best_div = div;
+		}
+
+		if (rrate <= rate + d->rate_margin)
+			break;
+	}
+
+	if (rrate == LONG_MAX)
+		return -EINVAL;
+
+	return rrate;
+}
+
+static long div_round_rate(struct clk *c, unsigned long rate)
+{
+	return __div_round_rate(c, rate, NULL);
+}
+
+static int div_set_rate(struct clk *c, unsigned long rate)
+{
+	struct div_clk *d = to_div_clk(c);
+	int div, rc = 0;
+	long rrate, old_prate;
+
+	rrate = __div_round_rate(c, rate, &div);
+	if (rrate != rate)
+		return -EINVAL;
+
+	if (div > d->div)
+		rc = d->ops->set_div(d, div);
+	if (rc)
+		return rc;
+
+	old_prate = clk_get_rate(c->parent);
+	rc = clk_set_rate(c->parent, rate * div);
+	if (rc)
+		goto set_rate_fail;
+
+	if (div < d->div)
+		rc = d->ops->set_div(d, div);
+	if (rc)
+		goto div_dec_fail;
+
+	d->div = div;
+
+	return 0;
+
+div_dec_fail:
+	WARN(clk_set_rate(c->parent, old_prate),
+		"Set rate failed for %s. Also in bad state!\n", c->dbg_name);
+set_rate_fail:
+	if (div > d->div)
+		WARN(d->ops->set_div(d, d->div),
+			"Set rate failed for %s. Also in bad state!\n",
+			c->dbg_name);
+	return rc;
+}
+
+static int div_enable(struct clk *c)
+{
+	struct div_clk *d = to_div_clk(c);
+	if (d->ops->enable)
+		return d->ops->enable(d);
+	return 0;
+}
+
+static void div_disable(struct clk *c)
+{
+	struct div_clk *d = to_div_clk(c);
+	if (d->ops->disable)
+		return d->ops->disable(d);
+}
+
+static enum handoff div_handoff(struct clk *c)
+{
+	struct div_clk *d = to_div_clk(c);
+
+	if (d->ops->get_div)
+		d->div = max(d->ops->get_div(d), 1);
+	d->div = max(d->div, 1U);
+	c->rate = clk_get_rate(c->parent) / d->div;
+
+	if (d->en_mask && d->ops && d->ops->is_enabled)
+		return d->ops->is_enabled(d)
+			? HANDOFF_ENABLED_CLK
+			: HANDOFF_DISABLED_CLK;
+
+	/*
+	 * If this function returns 'enabled' even when the clock downstream
+	 * of this clock is disabled, then handoff code will unnecessarily
+	 * enable the current parent of this clock. If this function always
+	 * returns 'disabled' and a clock downstream is on, the clock handoff
+	 * code will bump up the ref count for this clock and its current
+	 * parent as necessary. So, clocks without an actual HW gate can
+	 * always return disabled.
+	 */
+	return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_div = {
+	.enable = div_enable,
+	.disable = div_disable,
+	.round_rate = div_round_rate,
+	.set_rate = div_set_rate,
+	.handoff = div_handoff,
+};
+
+static long __slave_div_round_rate(struct clk *c, unsigned long rate,
+					int *best_div)
+{
+	struct div_clk *d = to_div_clk(c);
+	unsigned int div, min_div, max_div;
+	long p_rate;
+
+	rate = max(rate, 1UL);
+
+	if (!d->ops || !d->ops->set_div)
+		min_div = max_div = d->div;
+	else {
+		min_div = d->min_div;
+		max_div = d->max_div;
+	}
+
+	p_rate = clk_get_rate(c->parent);
+	div = p_rate / rate;
+	div = max(div, min_div);
+	div = min(div, max_div);
+	if (best_div)
+		*best_div = div;
+
+	return p_rate / div;
+}
+
+static long slave_div_round_rate(struct clk *c, unsigned long rate)
+{
+	return __slave_div_round_rate(c, rate, NULL);
+}
+
+static int slave_div_set_rate(struct clk *c, unsigned long rate)
+{
+	struct div_clk *d = to_div_clk(c);
+	int div, rc = 0;
+	long rrate;
+
+	rrate = __slave_div_round_rate(c, rate, &div);
+	if (rrate != rate)
+		return -EINVAL;
+
+	if (div == d->div)
+		return 0;
+
+	if (d->ops->set_div)
+		rc = d->ops->set_div(d, div);
+	if (rc)
+		return rc;
+
+	d->div = div;
+
+	return 0;
+}
+
+struct clk_ops clk_ops_slave_div = {
+	.enable = div_enable,
+	.disable = div_disable,
+	.round_rate = slave_div_round_rate,
+	.set_rate = slave_div_set_rate,
+	.handoff = div_handoff,
+};
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index f6c11b0..e67d973 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -667,7 +667,7 @@
 	return HANDOFF_ENABLED_CLK;
 }
 
-static enum handoff byte_rcg_handoff(struct clk *clk)
+enum handoff byte_rcg_handoff(struct clk *clk)
 {
 	struct rcg_clk *rcg = to_rcg_clk(clk);
 	u32 div_val;
@@ -718,7 +718,7 @@
 	return 0;
 }
 
-static enum handoff pixel_rcg_handoff(struct clk *clk)
+enum handoff pixel_rcg_handoff(struct clk *clk)
 {
 	struct rcg_clk *rcg = to_rcg_clk(clk);
 	u32 div_val, mval, nval, cfg_regval;
@@ -815,18 +815,18 @@
 /*
  * mux clock functions
  */
-static void mux_clk_halt_check(void)
+static void cam_mux_clk_halt_check(void)
 {
 	/* Ensure that the delay starts after the mux disable/enable. */
 	mb();
 	udelay(HALT_CHECK_DELAY_US);
 }
 
-static int mux_clk_enable(struct clk *c)
+static int cam_mux_clk_enable(struct clk *c)
 {
 	unsigned long flags;
 	u32 regval;
-	struct mux_clk *mux = to_mux_clk(c);
+	struct cam_mux_clk *mux = to_cam_mux_clk(c);
 
 	spin_lock_irqsave(&local_clock_reg_lock, flags);
 	regval = readl_relaxed(ENABLE_REG(mux));
@@ -835,15 +835,15 @@
 	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
 
 	/* Wait for clock to enable before continuing. */
-	mux_clk_halt_check();
+	cam_mux_clk_halt_check();
 
 	return 0;
 }
 
-static void mux_clk_disable(struct clk *c)
+static void cam_mux_clk_disable(struct clk *c)
 {
 	unsigned long flags;
-	struct mux_clk *mux = to_mux_clk(c);
+	struct cam_mux_clk *mux = to_cam_mux_clk(c);
 	u32 regval;
 
 	spin_lock_irqsave(&local_clock_reg_lock, flags);
@@ -853,10 +853,10 @@
 	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
 
 	/* Wait for clock to disable before continuing. */
-	mux_clk_halt_check();
+	cam_mux_clk_halt_check();
 }
 
-static int mux_source_switch(struct mux_clk *mux, struct mux_source *dest)
+static int mux_source_switch(struct cam_mux_clk *mux, struct mux_source *dest)
 {
 	unsigned long flags;
 	u32 regval;
@@ -879,9 +879,9 @@
 	return ret;
 }
 
-static int mux_clk_set_parent(struct clk *c, struct clk *parent)
+static int cam_mux_clk_set_parent(struct clk *c, struct clk *parent)
 {
-	struct mux_clk *mux = to_mux_clk(c);
+	struct cam_mux_clk *mux = to_cam_mux_clk(c);
 	struct mux_source *dest = NULL;
 	int ret;
 
@@ -908,9 +908,9 @@
 	return 0;
 }
 
-static enum handoff mux_clk_handoff(struct clk *c)
+static enum handoff cam_mux_clk_handoff(struct clk *c)
 {
-	struct mux_clk *mux = to_mux_clk(c);
+	struct cam_mux_clk *mux = to_cam_mux_clk(c);
 	u32 mask = mux->enable_mask;
 	u32 regval = readl_relaxed(ENABLE_REG(mux));
 
@@ -922,9 +922,9 @@
 	return HANDOFF_DISABLED_CLK;
 }
 
-static struct clk *mux_clk_get_parent(struct clk *c)
+static struct clk *cam_mux_clk_get_parent(struct clk *c)
 {
-	struct mux_clk *mux = to_mux_clk(c);
+	struct cam_mux_clk *mux = to_cam_mux_clk(c);
 	struct mux_source *parent = NULL;
 	u32 regval = readl_relaxed(SELECT_REG(mux));
 
@@ -943,9 +943,9 @@
 	return ERR_PTR(-EPERM);
 }
 
-static int mux_clk_list_rate(struct clk *c, unsigned n)
+static int cam_mux_clk_list_rate(struct clk *c, unsigned n)
 {
-	struct mux_clk *mux = to_mux_clk(c);
+	struct cam_mux_clk *mux = to_cam_mux_clk(c);
 	int i;
 
 	for (i = 0; i < n; i++)
@@ -1022,13 +1022,13 @@
 	.handoff = local_vote_clk_handoff,
 };
 
-struct clk_ops clk_ops_mux = {
-	.enable = mux_clk_enable,
-	.disable = mux_clk_disable,
-	.set_parent = mux_clk_set_parent,
-	.get_parent = mux_clk_get_parent,
-	.handoff = mux_clk_handoff,
-	.list_rate = mux_clk_list_rate,
+struct clk_ops clk_ops_cam_mux = {
+	.enable = cam_mux_clk_enable,
+	.disable = cam_mux_clk_disable,
+	.set_parent = cam_mux_clk_set_parent,
+	.get_parent = cam_mux_clk_get_parent,
+	.handoff = cam_mux_clk_handoff,
+	.list_rate = cam_mux_clk_list_rate,
 };
 
 
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index 7882edb..f307a2f 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -163,7 +163,7 @@
 };
 
 /**
- * struct mux_clk - branch clock
+ * struct cam_mux_clk - branch clock
  * @c: clk
  * @enable_reg: register that contains the enable bit(s) for the mux
  * @select_reg: register that contains the source selection bits for the mux
@@ -172,7 +172,7 @@
  * @sources: list of mux sources
  * @base: pointer to base address of ioremapped registers.
  */
-struct mux_clk {
+struct cam_mux_clk {
 	struct clk c;
 	const u32 enable_reg;
 	const u32 select_reg;
@@ -184,9 +184,9 @@
 	void *const __iomem *base;
 };
 
-static inline struct mux_clk *to_mux_clk(struct clk *clk)
+static inline struct cam_mux_clk *to_cam_mux_clk(struct clk *clk)
 {
-	return container_of(clk, struct mux_clk, c);
+	return container_of(clk, struct cam_mux_clk, c);
 }
 
 /*
@@ -200,7 +200,7 @@
  */
 extern spinlock_t local_clock_reg_lock;
 
-extern struct clk_ops clk_ops_mux;
+extern struct clk_ops clk_ops_cam_mux;
 extern struct clk_ops clk_ops_empty;
 extern struct clk_ops clk_ops_rcg;
 extern struct clk_ops clk_ops_rcg_mnd;
@@ -210,6 +210,9 @@
 extern struct clk_ops clk_ops_byte;
 extern struct clk_ops clk_ops_pixel;
 
+enum handoff pixel_rcg_handoff(struct clk *clk);
+enum handoff byte_rcg_handoff(struct clk *clk);
+
 /*
  * Clock definition macros
  */
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 044fc2c..2e12e27 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -62,7 +62,7 @@
 {
 	int level, rc = 0, i;
 	struct regulator **r = vdd_class->regulator;
-	const int **vdd_uv = vdd_class->vdd_uv;
+	int **vdd_uv = vdd_class->vdd_uv;
 	int max_level = vdd_class->num_levels - 1;
 
 	for (level = max_level; level > 0; level--)
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index d02ab66..d5084e4 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -3,7 +3,7 @@
  * MSM architecture cpufreq driver
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
  * Author: Mike A. Chan <mikechan@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -261,6 +261,7 @@
 {
 	int cur_freq;
 	int index;
+	int ret = 0;
 	struct cpufreq_frequency_table *table;
 	struct cpufreq_work_struct *cpu_work = NULL;
 
@@ -296,19 +297,16 @@
 				policy->cpu, cur_freq);
 		return -EINVAL;
 	}
-
-	if (cur_freq != table[index].frequency) {
-		int ret = 0;
-		ret = acpuclk_set_rate(policy->cpu, table[index].frequency,
-				SETRATE_CPUFREQ);
-		if (ret)
-			return ret;
-		pr_info("cpufreq: cpu%d init at %d switching to %d\n",
-				policy->cpu, cur_freq, table[index].frequency);
-		cur_freq = table[index].frequency;
-	}
-
-	policy->cur = cur_freq;
+	/*
+	 * Call set_cpu_freq unconditionally so that when cpu is set to
+	 * online, frequency limit will always be updated.
+	 */
+	ret = set_cpu_freq(policy, table[index].frequency);
+	if (ret)
+		return ret;
+	pr_debug("cpufreq: cpu%d init at %d switching to %d\n",
+			policy->cpu, cur_freq, table[index].frequency);
+	policy->cur = table[index].frequency;
 
 	policy->cpuinfo.transition_latency =
 		acpuclk_get_switch_time() * NSEC_PER_USEC;
@@ -410,4 +408,4 @@
 	return cpufreq_register_driver(&msm_cpufreq_driver);
 }
 
-late_initcall(msm_cpufreq_register);
+device_initcall(msm_cpufreq_register);
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 837aef3..cb8ffc1 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -2510,6 +2510,11 @@
 	.id	= -1,
 };
 
+struct platform_device msm_fm_loopback = {
+	.name	= "msm-pcm-loopback",
+	.id	= -1,
+};
+
 static struct fs_driver_data gfx2d0_fs_data = {
 	.clks = (struct fs_clk_data[]){
 		{ .name = "core_clk" },
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 327c11d..eb12383 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -260,6 +260,7 @@
 extern struct platform_device msm_i2s_cpudai4;
 extern struct platform_device msm_i2s_cpudai5;
 extern struct platform_device msm_cpudai_stub;
+extern struct platform_device msm_fm_loopback;
 
 extern struct platform_device msm_pil_q6v3;
 extern struct platform_device msm_pil_modem;
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 6665d66..30a034e 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -22,6 +22,7 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/of_regulator.h>
+#include <linux/slab.h>
 #include <linux/clk.h>
 #include <mach/clk.h>
 
@@ -44,7 +45,9 @@
 	struct regulator_dev	*rdev;
 	struct regulator_desc	rdesc;
 	void __iomem		*gdscr;
-	struct clk		*core_clk;
+	struct clk		**clocks;
+	int			clock_count;
+	bool			toggle_mems;
 };
 
 static int gdsc_is_enabled(struct regulator_dev *rdev)
@@ -58,7 +61,7 @@
 {
 	struct gdsc *sc = rdev_get_drvdata(rdev);
 	uint32_t regval;
-	int ret;
+	int i, ret;
 
 	regval = readl_relaxed(sc->gdscr);
 	regval &= ~SW_COLLAPSE_MASK;
@@ -71,9 +74,18 @@
 		return ret;
 	}
 
+	if (sc->toggle_mems) {
+		for (i = 0; i < sc->clock_count; i++) {
+			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
+			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
+		}
+	}
+
 	/*
 	 * If clocks to this power domain were already on, they will take an
 	 * additional 4 clock cycles to re-enable after the rail is enabled.
+	 * Delay to account for this. A delay is also needed to ensure clocks
+	 * are not enabled within 400ns of enabling power to the memories.
 	 */
 	udelay(1);
 
@@ -84,7 +96,7 @@
 {
 	struct gdsc *sc = rdev_get_drvdata(rdev);
 	uint32_t regval;
-	int ret;
+	int i, ret;
 
 	regval = readl_relaxed(sc->gdscr);
 	regval |= SW_COLLAPSE_MASK;
@@ -95,6 +107,13 @@
 	if (ret)
 		dev_err(&rdev->dev, "%s disable timed out\n", sc->rdesc.name);
 
+	if (sc->toggle_mems) {
+		for (i = 0; i < sc->clock_count; i++) {
+			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+		}
+	}
+
 	return ret;
 }
 
@@ -112,7 +131,7 @@
 	struct gdsc *sc;
 	uint32_t regval;
 	bool retain_mems;
-	int ret;
+	int i, ret;
 
 	sc = devm_kzalloc(&pdev->dev, sizeof(struct gdsc), GFP_KERNEL);
 	if (sc == NULL)
@@ -137,6 +156,34 @@
 	if (sc->gdscr == NULL)
 		return -ENOMEM;
 
+	sc->clock_count = of_property_count_strings(pdev->dev.of_node,
+					    "qcom,clock-names");
+	if (sc->clock_count == -EINVAL) {
+		sc->clock_count = 0;
+	} else if (IS_ERR_VALUE(sc->clock_count)) {
+		dev_err(&pdev->dev, "Failed to get clock names\n");
+		return -EINVAL;
+	}
+
+	sc->clocks = devm_kzalloc(&pdev->dev,
+			sizeof(struct clk *) * sc->clock_count, GFP_KERNEL);
+	if (!sc->clocks)
+		return -ENOMEM;
+	for (i = 0; i < sc->clock_count; i++) {
+		const char *clock_name;
+		of_property_read_string_index(pdev->dev.of_node,
+					      "qcom,clock-names", i,
+					      &clock_name);
+		sc->clocks[i] = devm_clk_get(&pdev->dev, clock_name);
+		if (IS_ERR(sc->clocks[i])) {
+			int rc = PTR_ERR(sc->clocks[i]);
+			if (rc != -EPROBE_DEFER)
+				dev_err(&pdev->dev, "Failed to get %s\n",
+					clock_name);
+			return rc;
+		}
+	}
+
 	sc->rdesc.id = atomic_inc_return(&gdsc_count);
 	sc->rdesc.ops = &gdsc_ops;
 	sc->rdesc.type = REGULATOR_VOLTAGE;
@@ -157,13 +204,16 @@
 
 	retain_mems = of_property_read_bool(pdev->dev.of_node,
 					    "qcom,retain-mems");
-	if (retain_mems) {
-		sc->core_clk = devm_clk_get(&pdev->dev, "core_clk");
-		if (IS_ERR(sc->core_clk))
-			return PTR_ERR(sc->core_clk);
-		clk_set_flags(sc->core_clk, CLKFLAG_RETAIN_MEM);
-		clk_set_flags(sc->core_clk, CLKFLAG_RETAIN_PERIPH);
+	for (i = 0; i < sc->clock_count; i++) {
+		if (retain_mems || (regval & PWR_ON_MASK)) {
+			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
+			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
+		} else {
+			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+		}
 	}
+	sc->toggle_mems = !retain_mems;
 
 	sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
 				      pdev->dev.of_node);
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 2a33228..b358b53 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -59,7 +59,7 @@
 	struct regulator **regulator;
 	int num_regulators;
 	int (*set_vdd)(struct clk_vdd_class *v_class, int level);
-	const int **vdd_uv;
+	int **vdd_uv;
 	int *level_votes;
 	int num_levels;
 	unsigned long cur_level;
diff --git a/arch/arm/mach-msm/include/mach/clock-generic.h b/arch/arm/mach-msm/include/mach/clock-generic.h
new file mode 100644
index 0000000..0f689f1
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/clock-generic.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MACH_CLOCK_GENERIC_H
+#define __MACH_CLOCK_GENERIC_H
+
+#include <mach/clk-provider.h>
+
+/* ==================== Mux clock ==================== */
+
+struct clk_src {
+	struct clk *src;
+	int sel;
+};
+
+struct mux_clk;
+
+struct clk_mux_ops {
+	int (*set_mux_sel)(struct mux_clk *clk, int sel);
+	int (*get_mux_sel)(struct mux_clk *clk);
+
+	/* Optional */
+	bool (*is_enabled)(struct mux_clk *clk);
+	int (*enable)(struct mux_clk *clk);
+	void (*disable)(struct mux_clk *clk);
+};
+
+#define MUX_SRC_LIST(...) \
+	.parents = (struct clk_src[]){__VA_ARGS__}, \
+	.num_parents = ARRAY_SIZE(((struct clk_src[]){__VA_ARGS__}))
+
+struct mux_clk {
+	/* Parents in decreasing order of preference for obtaining rates. */
+	struct clk_src	*parents;
+	int		num_parents;
+	struct clk	*safe_parent;
+	int		safe_sel;
+	struct clk_mux_ops *ops;
+
+	/* Fields not used by helper function. */
+	void *const __iomem *base;
+	u32		offset;
+	u32		mask;
+	u32		shift;
+	u32		en_mask;
+	void		*priv;
+
+	struct clk	c;
+};
+
+static inline struct mux_clk *to_mux_clk(struct clk *c)
+{
+	return container_of(c, struct mux_clk, c);
+}
+
+extern struct clk_ops clk_ops_gen_mux;
+
+/* ==================== Divider clock ==================== */
+
+struct div_clk;
+
+struct clk_div_ops {
+	int (*set_div)(struct div_clk *clk, int div);
+	int (*get_div)(struct div_clk *clk);
+
+	/* Optional */
+	bool (*is_enabled)(struct div_clk *clk);
+	int (*enable)(struct div_clk *clk);
+	void (*disable)(struct div_clk *clk);
+};
+
+struct div_clk {
+	unsigned int	div;
+	unsigned int	min_div;
+	unsigned int	max_div;
+	unsigned long	rate_margin;
+	struct clk_div_ops *ops;
+
+	/* Fields not used by helper function. */
+	void *const __iomem *base;
+	u32		offset;
+	u32		mask;
+	u32		shift;
+	u32		en_mask;
+	void		*priv;
+	struct clk	c;
+};
+
+static inline struct div_clk *to_div_clk(struct clk *c)
+{
+	return container_of(c, struct div_clk, c);
+}
+
+extern struct clk_ops clk_ops_div;
+extern struct clk_ops clk_ops_slave_div;
+
+#define DEFINE_FIXED_DIV_CLK(clk_name, _div, _parent) \
+static struct div_clk clk_name = {	\
+	.div = _div,				\
+	.c = {					\
+		.parent = _parent,		\
+		.dbg_name = #clk_name,		\
+		.ops = &clk_ops_div,		\
+		CLK_INIT(clk_name.c),		\
+	}					\
+}
+
+#define DEFINE_FIXED_SLAVE_DIV_CLK(clk_name, _div, _parent) \
+static struct div_clk clk_name = {	\
+	.div = _div,				\
+	.c = {					\
+		.parent = _parent,		\
+		.dbg_name = #clk_name,		\
+		.ops = &clk_ops_slave_div,		\
+		CLK_INIT(clk_name.c),		\
+	}					\
+}
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index 90757b6..db5e126 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -464,6 +464,13 @@
 int ipa_disconnect(u32 clnt_hdl);
 
 /*
+ * Resume / Suspend
+ */
+int ipa_resume(u32 clnt_hdl);
+
+int ipa_suspend(u32 clnt_hdl);
+
+/*
  * Configuration
  */
 int ipa_cfg_ep(u32 clnt_hdl, const struct ipa_ep_cfg *ipa_ep_cfg);
@@ -583,6 +590,8 @@
  */
 int ipa_rm_create_resource(struct ipa_rm_create_params *create_params);
 
+int ipa_rm_delete_resource(enum ipa_rm_resource_name resource_name);
+
 int ipa_rm_register(enum ipa_rm_resource_name resource_name,
 			struct ipa_rm_register_params *reg_params);
 
@@ -694,6 +703,19 @@
 }
 
 /*
+ * Resume / Suspend
+ */
+static inline int ipa_resume(u32 clnt_hdl)
+{
+	return -EPERM;
+}
+
+static inline int ipa_suspend(u32 clnt_hdl)
+{
+	return -EPERM;
+}
+
+/*
  * Configuration
  */
 static inline int ipa_cfg_ep(u32 clnt_hdl,
@@ -955,6 +977,12 @@
 	return -EPERM;
 }
 
+static inline int ipa_rm_delete_resource(
+		enum ipa_rm_resource_name resource_name)
+{
+	return -EPERM;
+}
+
 static inline int ipa_rm_register(enum ipa_rm_resource_name resource_name,
 			struct ipa_rm_register_params *reg_params)
 {
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8610.h b/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
index 2a62460..18e448d 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
@@ -24,6 +24,9 @@
 
 #define MSM8610_MSM_SHARED_RAM_PHYS	0x0D900000
 
+#define MSM8610_QGIC_DIST_PHYS	0xF9000000
+#define MSM8610_QGIC_DIST_SIZE	SZ_4K
+
 #define MSM8610_APCS_GCC_PHYS	0xF9011000
 #define MSM8610_APCS_GCC_SIZE	SZ_4K
 
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index d4ea4ac..64531f0 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -36,11 +36,14 @@
 #define of_board_is_rumi()	of_machine_is_compatible("qcom,rumi")
 #define of_board_is_fluid()	of_machine_is_compatible("qcom,fluid")
 #define of_board_is_liquid()	of_machine_is_compatible("qcom,liquid")
+#define of_board_is_dragonboard()	\
+	of_machine_is_compatible("qcom,dragonboard")
 
 #define machine_is_msm8974()	of_machine_is_compatible("qcom,msm8974")
 #define machine_is_msm9625()	of_machine_is_compatible("qcom,msm9625")
 #define machine_is_msm8610()	of_machine_is_compatible("qcom,msm8610")
 #define machine_is_msm8226()	of_machine_is_compatible("qcom,msm8226")
+#define machine_is_apq8074()	of_machine_is_compatible("qcom,apq8074")
 
 #define early_machine_is_msm8610()	\
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8610")
@@ -55,11 +58,13 @@
 #define of_board_is_rumi()		0
 #define of_board_is_fluid()		0
 #define of_board_is_liquid()		0
+#define of_board_is_dragonboard()	0
 
 #define machine_is_msm8974()		0
 #define machine_is_msm9625()		0
 #define machine_is_msm8610()		0
 #define machine_is_msm8226()		0
+#define machine_is_apq8074()		0
 
 #define early_machine_is_msm8610()	0
 #define early_machine_is_mpq8092()	0
@@ -67,6 +72,7 @@
 #define early_machine_is_msmkrypton()	0
 #endif
 
+#define PLATFORM_SUBTYPE_MDM	1
 #define PLATFORM_SUBTYPE_SGLTE	6
 
 enum msm_cpu {
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 67f643e..4d4703f 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -55,6 +55,7 @@
 	int (*powerup)(const struct subsys_desc *desc);
 	void (*crash_shutdown)(const struct subsys_desc *desc);
 	int (*ramdump)(int, const struct subsys_desc *desc);
+	unsigned int err_ready_irq;
 };
 
 #if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 37dbbab..1c4a317 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -574,6 +574,7 @@
 
 #ifdef CONFIG_ARCH_MSM8610
 static struct map_desc msm8610_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(QGIC_DIST, MSM8610),
 	MSM_CHIP_DEVICE(APCS_GCC, MSM8610),
 	MSM_CHIP_DEVICE(TLMM, MSM8610),
 	MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8610),
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 33a0aff..9014f37 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -133,6 +133,7 @@
 #define LDO_DELTA_MIN		10000
 #define LDO_DELTA_MAX		100000
 
+#define MSM_L2_SAW_PHYS		0xf9012000
 /**
  * struct pmic_gang_vreg -
  * @name:			the string used to represent the gang
@@ -1336,6 +1337,7 @@
 void secondary_cpu_hs_init(void *base_ptr)
 {
 	uint32_t reg_val;
+	void *l2_saw_base;
 
 	/* Turn on the BHS, turn off LDO Bypass and power down LDO */
 	reg_val =  BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
@@ -1361,9 +1363,26 @@
 	/* Finally turn on the bypass so that BHS supplies power */
 	reg_val |= LDO_BYP_MASK;
 	writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
+
+	if (the_gang && the_gang->manage_phases)
+		return;
+
+	/*
+	 * If the driver has not yet started to manage phases then enable
+	 * max phases.
+	 */
+	l2_saw_base = ioremap_nocache(MSM_L2_SAW_PHYS, SZ_4K);
+	if (!l2_saw_base) {
+		__WARN();
+		return;
+	}
+	writel_relaxed(0x10003, l2_saw_base + 0x1c);
+	mb();
+	udelay(PHASE_SETTLING_TIME_US);
+
+	iounmap(l2_saw_base);
 }
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("KRAIT POWER regulator driver");
-MODULE_VERSION("1.0");
 MODULE_ALIAS("platform:"KRAIT_REGULATOR_DRIVER_NAME);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index 6ff8152..5002a7d 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -574,6 +574,10 @@
 
 	curr = client->curr;
 	pdata = client->pdata;
+	if (!pdata) {
+		MSM_BUS_ERR("Null pdata passed to update-request\n");
+		return -ENXIO;
+	}
 
 	if (index >= pdata->num_usecases) {
 		MSM_BUS_ERR("Client %u passed invalid index: %d\n",
@@ -718,7 +722,7 @@
 {
 	int i, src, pnode, index;
 	struct msm_bus_client *client = (struct msm_bus_client *)(cl);
-	if (IS_ERR(client)) {
+	if (IS_ERR_OR_NULL(client)) {
 		MSM_BUS_ERR("msm_bus_scale_reset_pnodes error\n");
 		return;
 	}
@@ -739,7 +743,7 @@
 void msm_bus_scale_unregister_client(uint32_t cl)
 {
 	struct msm_bus_client *client = (struct msm_bus_client *)(cl);
-	if (IS_ERR(client) || (!client))
+	if (IS_ERR_OR_NULL(client))
 		return;
 	if (client->curr != 0)
 		msm_bus_scale_client_update_request(cl, 0);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
index b45efad..ff3dc21 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
@@ -437,10 +437,7 @@
 	},
 };
 
-static int mport_mdp[] = {
-	MSM_BUS_MASTER_PORT_MDP_PORT0,
-	MSM_BUS_MASTER_PORT_MDP_PORT1,
-};
+static int mport_mdp[] = {MSM_BUS_MASTER_PORT_MDP_PORT0,};
 static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
 static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
 static int mport_graphics_3d_port0[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D_PORT0,};
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
index 91d106e..af51355 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
@@ -377,10 +377,7 @@
 	},
 };
 
-static int mport_mdp[] = {
-	MSM_BUS_MASTER_PORT_MDP_PORT0,
-	MSM_BUS_MASTER_PORT_MDP_PORT1,
-};
+static int mport_mdp[] = {MSM_BUS_MASTER_PORT_MDP_PORT0,};
 static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
 static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
 static int mport_graphics_3d[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D,};
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
index 158dee3..295b91b 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
@@ -440,10 +440,7 @@
 	},
 };
 
-static int mport_mdp[] = {
-	MSM_BUS_MASTER_PORT_MDP_PORT0,
-	MSM_BUS_MASTER_PORT_MDP_PORT1,
-};
+static int mport_mdp[] = {MSM_BUS_MASTER_PORT_MDP_PORT0,};
 static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
 static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
 static int mport_graphics_3d[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D,};
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index cf29cf1..b186a4d 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -515,6 +515,17 @@
 	drv->subsys_desc.start = pronto_start;
 	drv->subsys_desc.stop = pronto_stop;
 
+	ret = of_get_named_gpio(pdev->dev.of_node,
+			"qcom,gpio-err-ready", 0);
+	if (ret < 0)
+		return ret;
+
+	ret = gpio_to_irq(ret);
+	if (ret < 0)
+		return ret;
+
+	drv->subsys_desc.err_ready_irq = ret;
+
 	INIT_DELAYED_WORK(&drv->cancel_vote_work, wcnss_post_bootup);
 
 	drv->subsys = subsys_register(&drv->subsys_desc);
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index c1c3100..3ce1283 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -650,6 +650,17 @@
 	drv->subsys_desc.start = mss_start;
 	drv->subsys_desc.stop = mss_stop;
 
+	ret = of_get_named_gpio(pdev->dev.of_node,
+			"qcom,gpio-err-ready", 0);
+	if (ret < 0)
+		return ret;
+
+	ret = gpio_to_irq(ret);
+	if (ret < 0)
+		return ret;
+
+	drv->subsys_desc.err_ready_irq = ret;
+
 	drv->subsys = subsys_register(&drv->subsys_desc);
 	if (IS_ERR(drv->subsys)) {
 		ret = PTR_ERR(drv->subsys);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index a39e38b..4fca346 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -1368,7 +1368,7 @@
 	if (!data)
 		return -EINVAL;
 
-	if (!bufu || count < 0)
+	if (!bufu)
 		return -EINVAL;
 
 	if (!access_ok(VERIFY_WRITE, bufu, count))
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index b20c7f5..8e94b3a 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -76,7 +76,7 @@
 	info.vlevel = vlevel;
 	info.err = -ENODEV;
 
-	if (cpu_online(cpu)) {
+	if ((smp_processor_id() != cpu) && cpu_online(cpu)) {
 		/**
 		 * We do not want to set the voltage of another core from
 		 * this core, as its possible that we may race the vdd change
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 5fe7a29..fb44e16 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -31,6 +31,7 @@
 #include <linux/idr.h>
 #include <linux/debugfs.h>
 #include <linux/miscdevice.h>
+#include <linux/interrupt.h>
 
 #include <asm/current.h>
 
@@ -132,6 +133,7 @@
  * @restart_order: order of other devices this devices restarts with
  * @dentry: debugfs directory for this device
  * @do_ramdump_on_put: ramdump on subsystem_put() if true
+ * @err_ready: completion variable to record error ready from subsystem
  */
 struct subsys_device {
 	struct subsys_desc *desc;
@@ -154,6 +156,7 @@
 	bool do_ramdump_on_put;
 	struct miscdevice misc_dev;
 	char miscdevice_name[32];
+	struct completion err_ready;
 };
 
 static struct subsys_device *to_subsys(struct device *d)
@@ -412,6 +415,21 @@
 	}
 }
 
+static int wait_for_err_ready(struct subsys_device *subsys)
+{
+	int ret;
+
+	if (!subsys->desc->err_ready_irq)
+		return 0;
+
+	ret = wait_for_completion_timeout(&subsys->err_ready,
+					  msecs_to_jiffies(10000));
+	if (!ret)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
 static void subsystem_shutdown(struct subsys_device *dev, void *data)
 {
 	const char *name = dev->desc->name;
@@ -436,10 +454,17 @@
 static void subsystem_powerup(struct subsys_device *dev, void *data)
 {
 	const char *name = dev->desc->name;
+	int ret;
 
 	pr_info("[%p]: Powering up %s\n", current, name);
+	init_completion(&dev->err_ready);
 	if (dev->desc->powerup(dev->desc) < 0)
-		panic("[%p]: Failed to powerup %s!", current, name);
+		panic("[%p]: Powerup error: %s!", current, name);
+
+	ret = wait_for_err_ready(dev);
+	if (ret)
+		panic("[%p]: Timed out waiting for error ready: %s!",
+			current, name);
 	subsys_set_state(dev, SUBSYS_ONLINE);
 }
 
@@ -465,8 +490,18 @@
 {
 	int ret;
 
+	init_completion(&subsys->err_ready);
 	ret = subsys->desc->start(subsys->desc);
-	if (!ret)
+	if (ret)
+		return ret;
+
+	ret = wait_for_err_ready(subsys);
+	if (ret)
+		/* pil-boot succeeded but we need to shutdown
+		 * the device because error ready timed out.
+		 */
+		subsys->desc->stop(subsys->desc);
+	else
 		subsys_set_state(subsys, SUBSYS_ONLINE);
 
 	return ret;
@@ -895,6 +930,14 @@
 	ida_simple_remove(&subsys_ida, subsys->id);
 	kfree(subsys);
 }
+static irqreturn_t subsys_err_ready_intr_handler(int irq, void *subsys)
+{
+	struct subsys_device *subsys_dev = subsys;
+	pr_info("Error ready interrupt occured for %s\n",
+		 subsys_dev->desc->name);
+	complete(&subsys_dev->err_ready);
+	return IRQ_HANDLED;
+}
 
 static int subsys_misc_device_add(struct subsys_device *subsys_dev)
 {
@@ -971,8 +1014,24 @@
 		goto err_register;
 	}
 
+	if (subsys->desc->err_ready_irq) {
+		ret = devm_request_irq(&subsys->dev,
+					subsys->desc->err_ready_irq,
+					subsys_err_ready_intr_handler,
+					IRQF_TRIGGER_RISING,
+					"error_ready_interrupt", subsys);
+		if (ret < 0) {
+			dev_err(&subsys->dev,
+				"[%s]: Unable to register err ready handler\n",
+				subsys->desc->name);
+			goto err_misc_device;
+		}
+	}
+
 	return subsys;
 
+err_misc_device:
+	subsys_misc_device_remove(subsys);
 err_register:
 	subsys_debugfs_remove(subsys);
 err_debugfs:
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 1f16497..58fa5c9 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -1704,7 +1704,14 @@
 	bam.summing_threshold = 64;
 	/* SPS driver wll handle the crypto BAM IRQ */
 	bam.irq = (u32)pce_dev->ce_sps.bam_irq;
-	bam.manage = SPS_BAM_MGR_LOCAL;
+	/*
+	 * Set flag to indicate BAM global device control is managed
+	 * remotely.
+	 */
+	if (pce_dev->support_cmd_dscr == false)
+		bam.manage = SPS_BAM_MGR_DEVICE_REMOTE;
+	else
+		bam.manage = SPS_BAM_MGR_LOCAL;
 	bam.ee = 1;
 
 	pr_debug("bam physical base=0x%x\n", (u32)bam.phys_addr);
@@ -2990,8 +2997,6 @@
 	pce_dev->dir = c_req->dir;
 	if  ((pce_dev->ce_sps.minor_version == 0) && (c_req->dir == QCE_DECRYPT)
 			&& (c_req->mode == QCE_MODE_CBC)) {
-		struct ablkcipher_request *areq =
-				(struct ablkcipher_request *)pce_dev->areq;
 		memcpy(pce_dev->dec_iv, (unsigned char *)sg_virt(areq->src) +
 					 areq->src->length - 16,
 			NUM_OF_CRYPTO_CNTR_IV_REG * CRYPTO_REG_SIZE);
@@ -3140,8 +3145,6 @@
 
 	pce_dev->is_shared = of_property_read_bool((&pdev->dev)->of_node,
 				"qcom,ce-hw-shared");
-	pce_dev->support_cmd_dscr = of_property_read_bool((&pdev->dev)->of_node,
-				"qcom,ce-hw-support-cmd-dscr");
 	if (of_property_read_u32((&pdev->dev)->of_node,
 				"qcom,bam-pipe-pair",
 				&pce_dev->ce_sps.pipe_pair_index)) {
@@ -3176,7 +3179,7 @@
 		pce_dev->ce_sps.bam_mem = resource->start;
 		pce_dev->ce_sps.bam_iobase = ioremap_nocache(resource->start,
 					resource_size(resource));
-		if (!pce_dev->iobase) {
+		if (!pce_dev->ce_sps.bam_iobase) {
 			rc = -ENOMEM;
 			pr_err("Can not map BAM io memory\n");
 			goto err_getting_bam_info;
@@ -3189,7 +3192,6 @@
 	pr_warn("ce_bam_phy_reg_base=0x%x  ", pce_dev->ce_sps.bam_mem);
 	pr_warn("ce_bam_virt_reg_base=0x%x\n",
 				(uint32_t)pce_dev->ce_sps.bam_iobase);
-
 	resource  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (resource) {
 		pce_dev->ce_sps.bam_irq = resource->start;
@@ -3355,6 +3357,7 @@
 void *qce_open(struct platform_device *pdev, int *rc)
 {
 	struct qce_device *pce_dev;
+	uint32_t bam_cfg = 0 ;
 
 	pce_dev = kzalloc(sizeof(struct qce_device), GFP_KERNEL);
 	if (!pce_dev) {
@@ -3396,10 +3399,16 @@
 		goto err;
 	}
 	*rc = 0;
+
+	bam_cfg = readl_relaxed(pce_dev->ce_sps.bam_iobase +
+					CRYPTO_BAM_CNFG_BITS_REG);
+	pce_dev->support_cmd_dscr = (bam_cfg & CRYPTO_BAM_CD_ENABLE_MASK) ?
+								true : false;
 	qce_init_ce_cfg_val(pce_dev);
 	qce_setup_ce_sps_data(pce_dev);
 	qce_sps_init(pce_dev);
 
+
 	qce_disable_clk(pce_dev);
 
 	return pce_dev;
@@ -3429,6 +3438,9 @@
 	if (handle == NULL)
 		return -ENODEV;
 
+	qce_enable_clk(pce_dev);
+	qce_sps_exit(pce_dev);
+
 	if (pce_dev->iobase)
 		iounmap(pce_dev->iobase);
 	if (pce_dev->coh_vmem)
@@ -3438,7 +3450,6 @@
 	qce_disable_clk(pce_dev);
 	__qce_deinit_clk(pce_dev);
 
-	qce_sps_exit(pce_dev);
 	kfree(handle);
 
 	return 0;
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 7666e74..a09bb42 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -323,10 +323,10 @@
 	u32 qcedev_sha_fail;
 };
 
-static struct qcedev_stat _qcedev_stat[MAX_QCE_DEVICE];
+static struct qcedev_stat _qcedev_stat;
 static struct dentry *_debug_dent;
 static char _debug_read_buf[DEBUG_MAX_RW_BUF];
-static int _debug_qcedev[MAX_QCE_DEVICE];
+static int _debug_qcedev;
 
 static struct qcedev_control *qcedev_minor_to_control(unsigned n)
 {
@@ -693,7 +693,7 @@
 	if (ret)
 		qcedev_areq->err = -EIO;
 
-	pstat = &_qcedev_stat[podev->pdev->id];
+	pstat = &_qcedev_stat;
 	if (qcedev_areq->op_type == QCEDEV_CRYPTO_OPER_CIPHER) {
 		switch (qcedev_areq->cipher_op_req.op) {
 		case QCEDEV_OPER_DEC:
@@ -1739,7 +1739,7 @@
 		return -ENOTTY;
 
 	init_completion(&qcedev_areq.complete);
-	pstat = &_qcedev_stat[podev->pdev->id];
+	pstat = &_qcedev_stat;
 
 	switch (cmd) {
 	case QCEDEV_IOCTL_LOCK_CE:
@@ -2026,11 +2026,7 @@
 	struct qcedev_stat *pstat;
 	int len = 0;
 
-	if (id < 0) {
-		pr_err("Crypto id is %d, cannot be negative\n", id);
-		return len;
-	}
-	pstat = &_qcedev_stat[id];
+	pstat = &_qcedev_stat;
 	len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
 			"\nQualcomm QCE dev driver %d Statistics:\n",
 				id + 1);
@@ -2076,10 +2072,7 @@
 static ssize_t _debug_stats_write(struct file *file, const char __user *buf,
 			size_t count, loff_t *ppos)
 {
-
-	int qcedev = *((int *) file->private_data);
-
-	memset((char *)&_qcedev_stat[qcedev], 0, sizeof(struct qcedev_stat));
+	memset((char *)&_qcedev_stat, 0, sizeof(struct qcedev_stat));
 	return count;
 };
 
@@ -2093,7 +2086,6 @@
 {
 	int rc;
 	char name[DEBUG_MAX_FNAME];
-	int i;
 	struct dentry *dent;
 
 	_debug_dent = debugfs_create_dir("qcedev", NULL);
@@ -2103,17 +2095,15 @@
 		return PTR_ERR(_debug_dent);
 	}
 
-	for (i = 0; i < MAX_QCE_DEVICE; i++) {
-		snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", i+1);
-		_debug_qcedev[i] = i;
-		dent = debugfs_create_file(name, 0644, _debug_dent,
-				&_debug_qcedev[i], &_debug_stats_ops);
-		if (dent == NULL) {
-			pr_err("qcedev debugfs_create_file fail, error %ld\n",
-					PTR_ERR(dent));
-			rc = PTR_ERR(dent);
-			goto err;
-		}
+	snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", 1);
+	_debug_qcedev = 0;
+	dent = debugfs_create_file(name, 0644, _debug_dent,
+			&_debug_qcedev, &_debug_stats_ops);
+	if (dent == NULL) {
+		pr_err("qcedev debugfs_create_file fail, error %ld\n",
+				PTR_ERR(dent));
+		rc = PTR_ERR(dent);
+		goto err;
 	}
 	return 0;
 err:
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 40fb29ac..d1cb933 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -42,7 +42,6 @@
 #include "qce.h"
 
 
-#define MAX_CRYPTO_DEVICE 3
 #define DEBUG_MAX_FNAME  16
 #define DEBUG_MAX_RW_BUF 1024
 
@@ -53,6 +52,8 @@
 	u32 aead_sha1_des_dec;
 	u32 aead_sha1_3des_enc;
 	u32 aead_sha1_3des_dec;
+	u32 aead_ccm_aes_enc;
+	u32 aead_ccm_aes_dec;
 	u32 aead_op_success;
 	u32 aead_op_fail;
 	u32 ablk_cipher_aes_enc;
@@ -72,7 +73,7 @@
 	u32 sha_hmac_op_success;
 	u32 sha_hmac_op_fail;
 };
-static struct crypto_stat _qcrypto_stat[MAX_CRYPTO_DEVICE];
+static struct crypto_stat _qcrypto_stat;
 static struct dentry *_debug_dent;
 static char _debug_read_buf[DEBUG_MAX_RW_BUF];
 
@@ -405,6 +406,39 @@
 	return i;
 }
 
+size_t qcrypto_sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
+			   void *buf, size_t buflen)
+{
+	int i;
+	size_t offset, len;
+
+	for (i = 0, offset = 0; i < nents; ++i) {
+		len = sg_copy_from_buffer(sgl, 1, buf, buflen);
+		buf += len;
+		buflen -= len;
+		offset += len;
+		sgl = scatterwalk_sg_next(sgl);
+	}
+
+	return offset;
+}
+
+size_t qcrypto_sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
+			 void *buf, size_t buflen)
+{
+	int i;
+	size_t offset, len;
+
+	for (i = 0, offset = 0; i < nents; ++i) {
+		len = sg_copy_to_buffer(sgl, 1, buf, buflen);
+		buf += len;
+		buflen -= len;
+		offset += len;
+		sgl = scatterwalk_sg_next(sgl);
+	}
+
+	return offset;
+}
 static struct qcrypto_alg *_qcrypto_sha_alg_alloc(struct crypto_priv *cp,
 		struct ahash_alg *template)
 {
@@ -581,11 +615,7 @@
 	struct crypto_stat *pstat;
 	int len = 0;
 
-	if (id < 0) {
-		pr_err("Crypto id is %d, cannot be negative\n", id);
-		return len;
-	}
-	pstat = &_qcrypto_stat[id];
+	pstat = &_qcrypto_stat;
 	len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
 			"\nQualcomm crypto accelerator %d Statistics:\n",
 				id + 1);
@@ -641,6 +671,13 @@
 					pstat->aead_sha1_3des_dec);
 
 	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+			"   AEAD CCM-AES encryption     : %d\n",
+					pstat->aead_ccm_aes_enc);
+	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+			"   AEAD CCM-AES decryption     : %d\n",
+					pstat->aead_ccm_aes_dec);
+
+	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   AEAD operation success       : %d\n",
 					pstat->aead_op_success);
 	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
@@ -858,7 +895,7 @@
 	uint32_t diglen = crypto_ahash_digestsize(ahash);
 	uint32_t *auth32 = (uint32_t *)authdata;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 #ifdef QCRYPTO_DEBUG
 	dev_info(&cp->pdev->dev, "_qce_ahash_complete: %p ret %d\n",
@@ -916,7 +953,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 #ifdef QCRYPTO_DEBUG
 	dev_info(&cp->pdev->dev, "_qce_ablk_cipher_complete: %p ret %d\n",
@@ -943,7 +980,7 @@
 		areq->dst = rctx->orig_dst;
 
 		num_sg = qcrypto_count_sg(areq->dst, areq->nbytes);
-		bytes = sg_copy_from_buffer(areq->dst, num_sg,
+		bytes = qcrypto_sg_copy_from_buffer(areq->dst, num_sg,
 			rctx->data, areq->nbytes);
 		if (bytes != areq->nbytes)
 			pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes,
@@ -967,7 +1004,7 @@
 	struct qcrypto_cipher_req_ctx *rctx;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	rctx = aead_request_ctx(areq);
 
@@ -988,7 +1025,7 @@
 				nbytes = areq->cryptlen -
 						crypto_aead_authsize(aead);
 			num_sg = qcrypto_count_sg(areq->dst, nbytes);
-			bytes = sg_copy_from_buffer(areq->dst, num_sg,
+			bytes = qcrypto_sg_copy_from_buffer(areq->dst, num_sg,
 					((char *)rctx->data + areq->assoclen),
 					nbytes);
 			if (bytes != nbytes)
@@ -1118,7 +1155,7 @@
 	qreq->assoclen = ALIGN((alen + len), 16);
 
 	num_sg = qcrypto_count_sg(sg, alen);
-	bytes = sg_copy_to_buffer(sg, num_sg, adata, alen);
+	bytes = qcrypto_sg_copy_to_buffer(sg, num_sg, adata, alen);
 	if (bytes != alen)
 		pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes, alen);
 
@@ -1145,7 +1182,7 @@
 
 		rctx->orig_src = req->src;
 		rctx->orig_dst = req->dst;
-		rctx->data = kzalloc((req->nbytes + 64), GFP_KERNEL);
+		rctx->data = kzalloc((req->nbytes + 64), GFP_ATOMIC);
 
 		if (rctx->data == NULL) {
 			pr_err("Mem Alloc fail rctx->data, err %ld for 0x%x\n",
@@ -1153,7 +1190,7 @@
 			return -ENOMEM;
 		}
 		num_sg = qcrypto_count_sg(req->src, req->nbytes);
-		bytes = sg_copy_to_buffer(req->src, num_sg, rctx->data,
+		bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg, rctx->data,
 								req->nbytes);
 		if (bytes != req->nbytes)
 			pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes,
@@ -1294,7 +1331,7 @@
 			rctx->orig_src = req->src;
 			rctx->orig_dst = req->dst;
 			rctx->data = kzalloc((req->cryptlen + qreq.assoclen +
-					qreq.authsize + 64*2), GFP_KERNEL);
+					qreq.authsize + 64*2), GFP_ATOMIC);
 			if (rctx->data == NULL) {
 				pr_err("Mem Alloc fail rctx->data, err %ld\n",
 							PTR_ERR(rctx->data));
@@ -1305,7 +1342,7 @@
 			memcpy((char *)rctx->data, qreq.assoc, qreq.assoclen);
 
 			num_sg = qcrypto_count_sg(req->src, req->cryptlen);
-			bytes = sg_copy_to_buffer(req->src, num_sg,
+			bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg,
 				rctx->data + qreq.assoclen , req->cryptlen);
 			if (bytes != req->cryptlen)
 				pr_warn("bytes copied=0x%x bytes to copy= 0x%x",
@@ -1358,7 +1395,7 @@
 	int ret = 0;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 again:
 	spin_lock_irqsave(&cp->lock, flags);
@@ -1434,7 +1471,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1458,7 +1495,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1482,7 +1519,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 				CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1506,7 +1543,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1533,7 +1570,7 @@
 		(ctx->auth_key_len != AES_KEYSIZE_256))
 		return  -EINVAL;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	rctx = aead_request_ctx(req);
 	rctx->aead = 1;
@@ -1542,7 +1579,7 @@
 	rctx->mode = QCE_MODE_CCM;
 	rctx->iv = req->iv;
 
-	pstat->aead_sha1_aes_enc++;
+	pstat->aead_ccm_aes_enc++;
 	return _qcrypto_queue_req(cp, &req->base);
 }
 
@@ -1553,7 +1590,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1574,7 +1611,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1595,7 +1632,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1616,7 +1653,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1637,7 +1674,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 				CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1661,7 +1698,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 				CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1686,7 +1723,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1712,7 +1749,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1733,7 +1770,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1754,7 +1791,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1775,7 +1812,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1796,7 +1833,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1824,7 +1861,7 @@
 		(ctx->auth_key_len != AES_KEYSIZE_256))
 		return  -EINVAL;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	rctx = aead_request_ctx(req);
 	rctx->aead = 1;
@@ -1833,7 +1870,7 @@
 	rctx->mode = QCE_MODE_CCM;
 	rctx->iv = req->iv;
 
-	pstat->aead_sha1_aes_dec++;
+	pstat->aead_ccm_aes_dec++;
 	return _qcrypto_queue_req(cp, &req->base);
 }
 
@@ -1939,7 +1976,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 #ifdef QCRYPTO_DEBUG
 	dev_info(&cp->pdev->dev, "_qcrypto_aead_encrypt_aes_cbc: %p\n", req);
@@ -1963,7 +2000,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 #ifdef QCRYPTO_DEBUG
 	dev_info(&cp->pdev->dev, "_qcrypto_aead_decrypt_aes_cbc: %p\n", req);
@@ -1988,7 +2025,7 @@
 	struct qcrypto_cipher_req_ctx *rctx;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	rctx = aead_request_ctx(areq);
 	rctx->aead = 1;
@@ -2012,7 +2049,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	rctx = aead_request_ctx(req);
 	rctx->aead = 1;
@@ -2032,7 +2069,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	rctx = aead_request_ctx(req);
 	rctx->aead = 1;
@@ -2057,7 +2094,7 @@
 	struct qcrypto_cipher_req_ctx *rctx;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	rctx = aead_request_ctx(areq);
 	rctx->aead = 1;
@@ -2081,7 +2118,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	rctx = aead_request_ctx(req);
 	rctx->aead = 1;
@@ -2101,7 +2138,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	rctx = aead_request_ctx(req);
 	rctx->aead = 1;
@@ -2123,7 +2160,7 @@
 	struct qcrypto_cipher_req_ctx *rctx;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	rctx = aead_request_ctx(areq);
 	rctx->aead = 1;
@@ -2146,7 +2183,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	rctx = aead_request_ctx(req);
 	rctx->aead = 1;
@@ -2166,7 +2203,7 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	rctx = aead_request_ctx(req);
 	rctx->aead = 1;
@@ -2188,7 +2225,7 @@
 	struct qcrypto_cipher_req_ctx *rctx;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	rctx = aead_request_ctx(areq);
 	rctx->aead = 1;
@@ -2220,10 +2257,9 @@
 static int _sha1_init(struct ahash_request *req)
 {
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
-	struct crypto_priv *cp = sha_ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	_sha_init(sha_ctx);
 	sha_ctx->alg = QCE_HASH_SHA1;
@@ -2241,10 +2277,9 @@
 static int _sha256_init(struct ahash_request *req)
 {
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
-	struct crypto_priv *cp = sha_ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 
 	_sha_init(sha_ctx);
 	sha_ctx->alg = QCE_HASH_SHA256;
@@ -2347,7 +2382,7 @@
 
 	srctx = ahash_request_ctx(req);
 	srctx->orig_src = req->src;
-	srctx->data = kzalloc((req->nbytes + 64), GFP_KERNEL);
+	srctx->data = kzalloc((req->nbytes + 64), GFP_ATOMIC);
 	if (srctx->data == NULL) {
 		pr_err("Mem Alloc fail rctx->data, err %ld for 0x%x\n",
 				PTR_ERR(srctx->data), (req->nbytes + 64));
@@ -2355,7 +2390,8 @@
 	}
 
 	num_sg = qcrypto_count_sg(req->src, req->nbytes);
-	bytes = sg_copy_to_buffer(req->src, num_sg, srctx->data, req->nbytes);
+	bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg, srctx->data,
+						req->nbytes);
 	if (bytes != req->nbytes)
 		pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes,
 							req->nbytes);
@@ -2390,7 +2426,7 @@
 	if (total <= sha_block_size) {
 		k_src = &sha_ctx->trailing_buf[sha_ctx->trailing_buf_len];
 		num_sg = qcrypto_count_sg(req->src, len);
-		bytes = sg_copy_to_buffer(req->src, num_sg, k_src, len);
+		bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg, k_src, len);
 
 		sha_ctx->trailing_buf_len = total;
 		if (sha_ctx->alg == QCE_HASH_SHA1)
@@ -2431,13 +2467,13 @@
 	if (sha_ctx->trailing_buf_len) {
 		if (cp->ce_support.aligned_only)  {
 			sha_ctx->sg = kzalloc(sizeof(struct scatterlist),
-								GFP_KERNEL);
+								GFP_ATOMIC);
 			if (sha_ctx->sg == NULL) {
 				pr_err("MemAlloc fail sha_ctx->sg, error %ld\n",
 						PTR_ERR(sha_ctx->sg));
 				return -ENOMEM;
 			}
-			rctx->data2 = kzalloc((req->nbytes + 64), GFP_KERNEL);
+			rctx->data2 = kzalloc((req->nbytes + 64), GFP_ATOMIC);
 			if (rctx->data2 == NULL) {
 				pr_err("Mem Alloc fail srctx->data2, err %ld\n",
 							PTR_ERR(rctx->data2));
@@ -2458,7 +2494,7 @@
 		} else {
 			sg_mark_end(sg_last);
 			sha_ctx->sg = kzalloc(2 * (sizeof(struct scatterlist)),
-								GFP_KERNEL);
+								GFP_ATOMIC);
 			if (sha_ctx->sg == NULL) {
 				pr_err("MEMalloc fail sha_ctx->sg, error %ld\n",
 							PTR_ERR(sha_ctx->sg));
@@ -2688,7 +2724,7 @@
 	struct crypto_stat *pstat;
 	int ret = 0;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 	pstat->sha1_hmac_digest++;
 
 	_sha_init(sha_ctx);
@@ -2715,7 +2751,7 @@
 	struct crypto_stat *pstat;
 	int ret = 0;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 	pstat->sha256_hmac_digest++;
 
 	_sha_init(sha_ctx);
@@ -2853,10 +2889,9 @@
 static int _sha1_hmac_digest(struct ahash_request *req)
 {
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
-	struct crypto_priv *cp = sha_ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 	pstat->sha1_hmac_digest++;
 
 	_sha_init(sha_ctx);
@@ -2871,10 +2906,9 @@
 static int _sha256_hmac_digest(struct ahash_request *req)
 {
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
-	struct crypto_priv *cp = sha_ctx->cp;
 	struct crypto_stat *pstat;
 
-	pstat = &_qcrypto_stat[cp->pdev->id];
+	pstat = &_qcrypto_stat;
 	pstat->sha256_hmac_digest++;
 
 	_sha_init(sha_ctx);
@@ -3327,12 +3361,6 @@
 	int i;
 	struct msm_ce_hw_support *platform_support;
 
-	if (pdev->id >= MAX_CRYPTO_DEVICE) {
-		pr_err("%s: device id %d  exceeds allowed %d\n",
-				__func__, pdev->id, MAX_CRYPTO_DEVICE);
-		return -ENOENT;
-	}
-
 	cp = kzalloc(sizeof(*cp), GFP_KERNEL);
 	if (!cp) {
 		pr_err("qcrypto Memory allocation of q_alg FAIL, error %ld\n",
@@ -3572,7 +3600,7 @@
 	},
 };
 
-static int _debug_qcrypto[MAX_CRYPTO_DEVICE];
+static int _debug_qcrypto;
 
 static int _debug_stats_open(struct inode *inode, struct file *file)
 {
@@ -3599,9 +3627,7 @@
 			size_t count, loff_t *ppos)
 {
 
-	int qcrypto = *((int *) file->private_data);
-
-	memset((char *)&_qcrypto_stat[qcrypto], 0, sizeof(struct crypto_stat));
+	memset((char *)&_qcrypto_stat, 0, sizeof(struct crypto_stat));
 	return count;
 };
 
@@ -3615,7 +3641,6 @@
 {
 	int rc;
 	char name[DEBUG_MAX_FNAME];
-	int i;
 	struct dentry *dent;
 
 	_debug_dent = debugfs_create_dir("qcrypto", NULL);
@@ -3625,17 +3650,15 @@
 		return PTR_ERR(_debug_dent);
 	}
 
-	for (i = 0; i < MAX_CRYPTO_DEVICE; i++) {
-		snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", i+1);
-		_debug_qcrypto[i] = i;
-		dent = debugfs_create_file(name, 0644, _debug_dent,
-				&_debug_qcrypto[i], &_debug_stats_ops);
-		if (dent == NULL) {
-			pr_err("qcrypto debugfs_create_file fail, error %ld\n",
-					PTR_ERR(dent));
-			rc = PTR_ERR(dent);
-			goto err;
-		}
+	snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", 1);
+	_debug_qcrypto = 0;
+	dent = debugfs_create_file(name, 0644, _debug_dent,
+				&_debug_qcrypto, &_debug_stats_ops);
+	if (dent == NULL) {
+		pr_err("qcrypto debugfs_create_file fail, error %ld\n",
+				PTR_ERR(dent));
+		rc = PTR_ERR(dent);
+		goto err;
 	}
 	return 0;
 err:
diff --git a/drivers/crypto/msm/qcryptohw_50.h b/drivers/crypto/msm/qcryptohw_50.h
index 245d737..2210dc8 100644
--- a/drivers/crypto/msm/qcryptohw_50.h
+++ b/drivers/crypto/msm/qcryptohw_50.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,10 @@
 #define _DRIVERS_CRYPTO_MSM_QCRYPTOHW_50_H_
 
 
+#define CRYPTO_BAM_CNFG_BITS_REG		0x0007C
+#define CRYPTO_BAM_CD_ENABLE			27
+#define CRYPTO_BAM_CD_ENABLE_MASK		(1 << CRYPTO_BAM_CD_ENABLE)
+
 #define QCE_AUTH_REG_BYTE_COUNT 4
 #define CRYPTO_VERSION_REG			0x1A000
 
@@ -28,7 +32,7 @@
 #define CRYPTO_DATA_OUT3_REG			0x1A02C
 
 #define CRYPTO_STATUS_REG			0x1A100
-#define CRYPTO_STATUS2_REG			0x1A100
+#define CRYPTO_STATUS2_REG			0x1A104
 #define CRYPTO_ENGINES_AVAIL			0x1A108
 #define CRYPTO_FIFO_SIZES_REG			0x1A10C
 
@@ -64,9 +68,9 @@
 #define CRYPTO_ENCR_PIPE0_KEY2_REG		0x1E008
 #define CRYPTO_ENCR_PIPE0_KEY3_REG		0x1E00C
 #define CRYPTO_ENCR_PIPE0_KEY4_REG		0x1E010
-#define CRYPTO_ENCR_PIPE0_KEY5_REG		0x1E004
-#define CRYPTO_ENCR_PIPE0_KEY6_REG		0x1E008
-#define CRYPTO_ENCR_PIPE0_KEY7_REG		0x1E00C
+#define CRYPTO_ENCR_PIPE0_KEY5_REG		0x1E014
+#define CRYPTO_ENCR_PIPE0_KEY6_REG		0x1E018
+#define CRYPTO_ENCR_PIPE0_KEY7_REG		0x1E01C
 
 #define CRYPTO_ENCR_PIPE1_KEY0_REG		0x1E020
 #define CRYPTO_ENCR_PIPE1_KEY1_REG		0x1E024
@@ -185,56 +189,56 @@
 #define CRYPTO_AUTH_PIPE0_KEY14_REG		0x1E838
 #define CRYPTO_AUTH_PIPE0_KEY15_REG		0x1E83C
 
-#define CRYPTO_AUTH_PIPE1_KEY0_REG		0x1E800
-#define CRYPTO_AUTH_PIPE1_KEY1_REG		0x1E804
-#define CRYPTO_AUTH_PIPE1_KEY2_REG		0x1E808
-#define CRYPTO_AUTH_PIPE1_KEY3_REG		0x1E80C
-#define CRYPTO_AUTH_PIPE1_KEY4_REG		0x1E810
-#define CRYPTO_AUTH_PIPE1_KEY5_REG		0x1E814
-#define CRYPTO_AUTH_PIPE1_KEY6_REG		0x1E818
-#define CRYPTO_AUTH_PIPE1_KEY7_REG		0x1E81C
-#define CRYPTO_AUTH_PIPE1_KEY8_REG		0x1E820
-#define CRYPTO_AUTH_PIPE1_KEY9_REG		0x1E824
-#define CRYPTO_AUTH_PIPE1_KEY10_REG		0x1E828
-#define CRYPTO_AUTH_PIPE1_KEY11_REG		0x1E82C
-#define CRYPTO_AUTH_PIPE1_KEY12_REG		0x1E830
-#define CRYPTO_AUTH_PIPE1_KEY13_REG		0x1E834
-#define CRYPTO_AUTH_PIPE1_KEY14_REG		0x1E838
-#define CRYPTO_AUTH_PIPE1_KEY15_REG		0x1E83C
+#define CRYPTO_AUTH_PIPE1_KEY0_REG		0x1E880
+#define CRYPTO_AUTH_PIPE1_KEY1_REG		0x1E884
+#define CRYPTO_AUTH_PIPE1_KEY2_REG		0x1E888
+#define CRYPTO_AUTH_PIPE1_KEY3_REG		0x1E88C
+#define CRYPTO_AUTH_PIPE1_KEY4_REG		0x1E890
+#define CRYPTO_AUTH_PIPE1_KEY5_REG		0x1E894
+#define CRYPTO_AUTH_PIPE1_KEY6_REG		0x1E898
+#define CRYPTO_AUTH_PIPE1_KEY7_REG		0x1E89C
+#define CRYPTO_AUTH_PIPE1_KEY8_REG		0x1E8A0
+#define CRYPTO_AUTH_PIPE1_KEY9_REG		0x1E8A4
+#define CRYPTO_AUTH_PIPE1_KEY10_REG		0x1E8A8
+#define CRYPTO_AUTH_PIPE1_KEY11_REG		0x1E8AC
+#define CRYPTO_AUTH_PIPE1_KEY12_REG		0x1E8B0
+#define CRYPTO_AUTH_PIPE1_KEY13_REG		0x1E8B4
+#define CRYPTO_AUTH_PIPE1_KEY14_REG		0x1E8B8
+#define CRYPTO_AUTH_PIPE1_KEY15_REG		0x1E8BC
 
-#define CRYPTO_AUTH_PIPE2_KEY0_REG		0x1E840
-#define CRYPTO_AUTH_PIPE2_KEY1_REG		0x1E844
-#define CRYPTO_AUTH_PIPE2_KEY2_REG		0x1E848
-#define CRYPTO_AUTH_PIPE2_KEY3_REG		0x1E84C
-#define CRYPTO_AUTH_PIPE2_KEY4_REG		0x1E850
-#define CRYPTO_AUTH_PIPE2_KEY5_REG		0x1E854
-#define CRYPTO_AUTH_PIPE2_KEY6_REG		0x1E858
-#define CRYPTO_AUTH_PIPE2_KEY7_REG		0x1E85C
-#define CRYPTO_AUTH_PIPE2_KEY8_REG		0x1E860
-#define CRYPTO_AUTH_PIPE2_KEY9_REG		0x1E864
-#define CRYPTO_AUTH_PIPE2_KEY10_REG		0x1E868
-#define CRYPTO_AUTH_PIPE2_KEY11_REG		0x1E86C
-#define CRYPTO_AUTH_PIPE2_KEY12_REG		0x1E870
-#define CRYPTO_AUTH_PIPE2_KEY13_REG		0x1E874
-#define CRYPTO_AUTH_PIPE2_KEY14_REG		0x1E878
-#define CRYPTO_AUTH_PIPE2_KEY15_REG		0x1E87C
+#define CRYPTO_AUTH_PIPE2_KEY0_REG		0x1E900
+#define CRYPTO_AUTH_PIPE2_KEY1_REG		0x1E904
+#define CRYPTO_AUTH_PIPE2_KEY2_REG		0x1E908
+#define CRYPTO_AUTH_PIPE2_KEY3_REG		0x1E90C
+#define CRYPTO_AUTH_PIPE2_KEY4_REG		0x1E910
+#define CRYPTO_AUTH_PIPE2_KEY5_REG		0x1E914
+#define CRYPTO_AUTH_PIPE2_KEY6_REG		0x1E918
+#define CRYPTO_AUTH_PIPE2_KEY7_REG		0x1E91C
+#define CRYPTO_AUTH_PIPE2_KEY8_REG		0x1E920
+#define CRYPTO_AUTH_PIPE2_KEY9_REG		0x1E924
+#define CRYPTO_AUTH_PIPE2_KEY10_REG		0x1E928
+#define CRYPTO_AUTH_PIPE2_KEY11_REG		0x1E92C
+#define CRYPTO_AUTH_PIPE2_KEY12_REG		0x1E930
+#define CRYPTO_AUTH_PIPE2_KEY13_REG		0x1E934
+#define CRYPTO_AUTH_PIPE2_KEY14_REG		0x1E938
+#define CRYPTO_AUTH_PIPE2_KEY15_REG		0x1E93C
 
-#define CRYPTO_AUTH_PIPE3_KEY0_REG		0x1E880
-#define CRYPTO_AUTH_PIPE3_KEY1_REG		0x1E884
-#define CRYPTO_AUTH_PIPE3_KEY2_REG		0x1E888
-#define CRYPTO_AUTH_PIPE3_KEY3_REG		0x1E88C
-#define CRYPTO_AUTH_PIPE3_KEY4_REG		0x1E890
-#define CRYPTO_AUTH_PIPE3_KEY5_REG		0x1E894
-#define CRYPTO_AUTH_PIPE3_KEY6_REG		0x1E898
-#define CRYPTO_AUTH_PIPE3_KEY7_REG		0x1E89C
-#define CRYPTO_AUTH_PIPE3_KEY8_REG		0x1E8A0
-#define CRYPTO_AUTH_PIPE3_KEY9_REG		0x1E8A4
-#define CRYPTO_AUTH_PIPE3_KEY10_REG		0x1E8A8
-#define CRYPTO_AUTH_PIPE3_KEY11_REG		0x1E8AC
-#define CRYPTO_AUTH_PIPE3_KEY12_REG		0x1E8B0
-#define CRYPTO_AUTH_PIPE3_KEY13_REG		0x1E8B4
-#define CRYPTO_AUTH_PIPE3_KEY14_REG		0x1E8B8
-#define CRYPTO_AUTH_PIPE3_KEY15_REG		0x1E8BC
+#define CRYPTO_AUTH_PIPE3_KEY0_REG		0x1E980
+#define CRYPTO_AUTH_PIPE3_KEY1_REG		0x1E984
+#define CRYPTO_AUTH_PIPE3_KEY2_REG		0x1E988
+#define CRYPTO_AUTH_PIPE3_KEY3_REG		0x1E98C
+#define CRYPTO_AUTH_PIPE3_KEY4_REG		0x1E990
+#define CRYPTO_AUTH_PIPE3_KEY5_REG		0x1E994
+#define CRYPTO_AUTH_PIPE3_KEY6_REG		0x1E998
+#define CRYPTO_AUTH_PIPE3_KEY7_REG		0x1E99C
+#define CRYPTO_AUTH_PIPE3_KEY8_REG		0x1E9A0
+#define CRYPTO_AUTH_PIPE3_KEY9_REG		0x1E9A4
+#define CRYPTO_AUTH_PIPE3_KEY10_REG		0x1E9A8
+#define CRYPTO_AUTH_PIPE3_KEY11_REG		0x1E9AC
+#define CRYPTO_AUTH_PIPE3_KEY12_REG		0x1E9B0
+#define CRYPTO_AUTH_PIPE3_KEY13_REG		0x1E9B4
+#define CRYPTO_AUTH_PIPE3_KEY14_REG		0x1E9B8
+#define CRYPTO_AUTH_PIPE3_KEY15_REG		0x1E9BC
 
 
 #define CRYPTO_AUTH_IV0_REG			0x1A310
@@ -421,6 +425,7 @@
 #define CRYPTO_AUTH_ALG_AES	2
 #define CRYPTO_AUTH_ALG_KASUMI	3
 #define CRYPTO_AUTH_ALG_SNOW3G	4
+#define CRYPTO_AUTH_ALG_ZUC	5
 
 /* encr_xts_du_size reg */
 #define CRYPTO_ENCR_XTS_DU_SIZE			0 /* bit 19-0  */
@@ -471,33 +476,49 @@
 #define CRYPTO_ENCR_KEY_SZ_3DES		1
 #define CRYPTO_ENCR_KEY_SZ_AES128	0
 #define CRYPTO_ENCR_KEY_SZ_AES256	2
-#define CRYPTO_ENCR_KEY_SZ_UEA1		0
-#define CRYPTO_ENCR_KEY_SZ_UEA2		1
 
 #define CRYPTO_ENCR_ALG				0 /* bit 2-0 */
 #define CRYPTO_ENCR_ALG_MASK			(7 << CRYPTO_ENCR_ALG)
 #define CRYPTO_ENCR_ALG_NONE		0
 #define CRYPTO_ENCR_ALG_DES		1
 #define CRYPTO_ENCR_ALG_AES		2
-#define CRYPTO_ENCR_ALG_KASUMI		3
+#define CRYPTO_ENCR_ALG_KASUMI		4
 #define CRYPTO_ENCR_ALG_SNOW_3G		5
+#define CRYPTO_ENCR_ALG_ZUC		6
 
 /* goproc reg */
 #define CRYPTO_GO				0
 #define CRYPTO_CLR_CNTXT			1
 #define CRYPTO_RESULTS_DUMP			2
 
+/*  F8 definition of CRYPTO_ENCR_CNTR1_IV1 REG  */
+#define CRYPTO_CNTR1_IV1_REG_F8_PKT_CNT		16	/* bit 31 - 16 */
+#define CRYPTO_CNTR1_IV1_REG_F8_PKT_CNT_MASK \
+		(0xffff << CRYPTO_CNTR1_IV1_REG_F8_PKT_CNT)
+
+#define CRYPTO_CNTR1_IV1_REG_F8_BEARER		0	/* bit 4 - 0 */
+#define CRYPTO_CNTR1_IV1_REG_F8_BEARER_MASK \
+		(0x1f << CRYPTO_CNTR1_IV1_REG_F8_BEARER)
+
+/* F9 definition of CRYPTO_AUTH_IV4 REG */
+#define CRYPTO_AUTH_IV4_REG_F9_VALID_BIS	0	/* bit 2 - 0 */
+#define CRYPTO_AUTH_IV4_REG_F9_VALID_BIS_MASK \
+		(0x7  << CRYPTO_AUTH_IV4_REG_F9_VALID_BIS)
 
 /* engines_avail */
 #define CRYPTO_ENCR_AES_SEL			0
-#define CRYPTO_DES_SEL				3
-#define CRYPTO_ENCR_SNOW3G_SEL			4
-#define CRYPTO_ENCR_KASUMI_SEL			5
-#define CRYPTO_SHA_SEL				6
-#define CRYPTO_SHA512_SEL			7
-#define CRYPTO_AUTH_AES_SEL			8
-#define CRYPTO_AUTH_SNOW3G_SEL			9
-#define CRYPTO_AUTH_KASUMI_SEL			10
-#define CRYPTO_BAM_SEL				11
-
+#define CRYPTO_DES_SEL				1
+#define CRYPTO_ENCR_SNOW3G_SEL			2
+#define CRYPTO_ENCR_KASUMI_SEL			3
+#define CRYPTO_SHA_SEL				4
+#define CRYPTO_SHA512_SEL			5
+#define CRYPTO_AUTH_AES_SEL			6
+#define CRYPTO_AUTH_SNOW3G_SEL			7
+#define CRYPTO_AUTH_KASUMI_SEL			8
+#define CRYPTO_BAM_PIPE_SETS			9	/* bit 12 - 9 */
+#define CRYPTO_AXI_WR_BEATS			13	/* bit 18 - 13 */
+#define CRYPTO_AXI_RD_BEATS			19	/* bit 24 - 19 */
+#define CRYPTO_ENCR_ZUC_SEL			26
+#define CRYPTO_AUTH_ZUC_SEL			27
+#define CRYPTO_ZUC_ENABLE			28
 #endif /* _DRIVERS_CRYPTO_MSM_QCRYPTOHW_50_H_ */
diff --git a/drivers/gpu/ion/Kconfig b/drivers/gpu/ion/Kconfig
index 39133b5..5bb254b 100644
--- a/drivers/gpu/ion/Kconfig
+++ b/drivers/gpu/ion/Kconfig
@@ -16,12 +16,3 @@
 	depends on ARCH_MSM && ION
 	help
 	  Choose this option if you wish to use ion on an MSM target.
-
-config ION_LEAK_CHECK
-	bool "Check for leaked Ion buffers (debugging)"
-	depends on ION
-	help
-	  Choose this option if you wish to enable checking for leaked
-	  ion buffers at runtime. Choosing this option will also add a
-	  debugfs node under the ion directory that can be used to
-	  enable/disable the leak checking.
diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile
index d7ff73a..0e460c8 100644
--- a/drivers/gpu/ion/Makefile
+++ b/drivers/gpu/ion/Makefile
@@ -1,6 +1,5 @@
-obj-$(CONFIG_ION) +=	ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o \
-			ion_iommu_heap.o ion_cp_heap.o ion_removed_heap.o \
-			ion_page_pool.o ion_chunk_heap.o
+obj-$(CONFIG_ION) +=	ion.o ion_heap.o ion_page_pool.o ion_system_heap.o \
+			ion_carveout_heap.o ion_chunk_heap.o
 obj-$(CONFIG_CMA) += ion_cma_heap.o ion_cma_secure_heap.o
 obj-$(CONFIG_ION_TEGRA) += tegra/
-obj-$(CONFIG_ION_MSM) += msm/
+obj-$(CONFIG_ION_MSM) += ion_iommu_heap.o ion_cp_heap.o ion_removed_heap.o msm/
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index fbe4da0..250b387 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -16,7 +16,6 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/device.h>
 #include <linux/file.h>
 #include <linux/freezer.h>
@@ -27,6 +26,7 @@
 #include <linux/list.h>
 #include <linux/memblock.h>
 #include <linux/miscdevice.h>
+#include <linux/export.h>
 #include <linux/mm.h>
 #include <linux/mm_types.h>
 #include <linux/rbtree.h>
@@ -41,7 +41,6 @@
 #include <trace/events/kmem.h>
 
 
-#include <mach/iommu_domains.h>
 #include "ion_priv.h"
 
 /**
@@ -83,7 +82,6 @@
 	struct ion_device *dev;
 	struct rb_root handles;
 	struct mutex lock;
-	unsigned int heap_type_mask;
 	char *name;
 	struct task_struct *task;
 	pid_t pid;
@@ -108,7 +106,6 @@
 	struct ion_buffer *buffer;
 	struct rb_node node;
 	unsigned int kmap_cnt;
-	unsigned int iommu_map_cnt;
 };
 
 bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
@@ -545,8 +542,8 @@
 	mutex_lock(&client->lock);
 	valid_handle = ion_handle_validate(client, handle);
 	if (!valid_handle) {
-		mutex_unlock(&client->lock);
 		WARN(1, "%s: invalid handle passed to free.\n", __func__);
+		mutex_unlock(&client->lock);
 		return;
 	}
 	ion_handle_put(handle);
@@ -678,30 +675,21 @@
 	struct ion_client *client = s->private;
 	struct rb_node *n;
 
-	seq_printf(s, "%16.16s: %16.16s : %16.16s : %12.12s : %12.12s : %s\n",
+	seq_printf(s, "%16.16s: %16.16s : %16.16s : %12.12s\n",
 			"heap_name", "size_in_bytes", "handle refcount",
-			"buffer", "physical", "[domain,partition] - virt");
+			"buffer");
 
 	mutex_lock(&client->lock);
 	for (n = rb_first(&client->handles); n; n = rb_next(n)) {
 		struct ion_handle *handle = rb_entry(n, struct ion_handle,
 						     node);
 
-		enum ion_heap_type type = handle->buffer->heap->type;
-
 		seq_printf(s, "%16.16s: %16x : %16d : %12p",
 				handle->buffer->heap->name,
 				handle->buffer->size,
 				atomic_read(&handle->ref.refcount),
 				handle->buffer);
 
-		if (type == ION_HEAP_TYPE_SYSTEM_CONTIG ||
-			type == ION_HEAP_TYPE_CARVEOUT ||
-			type == (enum ion_heap_type) ION_HEAP_TYPE_CP)
-			seq_printf(s, " : %12pa", &handle->buffer->priv_phys);
-		else
-			seq_printf(s, " : %12s", "N/A");
-
 		seq_printf(s, "\n");
 	}
 	mutex_unlock(&client->lock);
@@ -1287,8 +1275,8 @@
 		ion_free(client, data.handle);
 		break;
 	}
-	case ION_IOC_MAP:
 	case ION_IOC_SHARE:
+	case ION_IOC_MAP:
 	{
 		struct ion_fd_data data;
 		if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
@@ -1391,7 +1379,7 @@
 };
 
 static size_t ion_debug_heap_total(struct ion_client *client,
-				   enum ion_heap_ids id)
+				   unsigned int id)
 {
 	size_t size = 0;
 	struct rb_node *n;
@@ -1560,7 +1548,6 @@
 	size_t total_size = 0;
 	size_t total_orphaned_size = 0;
 
-	mutex_lock(&dev->buffer_lock);
 	seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size");
 	seq_printf(s, "----------------------------------------------------\n");
 
@@ -1584,25 +1571,31 @@
 	seq_printf(s, "----------------------------------------------------\n");
 	seq_printf(s, "orphaned allocations (info is from last known client):"
 		   "\n");
+	mutex_lock(&dev->buffer_lock);
 	for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
 		struct ion_buffer *buffer = rb_entry(n, struct ion_buffer,
 						     node);
-		if (buffer->heap->type == heap->type)
-			total_size += buffer->size;
+		if (buffer->heap->id != heap->id)
+			continue;
+		total_size += buffer->size;
 		if (!buffer->handle_count) {
-			seq_printf(s, "%16.s %16u %16u\n", buffer->task_comm,
-				   buffer->pid, buffer->size);
+			seq_printf(s, "%16.s %16u %16u %d %d\n", buffer->task_comm,
+				   buffer->pid, buffer->size, buffer->kmap_cnt,
+				   atomic_read(&buffer->ref.refcount));
 			total_orphaned_size += buffer->size;
 		}
 	}
+	mutex_unlock(&dev->buffer_lock);
 	seq_printf(s, "----------------------------------------------------\n");
 	seq_printf(s, "%16.s %16u\n", "total orphaned",
 		   total_orphaned_size);
 	seq_printf(s, "%16.s %16u\n", "total ", total_size);
 	seq_printf(s, "----------------------------------------------------\n");
 
+	if (heap->debug_show)
+		heap->debug_show(heap, s, unused);
+
 	ion_heap_print_debug(s, heap);
-	mutex_unlock(&dev->buffer_lock);
 	return 0;
 }
 
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 0dd3054..08921299 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -37,7 +37,6 @@
 	ion_phys_addr_t base;
 	unsigned long allocated_bytes;
 	unsigned long total_size;
-	unsigned int has_outer_cache;
 };
 
 ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap,
@@ -254,7 +253,6 @@
 	carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;
 	carveout_heap->allocated_bytes = 0;
 	carveout_heap->total_size = heap_data->size;
-	carveout_heap->has_outer_cache = heap_data->has_outer_cache;
 
 	return &carveout_heap->heap;
 }
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 4b724df..e3fbbda 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -247,14 +247,12 @@
 				      unsigned long align);
 void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
 		       unsigned long size);
-
 /**
  * The carveout heap returns physical addresses, since 0 may be a valid
  * physical address, this is used to indicate allocation failed
  */
 #define ION_CARVEOUT_ALLOCATE_FAIL -1
 
-
 /**
  * functions for creating and destroying a heap pool -- allows you
  * to keep a pool of pre allocated memory to use from your heap.  Keeping
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index a44011f..fb6dc2d 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -26,9 +26,6 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include "ion_priv.h"
-#include <mach/memory.h>
-#include <asm/cacheflush.h>
-#include <linux/msm_ion.h>
 #include <linux/dma-mapping.h>
 #include <trace/events/kmem.h>
 
@@ -265,7 +262,27 @@
 	.map_user = ion_heap_map_user,
 };
 
-struct ion_heap *ion_system_heap_create(struct ion_platform_heap *pheap)
+static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
+				      void *unused)
+{
+
+	struct ion_system_heap *sys_heap = container_of(heap,
+							struct ion_system_heap,
+							heap);
+	int i;
+	for (i = 0; i < num_orders; i++) {
+		struct ion_page_pool *pool = sys_heap->pools[i];
+		seq_printf(s, "%d order %u highmem pages in pool = %lu total\n",
+			   pool->high_count, pool->order,
+			   (1 << pool->order) * PAGE_SIZE * pool->high_count);
+		seq_printf(s, "%d order %u lowmem pages in pool = %lu total\n",
+			   pool->low_count, pool->order,
+			   (1 << pool->order) * PAGE_SIZE * pool->low_count);
+	}
+	return 0;
+}
+
+struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
 {
 	struct ion_system_heap *heap;
 	int i;
@@ -291,6 +308,7 @@
 			goto err_create_pool;
 		heap->pools[i] = pool;
 	}
+	heap->heap.debug_show = ion_system_heap_debug_show;
 	return &heap->heap;
 err_create_pool:
 	for (i = 0; i < num_orders; i++)
@@ -378,7 +396,7 @@
 	.map_user = ion_heap_map_user,
 };
 
-struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *pheap)
+struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *unused)
 {
 	struct ion_heap *heap;
 
diff --git a/drivers/gpu/ion/msm/ion_iommu_map.c b/drivers/gpu/ion/msm/ion_iommu_map.c
index 5ce03db..c8fb3c1 100644
--- a/drivers/gpu/ion/msm/ion_iommu_map.c
+++ b/drivers/gpu/ion/msm/ion_iommu_map.c
@@ -11,6 +11,7 @@
  *
  */
 
+#include <linux/dma-buf.h>
 #include <linux/export.h>
 #include <linux/iommu.h>
 #include <linux/ion.h>
@@ -69,6 +70,7 @@
 	struct sg_table *table;
 	unsigned long size;
 	struct mutex lock;
+	struct dma_buf *dbuf;
 };
 
 static struct rb_root iommu_root;
@@ -85,9 +87,9 @@
 		parent = *p;
 		entry = rb_entry(parent, struct ion_iommu_meta, node);
 
-		if (meta->handle < entry->handle) {
+		if (meta->table < entry->table) {
 			p = &(*p)->rb_left;
-		} else if (meta->handle > entry->handle) {
+		} else if (meta->table > entry->table) {
 			p = &(*p)->rb_right;
 		} else {
 			pr_err("%s: handle %p already exists\n", __func__,
@@ -101,7 +103,7 @@
 }
 
 
-static struct ion_iommu_meta *ion_iommu_meta_lookup(struct ion_handle *handle)
+static struct ion_iommu_meta *ion_iommu_meta_lookup(struct sg_table *table)
 {
 	struct rb_root *root = &iommu_root;
 	struct rb_node **p = &root->rb_node;
@@ -112,9 +114,9 @@
 		parent = *p;
 		entry = rb_entry(parent, struct ion_iommu_meta, node);
 
-		if (handle < entry->handle)
+		if (table < entry->table)
 			p = &(*p)->rb_left;
-		else if (handle > entry->handle)
+		else if (table > entry->table)
 			p = &(*p)->rb_right;
 		else
 			return entry;
@@ -319,7 +321,8 @@
 	return ERR_PTR(ret);
 }
 
-static struct ion_iommu_meta *ion_iommu_meta_create(struct ion_handle *handle,
+static struct ion_iommu_meta *ion_iommu_meta_create(struct ion_client *client,
+						struct ion_handle *handle,
 						struct sg_table *table,
 						unsigned long size)
 {
@@ -333,6 +336,7 @@
 	meta->handle = handle;
 	meta->table = table;
 	meta->size = size;
+	meta->dbuf = ion_share_dma_buf(client, handle);
 	kref_init(&meta->ref);
 	mutex_init(&meta->lock);
 	ion_iommu_meta_add(meta);
@@ -347,6 +351,7 @@
 
 
 	rb_erase(&meta->node, &iommu_root);
+	dma_buf_put(meta->dbuf);
 	kfree(meta);
 }
 
@@ -427,13 +432,13 @@
 	}
 
 	mutex_lock(&msm_iommu_map_mutex);
-	iommu_meta = ion_iommu_meta_lookup(handle);
+	iommu_meta = ion_iommu_meta_lookup(table);
 
 	if (!iommu_meta)
-		iommu_meta = ion_iommu_meta_create(handle, table, size);
+		iommu_meta = ion_iommu_meta_create(client, handle, table, size);
 	else
 		kref_get(&iommu_meta->ref);
-
+	BUG_ON(iommu_meta->size != size);
 	mutex_unlock(&msm_iommu_map_mutex);
 
 	iommu_map = ion_iommu_lookup(iommu_meta, domain_num, partition_num);
@@ -493,6 +498,7 @@
 {
 	struct ion_iommu_map *iommu_map;
 	struct ion_iommu_meta *meta;
+	struct sg_table *table;
 
 	if (IS_ERR_OR_NULL(client)) {
 		pr_err("%s: client pointer is invalid\n", __func__);
@@ -503,9 +509,10 @@
 		return;
 	}
 
+	table = ion_sg_table(client, handle);
 
 	mutex_lock(&msm_iommu_map_mutex);
-	meta = ion_iommu_meta_lookup(handle);
+	meta = ion_iommu_meta_lookup(table);
 	if (!meta) {
 		WARN(1, "%s: (%d,%d) was never mapped for %p\n", __func__,
 				domain_num, partition_num, handle);
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index f43d276..4a45313 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -89,7 +89,7 @@
 	},
 	{
 		.id	= ION_QSECOM_HEAP_ID,
-		.type	= ION_HEAP_TYPE_CARVEOUT,
+		.type	= ION_HEAP_TYPE_DMA,
 		.name	= ION_QSECOM_HEAP_NAME,
 	},
 	{
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 08791a3..e6c345b 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2323,7 +2323,7 @@
 	}
 
 	/* Check if we detected a long running IB, if false return */
-	if (adreno_dev->long_ib) {
+	if ((adreno_context) && (adreno_dev->long_ib)) {
 		long_ib = _adreno_check_long_ib(device);
 		if (!long_ib) {
 			adreno_context->flags &= ~CTXT_FLAGS_GPU_HANG;
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index a76ed87..967e4ab 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -785,13 +785,13 @@
 
 			struct kgsl_memdesc *memdesc =
 				adreno_find_ctxtmem(device, ptbase, ibaddr,
-					ibsize);
+					ibsize << 2);
 
 			/* IOMMU uses a NOP IB placed in setsate memory */
 			if (NULL == memdesc)
 				if (kgsl_gpuaddr_in_memdesc(
 						&device->mmu.setstate_memory,
-						ibaddr, ibsize))
+						ibaddr, ibsize << 2))
 					memdesc = &device->mmu.setstate_memory;
 			/*
 			 * The IB from CP_IB1_BASE and the IBs for legacy
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 5275267..60e457d 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -144,10 +144,13 @@
  * @ptbase - the pagetable base of the object
  * @gpuaddr - the GPU address of the object
  * @size - Size of the region to search
+ *
+ * Caller must kgsl_mem_entry_put() the returned entry when finished using it.
  */
 
-struct kgsl_mem_entry *kgsl_get_mem_entry(struct kgsl_device *device,
-	unsigned int ptbase, unsigned int gpuaddr, unsigned int size)
+struct kgsl_mem_entry * __must_check
+kgsl_get_mem_entry(struct kgsl_device *device, unsigned int ptbase,
+		   unsigned int gpuaddr, unsigned int size)
 {
 	struct kgsl_process_private *priv;
 	struct kgsl_mem_entry *entry;
@@ -157,15 +160,12 @@
 	list_for_each_entry(priv, &kgsl_driver.process_list, list) {
 		if (!kgsl_mmu_pt_equal(&device->mmu, priv->pagetable, ptbase))
 			continue;
-		spin_lock(&priv->mem_lock);
 		entry = kgsl_sharedmem_find_region(priv, gpuaddr, size);
 
 		if (entry) {
-			spin_unlock(&priv->mem_lock);
 			mutex_unlock(&kgsl_driver.process_mutex);
 			return entry;
 		}
-		spin_unlock(&priv->mem_lock);
 	}
 	mutex_unlock(&kgsl_driver.process_mutex);
 
@@ -913,8 +913,17 @@
 	return result;
 }
 
-/*call with private->mem_lock locked */
-struct kgsl_mem_entry *
+/**
+ * kgsl_sharedmem_find_region() - Find a gpu memory allocation
+ *
+ * @private: private data for the process to check.
+ * @gpuaddr: start address of the region
+ * @size: size of the region
+ *
+ * Find a gpu allocation. Caller must kgsl_mem_entry_put()
+ * the returned entry when finished using it.
+ */
+struct kgsl_mem_entry * __must_check
 kgsl_sharedmem_find_region(struct kgsl_process_private *private,
 	unsigned int gpuaddr, size_t size)
 {
@@ -923,46 +932,57 @@
 	if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, gpuaddr))
 		return NULL;
 
+	spin_lock(&private->mem_lock);
 	while (node != NULL) {
 		struct kgsl_mem_entry *entry;
 
 		entry = rb_entry(node, struct kgsl_mem_entry, node);
 
-
-		if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size))
+		if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size)) {
+			kgsl_mem_entry_get(entry);
+			spin_unlock(&private->mem_lock);
 			return entry;
-
+		}
 		if (gpuaddr < entry->memdesc.gpuaddr)
 			node = node->rb_left;
 		else if (gpuaddr >=
 			(entry->memdesc.gpuaddr + entry->memdesc.size))
 			node = node->rb_right;
 		else {
+			spin_unlock(&private->mem_lock);
 			return NULL;
 		}
 	}
+	spin_unlock(&private->mem_lock);
 
 	return NULL;
 }
 EXPORT_SYMBOL(kgsl_sharedmem_find_region);
 
-/*call with private->mem_lock locked */
-static inline struct kgsl_mem_entry *
+/**
+ * kgsl_sharedmem_find() - Find a gpu memory allocation
+ *
+ * @private: private data for the process to check.
+ * @gpuaddr: start address of the region
+ *
+ * Find a gpu allocation. Caller must kgsl_mem_entry_put()
+ * the returned entry when finished using it.
+ */
+static inline struct kgsl_mem_entry * __must_check
 kgsl_sharedmem_find(struct kgsl_process_private *private, unsigned int gpuaddr)
 {
 	return kgsl_sharedmem_find_region(private, gpuaddr, 1);
 }
 
 /**
- * kgsl_sharedmem_region_empty - Check if an addression region is empty
+ * kgsl_sharedmem_region_empty() - Check if an addression region is empty
  *
  * @private: private data for the process to check.
  * @gpuaddr: start address of the region
  * @size: length of the region.
  *
  * Checks that there are no existing allocations within an address
- * region. Note that unlike other kgsl_sharedmem* search functions,
- * this one manages locking on its own.
+ * region.
  */
 int
 kgsl_sharedmem_region_empty(struct kgsl_process_private *private,
@@ -1006,19 +1026,24 @@
 }
 
 /**
- * kgsl_sharedmem_find_id - find a memory entry by id
+ * kgsl_sharedmem_find_id() - find a memory entry by id
  * @process: the owning process
  * @id: id to find
  *
  * @returns - the mem_entry or NULL
+ *
+ * Caller must kgsl_mem_entry_put() the returned entry, when finished using
+ * it.
  */
-static inline struct kgsl_mem_entry *
+static inline struct kgsl_mem_entry * __must_check
 kgsl_sharedmem_find_id(struct kgsl_process_private *process, unsigned int id)
 {
 	struct kgsl_mem_entry *entry;
 
 	rcu_read_lock();
 	entry = idr_find(&process->mem_idr, id);
+	if (entry)
+		kgsl_mem_entry_get(entry);
 	rcu_read_unlock();
 
 	return entry;
@@ -1314,15 +1339,12 @@
 	struct kgsl_device *device = dev_priv->device;
 	unsigned int context_id = context ? context->id : KGSL_MEMSTORE_GLOBAL;
 
-	spin_lock(&dev_priv->process_priv->mem_lock);
 	entry = kgsl_sharedmem_find(dev_priv->process_priv, gpuaddr);
-	spin_unlock(&dev_priv->process_priv->mem_lock);
 
 	if (!entry) {
 		KGSL_DRV_ERR(dev_priv->device,
 				"invalid gpuaddr %08x\n", gpuaddr);
-		result = -EINVAL;
-		goto done;
+		return -EINVAL;
 	}
 	trace_kgsl_mem_timestamp_queue(device, entry, context_id,
 				       kgsl_readtimestamp(device, context,
@@ -1330,7 +1352,7 @@
 				       timestamp);
 	result = kgsl_add_event(dev_priv->device, context_id, timestamp,
 				kgsl_freemem_event_cb, entry, dev_priv);
-done:
+	kgsl_mem_entry_put(entry);
 	return result;
 }
 
@@ -1416,15 +1438,13 @@
 	struct kgsl_process_private *private = dev_priv->process_priv;
 	struct kgsl_mem_entry *entry = NULL;
 
-	spin_lock(&private->mem_lock);
 	entry = kgsl_sharedmem_find(private, param->gpuaddr);
-	spin_unlock(&private->mem_lock);
-
 	if (!entry) {
 		KGSL_MEM_INFO(dev_priv->device, "invalid gpuaddr %08x\n",
 				param->gpuaddr);
 		return -EINVAL;
 	}
+
 	trace_kgsl_mem_free(entry);
 
 	kgsl_memfree_hist_set_event(entry->priv->pid,
@@ -1433,6 +1453,7 @@
 				    entry->memdesc.flags);
 
 	kgsl_mem_entry_detach_process(entry);
+	kgsl_mem_entry_put(entry);
 	return 0;
 }
 
@@ -1457,6 +1478,7 @@
 				    entry->memdesc.flags);
 
 	kgsl_mem_entry_detach_process(entry);
+	kgsl_mem_entry_put(entry);
 	return 0;
 }
 
@@ -1990,6 +2012,7 @@
 	struct kgsl_gpumem_sync_cache *param = data;
 	struct kgsl_process_private *private = dev_priv->process_priv;
 	struct kgsl_mem_entry *entry = NULL;
+	long ret;
 
 	if (param->id != 0) {
 		entry = kgsl_sharedmem_find_id(private, param->id);
@@ -1999,9 +2022,7 @@
 			return -EINVAL;
 		}
 	} else if (param->gpuaddr != 0) {
-		spin_lock(&private->mem_lock);
 		entry = kgsl_sharedmem_find(private, param->gpuaddr);
-		spin_unlock(&private->mem_lock);
 		if (entry == NULL) {
 			KGSL_MEM_INFO(dev_priv->device,
 					"can't find gpuaddr %x\n",
@@ -2012,7 +2033,9 @@
 		return -EINVAL;
 	}
 
-	return _kgsl_gpumem_sync_cache(entry, param->op);
+	ret = _kgsl_gpumem_sync_cache(entry, param->op);
+	kgsl_mem_entry_put(entry);
+	return ret;
 }
 
 /* Legacy cache function, does a flush (clean  + invalidate) */
@@ -2024,10 +2047,9 @@
 	struct kgsl_sharedmem_free *param = data;
 	struct kgsl_process_private *private = dev_priv->process_priv;
 	struct kgsl_mem_entry *entry = NULL;
+	long ret;
 
-	spin_lock(&private->mem_lock);
 	entry = kgsl_sharedmem_find(private, param->gpuaddr);
-	spin_unlock(&private->mem_lock);
 	if (entry == NULL) {
 		KGSL_MEM_INFO(dev_priv->device,
 				"can't find gpuaddr %x\n",
@@ -2035,7 +2057,9 @@
 		return -EINVAL;
 	}
 
-	return _kgsl_gpumem_sync_cache(entry, KGSL_GPUMEM_CACHE_FLUSH);
+	ret = _kgsl_gpumem_sync_cache(entry, KGSL_GPUMEM_CACHE_FLUSH);
+	kgsl_mem_entry_put(entry);
+	return ret;
 }
 
 /*
@@ -2173,9 +2197,7 @@
 			return -EINVAL;
 		}
 	} else if (param->gpuaddr != 0) {
-		spin_lock(&private->mem_lock);
 		entry = kgsl_sharedmem_find(private, param->gpuaddr);
-		spin_unlock(&private->mem_lock);
 		if (entry == NULL) {
 			KGSL_MEM_INFO(dev_priv->device,
 					"can't find gpuaddr %lx\n",
@@ -2191,6 +2213,8 @@
 	param->size = entry->memdesc.size;
 	param->mmapsize = kgsl_memdesc_mmapsize(&entry->memdesc);
 	param->useraddr = entry->memdesc.useraddr;
+
+	kgsl_mem_entry_put(entry);
 	return result;
 }
 
@@ -2202,14 +2226,14 @@
 	struct kgsl_process_private *private = dev_priv->process_priv;
 	struct kgsl_mem_entry *entry = NULL;
 
-	spin_lock(&private->mem_lock);
 	entry = kgsl_sharedmem_find_region(private, param->gpuaddr, param->len);
-	if (entry)
-		kgsl_cffdump_syncmem(dev_priv, &entry->memdesc, param->gpuaddr,
-				     param->len, true);
-	else
-		result = -EINVAL;
-	spin_unlock(&private->mem_lock);
+	if (!entry)
+		return -EINVAL;
+
+	kgsl_cffdump_syncmem(dev_priv, &entry->memdesc, param->gpuaddr,
+			     param->len, true);
+
+	kgsl_mem_entry_put(entry);
 	return result;
 }
 
@@ -2601,21 +2625,17 @@
 		struct kgsl_mem_entry **out_entry, unsigned long pgoff,
 		unsigned long len)
 {
-	int ret = -EINVAL;
+	int ret = 0;
 	struct kgsl_mem_entry *entry;
 
 	entry = kgsl_sharedmem_find_id(private, pgoff);
 	if (entry == NULL) {
-		spin_lock(&private->mem_lock);
 		entry = kgsl_sharedmem_find(private, pgoff << PAGE_SHIFT);
-		spin_unlock(&private->mem_lock);
 	}
 
 	if (!entry)
 		return -EINVAL;
 
-	kgsl_mem_entry_get(entry);
-
 	if (!entry->memdesc.ops ||
 		!entry->memdesc.ops->vmflags ||
 		!entry->memdesc.ops->vmfault) {
@@ -2768,6 +2788,10 @@
 	if (vma_offset == device->memstore.gpuaddr)
 		return kgsl_mmap_memstore(device, vma);
 
+	/*
+	 * The reference count on the entry that we get from
+	 * get_mmap_entry() will be held until kgsl_gpumem_vm_close().
+	 */
 	ret = get_mmap_entry(private, &entry, vma->vm_pgoff,
 				vma->vm_end - vma->vm_start);
 	if (ret)
@@ -2837,7 +2861,6 @@
 	entry->memdesc.useraddr = vma->vm_start;
 
 	trace_kgsl_mem_mmap(entry);
-
 	return 0;
 }
 
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 869ab25..206f4ef 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -268,6 +268,8 @@
 	void *base = kgsl_driver.memfree_hist.base_hist_rb;
 	struct kgsl_memfree_hist_elem *wptr;
 	struct kgsl_memfree_hist_elem *p;
+	char name[32];
+	memset(name, 0, sizeof(name));
 
 	mutex_lock(&kgsl_driver.memfree_hist_mutex);
 	wptr = kgsl_driver.memfree_hist.wptr;
@@ -277,12 +279,15 @@
 			if (addr >= p->gpuaddr &&
 				addr < (p->gpuaddr + p->size)) {
 
+				kgsl_get_memory_usage(name, sizeof(name) - 1,
+					p->flags),
 				KGSL_LOG_DUMP(iommu_dev->kgsldev,
 					"---- premature free ----\n");
 				KGSL_LOG_DUMP(iommu_dev->kgsldev,
-					"[%8.8X-%8.8X] was already freed by pid %d\n",
+					"[%8.8X-%8.8X] (%s) was already freed by pid %d\n",
 					p->gpuaddr,
 					p->gpuaddr + p->size,
+					name,
 					p->pid);
 			}
 		p++;
@@ -347,22 +352,17 @@
 			KGSL_IOMMU_V1_FSYNR0_WNR_SHIFT)) ? 1 : 0);
 
 	pid = kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase);
-	KGSL_MEM_CRIT(iommu_dev->kgsldev,
-		"GPU PAGE FAULT: addr = %lX pid = %d\n", addr, pid);
-	KGSL_MEM_CRIT(iommu_dev->kgsldev,
-		"context = %d FSR = %X FSYNR0 = %X FSYNR1 = %X(%s fault)\n",
-		iommu_dev->ctx_id, fsr, fsynr0, fsynr1,
-		write ? "write" : "read");
 
 	if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE)
 		no_page_fault_log = kgsl_mmu_log_fault_addr(mmu, ptbase, addr);
 
 	if (!no_page_fault_log) {
 		KGSL_MEM_CRIT(iommu_dev->kgsldev,
-			"GPU PAGE FAULT: addr = %lX pid = %d\n",
-			addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
-		KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
-			iommu_dev->ctx_id, fsr);
+			"GPU PAGE FAULT: addr = %lX pid = %d\n", addr, pid);
+		KGSL_MEM_CRIT(iommu_dev->kgsldev,
+		 "context = %d FSR = %X FSYNR0 = %X FSYNR1 = %X(%s fault)\n",
+			iommu_dev->ctx_id, fsr, fsynr0, fsynr1,
+			write ? "write" : "read");
 
 		_check_if_freed(iommu_dev, addr, pid);
 
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index abcebfb..4165690 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -345,6 +345,7 @@
 	struct kgsl_mem_entry *entry;
 	struct kgsl_snapshot_object *obj;
 	int offset;
+	int ret = -EINVAL;
 
 	entry = kgsl_get_mem_entry(device, ptbase, gpuaddr, size);
 
@@ -358,7 +359,7 @@
 	if (entry->memtype != KGSL_MEM_ENTRY_KERNEL) {
 		KGSL_DRV_ERR(device,
 			"Only internal GPU buffers can be frozen\n");
-		return -EINVAL;
+		goto err_put;
 	}
 
 	/*
@@ -381,7 +382,7 @@
 	if (size + offset > entry->memdesc.size) {
 		KGSL_DRV_ERR(device, "Invalid size for GPU buffer %8.8X\n",
 				gpuaddr);
-		return -EINVAL;
+		goto err_put;
 	}
 
 	/* If the buffer is already on the list, skip it */
@@ -390,27 +391,24 @@
 			/* If the size is different, use the bigger size */
 			if (obj->size < size)
 				obj->size = size;
-
-			return 0;
+			ret = 0;
+			goto err_put;
 		}
 	}
 
 	if (kgsl_memdesc_map(&entry->memdesc) == NULL) {
 		KGSL_DRV_ERR(device, "Unable to map GPU buffer %X\n",
 				gpuaddr);
-		return -EINVAL;
+		goto err_put;
 	}
 
 	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
 
 	if (obj == NULL) {
 		KGSL_DRV_ERR(device, "Unable to allocate memory\n");
-		return -EINVAL;
+		goto err_put;
 	}
 
-	/* Ref count the mem entry */
-	kgsl_mem_entry_get(entry);
-
 	obj->type = type;
 	obj->entry = entry;
 	obj->gpuaddr = gpuaddr;
@@ -428,12 +426,15 @@
 	 * 0 so it doesn't get counted twice
 	 */
 
-	if (entry->memdesc.priv & KGSL_MEMDESC_FROZEN)
-		return 0;
+	ret = (entry->memdesc.priv & KGSL_MEMDESC_FROZEN) ? 0
+		: entry->memdesc.size;
 
 	entry->memdesc.priv |= KGSL_MEMDESC_FROZEN;
 
-	return entry->memdesc.size;
+	return ret;
+err_put:
+	kgsl_mem_entry_put(entry);
+	return ret;
 }
 EXPORT_SYMBOL(kgsl_snapshot_get_object);
 
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index 813305a..aad8ef1 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -168,7 +168,6 @@
 fail_event:
 fail_copy_fd:
 	/* clean up sync_fence_install */
-	sync_fence_put(fence);
 	put_unused_fd(priv.fence_fd);
 fail_fd:
 	/* clean up sync_fence_create */
diff --git a/drivers/gpu/msm/z180_postmortem.c b/drivers/gpu/msm/z180_postmortem.c
index c1e5f07..55b8faa 100644
--- a/drivers/gpu/msm/z180_postmortem.c
+++ b/drivers/gpu/msm/z180_postmortem.c
@@ -168,6 +168,7 @@
 				KGSL_LOG_DUMP(device,
 				"Could not map IB to kernel memory, Ringbuffer Slot: %d\n",
 				rb_slot_num);
+				kgsl_mem_entry_put(entry);
 				continue;
 			}
 
@@ -190,6 +191,7 @@
 						linebuf);
 			}
 			KGSL_LOG_DUMP(device, "IB Dump Finished\n");
+			kgsl_mem_entry_put(entry);
 		}
 	}
 }
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 0fab4d1..8e350f0 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -130,6 +130,60 @@
 	{790,	203}
 };
 
+static const struct qpnp_vadc_map_pt adcmap_qrd_btm_threshold[] = {
+	{-200,	1672},
+	{-180,	1656},
+	{-160,	1639},
+	{-140,	1620},
+	{-120,	1599},
+	{-100,	1577},
+	{-80,	1553},
+	{-60,	1527},
+	{-40,	1550},
+	{-20,	1471},
+	{0,	1440},
+	{20,	1408},
+	{40,	1374},
+	{60,	1339},
+	{80,	1303},
+	{100,	1266},
+	{120,	1228},
+	{140,	1190},
+	{160,	1150},
+	{180,	1111},
+	{200,	1071},
+	{220,	1032},
+	{240,	992},
+	{260,	953},
+	{280,	915},
+	{300,	877},
+	{320,	841},
+	{340,	805},
+	{360,	770},
+	{380,	736},
+	{400,	704},
+	{420,	673},
+	{440,	643},
+	{460,	614},
+	{480,	587},
+	{500,	561},
+	{520,	536},
+	{540,	513},
+	{560,	491},
+	{580,	470},
+	{600,	450},
+	{620,	431},
+	{640,	414},
+	{660,	397},
+	{680,	382},
+	{700,	367},
+	{720,	353},
+	{740,	340},
+	{760,	328},
+	{780,	317},
+	{800,	306},
+};
+
 /* Voltage to temperature */
 static const struct qpnp_vadc_map_pt adcmap_100k_104ef_104fb[] = {
 	{1758,	-40},
@@ -463,6 +517,24 @@
 }
 EXPORT_SYMBOL(qpnp_adc_scale_batt_therm);
 
+int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int64_t bat_voltage = 0;
+
+	bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+			adc_properties, chan_properties);
+
+	return qpnp_adc_map_temp_voltage(
+			adcmap_qrd_btm_threshold,
+			ARRAY_SIZE(adcmap_qrd_btm_threshold),
+			bat_voltage,
+			&adc_chan_result->physical);
+}
+EXPORT_SYMBOL(qpnp_adc_scale_qrd_batt_therm);
+
 int32_t qpnp_adc_scale_therm_pu1(int32_t adc_code,
 		const struct qpnp_adc_properties *adc_properties,
 		const struct qpnp_vadc_chan_properties *chan_properties,
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 68cff09..edb1d66 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -112,6 +112,7 @@
 	[SCALE_XOTHERM] = {qpnp_adc_tdkntcg_therm},
 	[SCALE_THERM_100K_PULLUP] = {qpnp_adc_scale_therm_pu2},
 	[SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
+	[SCALE_QRD_BATT_THERM] = {qpnp_adc_scale_qrd_batt_therm},
 };
 
 static int32_t qpnp_vadc_read_reg(int16_t reg, u8 *data)
@@ -431,12 +432,32 @@
 	return 0;
 }
 
-static uint32_t qpnp_vadc_calib_device(void)
+static void qpnp_vadc_625mv_channel_sel(uint32_t *ref_channel_sel)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+	uint32_t dt_index = 0;
+
+	/* Check if the buffered 625mV channel exists */
+	while ((vadc->adc->adc_channels[dt_index].channel_num
+		!= SPARE1) && (dt_index < vadc->max_channels_available))
+		dt_index++;
+
+	if (dt_index >= vadc->max_channels_available) {
+		pr_debug("Use default 625mV ref channel\n");
+		*ref_channel_sel = REF_625MV;
+	} else {
+		pr_debug("Use buffered 625mV ref channel\n");
+		*ref_channel_sel = SPARE1;
+	}
+}
+
+static int32_t qpnp_vadc_calib_device(void)
 {
 	struct qpnp_vadc_drv *vadc = qpnp_vadc;
 	struct qpnp_adc_amux_properties conv;
 	int rc, calib_read_1, calib_read_2, count = 0;
 	u8 status1 = 0;
+	uint32_t ref_channel_sel = 0;
 
 	conv.amux_channel = REF_125V;
 	conv.decimation = DECIMATION_TYPE2;
@@ -470,7 +491,8 @@
 		goto calib_fail;
 	}
 
-	conv.amux_channel = REF_625MV;
+	qpnp_vadc_625mv_channel_sel(&ref_channel_sel);
+	conv.amux_channel = ref_channel_sel;
 	conv.decimation = DECIMATION_TYPE2;
 	conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
 	conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
@@ -647,6 +669,7 @@
 {
 	struct qpnp_vadc_drv *vadc = qpnp_vadc;
 	int rc = 0, scale_type, amux_prescaling, dt_index = 0;
+	uint32_t ref_channel;
 
 	if (!vadc || !vadc->vadc_initialized)
 		return -EPROBE_DEFER;
@@ -666,6 +689,11 @@
 			vadc->vadc_init_calib = true;
 	}
 
+	if (channel == REF_625MV) {
+		qpnp_vadc_625mv_channel_sel(&ref_channel);
+		channel = ref_channel;
+	}
+
 	vadc->adc->amux_prop->amux_channel = channel;
 
 	while ((vadc->adc->adc_channels[dt_index].channel_num
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 4a021e1..426c7e7 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -1082,17 +1082,25 @@
 		bool enable)
 {
 	int retval = 0;
-	unsigned char intr_status;
+	unsigned char *intr_status;
 
 	if (enable) {
 		if (rmi4_data->irq_enabled)
 			return retval;
 
+		intr_status = kzalloc(rmi4_data->num_of_intr_regs, GFP_KERNEL);
+		if (!intr_status) {
+			dev_err(&rmi4_data->i2c_client->dev,
+					"%s: Failed to alloc memory\n",
+					__func__);
+			return -ENOMEM;
+		}
 		/* Clear interrupts first */
 		retval = synaptics_rmi4_i2c_read(rmi4_data,
 				rmi4_data->f01_data_base_addr + 1,
-				&intr_status,
+				intr_status,
 				rmi4_data->num_of_intr_regs);
+		kfree(intr_status);
 		if (retval < 0)
 			return retval;
 
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 89500f9..fcade49 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -246,7 +246,10 @@
 				struct dmx_secure_mode *sec_mode);
 	int (*oob_command) (struct dmx_ts_feed *feed,
 			struct dmx_oob_command *cmd);
-
+	int (*ts_insertion_init)(struct dmx_ts_feed *feed);
+	int (*ts_insertion_terminate)(struct dmx_ts_feed *feed);
+	int (*ts_insertion_insert_buffer)(struct dmx_ts_feed *feed,
+			char *data, size_t size);
 };
 
 /*--------------------------------------------------------------------------*/
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 5e7a09e..7347b37 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -34,6 +34,8 @@
 #include <linux/uaccess.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
 #include "dmxdev.h"
 
 static int debug;
@@ -416,7 +418,33 @@
 	return 0;
 }
 
-static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
+static inline int dvb_dmxdev_check_data(struct dmxdev_filter *filter,
+			struct dvb_ringbuffer *src)
+{
+	int data_status_change;
+
+	if (filter)
+		if (mutex_lock_interruptible(&filter->mutex))
+			return -ERESTARTSYS;
+
+	if (!src->data ||
+		!dvb_ringbuffer_empty(src) ||
+		src->error ||
+		(filter &&
+		 (filter->state != DMXDEV_STATE_GO) &&
+		 (filter->state != DMXDEV_STATE_DONE)))
+		data_status_change = 1;
+	else
+		data_status_change = 0;
+
+	if (filter)
+		mutex_unlock(&filter->mutex);
+
+	return data_status_change;
+}
+
+static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_filter *filter,
+					struct dvb_ringbuffer *src,
 					int non_blocking, char __user *buf,
 					size_t count, loff_t *ppos)
 {
@@ -439,9 +467,26 @@
 			break;
 		}
 
-		ret = wait_event_interruptible(src->queue, (!src->data) ||
-						!dvb_ringbuffer_empty(src) ||
-						(src->error != 0));
+		if (filter) {
+			if ((filter->state == DMXDEV_STATE_DONE) &&
+				dvb_ringbuffer_empty(src))
+				break;
+
+			mutex_unlock(&filter->mutex);
+		}
+
+		ret = wait_event_interruptible(src->queue,
+				dvb_dmxdev_check_data(filter, src));
+
+		if (filter) {
+			if (mutex_lock_interruptible(&filter->mutex))
+				return -ERESTARTSYS;
+
+			if ((filter->state != DMXDEV_STATE_GO) &&
+				(filter->state != DMXDEV_STATE_DONE))
+				return -ENODEV;
+		}
+
 		if (ret < 0)
 			break;
 
@@ -1108,9 +1153,9 @@
 	if (dmxdev->exit)
 		return -ENODEV;
 
-	res = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
-				      file->f_flags & O_NONBLOCK,
-				      buf, count, ppos);
+	res = dvb_dmxdev_buffer_read(NULL, &dmxdev->dvr_buffer,
+				file->f_flags & O_NONBLOCK,
+				buf, count, ppos);
 
 	if (res > 0) {
 		dvb_dmxdev_notify_data_read(dmxdev->dvr_feed, res);
@@ -1751,6 +1796,213 @@
 	return 0;
 }
 
+static void dvb_dmxdev_ts_insertion_timer(unsigned long data)
+{
+	struct ts_insertion_buffer *ts_buffer =
+		(struct ts_insertion_buffer *)data;
+
+	if (ts_buffer && !ts_buffer->abort)
+		schedule_work(&ts_buffer->work);
+}
+
+static void dvb_dmxdev_ts_insertion_work(struct work_struct *worker)
+{
+	struct ts_insertion_buffer *ts_buffer =
+		container_of(worker, struct ts_insertion_buffer, work);
+	struct dmxdev_feed *feed;
+	size_t free_bytes;
+	struct dmx_ts_feed *ts;
+
+	mutex_lock(&ts_buffer->dmxdevfilter->mutex);
+
+	if (ts_buffer->abort ||
+		(ts_buffer->dmxdevfilter->state != DMXDEV_STATE_GO)) {
+		mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
+		return;
+	}
+
+	feed = list_first_entry(&ts_buffer->dmxdevfilter->feed.ts,
+				struct dmxdev_feed, next);
+	ts = feed->ts;
+	free_bytes = dvb_ringbuffer_free(&ts_buffer->dmxdevfilter->buffer);
+
+	mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
+
+	if (ts_buffer->size < free_bytes)
+		ts->ts_insertion_insert_buffer(ts,
+			ts_buffer->buffer, ts_buffer->size);
+
+	if (ts_buffer->repetition_time)
+		mod_timer(&ts_buffer->timer, jiffies +
+				msecs_to_jiffies(ts_buffer->repetition_time));
+}
+
+static void dvb_dmxdev_queue_ts_insertion(
+		struct ts_insertion_buffer *ts_buffer)
+{
+	size_t tsp_size;
+
+	if (ts_buffer->dmxdevfilter->dmx_tsp_format == DMX_TSP_FORMAT_188)
+		tsp_size = 188;
+	else
+		tsp_size = 192;
+
+	if (ts_buffer->size % tsp_size) {
+		printk(KERN_ERR "%s: Wrong buffer alignment, size=%d, tsp_size=%d\n",
+			__func__, ts_buffer->size, tsp_size);
+		return;
+	}
+
+	ts_buffer->abort = 0;
+	schedule_work(&ts_buffer->work);
+}
+
+static void dvb_dmxdev_cancel_ts_insertion(
+		struct ts_insertion_buffer *ts_buffer)
+{
+	/*
+	 * This function assumes it is called while mutex
+	 * of demux filter is taken. Since work in workqueue
+	 * captures the filter's mutex to protect against the DB,
+	 * mutex needs to be released before waiting for the work
+	 * to get finished otherwise work in workqueue will
+	 * never be finished.
+	 */
+	if (!mutex_is_locked(&ts_buffer->dmxdevfilter->mutex)) {
+		printk(KERN_ERR "%s: mutex is not locked!\n", __func__);
+		return;
+	}
+
+	/*
+	 * Work should be stopped first as it might re-trigger the timer
+	 * until it is stopped. Timer would not re-schedule the work
+	 * due to the abort flag.
+	 */
+	ts_buffer->abort = 1;
+
+	mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
+	cancel_work_sync(&ts_buffer->work);
+	del_timer_sync(&ts_buffer->timer);
+	mutex_lock(&ts_buffer->dmxdevfilter->mutex);
+}
+
+static int dvb_dmxdev_set_ts_insertion(struct dmxdev_filter *dmxdevfilter,
+		struct dmx_set_ts_insertion *params)
+{
+	int ret = 0;
+	int first_buffer;
+	struct dmxdev_feed *feed;
+	struct ts_insertion_buffer *ts_buffer;
+
+	if (!params ||
+		!params->size ||
+		!(dmxdevfilter->dev->capabilities & DMXDEV_CAP_TS_INSERTION) ||
+		(dmxdevfilter->state < DMXDEV_STATE_SET) ||
+		(dmxdevfilter->type != DMXDEV_TYPE_PES) ||
+		((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) &&
+		 (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP)))
+		return -EINVAL;
+
+	ts_buffer = vmalloc(sizeof(struct ts_insertion_buffer));
+	if (!ts_buffer)
+		return -ENOMEM;
+
+	ts_buffer->buffer = vmalloc(params->size);
+	if (!ts_buffer->buffer) {
+		vfree(ts_buffer);
+		return -ENOMEM;
+	}
+
+	if (copy_from_user(ts_buffer->buffer,
+			params->ts_packets, params->size)) {
+		vfree(ts_buffer->buffer);
+		vfree(ts_buffer);
+		return -EFAULT;
+	}
+
+	if (params->repetition_time &&
+		params->repetition_time < DMX_MIN_INSERTION_REPETITION_TIME)
+		params->repetition_time = DMX_MIN_INSERTION_REPETITION_TIME;
+
+	ts_buffer->size = params->size;
+	ts_buffer->identifier = params->identifier;
+	ts_buffer->repetition_time = params->repetition_time;
+	ts_buffer->dmxdevfilter = dmxdevfilter;
+	init_timer(&ts_buffer->timer);
+	ts_buffer->timer.function = dvb_dmxdev_ts_insertion_timer;
+	ts_buffer->timer.data = (unsigned long)ts_buffer;
+	ts_buffer->timer.expires = 0xffffffffL;
+	INIT_WORK(&ts_buffer->work, dvb_dmxdev_ts_insertion_work);
+
+	first_buffer = list_empty(&dmxdevfilter->insertion_buffers);
+	list_add_tail(&ts_buffer->next, &dmxdevfilter->insertion_buffers);
+
+	if (dmxdevfilter->state != DMXDEV_STATE_GO)
+		return 0;
+
+	feed = list_first_entry(&dmxdevfilter->feed.ts,
+				struct dmxdev_feed, next);
+
+	if (first_buffer && feed->ts->ts_insertion_init)
+		ret = feed->ts->ts_insertion_init(feed->ts);
+
+	if (!ret) {
+		dvb_dmxdev_queue_ts_insertion(ts_buffer);
+	} else {
+		list_del(&ts_buffer->next);
+		vfree(ts_buffer->buffer);
+		vfree(ts_buffer);
+	}
+
+	return ret;
+}
+
+static int dvb_dmxdev_abort_ts_insertion(struct dmxdev_filter *dmxdevfilter,
+		struct dmx_abort_ts_insertion *params)
+{
+	int ret = 0;
+	int found_buffer;
+	struct dmxdev_feed *feed;
+	struct ts_insertion_buffer *ts_buffer, *tmp;
+
+	if (!params ||
+		!(dmxdevfilter->dev->capabilities & DMXDEV_CAP_TS_INSERTION) ||
+		(dmxdevfilter->state < DMXDEV_STATE_SET) ||
+		(dmxdevfilter->type != DMXDEV_TYPE_PES) ||
+		((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) &&
+		 (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP)))
+		return -EINVAL;
+
+	found_buffer = 0;
+	list_for_each_entry_safe(ts_buffer, tmp,
+			&dmxdevfilter->insertion_buffers, next) {
+		if (ts_buffer->identifier == params->identifier) {
+			list_del(&ts_buffer->next);
+			found_buffer = 1;
+			break;
+		}
+	}
+
+	if (!found_buffer)
+		return -EINVAL;
+
+	if (dmxdevfilter->state == DMXDEV_STATE_GO) {
+		dvb_dmxdev_cancel_ts_insertion(ts_buffer);
+		if (list_empty(&dmxdevfilter->insertion_buffers)) {
+			feed = list_first_entry(&dmxdevfilter->feed.ts,
+						struct dmxdev_feed, next);
+			if (feed->ts->ts_insertion_terminate)
+				ret = feed->ts->ts_insertion_terminate(
+							feed->ts);
+		}
+	}
+
+	vfree(ts_buffer->buffer);
+	vfree(ts_buffer);
+
+	return ret;
+}
+
 static int dvb_dmxdev_ts_fullness_callback(struct dmx_ts_feed *filter,
 				int required_space)
 {
@@ -2006,6 +2258,9 @@
 		dvb_ringbuffer_flush(&dmxdevfilter->buffer);
 		dvb_dmxdev_notify_data_read(dmxdevfilter, flush_len);
 		dmxdevfilter->buffer.error = 0;
+	} else if (event->type == DMX_EVENT_SECTION_TIMEOUT) {
+		/* clear buffer error now that user was notified */
+		dmxdevfilter->buffer.error = 0;
 	}
 
 	/*
@@ -2036,10 +2291,13 @@
 static void dvb_dmxdev_filter_timeout(unsigned long data)
 {
 	struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
+	struct dmx_filter_event event;
 
 	dmxdevfilter->buffer.error = -ETIMEDOUT;
 	spin_lock_irq(&dmxdevfilter->dev->lock);
 	dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
+	event.type = DMX_EVENT_SECTION_TIMEOUT;
+	dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
 	spin_unlock_irq(&dmxdevfilter->dev->lock);
 	wake_up_all(&dmxdevfilter->buffer.queue);
 }
@@ -2612,6 +2870,7 @@
 {
 	struct dmxdev_feed *feed;
 	struct dmx_demux *demux;
+	struct ts_insertion_buffer *ts_buffer;
 
 	if (dmxdevfilter->state < DMXDEV_STATE_GO)
 		return 0;
@@ -2631,6 +2890,18 @@
 	case DMXDEV_TYPE_PES:
 		dvb_dmxdev_feed_stop(dmxdevfilter);
 		demux = dmxdevfilter->dev->demux;
+
+		if (!list_empty(&dmxdevfilter->insertion_buffers)) {
+			feed = list_first_entry(&dmxdevfilter->feed.ts,
+				struct dmxdev_feed, next);
+
+			list_for_each_entry(ts_buffer,
+					&dmxdevfilter->insertion_buffers, next)
+				dvb_dmxdev_cancel_ts_insertion(ts_buffer);
+			if (feed->ts->ts_insertion_terminate)
+				feed->ts->ts_insertion_terminate(feed->ts);
+		}
+
 		list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
 			demux->release_ts_feed(demux, feed->ts);
 			feed->ts = NULL;
@@ -2971,6 +3242,29 @@
 	}
 
 	dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
+
+	if ((filter->type == DMXDEV_TYPE_PES) &&
+		!list_empty(&filter->insertion_buffers)) {
+		struct ts_insertion_buffer *ts_buffer;
+
+		feed = list_first_entry(&filter->feed.ts,
+			struct dmxdev_feed, next);
+
+		ret = 0;
+		if (feed->ts->ts_insertion_init)
+			ret = feed->ts->ts_insertion_init(feed->ts);
+		if (!ret) {
+			list_for_each_entry(ts_buffer,
+				&filter->insertion_buffers, next)
+				dvb_dmxdev_queue_ts_insertion(
+					ts_buffer);
+		} else {
+			printk(KERN_ERR
+				"%s: ts_insertion_init failed, err %d\n",
+				__func__, ret);
+		}
+	}
+
 	return 0;
 }
 
@@ -3017,6 +3311,8 @@
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
 	init_timer(&dmxdevfilter->timer);
 
+	INIT_LIST_HEAD(&dmxdevfilter->insertion_buffers);
+
 	dmxdevfilter->dmx_tsp_format = DMX_TSP_FORMAT_188;
 	dvbdev->users++;
 
@@ -3027,6 +3323,8 @@
 static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
 				  struct dmxdev_filter *dmxdevfilter)
 {
+	struct ts_insertion_buffer *ts_buffer, *tmp;
+
 	mutex_lock(&dmxdev->mutex);
 	mutex_lock(&dmxdevfilter->mutex);
 
@@ -3034,6 +3332,13 @@
 
 	dvb_dmxdev_filter_reset(dmxdevfilter);
 
+	list_for_each_entry_safe(ts_buffer, tmp,
+			&dmxdevfilter->insertion_buffers, next) {
+		list_del(&ts_buffer->next);
+		vfree(ts_buffer->buffer);
+		vfree(ts_buffer);
+	}
+
 	if (dmxdevfilter->buffer.data) {
 		void *mem = dmxdevfilter->buffer.data;
 
@@ -3098,12 +3403,20 @@
 static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
 				  struct dmxdev_filter *filter, u16 pid)
 {
+	int feed_count;
 	struct dmxdev_feed *feed, *tmp;
 
 	if ((filter->type != DMXDEV_TYPE_PES) ||
 	    (filter->state < DMXDEV_STATE_SET))
 		return -EINVAL;
 
+	feed_count = 0;
+	list_for_each_entry(tmp, &filter->feed.ts, next)
+		feed_count++;
+
+	if (feed_count <= 1)
+		return -EINVAL;
+
 	list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
 		if (feed->pid == pid) {
 			if (feed->ts != NULL) {
@@ -3283,7 +3596,7 @@
 		hcount = 3 + dfil->todo;
 		if (hcount > count)
 			hcount = count;
-		result = dvb_dmxdev_buffer_read(&dfil->buffer,
+		result = dvb_dmxdev_buffer_read(dfil, &dfil->buffer,
 						file->f_flags & O_NONBLOCK,
 						buf, hcount, ppos);
 		if (result < 0) {
@@ -3304,7 +3617,7 @@
 	}
 	if (count > dfil->todo)
 		count = dfil->todo;
-	result = dvb_dmxdev_buffer_read(&dfil->buffer,
+	result = dvb_dmxdev_buffer_read(dfil, &dfil->buffer,
 					file->f_flags & O_NONBLOCK,
 					buf, count, ppos);
 	if (result < 0)
@@ -3333,9 +3646,10 @@
 	if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
 		ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
 	else
-		ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
-					    file->f_flags & O_NONBLOCK,
-					    buf, count, ppos);
+		ret = dvb_dmxdev_buffer_read(dmxdevfilter,
+					&dmxdevfilter->buffer,
+					file->f_flags & O_NONBLOCK,
+					buf, count, ppos);
 
 	if (ret > 0) {
 		dvb_dmxdev_notify_data_read(dmxdevfilter, ret);
@@ -3625,6 +3939,24 @@
 		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
+	case DMX_SET_TS_INSERTION:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_set_ts_insertion(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_ABORT_TS_INSERTION:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_abort_ts_insertion(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 2ed99ae..d8cd982 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -114,6 +114,35 @@
 	struct dmx_filter_event queue[DMX_EVENT_QUEUE_SIZE];
 };
 
+#define DMX_MIN_INSERTION_REPETITION_TIME	25 /* in msec */
+struct ts_insertion_buffer {
+	/* work scheduled for insertion of this buffer */
+	struct work_struct work;
+
+	struct list_head next;
+
+	/* buffer holding TS packets for insertion */
+	char *buffer;
+
+	/* buffer size */
+	size_t size;
+
+	/* buffer ID from user */
+	u32 identifier;
+
+	/* repetition time for the buffer insertion */
+	u32 repetition_time;
+
+	/* timer used for insertion of the buffer */
+	struct timer_list timer;
+
+	/* the recording filter to which this buffer belongs */
+	struct dmxdev_filter *dmxdevfilter;
+
+	/* indication whether insertion should be aborted */
+	int abort;
+};
+
 struct dmxdev_filter {
 	union {
 		struct dmx_section_filter *sec;
@@ -145,6 +174,9 @@
 	enum dmx_tsp_format_t dmx_tsp_format;
 	u32 rec_chunk_size;
 
+	/* list of buffers used for insertion (struct ts_insertion_buffer) */
+	struct list_head insertion_buffers;
+
 	/* End-of-stream indication has been received */
 	int eos_state;
 
@@ -170,6 +202,8 @@
 #define DMXDEV_CAP_PULL_MODE	0x02
 #define DMXDEV_CAP_INDEXING	0x04
 #define DMXDEV_CAP_EXTERNAL_BUFFS_ONLY	0x08
+#define DMXDEV_CAP_TS_INSERTION	0x10
+
 
 	enum dmx_playback_mode_t playback_mode;
 	dmx_source_t source;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 3f3d222..939d591 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -2331,6 +2331,25 @@
 	return ret;
 }
 
+static int dvbdmx_ts_insertion_insert_buffer(struct dmx_ts_feed *ts_feed,
+			char *data, size_t size)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *demux = feed->demux;
+
+	spin_lock(&demux->lock);
+	if (!ts_feed->is_filtering) {
+		spin_unlock(&demux->lock);
+		return 0;
+	}
+
+	feed->cb.ts(data, size, NULL, 0, ts_feed, DMX_OK);
+
+	spin_unlock(&demux->lock);
+
+	return 0;
+}
+
 static int dmx_ts_set_tsp_out_format(
 	struct dmx_ts_feed *ts_feed,
 	enum dmx_tsp_format_t tsp_format)
@@ -2401,6 +2420,10 @@
 	(*ts_feed)->notify_data_read = NULL;
 	(*ts_feed)->set_secure_mode = dmx_ts_set_secure_mode;
 	(*ts_feed)->oob_command = dvbdmx_ts_feed_oob_cmd;
+	(*ts_feed)->ts_insertion_init = NULL;
+	(*ts_feed)->ts_insertion_terminate = NULL;
+	(*ts_feed)->ts_insertion_insert_buffer =
+		dvbdmx_ts_insertion_insert_buffer;
 
 	if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
 		feed->state = DMX_STATE_FREE;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 8ea1a00..59858b5 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -256,6 +256,13 @@
 				buf_info->state ==
 					MSM_ISP_BUFFER_STATE_INITIALIZED)
 			continue;
+
+		if (!BUF_SRC(bufq->stream_id)) {
+			if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED ||
+			buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED)
+				buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf,
+					bufq->session_id, bufq->stream_id);
+		}
 		msm_isp_unprepare_v4l2_buf(buf_mgr, buf_info);
 	}
 	return 0;
@@ -378,7 +385,6 @@
 	switch (buf_info->state) {
 	case MSM_ISP_BUFFER_STATE_PREPARED:
 	case MSM_ISP_BUFFER_STATE_DEQUEUED:
-	case MSM_ISP_BUFFER_STATE_DISPATCHED:
 	case MSM_ISP_BUFFER_STATE_DIVERTED:
 		if (BUF_SRC(bufq->stream_id))
 			list_add_tail(&buf_info->list, &bufq->head);
@@ -388,6 +394,13 @@
 		buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED;
 		rc = 0;
 		break;
+	case MSM_ISP_BUFFER_STATE_DISPATCHED:
+		buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED;
+		rc = 0;
+		break;
+	case MSM_ISP_BUFFER_STATE_QUEUED:
+		rc = 0;
+		break;
 	default:
 		pr_err("%s: incorrect state = %d",
 			__func__, buf_info->state);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index a251f0a..679c5cb 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -142,14 +142,13 @@
 		return;
 
 	if (irq_status0 & BIT(0)) {
-		ISP_DBG("%s: PIX0 frame id: %lu\n", __func__,
-			vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
-		msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
 		ISP_DBG("%s: SOF IRQ\n", __func__);
 		if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
 			&& vfe_dev->axi_data.src_info[VFE_PIX_0].
 			pix_stream_count == 0) {
 			msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
+			if (vfe_dev->axi_data.stream_update)
+				msm_isp_axi_stream_update(vfe_dev);
 			msm_isp_update_framedrop_reg(vfe_dev);
 		}
 	}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 5a17635..731056b 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -299,6 +299,8 @@
 			&& vfe_dev->axi_data.src_info[VFE_PIX_0].
 			pix_stream_count == 0) {
 			msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
+			if (vfe_dev->axi_data.stream_update)
+				msm_isp_axi_stream_update(vfe_dev);
 			msm_isp_update_framedrop_reg(vfe_dev);
 		}
 	}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 728e172..13160ee 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -399,7 +399,10 @@
 	uint32_t framedrop_period = msm_isp_get_framedrop_period(
 	   stream_cfg_cmd->frame_skip_pattern);
 
-	stream_info->framedrop_pattern = 0x1;
+	if (stream_cfg_cmd->frame_skip_pattern == SKIP_ALL)
+		stream_info->framedrop_pattern = 0x0;
+	else
+		stream_info->framedrop_pattern = 0x1;
 	stream_info->framedrop_period = framedrop_period - 1;
 
 	if (stream_cfg_cmd->init_frame_drop < framedrop_period) {
@@ -706,35 +709,60 @@
 	}
 }
 
-enum msm_isp_camif_update_state
-	msm_isp_update_camif_output_count(
-	struct vfe_device *vfe_dev,
+static enum msm_isp_camif_update_state
+	msm_isp_get_camif_update_state(struct vfe_device *vfe_dev,
 	struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
 {
 	int i;
 	struct msm_vfe_axi_stream *stream_info;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
-	uint8_t cur_pix_count = axi_data->src_info[VFE_PIX_0].
-		pix_stream_count;
-	uint8_t cur_raw_count = axi_data->src_info[VFE_PIX_0].
-		raw_stream_count;
-	uint8_t pix_stream_cnt = 0;
+	uint8_t pix_stream_cnt = 0, cur_pix_stream_cnt;
+	cur_pix_stream_cnt =
+		axi_data->src_info[VFE_PIX_0].pix_stream_count +
+		axi_data->src_info[VFE_PIX_0].raw_stream_count;
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
 		stream_info =
 			&axi_data->stream_info[
 			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
 		if (stream_info->stream_src  < RDI_INTF_0)
 			pix_stream_cnt++;
+	}
+
+	if (pix_stream_cnt) {
+		if (cur_pix_stream_cnt == 0 && pix_stream_cnt &&
+			stream_cfg_cmd->cmd == START_STREAM)
+			return ENABLE_CAMIF;
+		else if (cur_pix_stream_cnt &&
+			(cur_pix_stream_cnt - pix_stream_cnt) == 0 &&
+			stream_cfg_cmd->cmd == STOP_STREAM)
+			return DISABLE_CAMIF;
+	}
+	return NO_UPDATE;
+}
+
+static void msm_isp_update_camif_output_count(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
+{
+	int i;
+	struct msm_vfe_axi_stream *stream_info;
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		stream_info =
+			&axi_data->stream_info[
+			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
+		if (stream_info->stream_src >= RDI_INTF_0)
+			return;
 		if (stream_info->stream_src == PIX_ENCODER ||
-				stream_info->stream_src == PIX_VIEWFINDER) {
+			stream_info->stream_src == PIX_VIEWFINDER ||
+			stream_info->stream_src == IDEAL_RAW) {
 			if (stream_cfg_cmd->cmd == START_STREAM)
 				vfe_dev->axi_data.src_info[VFE_PIX_0].
 					pix_stream_count++;
 			else
 				vfe_dev->axi_data.src_info[VFE_PIX_0].
 					pix_stream_count--;
-		} else if (stream_info->stream_src == CAMIF_RAW ||
-				stream_info->stream_src == IDEAL_RAW) {
+		} else if (stream_info->stream_src == CAMIF_RAW) {
 			if (stream_cfg_cmd->cmd == START_STREAM)
 				vfe_dev->axi_data.src_info[VFE_PIX_0].
 					raw_stream_count++;
@@ -743,25 +771,6 @@
 					raw_stream_count--;
 		}
 	}
-	if (pix_stream_cnt) {
-		if ((cur_pix_count + cur_raw_count == 0) &&
-				(axi_data->src_info[VFE_PIX_0].
-				pix_stream_count +
-				axi_data->src_info[VFE_PIX_0].
-					raw_stream_count != 0)) {
-			return ENABLE_CAMIF;
-		}
-
-		if ((cur_pix_count + cur_raw_count != 0) &&
-				(axi_data->src_info[VFE_PIX_0].
-				pix_stream_count +
-				axi_data->src_info[VFE_PIX_0].
-					raw_stream_count == 0)) {
-			return DISABLE_CAMIF;
-		}
-	}
-
-	return NO_UPDATE;
 }
 
 void msm_camera_io_dump_2(void __iomem *addr, int size)
@@ -886,6 +895,20 @@
 	return rc;
 }
 
+static void msm_isp_deinit_stream_ping_pong_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int i;
+	for (i = 0; i < 2; i++) {
+		struct msm_isp_buffer *buf;
+		buf = stream_info->buf[i];
+		if (buf)
+			vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
+				buf->bufq_handle, buf->buf_idx);
+	}
+}
+
 static void msm_isp_get_stream_wm_mask(
 	struct msm_vfe_axi_stream *stream_info,
 	uint32_t *wm_reload_mask)
@@ -937,6 +960,7 @@
 	vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, wm_reload_mask);
 	vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
 
+	msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
 	if (camif_update == ENABLE_CAMIF)
 		vfe_dev->hw_info->vfe_ops.core_ops.
 			update_camif_state(vfe_dev, camif_update);
@@ -969,6 +993,13 @@
 	if (camif_update == DISABLE_CAMIF)
 		vfe_dev->hw_info->vfe_ops.core_ops.
 			update_camif_state(vfe_dev, DISABLE_CAMIF);
+	msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
+
+	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		stream_info = &axi_data->stream_info[
+			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
+		msm_isp_deinit_stream_ping_pong_reg(vfe_dev, stream_info);
+	}
 	return rc;
 }
 
@@ -990,8 +1021,7 @@
 		/*Configure UB*/
 		vfe_dev->hw_info->vfe_ops.axi_ops.cfg_ub(vfe_dev);
 	}
-	camif_update =
-		msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
+	camif_update = msm_isp_get_camif_update_state(vfe_dev, stream_cfg_cmd);
 
 	if (stream_cfg_cmd->cmd == START_STREAM)
 		rc = msm_isp_start_axi_stream(
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index e08dea2..ce71235 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -206,7 +206,11 @@
 
 	framedrop_period = msm_isp_get_framedrop_period(
 	   stream_req_cmd->framedrop_pattern);
-	stream_info->framedrop_pattern = 0x1;
+
+	if (stream_req_cmd->framedrop_pattern == SKIP_ALL)
+		stream_info->framedrop_pattern = 0x0;
+	else
+		stream_info->framedrop_pattern = 0x1;
 	stream_info->framedrop_period = framedrop_period - 1;
 
 	if (!stream_info->composite_flag)
@@ -277,6 +281,20 @@
 	return rc;
 }
 
+static void msm_isp_deinit_stats_ping_pong_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int i;
+	struct msm_isp_buffer *buf;
+	for (i = 0; i < 2; i++) {
+		buf = stream_info->buf[i];
+		if (buf)
+			vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
+				buf->bufq_handle, buf->buf_idx);
+	}
+}
+
 void msm_isp_stats_stream_update(struct vfe_device *vfe_dev)
 {
 	int i;
@@ -415,6 +433,12 @@
 		vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask(
 		   vfe_dev, comp_stats_mask, 0);
 	}
+
+	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
+		stream_info = &stats_data->stream_info[idx];
+		msm_isp_deinit_stats_ping_pong_reg(vfe_dev, stream_info);
+	}
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index c981901..613ad86 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -174,6 +174,8 @@
 	case EVERY_32FRAME:
 		return 32;
 		break;
+	case SKIP_ALL:
+		return 1;
 	default:
 		return 1;
 	}
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index 35210a0..b0ff832 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -35,7 +35,7 @@
 	new_entry->vb2_buf = buf_mngr_dev->vb2_ops.get_buf(buf_info->session_id,
 		buf_info->stream_id);
 	if (!new_entry->vb2_buf) {
-		pr_err("%s:Get buf is null\n", __func__);
+		pr_debug("%s:Get buf is null\n", __func__);
 		kfree(new_entry);
 		return -EINVAL;
 	}
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 8cdaa4b..5a174f5 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -860,7 +860,7 @@
 	rc = v4l2_subdev_call(cpp_dev->buf_mgr_subdev, core, ioctl,
 		buff_mgr_ops, buff_mgr_info);
 	if (rc < 0)
-		pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+		pr_debug("%s: line %d rc = %d\n", __func__, __LINE__, rc);
 	return rc;
 }
 
@@ -1010,7 +1010,7 @@
 		&buff_mgr_info);
 	if (rc < 0) {
 		rc = -EAGAIN;
-		pr_err("error getting buffer rc:%d\n", rc);
+		pr_debug("error getting buffer rc:%d\n", rc);
 		goto ERROR2;
 	}
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
index 76aa695..ac697fb 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
@@ -40,7 +40,7 @@
 	struct msm_flash_fn_t *func_tbl;
 	const char *led_trigger_name[MAX_LED_TRIGGERS];
 	struct led_trigger *led_trigger[MAX_LED_TRIGGERS];
-	uint32_t max_current[MAX_LED_TRIGGERS];
+	uint32_t op_current[MAX_LED_TRIGGERS];
 	void *data;
 };
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index 1a75a5a..c6f1f72 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -59,11 +59,11 @@
 
 	case MSM_CAMERA_LED_LOW:
 		led_trigger_event(fctrl->led_trigger[0],
-			fctrl->max_current[0] / 2);
+			fctrl->op_current[0] / 2);
 		break;
 
 	case MSM_CAMERA_LED_HIGH:
-		led_trigger_event(fctrl->led_trigger[0], fctrl->max_current[0]);
+		led_trigger_event(fctrl->led_trigger[0], fctrl->op_current[0]);
 		break;
 
 	case MSM_CAMERA_LED_INIT:
@@ -144,7 +144,7 @@
 			CDBG("default trigger %s\n", fctrl.led_trigger_name[i]);
 
 			rc = of_property_read_u32(flash_src_node,
-				"qcom,max-current", &fctrl.max_current[i]);
+				"qcom,current", &fctrl.op_current[i]);
 			if (rc < 0) {
 				pr_err("failed rc %d\n", rc);
 				of_node_put(flash_src_node);
@@ -153,7 +153,7 @@
 
 			of_node_put(flash_src_node);
 
-			CDBG("max_current[%d] %d\n", i, fctrl.max_current[i]);
+			CDBG("max_current[%d] %d\n", i, fctrl.op_current[i]);
 
 			led_trigger_register_simple(fctrl.led_trigger_name[i],
 				&fctrl.led_trigger[i]);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
index 8855e85..29369de 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
@@ -703,7 +703,8 @@
 	mpq_demux->dmxdev.capabilities =
 		DMXDEV_CAP_DUPLEX |
 		DMXDEV_CAP_PULL_MODE |
-		DMXDEV_CAP_INDEXING;
+		DMXDEV_CAP_INDEXING |
+		DMXDEV_CAP_TS_INSERTION;
 
 	mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
 	mpq_demux->dmxdev.demux->get_stc = mpq_tsif_dmx_get_stc;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
index 43a65e9..5e14d0c 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
@@ -1759,7 +1759,8 @@
 	mpq_demux->dmxdev.capabilities =
 		DMXDEV_CAP_DUPLEX |
 		DMXDEV_CAP_PULL_MODE |
-		DMXDEV_CAP_INDEXING;
+		DMXDEV_CAP_INDEXING |
+		DMXDEV_CAP_TS_INSERTION;
 
 	mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
 	mpq_demux->dmxdev.demux->get_stc = mpq_tspp_dmx_get_stc;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
index c306488..60e3cb4 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
@@ -143,7 +143,8 @@
 	mpq_demux->dmxdev.capabilities =
 		DMXDEV_CAP_DUPLEX |
 		DMXDEV_CAP_PULL_MODE |
-		DMXDEV_CAP_INDEXING;
+		DMXDEV_CAP_INDEXING |
+		DMXDEV_CAP_TS_INSERTION;
 
 	mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
 	mpq_demux->dmxdev.demux->get_caps = mpq_tspp_dmx_get_caps;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index feb239e..eb5a03c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -729,6 +729,8 @@
 			vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOSEQ)
 			vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_EOSEQ;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DECODEONLY)
+			vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_DECODEONLY;
 		switch (fill_buf_done->picture_type) {
 		case HAL_PICTURE_IDR:
 		case HAL_PICTURE_I:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 3208df9..ae1e9b7 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -198,6 +198,7 @@
 	write_str(&dbg_buf, "core: 0x%p\n", inst->core);
 	write_str(&dbg_buf, "height: %d\n", inst->prop.height);
 	write_str(&dbg_buf, "width: %d\n", inst->prop.width);
+	write_str(&dbg_buf, "fps: %d\n", inst->prop.fps);
 	write_str(&dbg_buf, "state: %d\n", inst->state);
 	write_str(&dbg_buf, "-----------Formats-------------\n");
 	for (i = 0; i < MAX_PORT_NUM; i++) {
diff --git a/drivers/media/platform/msm/wfd/enc-mfc-subdev.c b/drivers/media/platform/msm/wfd/enc-mfc-subdev.c
index ceb0149..26e24da 100644
--- a/drivers/media/platform/msm/wfd/enc-mfc-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-mfc-subdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -20,6 +20,7 @@
 #include <media/msm/vcd_property.h>
 #include <linux/time.h>
 #include <linux/ktime.h>
+#include <linux/slab.h>
 
 #define VID_ENC_MAX_ENCODER_CLIENTS 1
 #define MAX_NUM_CTRLS 20
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 4f7fb44..722aa8f 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -18,6 +18,7 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/wait.h>
+#include <linux/slab.h>
 #include <mach/iommu_domains.h>
 #include <media/msm_vidc.h>
 #include <media/v4l2-subdev.h>
diff --git a/drivers/media/platform/msm/wfd/mdp-4-subdev.c b/drivers/media/platform/msm/wfd/mdp-4-subdev.c
index 465ec21..2d79622 100644
--- a/drivers/media/platform/msm/wfd/mdp-4-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-4-subdev.c
@@ -11,6 +11,7 @@
 *
 */
 #include <linux/msm_mdp.h>
+#include <linux/slab.h>
 #include <mach/iommu_domains.h>
 #include <media/videobuf2-core.h>
 #include "enc-subdev.h"
diff --git a/drivers/media/platform/msm/wfd/mdp-5-subdev.c b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
index 3c546d0..6399117 100644
--- a/drivers/media/platform/msm/wfd/mdp-5-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
@@ -11,6 +11,7 @@
 *
 */
 #include <linux/msm_mdp.h>
+#include <linux/slab.h>
 #include <mach/iommu_domains.h>
 #include <media/videobuf2-core.h>
 #include "enc-subdev.h"
diff --git a/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c b/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
index 2242c76..10ba3c3 100644
--- a/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
@@ -12,6 +12,7 @@
 */
 #include <linux/list.h>
 #include <linux/msm_mdp.h>
+#include <linux/slab.h>
 #include <media/videobuf2-core.h>
 
 #include "enc-subdev.h"
diff --git a/drivers/media/platform/msm/wfd/vsg-subdev.c b/drivers/media/platform/msm/wfd/vsg-subdev.c
index 90b1957..e0a46cc 100644
--- a/drivers/media/platform/msm/wfd/vsg-subdev.c
+++ b/drivers/media/platform/msm/wfd/vsg-subdev.c
@@ -13,6 +13,7 @@
 #include <linux/hrtimer.h>
 #include <linux/time.h>
 #include <linux/list.h>
+#include <linux/slab.h>
 #include <media/videobuf2-core.h>
 #include "enc-subdev.h"
 #include "vsg-subdev.h"
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index b1b1980..d44792c 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -14,14 +14,14 @@
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/ioctl.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/init.h>
 #include <linux/version.h>
 #include <linux/platform_device.h>
-
 #include <linux/sched.h>
 #include <linux/kthread.h>
 #include <linux/time.h>
+#include <linux/slab.h>
 #include <mach/board.h>
 
 #include <media/v4l2-dev.h>
@@ -78,7 +78,8 @@
 
 struct wfd_inst {
 	struct vb2_queue vid_bufq;
-	spinlock_t inst_lock;
+	struct mutex lock;
+	struct mutex vb2_lock;
 	u32 buf_count;
 	struct task_struct *mdp_task;
 	void *mdp_inst;
@@ -114,7 +115,6 @@
 {
 	struct file *priv_data = (struct file *)(q->drv_priv);
 	struct wfd_inst *inst = file_to_inst(priv_data);
-	unsigned long flags;
 	int i;
 
 	WFD_MSG_DBG("In %s\n", __func__);
@@ -122,12 +122,12 @@
 		return -EINVAL;
 
 	*num_planes = 1;
-	spin_lock_irqsave(&inst->inst_lock, flags);
+	mutex_lock(&inst->lock);
 	for (i = 0; i < *num_planes; ++i) {
 		sizes[i] = inst->out_buf_size;
 		alloc_ctxs[i] = inst;
 	}
-	spin_unlock_irqrestore(&inst->inst_lock, flags);
+	mutex_unlock(&inst->lock);
 
 	return 0;
 }
@@ -257,16 +257,15 @@
 	struct mem_region *enc_mregion, *mdp_mregion;
 	struct mem_region_pair *mpair;
 	int rc;
-	unsigned long flags;
 	struct mdp_buf_info mdp_buf = {0};
 	struct mem_region_map mmap_context = {0};
-	spin_lock_irqsave(&inst->inst_lock, flags);
+	mutex_lock(&inst->lock);
 	if (inst->input_bufs_allocated) {
-		spin_unlock_irqrestore(&inst->inst_lock, flags);
+		mutex_unlock(&inst->lock);
 		return 0;
 	}
 	inst->input_bufs_allocated = true;
-	spin_unlock_irqrestore(&inst->inst_lock, flags);
+	mutex_unlock(&inst->lock);
 
 	for (i = 0; i < VENC_INPUT_BUFFERS; ++i) {
 		mpair = kzalloc(sizeof(*mpair), GFP_KERNEL);
@@ -409,15 +408,14 @@
 {
 	struct list_head *ptr, *next;
 	struct mem_region_pair *mpair;
-	unsigned long flags;
 	int rc = 0;
-	spin_lock_irqsave(&inst->inst_lock, flags);
+	mutex_lock(&inst->lock);
 	if (!inst->input_bufs_allocated) {
-		spin_unlock_irqrestore(&inst->inst_lock, flags);
+		mutex_unlock(&inst->lock);
 		return;
 	}
 	inst->input_bufs_allocated = false;
-	spin_unlock_irqrestore(&inst->inst_lock, flags);
+	mutex_unlock(&inst->lock);
 	if (!list_empty(&inst->input_mem_list)) {
 		list_for_each_safe(ptr, next,
 				&inst->input_mem_list) {
@@ -470,8 +468,7 @@
 {
 	struct mem_info_entry *temp;
 	struct mem_info *ret = NULL;
-	unsigned long flags;
-	spin_lock_irqsave(&inst->inst_lock, flags);
+	mutex_lock(&inst->lock);
 	if (!list_empty(&inst->minfo_list)) {
 		list_for_each_entry(temp, &inst->minfo_list, list) {
 			if (temp && temp->userptr == userptr) {
@@ -480,7 +477,7 @@
 			}
 		}
 	}
-	spin_unlock_irqrestore(&inst->inst_lock, flags);
+	mutex_unlock(&inst->lock);
 	return ret;
 }
 
@@ -489,8 +486,7 @@
 {
 	struct list_head *ptr, *next;
 	struct mem_info_entry *temp;
-	unsigned long flags;
-	spin_lock_irqsave(&inst->inst_lock, flags);
+	mutex_lock(&inst->lock);
 	if (!list_empty(&inst->minfo_list)) {
 		list_for_each_safe(ptr, next,
 				&inst->minfo_list) {
@@ -502,7 +498,7 @@
 			}
 		}
 	}
-	spin_unlock_irqrestore(&inst->inst_lock, flags);
+	mutex_unlock(&inst->lock);
 }
 static void wfd_unregister_out_buf(struct wfd_inst *inst,
 		struct mem_info *minfo)
@@ -806,7 +802,6 @@
 			struct v4l2_format *fmt)
 {
 	struct wfd_inst *inst = file_to_inst(filp);
-	unsigned long flags;
 	if (!fmt) {
 		WFD_MSG_ERR("Invalid argument\n");
 		return -EINVAL;
@@ -815,13 +810,13 @@
 		WFD_MSG_ERR("Only V4L2_BUF_TYPE_VIDEO_CAPTURE is supported\n");
 		return -EINVAL;
 	}
-	spin_lock_irqsave(&inst->inst_lock, flags);
+	mutex_lock(&inst->lock);
 	fmt->fmt.pix.width = inst->width;
 	fmt->fmt.pix.height = inst->height;
 	fmt->fmt.pix.pixelformat = inst->pixelformat;
 	fmt->fmt.pix.sizeimage = inst->out_buf_size;
 	fmt->fmt.pix.priv = 0;
-	spin_unlock_irqrestore(&inst->inst_lock, flags);
+	mutex_unlock(&inst->lock);
 	return 0;
 }
 
@@ -832,7 +827,6 @@
 	struct wfd_inst *inst = file_to_inst(filp);
 	struct wfd_device *wfd_dev = video_drvdata(filp);
 	struct mdp_prop prop;
-	unsigned long flags;
 	struct bufreq breq;
 	if (!fmt) {
 		WFD_MSG_ERR("Invalid argument\n");
@@ -864,13 +858,13 @@
 		WFD_MSG_ERR("Failed to set buffer reqs on encoder\n");
 		return rc;
 	}
-	spin_lock_irqsave(&inst->inst_lock, flags);
+	mutex_lock(&inst->lock);
 	inst->input_buf_size = breq.size;
 	inst->out_buf_size = fmt->fmt.pix.sizeimage;
 	prop.height = inst->height = fmt->fmt.pix.height;
 	prop.width = inst->width = fmt->fmt.pix.width;
 	prop.inst = inst->mdp_inst;
-	spin_unlock_irqrestore(&inst->inst_lock, flags);
+	mutex_unlock(&inst->lock);
 	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_SET_PROP,
 				(void *)&prop);
 	if (rc)
@@ -882,7 +876,6 @@
 {
 	struct wfd_inst *inst = file_to_inst(filp);
 	struct wfd_device *wfd_dev = video_drvdata(filp);
-	unsigned long flags;
 	int rc = 0;
 
 	if (b->type != V4L2_CAP_VIDEO_CAPTURE ||
@@ -897,9 +890,9 @@
 		WFD_MSG_ERR("Failed to get buf reqs from encoder\n");
 		return rc;
 	}
-	spin_lock_irqsave(&inst->inst_lock, flags);
+	mutex_lock(&inst->lock);
 	inst->buf_count = b->count;
-	spin_unlock_irqrestore(&inst->inst_lock, flags);
+	mutex_unlock(&inst->lock);
 	rc = vb2_reqbufs(&inst->vid_bufq, b);
 	return rc;
 }
@@ -908,7 +901,6 @@
 {
 	struct mem_info_entry *minfo_entry;
 	struct mem_info *minfo;
-	unsigned long flags;
 	if (!b || !inst || !b->reserved) {
 		WFD_MSG_ERR("Invalid arguments\n");
 		return -EINVAL;
@@ -924,9 +916,9 @@
 			return -EINVAL;
 		}
 		minfo_entry->userptr = b->m.userptr;
-		spin_lock_irqsave(&inst->inst_lock, flags);
+		mutex_lock(&inst->lock);
 		list_add_tail(&minfo_entry->list, &inst->minfo_list);
-		spin_unlock_irqrestore(&inst->inst_lock, flags);
+		mutex_unlock(&inst->lock);
 	} else
 		WFD_MSG_DBG("Buffer already registered\n");
 
@@ -948,7 +940,10 @@
 		return rc;
 	}
 
+	mutex_lock(&inst->vb2_lock);
 	rc = vb2_qbuf(&inst->vid_bufq, b);
+	mutex_unlock(&inst->vb2_lock);
+
 	if (rc)
 		WFD_MSG_ERR("Failed to queue buffer\n");
 	else
@@ -962,16 +957,15 @@
 {
 	int rc = 0;
 	struct wfd_inst *inst = file_to_inst(filp);
-	unsigned long flags;
 	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 		WFD_MSG_ERR("stream on for buffer type = %d is not "
 			"supported.\n", i);
 		return -EINVAL;
 	}
 
-	spin_lock_irqsave(&inst->inst_lock, flags);
+	mutex_lock(&inst->lock);
 	inst->streamoff = false;
-	spin_unlock_irqrestore(&inst->inst_lock, flags);
+	mutex_unlock(&inst->lock);
 
 	rc = vb2_streamon(&inst->vid_bufq, i);
 	if (rc) {
@@ -988,7 +982,6 @@
 		enum v4l2_buf_type i)
 {
 	struct wfd_inst *inst = file_to_inst(filp);
-	unsigned long flags;
 
 	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 		WFD_MSG_ERR("stream off for buffer type = %d is not "
@@ -996,14 +989,14 @@
 		return -EINVAL;
 	}
 
-	spin_lock_irqsave(&inst->inst_lock, flags);
+	mutex_lock(&inst->lock);
 	if (inst->streamoff) {
 		WFD_MSG_ERR("Module is already in streamoff state\n");
-		spin_unlock_irqrestore(&inst->inst_lock, flags);
+		mutex_unlock(&inst->lock);
 		return -EINVAL;
 	}
 	inst->streamoff = true;
-	spin_unlock_irqrestore(&inst->inst_lock, flags);
+	mutex_unlock(&inst->lock);
 	WFD_MSG_DBG("Calling videobuf_streamoff\n");
 	vb2_streamoff(&inst->vid_bufq, i);
 	wake_up(&inst->event_handler.wait);
@@ -1016,7 +1009,10 @@
 	int rc;
 
 	WFD_MSG_DBG("Waiting to dequeue buffer\n");
-	rc = vb2_dqbuf(&inst->vid_bufq, b, 0);
+
+	/* XXX: If we switch to non-blocking mode in the future,
+	 * we'll need to lock this with vb2_lock */
+	rc = vb2_dqbuf(&inst->vid_bufq, b, false /* blocking */);
 
 	if (rc)
 		WFD_MSG_ERR("Failed to dequeue buffer\n");
@@ -1233,7 +1229,6 @@
 };
 static int wfd_set_default_properties(struct file *filp)
 {
-	unsigned long flags;
 	struct v4l2_format fmt;
 	struct v4l2_control ctrl;
 	struct wfd_inst *inst = file_to_inst(filp);
@@ -1241,13 +1236,13 @@
 		WFD_MSG_ERR("Invalid argument\n");
 		return -EINVAL;
 	}
-	spin_lock_irqsave(&inst->inst_lock, flags);
+	mutex_lock(&inst->lock);
 	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	fmt.fmt.pix.height = inst->height = DEFAULT_WFD_HEIGHT;
 	fmt.fmt.pix.width = inst->width = DEFAULT_WFD_WIDTH;
 	fmt.fmt.pix.pixelformat = inst->pixelformat
 			= V4L2_PIX_FMT_H264;
-	spin_unlock_irqrestore(&inst->inst_lock, flags);
+	mutex_unlock(&inst->lock);
 	wfdioc_s_fmt(filp, filp->private_data, &fmt);
 
 	ctrl.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE;
@@ -1258,8 +1253,13 @@
 static void venc_op_buffer_done(void *cookie, u32 status,
 			struct vb2_buffer *buf)
 {
+	struct file *filp = cookie;
+	struct wfd_inst *inst = file_to_inst(filp);
+
 	WFD_MSG_DBG("yay!! got callback\n");
+	mutex_lock(&inst->vb2_lock);
 	vb2_buffer_done(buf, VB2_BUF_STATE_DONE);
+	mutex_unlock(&inst->vb2_lock);
 }
 
 static void venc_ip_buffer_done(void *cookie, u32 status,
@@ -1430,7 +1430,8 @@
 		goto err_mdp_open;
 	}
 	filp->private_data = &inst->event_handler;
-	spin_lock_init(&inst->inst_lock);
+	mutex_init(&inst->lock);
+	mutex_init(&inst->vb2_lock);
 	INIT_LIST_HEAD(&inst->input_mem_list);
 	INIT_LIST_HEAD(&inst->minfo_list);
 
@@ -1531,6 +1532,8 @@
 
 		wfd_stats_deinit(&inst->stats);
 		v4l2_fh_del(&inst->event_handler);
+		mutex_destroy(&inst->lock);
+		mutex_destroy(&inst->vb2_lock);
 		kfree(inst);
 	}
 
@@ -1546,22 +1549,21 @@
 unsigned int wfd_poll(struct file *filp, struct poll_table_struct *pt)
 {
 	struct wfd_inst *inst = file_to_inst(filp);
-	unsigned int poll_flags = 0;
-	unsigned long flags;
+	unsigned long flags = 0;
 	bool streamoff = false;
 
 	poll_wait(filp, &inst->event_handler.wait, pt);
 
-	spin_lock_irqsave(&inst->inst_lock, flags);
+	mutex_lock(&inst->lock);
 	streamoff = inst->streamoff;
-	spin_unlock_irqrestore(&inst->inst_lock, flags);
+	mutex_unlock(&inst->lock);
 
 	if (v4l2_event_pending(&inst->event_handler))
-		poll_flags |= POLLPRI;
+		flags |= POLLPRI;
 	if (streamoff)
-		poll_flags |= POLLERR;
+		flags |= POLLERR;
 
-	return poll_flags;
+	return flags;
 }
 
 static const struct v4l2_file_operations g_wfd_fops = {
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 2573a16..a7932ba 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -51,10 +51,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad525x_dpot-spi.
 
-config ANDROID_PMEM
-	bool "Android pmem allocator"
-	default y
-
 config ATMEL_PWM
 	tristate "Atmel AT32/AT91 PWM support"
 	depends on HAVE_CLK
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 327d1ec..760f768 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -19,7 +19,6 @@
 obj-$(CONFIG_SENSORS_BH1780)	+= bh1780gli.o
 obj-$(CONFIG_SENSORS_BH1770)	+= bh1770glc.o
 obj-$(CONFIG_SENSORS_APDS990X)	+= apds990x.o
-obj-$(CONFIG_ANDROID_PMEM)	+= pmem.o
 obj-$(CONFIG_SGI_IOC4)		+= ioc4.o
 obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
 obj-$(CONFIG_KGDB_TESTS)	+= kgdbts.o
diff --git a/drivers/misc/pmem.c b/drivers/misc/pmem.c
deleted file mode 100644
index e91db7a..0000000
--- a/drivers/misc/pmem.c
+++ /dev/null
@@ -1,2961 +0,0 @@
-/* drivers/android/pmem.c
- *
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/export.h>
-#include <linux/miscdevice.h>
-#include <linux/platform_device.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/fmem.h>
-#include <linux/mm.h>
-#include <linux/list.h>
-#include <linux/debugfs.h>
-#include <linux/android_pmem.h>
-#include <linux/mempolicy.h>
-#include <linux/sched.h>
-#include <linux/kobject.h>
-#include <linux/pm_runtime.h>
-#include <linux/memory_alloc.h>
-#include <linux/vmalloc.h>
-#include <linux/io.h>
-#include <linux/mm_types.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/cacheflush.h>
-#include <asm/sizes.h>
-#include <asm/mach/map.h>
-#include <asm/page.h>
-
-#define PMEM_MAX_DEVICES (10)
-
-#define PMEM_MAX_ORDER (128)
-#define PMEM_MIN_ALLOC PAGE_SIZE
-
-#define PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS (64)
-
-#define PMEM_32BIT_WORD_ORDER (5)
-#define PMEM_BITS_PER_WORD_MASK (BITS_PER_LONG - 1)
-
-#ifdef CONFIG_ANDROID_PMEM_DEBUG
-#define PMEM_DEBUG 1
-#else
-#define PMEM_DEBUG 0
-#endif
-
-#define SYSTEM_ALLOC_RETRY 10
-
-/* indicates that a refernce to this file has been taken via get_pmem_file,
- * the file should not be released until put_pmem_file is called */
-#define PMEM_FLAGS_BUSY 0x1
-/* indicates that this is a suballocation of a larger master range */
-#define PMEM_FLAGS_CONNECTED 0x1 << 1
-/* indicates this is a master and not a sub allocation and that it is mmaped */
-#define PMEM_FLAGS_MASTERMAP 0x1 << 2
-/* submap and unsubmap flags indicate:
- * 00: subregion has never been mmaped
- * 10: subregion has been mmaped, reference to the mm was taken
- * 11: subretion has ben released, refernece to the mm still held
- * 01: subretion has been released, reference to the mm has been released
- */
-#define PMEM_FLAGS_SUBMAP 0x1 << 3
-#define PMEM_FLAGS_UNSUBMAP 0x1 << 4
-
-struct pmem_data {
-	/* in alloc mode: an index into the bitmap
-	 * in no_alloc mode: the size of the allocation */
-	int index;
-	/* see flags above for descriptions */
-	unsigned int flags;
-	/* protects this data field, if the mm_mmap sem will be held at the
-	 * same time as this sem, the mm sem must be taken first (as this is
-	 * the order for vma_open and vma_close ops */
-	struct rw_semaphore sem;
-	/* info about the mmaping process */
-	struct vm_area_struct *vma;
-	/* task struct of the mapping process */
-	struct task_struct *task;
-	/* process id of teh mapping process */
-	pid_t pid;
-	/* file descriptor of the master */
-	int master_fd;
-	/* file struct of the master */
-	struct file *master_file;
-	/* a list of currently available regions if this is a suballocation */
-	struct list_head region_list;
-	/* a linked list of data so we can access them for debugging */
-	struct list_head list;
-#if PMEM_DEBUG
-	int ref;
-#endif
-};
-
-struct pmem_bits {
-	unsigned allocated:1;		/* 1 if allocated, 0 if free */
-	unsigned order:7;		/* size of the region in pmem space */
-};
-
-struct pmem_region_node {
-	struct pmem_region region;
-	struct list_head list;
-};
-
-#define PMEM_DEBUG_MSGS 0
-#if PMEM_DEBUG_MSGS
-#define DLOG(fmt,args...) \
-	do { pr_debug("[%s:%s:%d] "fmt, __FILE__, __func__, __LINE__, \
-		    ##args); } \
-	while (0)
-#else
-#define DLOG(x...) do {} while (0)
-#endif
-
-enum pmem_align {
-	PMEM_ALIGN_4K,
-	PMEM_ALIGN_1M,
-};
-
-#define PMEM_NAME_SIZE 16
-
-struct alloc_list {
-	void *addr;                  /* physical addr of allocation */
-	void *aaddr;                 /* aligned physical addr       */
-	unsigned int size;           /* total size of allocation    */
-	unsigned char __iomem *vaddr; /* Virtual addr                */
-	struct list_head allocs;
-};
-
-struct pmem_info {
-	struct miscdevice dev;
-	/* physical start address of the remaped pmem space */
-	unsigned long base;
-	/* vitual start address of the remaped pmem space */
-	unsigned char __iomem *vbase;
-	/* total size of the pmem space */
-	unsigned long size;
-	/* number of entries in the pmem space */
-	unsigned long num_entries;
-	/* pfn of the garbage page in memory */
-	unsigned long garbage_pfn;
-	/* which memory type (i.e. SMI, EBI1) this PMEM device is backed by */
-	unsigned memory_type;
-
-	char name[PMEM_NAME_SIZE];
-
-	/* index of the garbage page in the pmem space */
-	int garbage_index;
-	/* reserved virtual address range */
-	struct vm_struct *area;
-
-	enum pmem_allocator_type allocator_type;
-
-	int (*allocate)(const int,
-			const unsigned long,
-			const unsigned int);
-	int (*free)(int, int);
-	int (*free_space)(int, struct pmem_freespace *);
-	unsigned long (*len)(int, struct pmem_data *);
-	unsigned long (*start_addr)(int, struct pmem_data *);
-
-	/* actual size of memory element, e.g.: (4 << 10) is 4K */
-	unsigned int quantum;
-
-	/* indicates maps of this region should be cached, if a mix of
-	 * cached and uncached is desired, set this and open the device with
-	 * O_SYNC to get an uncached region */
-	unsigned cached;
-	unsigned buffered;
-	union {
-		struct {
-			/* in all_or_nothing allocator mode the first mapper
-			 * gets the whole space and sets this flag */
-			unsigned allocated;
-		} all_or_nothing;
-
-		struct {
-			/* the buddy allocator bitmap for the region
-			 * indicating which entries are allocated and which
-			 * are free.
-			 */
-
-			struct pmem_bits *buddy_bitmap;
-		} buddy_bestfit;
-
-		struct {
-			unsigned int bitmap_free; /* # of zero bits/quanta */
-			uint32_t *bitmap;
-			int32_t bitmap_allocs;
-			struct {
-				short bit;
-				unsigned short quanta;
-			} *bitm_alloc;
-		} bitmap;
-
-		struct {
-			unsigned long used;      /* Bytes currently allocated */
-			struct list_head alist;  /* List of allocations       */
-		} system_mem;
-	} allocator;
-
-	int id;
-	struct kobject kobj;
-
-	/* for debugging, creates a list of pmem file structs, the
-	 * data_list_mutex should be taken before pmem_data->sem if both are
-	 * needed */
-	struct mutex data_list_mutex;
-	struct list_head data_list;
-	/* arena_mutex protects the global allocation arena
-	 *
-	 * IF YOU TAKE BOTH LOCKS TAKE THEM IN THIS ORDER:
-	 * down(pmem_data->sem) => mutex_lock(arena_mutex)
-	 */
-	struct mutex arena_mutex;
-
-	long (*ioctl)(struct file *, unsigned int, unsigned long);
-	int (*release)(struct inode *, struct file *);
-	/* reference count of allocations */
-	atomic_t allocation_cnt;
-	/*
-	 * request function for a region when the allocation count goes
-	 * from 0 -> 1
-	 */
-	int (*mem_request)(void *);
-	/*
-	 * release function for a region when the allocation count goes
-	 * from 1 -> 0
-	 */
-	int (*mem_release)(void *);
-	/*
-	 * private data for the request/release callback
-	 */
-	void *region_data;
-	/*
-	 * map and unmap as needed
-	 */
-	int map_on_demand;
-	/*
-	 * memory will be reused through fmem
-	 */
-	int reusable;
-};
-#define to_pmem_info_id(a) (container_of(a, struct pmem_info, kobj)->id)
-
-static void ioremap_pmem(int id);
-static void pmem_put_region(int id);
-static int pmem_get_region(int id);
-
-static struct pmem_info pmem[PMEM_MAX_DEVICES];
-static int id_count;
-
-#define PMEM_SYSFS_DIR_NAME "pmem_regions" /* under /sys/kernel/ */
-static struct kset *pmem_kset;
-
-#define PMEM_IS_FREE_BUDDY(id, index) \
-	(!(pmem[id].allocator.buddy_bestfit.buddy_bitmap[index].allocated))
-#define PMEM_BUDDY_ORDER(id, index) \
-	(pmem[id].allocator.buddy_bestfit.buddy_bitmap[index].order)
-#define PMEM_BUDDY_INDEX(id, index) \
-	(index ^ (1 << PMEM_BUDDY_ORDER(id, index)))
-#define PMEM_BUDDY_NEXT_INDEX(id, index) \
-	(index + (1 << PMEM_BUDDY_ORDER(id, index)))
-#define PMEM_OFFSET(index) (index * pmem[id].quantum)
-#define PMEM_START_ADDR(id, index) \
-	(PMEM_OFFSET(index) + pmem[id].base)
-#define PMEM_BUDDY_LEN(id, index) \
-	((1 << PMEM_BUDDY_ORDER(id, index)) * pmem[id].quantum)
-#define PMEM_END_ADDR(id, index) \
-	(PMEM_START_ADDR(id, index) + PMEM_LEN(id, index))
-#define PMEM_START_VADDR(id, index) \
-	(PMEM_OFFSET(id, index) + pmem[id].vbase)
-#define PMEM_END_VADDR(id, index) \
-	(PMEM_START_VADDR(id, index) + PMEM_LEN(id, index))
-#define PMEM_REVOKED(data) (data->flags & PMEM_FLAGS_REVOKED)
-#define PMEM_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK)))
-#define PMEM_IS_SUBMAP(data) \
-	((data->flags & PMEM_FLAGS_SUBMAP) && \
-	(!(data->flags & PMEM_FLAGS_UNSUBMAP)))
-
-static int pmem_release(struct inode *, struct file *);
-static int pmem_mmap(struct file *, struct vm_area_struct *);
-static int pmem_open(struct inode *, struct file *);
-static long pmem_ioctl(struct file *, unsigned int, unsigned long);
-
-struct file_operations pmem_fops = {
-	.release = pmem_release,
-	.mmap = pmem_mmap,
-	.open = pmem_open,
-	.unlocked_ioctl = pmem_ioctl,
-};
-
-#define PMEM_ATTR(_name, _mode, _show, _store) {            \
-	.attr = {.name = __stringify(_name), .mode = _mode }, \
-	.show = _show,                                        \
-	.store = _store,                                      \
-}
-
-struct pmem_attr {
-	struct attribute attr;
-	ssize_t(*show) (const int id, char * const);
-	ssize_t(*store) (const int id, const char * const, const size_t count);
-};
-#define to_pmem_attr(a) container_of(a, struct pmem_attr, attr)
-
-#define RW_PMEM_ATTR(name)  \
-static struct pmem_attr pmem_attr_## name = \
- PMEM_ATTR(name, S_IRUGO | S_IWUSR, show_pmem_## name, store_pmem_## name)
-
-#define RO_PMEM_ATTR(name)  \
-static struct pmem_attr pmem_attr_## name = \
- PMEM_ATTR(name, S_IRUGO, show_pmem_## name, NULL)
-
-#define WO_PMEM_ATTR(name)  \
-static struct pmem_attr pmem_attr_## name = \
- PMEM_ATTR(name, S_IWUSR, NULL, store_pmem_## name)
-
-static ssize_t show_pmem(struct kobject *kobj,
-			struct attribute *attr,
-			char *buf)
-{
-	struct pmem_attr *a = to_pmem_attr(attr);
-	return a->show ? a->show(to_pmem_info_id(kobj), buf) : -EIO;
-}
-
-static ssize_t store_pmem(struct kobject *kobj, struct attribute *attr,
-		     const char *buf, size_t count)
-{
-	struct pmem_attr *a = to_pmem_attr(attr);
-	return a->store ? a->store(to_pmem_info_id(kobj), buf, count) : -EIO;
-}
-
-static struct sysfs_ops pmem_ops = {
-	.show = show_pmem,
-	.store = store_pmem,
-};
-
-static ssize_t show_pmem_base(int id, char *buf)
-{
-	return scnprintf(buf, PAGE_SIZE, "%lu(%#lx)\n",
-		pmem[id].base, pmem[id].base);
-}
-RO_PMEM_ATTR(base);
-
-static ssize_t show_pmem_size(int id, char *buf)
-{
-	return scnprintf(buf, PAGE_SIZE, "%lu(%#lx)\n",
-		pmem[id].size, pmem[id].size);
-}
-RO_PMEM_ATTR(size);
-
-static ssize_t show_pmem_allocator_type(int id, char *buf)
-{
-	switch (pmem[id].allocator_type) {
-	case  PMEM_ALLOCATORTYPE_ALLORNOTHING:
-		return scnprintf(buf, PAGE_SIZE, "%s\n", "All or Nothing");
-	case  PMEM_ALLOCATORTYPE_BUDDYBESTFIT:
-		return scnprintf(buf, PAGE_SIZE, "%s\n", "Buddy Bestfit");
-	case  PMEM_ALLOCATORTYPE_BITMAP:
-		return scnprintf(buf, PAGE_SIZE, "%s\n", "Bitmap");
-	case PMEM_ALLOCATORTYPE_SYSTEM:
-		return scnprintf(buf, PAGE_SIZE, "%s\n", "System heap");
-	default:
-		return scnprintf(buf, PAGE_SIZE,
-			"??? Invalid allocator type (%d) for this region! "
-			"Something isn't right.\n",
-			pmem[id].allocator_type);
-	}
-}
-RO_PMEM_ATTR(allocator_type);
-
-static ssize_t show_pmem_mapped_regions(int id, char *buf)
-{
-	struct list_head *elt;
-	int ret;
-
-	ret = scnprintf(buf, PAGE_SIZE,
-		      "pid #: mapped regions (offset, len) (offset,len)...\n");
-
-	mutex_lock(&pmem[id].data_list_mutex);
-	list_for_each(elt, &pmem[id].data_list) {
-		struct pmem_data *data =
-			list_entry(elt, struct pmem_data, list);
-		struct list_head *elt2;
-
-		down_read(&data->sem);
-		ret += scnprintf(buf + ret, PAGE_SIZE - ret, "pid %u:",
-				data->pid);
-		list_for_each(elt2, &data->region_list) {
-			struct pmem_region_node *region_node = list_entry(elt2,
-					struct pmem_region_node,
-					list);
-			ret += scnprintf(buf + ret, PAGE_SIZE - ret,
-					"(%lx,%lx) ",
-					region_node->region.offset,
-					region_node->region.len);
-		}
-		up_read(&data->sem);
-		ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
-	}
-	mutex_unlock(&pmem[id].data_list_mutex);
-	return ret;
-}
-RO_PMEM_ATTR(mapped_regions);
-
-#define PMEM_COMMON_SYSFS_ATTRS \
-	&pmem_attr_base.attr, \
-	&pmem_attr_size.attr, \
-	&pmem_attr_allocator_type.attr, \
-	&pmem_attr_mapped_regions.attr
-
-
-static ssize_t show_pmem_allocated(int id, char *buf)
-{
-	ssize_t ret;
-
-	mutex_lock(&pmem[id].arena_mutex);
-	ret = scnprintf(buf, PAGE_SIZE, "%s\n",
-		pmem[id].allocator.all_or_nothing.allocated ?
-		"is allocated" : "is NOT allocated");
-	mutex_unlock(&pmem[id].arena_mutex);
-	return ret;
-}
-RO_PMEM_ATTR(allocated);
-
-static struct attribute *pmem_allornothing_attrs[] = {
-	PMEM_COMMON_SYSFS_ATTRS,
-
-	&pmem_attr_allocated.attr,
-
-	NULL
-};
-
-static struct kobj_type pmem_allornothing_ktype = {
-	.sysfs_ops = &pmem_ops,
-	.default_attrs = pmem_allornothing_attrs,
-};
-
-static ssize_t show_pmem_total_entries(int id, char *buf)
-{
-	return scnprintf(buf, PAGE_SIZE, "%lu\n", pmem[id].num_entries);
-}
-RO_PMEM_ATTR(total_entries);
-
-static ssize_t show_pmem_quantum_size(int id, char *buf)
-{
-	return scnprintf(buf, PAGE_SIZE, "%u (%#x)\n",
-		pmem[id].quantum, pmem[id].quantum);
-}
-RO_PMEM_ATTR(quantum_size);
-
-static ssize_t show_pmem_buddy_bitmap_dump(int id, char *buf)
-{
-	int ret, i;
-
-	mutex_lock(&pmem[id].data_list_mutex);
-	ret = scnprintf(buf, PAGE_SIZE, "index\torder\tlength\tallocated\n");
-
-	for (i = 0; i < pmem[id].num_entries && (PAGE_SIZE - ret);
-			i = PMEM_BUDDY_NEXT_INDEX(id, i))
-		ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%d\t%d\t%d\t%d\n",
-			i, PMEM_BUDDY_ORDER(id, i),
-			PMEM_BUDDY_LEN(id, i),
-			!PMEM_IS_FREE_BUDDY(id, i));
-
-	mutex_unlock(&pmem[id].data_list_mutex);
-	return ret;
-}
-RO_PMEM_ATTR(buddy_bitmap_dump);
-
-#define PMEM_BITMAP_BUDDY_BESTFIT_COMMON_SYSFS_ATTRS \
-	&pmem_attr_quantum_size.attr, \
-	&pmem_attr_total_entries.attr
-
-static struct attribute *pmem_buddy_bestfit_attrs[] = {
-	PMEM_COMMON_SYSFS_ATTRS,
-
-	PMEM_BITMAP_BUDDY_BESTFIT_COMMON_SYSFS_ATTRS,
-
-	&pmem_attr_buddy_bitmap_dump.attr,
-
-	NULL
-};
-
-static struct kobj_type pmem_buddy_bestfit_ktype = {
-	.sysfs_ops = &pmem_ops,
-	.default_attrs = pmem_buddy_bestfit_attrs,
-};
-
-static ssize_t show_pmem_free_quanta(int id, char *buf)
-{
-	ssize_t ret;
-
-	mutex_lock(&pmem[id].arena_mutex);
-	ret = scnprintf(buf, PAGE_SIZE, "%u\n",
-		pmem[id].allocator.bitmap.bitmap_free);
-	mutex_unlock(&pmem[id].arena_mutex);
-	return ret;
-}
-RO_PMEM_ATTR(free_quanta);
-
-static ssize_t show_pmem_bits_allocated(int id, char *buf)
-{
-	ssize_t ret;
-	unsigned int i;
-
-	mutex_lock(&pmem[id].arena_mutex);
-
-	ret = scnprintf(buf, PAGE_SIZE,
-		"id: %d\nbitnum\tindex\tquanta allocated\n", id);
-
-	for (i = 0; i < pmem[id].allocator.bitmap.bitmap_allocs; i++)
-		if (pmem[id].allocator.bitmap.bitm_alloc[i].bit != -1)
-			ret += scnprintf(buf + ret, PAGE_SIZE - ret,
-				"%u\t%u\t%u\n",
-				i,
-				pmem[id].allocator.bitmap.bitm_alloc[i].bit,
-				pmem[id].allocator.bitmap.bitm_alloc[i].quanta
-				);
-
-	mutex_unlock(&pmem[id].arena_mutex);
-	return ret;
-}
-RO_PMEM_ATTR(bits_allocated);
-
-static struct attribute *pmem_bitmap_attrs[] = {
-	PMEM_COMMON_SYSFS_ATTRS,
-
-	PMEM_BITMAP_BUDDY_BESTFIT_COMMON_SYSFS_ATTRS,
-
-	&pmem_attr_free_quanta.attr,
-	&pmem_attr_bits_allocated.attr,
-
-	NULL
-};
-
-static struct attribute *pmem_system_attrs[] = {
-	PMEM_COMMON_SYSFS_ATTRS,
-
-	NULL
-};
-
-static struct kobj_type pmem_bitmap_ktype = {
-	.sysfs_ops = &pmem_ops,
-	.default_attrs = pmem_bitmap_attrs,
-};
-
-static struct kobj_type pmem_system_ktype = {
-	.sysfs_ops = &pmem_ops,
-	.default_attrs = pmem_system_attrs,
-};
-
-static int pmem_allocate_from_id(const int id, const unsigned long size,
-						const unsigned int align)
-{
-	int ret;
-	ret = pmem_get_region(id);
-
-	if (ret)
-		return -1;
-
-	ret = pmem[id].allocate(id, size, align);
-
-	if (ret < 0)
-		pmem_put_region(id);
-
-	return ret;
-}
-
-static int pmem_free_from_id(const int id, const int index)
-{
-	pmem_put_region(id);
-	return pmem[id].free(id, index);
-}
-
-static int pmem_get_region(int id)
-{
-	/* Must be called with arena mutex locked */
-	atomic_inc(&pmem[id].allocation_cnt);
-	if (!pmem[id].vbase) {
-		DLOG("PMEMDEBUG: mapping for %s", pmem[id].name);
-		if (pmem[id].mem_request) {
-			int ret = pmem[id].mem_request(pmem[id].region_data);
-			if (ret) {
-				atomic_dec(&pmem[id].allocation_cnt);
-				return 1;
-			}
-		}
-		ioremap_pmem(id);
-	}
-
-	if (pmem[id].vbase) {
-		return 0;
-	} else {
-		if (pmem[id].mem_release)
-			pmem[id].mem_release(pmem[id].region_data);
-		atomic_dec(&pmem[id].allocation_cnt);
-		return 1;
-	}
-}
-
-static void pmem_put_region(int id)
-{
-	/* Must be called with arena mutex locked */
-	if (atomic_dec_and_test(&pmem[id].allocation_cnt)) {
-		DLOG("PMEMDEBUG: unmapping for %s", pmem[id].name);
-		BUG_ON(!pmem[id].vbase);
-		if (pmem[id].map_on_demand) {
-			/* unmap_kernel_range() flushes the caches
-			 * and removes the page table entries
-			 */
-			unmap_kernel_range((unsigned long)pmem[id].vbase,
-				 pmem[id].size);
-			pmem[id].vbase = NULL;
-			if (pmem[id].mem_release) {
-				int ret = pmem[id].mem_release(
-						pmem[id].region_data);
-				WARN(ret, "mem_release failed");
-			}
-
-		}
-	}
-}
-
-static int get_id(struct file *file)
-{
-	return MINOR(file->f_dentry->d_inode->i_rdev);
-}
-
-static char *get_name(struct file *file)
-{
-	int id = get_id(file);
-	return pmem[id].name;
-}
-
-static int is_pmem_file(struct file *file)
-{
-	int id;
-
-	if (unlikely(!file || !file->f_dentry || !file->f_dentry->d_inode))
-		return 0;
-
-	id = get_id(file);
-	return (unlikely(id >= PMEM_MAX_DEVICES ||
-		file->f_dentry->d_inode->i_rdev !=
-		     MKDEV(MISC_MAJOR, pmem[id].dev.minor))) ? 0 : 1;
-}
-
-static int has_allocation(struct file *file)
-{
-	/* must be called with at least read lock held on
-	 * ((struct pmem_data *)(file->private_data))->sem which
-	 * means that file is guaranteed not to be NULL upon entry!!
-	 * check is_pmem_file first if not accessed via pmem_file_ops */
-	struct pmem_data *pdata = file->private_data;
-	return pdata && pdata->index != -1;
-}
-
-static int is_master_owner(struct file *file)
-{
-	struct file *master_file;
-	struct pmem_data *data = file->private_data;
-	int put_needed, ret = 0;
-
-	if (!has_allocation(file))
-		return 0;
-	if (PMEM_FLAGS_MASTERMAP & data->flags)
-		return 1;
-	master_file = fget_light(data->master_fd, &put_needed);
-	if (master_file && data->master_file == master_file)
-		ret = 1;
-	if (master_file)
-		fput_light(master_file, put_needed);
-	return ret;
-}
-
-static int pmem_free_all_or_nothing(int id, int index)
-{
-	/* caller should hold the lock on arena_mutex! */
-	DLOG("index %d\n", index);
-
-	pmem[id].allocator.all_or_nothing.allocated =  0;
-	return 0;
-}
-
-static int pmem_free_space_all_or_nothing(int id,
-		struct pmem_freespace *fs)
-{
-	/* caller should hold the lock on arena_mutex! */
-	fs->total = (unsigned long)
-		pmem[id].allocator.all_or_nothing.allocated == 0 ?
-		pmem[id].size : 0;
-
-	fs->largest = fs->total;
-	return 0;
-}
-
-
-static int pmem_free_buddy_bestfit(int id, int index)
-{
-	/* caller should hold the lock on arena_mutex! */
-	int curr = index;
-	DLOG("index %d\n", index);
-
-
-	/* clean up the bitmap, merging any buddies */
-	pmem[id].allocator.buddy_bestfit.buddy_bitmap[curr].allocated = 0;
-	/* find a slots buddy Buddy# = Slot# ^ (1 << order)
-	 * if the buddy is also free merge them
-	 * repeat until the buddy is not free or end of the bitmap is reached
-	 */
-	do {
-		int buddy = PMEM_BUDDY_INDEX(id, curr);
-		if (buddy < pmem[id].num_entries &&
-		    PMEM_IS_FREE_BUDDY(id, buddy) &&
-		    PMEM_BUDDY_ORDER(id, buddy) ==
-				PMEM_BUDDY_ORDER(id, curr)) {
-			PMEM_BUDDY_ORDER(id, buddy)++;
-			PMEM_BUDDY_ORDER(id, curr)++;
-			curr = min(buddy, curr);
-		} else {
-			break;
-		}
-	} while (curr < pmem[id].num_entries);
-
-	return 0;
-}
-
-
-static int pmem_free_space_buddy_bestfit(int id,
-		struct pmem_freespace *fs)
-{
-	/* caller should hold the lock on arena_mutex! */
-	int curr;
-	unsigned long size;
-	fs->total = 0;
-	fs->largest = 0;
-
-	for (curr = 0; curr < pmem[id].num_entries;
-	     curr = PMEM_BUDDY_NEXT_INDEX(id, curr)) {
-		if (PMEM_IS_FREE_BUDDY(id, curr)) {
-			size = PMEM_BUDDY_LEN(id, curr);
-			if (size > fs->largest)
-				fs->largest = size;
-			fs->total += size;
-		}
-	}
-	return 0;
-}
-
-
-static inline uint32_t start_mask(int bit_start)
-{
-	return (uint32_t)(~0) << (bit_start & PMEM_BITS_PER_WORD_MASK);
-}
-
-static inline uint32_t end_mask(int bit_end)
-{
-	return (uint32_t)(~0) >>
-		((BITS_PER_LONG - bit_end) & PMEM_BITS_PER_WORD_MASK);
-}
-
-static inline int compute_total_words(int bit_end, int word_index)
-{
-	return ((bit_end + BITS_PER_LONG - 1) >>
-			PMEM_32BIT_WORD_ORDER) - word_index;
-}
-
-static void bitmap_bits_clear_all(uint32_t *bitp, int bit_start, int bit_end)
-{
-	int word_index = bit_start >> PMEM_32BIT_WORD_ORDER, total_words;
-
-	total_words = compute_total_words(bit_end, word_index);
-	if (total_words > 0) {
-		if (total_words == 1) {
-			bitp[word_index] &=
-				~(start_mask(bit_start) & end_mask(bit_end));
-		} else {
-			bitp[word_index++] &= ~start_mask(bit_start);
-			if (total_words > 2) {
-				int total_bytes;
-
-				total_words -= 2;
-				total_bytes = total_words << 2;
-
-				memset(&bitp[word_index], 0, total_bytes);
-				word_index += total_words;
-			}
-			bitp[word_index] &= ~end_mask(bit_end);
-		}
-	}
-}
-
-static int pmem_free_bitmap(int id, int bitnum)
-{
-	/* caller should hold the lock on arena_mutex! */
-	int i;
-	char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-
-	DLOG("bitnum %d\n", bitnum);
-
-	for (i = 0; i < pmem[id].allocator.bitmap.bitmap_allocs; i++) {
-		const int curr_bit =
-			pmem[id].allocator.bitmap.bitm_alloc[i].bit;
-
-		if (curr_bit == bitnum) {
-			const int curr_quanta =
-				pmem[id].allocator.bitmap.bitm_alloc[i].quanta;
-
-			bitmap_bits_clear_all(pmem[id].allocator.bitmap.bitmap,
-				curr_bit, curr_bit + curr_quanta);
-			pmem[id].allocator.bitmap.bitmap_free += curr_quanta;
-			pmem[id].allocator.bitmap.bitm_alloc[i].bit = -1;
-			pmem[id].allocator.bitmap.bitm_alloc[i].quanta = 0;
-			return 0;
-		}
-	}
-	printk(KERN_ALERT "pmem: %s: Attempt to free unallocated index %d, id"
-		" %d, pid %d(%s)\n", __func__, bitnum, id,  current->pid,
-		get_task_comm(currtask_name, current));
-
-	return -1;
-}
-
-static int pmem_free_system(int id, int index)
-{
-	/* caller should hold the lock on arena_mutex! */
-	struct alloc_list *item;
-
-	DLOG("index %d\n", index);
-	if (index != 0)
-		item = (struct alloc_list *)index;
-	else
-		return 0;
-
-	if (item->vaddr != NULL) {
-		iounmap(item->vaddr);
-		kfree(__va(item->addr));
-		list_del(&item->allocs);
-		kfree(item);
-	}
-
-	return 0;
-}
-
-static int pmem_free_space_bitmap(int id, struct pmem_freespace *fs)
-{
-	int i, j;
-	int max_allocs = pmem[id].allocator.bitmap.bitmap_allocs;
-	int alloc_start = 0;
-	int next_alloc;
-	unsigned long size = 0;
-
-	fs->total = 0;
-	fs->largest = 0;
-
-	for (i = 0; i < max_allocs; i++) {
-
-		int alloc_quanta = 0;
-		int alloc_idx = 0;
-		next_alloc = pmem[id].num_entries;
-
-		/* Look for the lowest bit where next allocation starts */
-		for (j = 0; j < max_allocs; j++) {
-			const int curr_alloc = pmem[id].allocator.
-						bitmap.bitm_alloc[j].bit;
-			if (curr_alloc != -1) {
-				if (alloc_start == curr_alloc)
-					alloc_idx = j;
-				if (alloc_start >= curr_alloc)
-					continue;
-				if (curr_alloc < next_alloc)
-					next_alloc = curr_alloc;
-			}
-		}
-		alloc_quanta = pmem[id].allocator.bitmap.
-				bitm_alloc[alloc_idx].quanta;
-		size = (next_alloc - (alloc_start + alloc_quanta)) *
-				pmem[id].quantum;
-
-		if (size > fs->largest)
-			fs->largest = size;
-		fs->total += size;
-
-		if (next_alloc == pmem[id].num_entries)
-			break;
-		else
-			alloc_start = next_alloc;
-	}
-
-	return 0;
-}
-
-static int pmem_free_space_system(int id, struct pmem_freespace *fs)
-{
-	fs->total = pmem[id].size;
-	fs->largest = pmem[id].size;
-
-	return 0;
-}
-
-static void pmem_revoke(struct file *file, struct pmem_data *data);
-
-static int pmem_release(struct inode *inode, struct file *file)
-{
-	struct pmem_data *data = file->private_data;
-	struct pmem_region_node *region_node;
-	struct list_head *elt, *elt2;
-	int id = get_id(file), ret = 0;
-
-#if PMEM_DEBUG_MSGS
-	char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-	DLOG("releasing memory pid %u(%s) file %p(%ld) dev %s(id: %d)\n",
-		current->pid, get_task_comm(currtask_name, current),
-		file, file_count(file), get_name(file), id);
-	mutex_lock(&pmem[id].data_list_mutex);
-	/* if this file is a master, revoke all the memory in the connected
-	 *  files */
-	if (PMEM_FLAGS_MASTERMAP & data->flags) {
-		list_for_each(elt, &pmem[id].data_list) {
-			struct pmem_data *sub_data =
-				list_entry(elt, struct pmem_data, list);
-			int is_master;
-
-			down_read(&sub_data->sem);
-			is_master = (PMEM_IS_SUBMAP(sub_data) &&
-				file == sub_data->master_file);
-			up_read(&sub_data->sem);
-
-			if (is_master)
-				pmem_revoke(file, sub_data);
-		}
-	}
-	list_del(&data->list);
-	mutex_unlock(&pmem[id].data_list_mutex);
-
-	down_write(&data->sem);
-
-	/* if it is not a connected file and it has an allocation, free it */
-	if (!(PMEM_FLAGS_CONNECTED & data->flags) && has_allocation(file)) {
-		mutex_lock(&pmem[id].arena_mutex);
-		ret = pmem_free_from_id(id, data->index);
-		mutex_unlock(&pmem[id].arena_mutex);
-	}
-
-	/* if this file is a submap (mapped, connected file), downref the
-	 * task struct */
-	if (PMEM_FLAGS_SUBMAP & data->flags)
-		if (data->task) {
-			put_task_struct(data->task);
-			data->task = NULL;
-		}
-
-	file->private_data = NULL;
-
-	list_for_each_safe(elt, elt2, &data->region_list) {
-		region_node = list_entry(elt, struct pmem_region_node, list);
-		list_del(elt);
-		kfree(region_node);
-	}
-	BUG_ON(!list_empty(&data->region_list));
-
-	up_write(&data->sem);
-	kfree(data);
-	if (pmem[id].release)
-		ret = pmem[id].release(inode, file);
-
-	return ret;
-}
-
-static int pmem_open(struct inode *inode, struct file *file)
-{
-	struct pmem_data *data;
-	int id = get_id(file);
-	int ret = 0;
-#if PMEM_DEBUG_MSGS
-	char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-
-	DLOG("pid %u(%s) file %p(%ld) dev %s(id: %d)\n",
-		current->pid, get_task_comm(currtask_name, current),
-		file, file_count(file), get_name(file), id);
-	data = kmalloc(sizeof(struct pmem_data), GFP_KERNEL);
-	if (!data) {
-		printk(KERN_ALERT "pmem: %s: unable to allocate memory for "
-				"pmem metadata.", __func__);
-		return -1;
-	}
-	data->flags = 0;
-	data->index = -1;
-	data->task = NULL;
-	data->vma = NULL;
-	data->pid = 0;
-	data->master_file = NULL;
-#if PMEM_DEBUG
-	data->ref = 0;
-#endif
-	INIT_LIST_HEAD(&data->region_list);
-	init_rwsem(&data->sem);
-
-	file->private_data = data;
-	INIT_LIST_HEAD(&data->list);
-
-	mutex_lock(&pmem[id].data_list_mutex);
-	list_add(&data->list, &pmem[id].data_list);
-	mutex_unlock(&pmem[id].data_list_mutex);
-	return ret;
-}
-
-static unsigned long pmem_order(unsigned long len, int id)
-{
-	int i;
-
-	len = (len + pmem[id].quantum - 1)/pmem[id].quantum;
-	len--;
-	for (i = 0; i < sizeof(len)*8; i++)
-		if (len >> i == 0)
-			break;
-	return i;
-}
-
-static int pmem_allocator_all_or_nothing(const int id,
-		const unsigned long len,
-		const unsigned int align)
-{
-	/* caller should hold the lock on arena_mutex! */
-	DLOG("all or nothing\n");
-	if ((len > pmem[id].size) ||
-		pmem[id].allocator.all_or_nothing.allocated)
-		return -1;
-	pmem[id].allocator.all_or_nothing.allocated = 1;
-	return len;
-}
-
-static int pmem_allocator_buddy_bestfit(const int id,
-		const unsigned long len,
-		unsigned int align)
-{
-	/* caller should hold the lock on arena_mutex! */
-	int curr;
-	int best_fit = -1;
-	unsigned long order;
-
-	DLOG("buddy bestfit\n");
-	order = pmem_order(len, id);
-	if (order > PMEM_MAX_ORDER)
-		goto out;
-
-	DLOG("order %lx\n", order);
-
-	/* Look through the bitmap.
-	 * 	If a free slot of the correct order is found, use it.
-	 * 	Otherwise, use the best fit (smallest with size > order) slot.
-	 */
-	for (curr = 0;
-	     curr < pmem[id].num_entries;
-	     curr = PMEM_BUDDY_NEXT_INDEX(id, curr))
-		if (PMEM_IS_FREE_BUDDY(id, curr)) {
-			if (PMEM_BUDDY_ORDER(id, curr) ==
-					(unsigned char)order) {
-				/* set the not free bit and clear others */
-				best_fit = curr;
-				break;
-			}
-			if (PMEM_BUDDY_ORDER(id, curr) >
-					(unsigned char)order &&
-			    (best_fit < 0 ||
-			     PMEM_BUDDY_ORDER(id, curr) <
-					PMEM_BUDDY_ORDER(id, best_fit)))
-				best_fit = curr;
-		}
-
-	/* if best_fit < 0, there are no suitable slots; return an error */
-	if (best_fit < 0) {
-#if PMEM_DEBUG
-		printk(KERN_ALERT "pmem: %s: no space left to allocate!\n",
-			__func__);
-#endif
-		goto out;
-	}
-
-	/* now partition the best fit:
-	 * 	split the slot into 2 buddies of order - 1
-	 * 	repeat until the slot is of the correct order
-	 */
-	while (PMEM_BUDDY_ORDER(id, best_fit) > (unsigned char)order) {
-		int buddy;
-		PMEM_BUDDY_ORDER(id, best_fit) -= 1;
-		buddy = PMEM_BUDDY_INDEX(id, best_fit);
-		PMEM_BUDDY_ORDER(id, buddy) = PMEM_BUDDY_ORDER(id, best_fit);
-	}
-	pmem[id].allocator.buddy_bestfit.buddy_bitmap[best_fit].allocated = 1;
-out:
-	return best_fit;
-}
-
-
-static inline unsigned long paddr_from_bit(const int id, const int bitnum)
-{
-	return pmem[id].base + pmem[id].quantum * bitnum;
-}
-
-static inline unsigned long bit_from_paddr(const int id,
-		const unsigned long paddr)
-{
-	return (paddr - pmem[id].base) / pmem[id].quantum;
-}
-
-static void bitmap_bits_set_all(uint32_t *bitp, int bit_start, int bit_end)
-{
-	int word_index = bit_start >> PMEM_32BIT_WORD_ORDER, total_words;
-
-	total_words = compute_total_words(bit_end, word_index);
-	if (total_words > 0) {
-		if (total_words == 1) {
-			bitp[word_index] |=
-				(start_mask(bit_start) & end_mask(bit_end));
-		} else {
-			bitp[word_index++] |= start_mask(bit_start);
-			if (total_words > 2) {
-				int total_bytes;
-
-				total_words -= 2;
-				total_bytes = total_words << 2;
-
-				memset(&bitp[word_index], ~0, total_bytes);
-				word_index += total_words;
-			}
-			bitp[word_index] |= end_mask(bit_end);
-		}
-	}
-}
-
-static int
-bitmap_allocate_contiguous(uint32_t *bitp, int num_bits_to_alloc,
-		int total_bits, int spacing, int start_bit)
-{
-	int bit_start, last_bit, word_index;
-
-	if (num_bits_to_alloc <= 0)
-		return -1;
-
-	for (bit_start = start_bit; ;
-		bit_start = ((last_bit +
-			(word_index << PMEM_32BIT_WORD_ORDER) + spacing - 1)
-			& ~(spacing - 1)) + start_bit) {
-		int bit_end = bit_start + num_bits_to_alloc, total_words;
-
-		if (bit_end > total_bits)
-			return -1; /* out of contiguous memory */
-
-		word_index = bit_start >> PMEM_32BIT_WORD_ORDER;
-		total_words = compute_total_words(bit_end, word_index);
-
-		if (total_words <= 0)
-			return -1;
-
-		if (total_words == 1) {
-			last_bit = fls(bitp[word_index] &
-					(start_mask(bit_start) &
-						end_mask(bit_end)));
-			if (last_bit)
-				continue;
-		} else {
-			int end_word = word_index + (total_words - 1);
-			last_bit =
-				fls(bitp[word_index] & start_mask(bit_start));
-			if (last_bit)
-				continue;
-
-			for (word_index++;
-					word_index < end_word;
-					word_index++) {
-				last_bit = fls(bitp[word_index]);
-				if (last_bit)
-					break;
-			}
-			if (last_bit)
-				continue;
-
-			last_bit = fls(bitp[word_index] & end_mask(bit_end));
-			if (last_bit)
-				continue;
-		}
-		bitmap_bits_set_all(bitp, bit_start, bit_end);
-		return bit_start;
-	}
-	return -1;
-}
-
-static int reserve_quanta(const unsigned int quanta_needed,
-		const int id,
-		unsigned int align)
-{
-	/* alignment should be a valid power of 2 */
-	int ret = -1, start_bit = 0, spacing = 1;
-
-	/* Sanity check */
-	if (quanta_needed > pmem[id].allocator.bitmap.bitmap_free) {
-#if PMEM_DEBUG
-		printk(KERN_ALERT "pmem: %s: request (%d) too big for"
-			" available free (%d)\n", __func__, quanta_needed,
-			pmem[id].allocator.bitmap.bitmap_free);
-#endif
-		return -1;
-	}
-
-	start_bit = bit_from_paddr(id,
-		(pmem[id].base + align - 1) & ~(align - 1));
-	if (start_bit <= -1) {
-#if PMEM_DEBUG
-		printk(KERN_ALERT
-			"pmem: %s: bit_from_paddr fails for"
-			" %u alignment.\n", __func__, align);
-#endif
-		return -1;
-	}
-	spacing = align / pmem[id].quantum;
-	spacing = spacing > 1 ? spacing : 1;
-
-	ret = bitmap_allocate_contiguous(pmem[id].allocator.bitmap.bitmap,
-		quanta_needed,
-		(pmem[id].size + pmem[id].quantum - 1) / pmem[id].quantum,
-		spacing,
-		start_bit);
-
-#if PMEM_DEBUG
-	if (ret < 0)
-		printk(KERN_ALERT "pmem: %s: not enough contiguous bits free "
-			"in bitmap! Region memory is either too fragmented or"
-			" request is too large for available memory.\n",
-			__func__);
-#endif
-
-	return ret;
-}
-
-static int pmem_allocator_bitmap(const int id,
-		const unsigned long len,
-		const unsigned int align)
-{
-	/* caller should hold the lock on arena_mutex! */
-	int bitnum, i;
-	unsigned int quanta_needed;
-
-	DLOG("bitmap id %d, len %ld, align %u\n", id, len, align);
-	if (!pmem[id].allocator.bitmap.bitm_alloc) {
-#if PMEM_DEBUG
-		printk(KERN_ALERT "pmem: bitm_alloc not present! id: %d\n",
-			id);
-#endif
-		return -1;
-	}
-
-	quanta_needed = (len + pmem[id].quantum - 1) / pmem[id].quantum;
-	DLOG("quantum size %u quanta needed %u free %u id %d\n",
-		pmem[id].quantum, quanta_needed,
-		pmem[id].allocator.bitmap.bitmap_free, id);
-
-	if (pmem[id].allocator.bitmap.bitmap_free < quanta_needed) {
-#if PMEM_DEBUG
-		printk(KERN_ALERT "pmem: memory allocation failure. "
-			"PMEM memory region exhausted, id %d."
-			" Unable to comply with allocation request.\n", id);
-#endif
-		return -1;
-	}
-
-	bitnum = reserve_quanta(quanta_needed, id, align);
-	if (bitnum == -1)
-		goto leave;
-
-	for (i = 0;
-		i < pmem[id].allocator.bitmap.bitmap_allocs &&
-			pmem[id].allocator.bitmap.bitm_alloc[i].bit != -1;
-		i++)
-		;
-
-	if (i >= pmem[id].allocator.bitmap.bitmap_allocs) {
-		void *temp;
-		int32_t new_bitmap_allocs =
-			pmem[id].allocator.bitmap.bitmap_allocs << 1;
-		int j;
-
-		if (!new_bitmap_allocs) { /* failed sanity check!! */
-#if PMEM_DEBUG
-			pr_alert("pmem: bitmap_allocs number"
-				" wrapped around to zero! Something "
-				"is VERY wrong.\n");
-#endif
-			return -1;
-		}
-
-		if (new_bitmap_allocs > pmem[id].num_entries) {
-			/* failed sanity check!! */
-#if PMEM_DEBUG
-			pr_alert("pmem: required bitmap_allocs"
-				" number exceeds maximum entries possible"
-				" for current quanta\n");
-#endif
-			return -1;
-		}
-
-		temp = krealloc(pmem[id].allocator.bitmap.bitm_alloc,
-				new_bitmap_allocs *
-				sizeof(*pmem[id].allocator.bitmap.bitm_alloc),
-				GFP_KERNEL);
-		if (!temp) {
-#if PMEM_DEBUG
-			pr_alert("pmem: can't realloc bitmap_allocs,"
-				"id %d, current num bitmap allocs %d\n",
-				id, pmem[id].allocator.bitmap.bitmap_allocs);
-#endif
-			return -1;
-		}
-		pmem[id].allocator.bitmap.bitmap_allocs = new_bitmap_allocs;
-		pmem[id].allocator.bitmap.bitm_alloc = temp;
-
-		for (j = i; j < new_bitmap_allocs; j++) {
-			pmem[id].allocator.bitmap.bitm_alloc[j].bit = -1;
-			pmem[id].allocator.bitmap.bitm_alloc[i].quanta = 0;
-		}
-
-		DLOG("increased # of allocated regions to %d for id %d\n",
-			pmem[id].allocator.bitmap.bitmap_allocs, id);
-	}
-
-	DLOG("bitnum %d, bitm_alloc index %d\n", bitnum, i);
-
-	pmem[id].allocator.bitmap.bitmap_free -= quanta_needed;
-	pmem[id].allocator.bitmap.bitm_alloc[i].bit = bitnum;
-	pmem[id].allocator.bitmap.bitm_alloc[i].quanta = quanta_needed;
-leave:
-	return bitnum;
-}
-
-static int pmem_allocator_system(const int id,
-		const unsigned long len,
-		const unsigned int align)
-{
-	/* caller should hold the lock on arena_mutex! */
-	struct alloc_list *list;
-	unsigned long aligned_len;
-	int count = SYSTEM_ALLOC_RETRY;
-	void *buf;
-
-	DLOG("system id %d, len %ld, align %u\n", id, len, align);
-
-	if ((pmem[id].allocator.system_mem.used + len) > pmem[id].size) {
-		DLOG("requested size would be larger than quota\n");
-		return -1;
-	}
-
-	/* Handle alignment */
-	aligned_len = len + align;
-
-	/* Attempt allocation */
-	list = kmalloc(sizeof(struct alloc_list), GFP_KERNEL);
-	if (list == NULL) {
-		printk(KERN_ERR "pmem: failed to allocate system metadata\n");
-		return -1;
-	}
-	list->vaddr = NULL;
-
-	buf = NULL;
-	while ((buf == NULL) && count--) {
-		buf = kmalloc((aligned_len), GFP_KERNEL);
-		if (buf == NULL) {
-			DLOG("pmem: kmalloc %d temporarily failed len= %ld\n",
-				count, aligned_len);
-		}
-	}
-	if (!buf) {
-		printk(KERN_CRIT "pmem: kmalloc failed for id= %d len= %ld\n",
-			id, aligned_len);
-		kfree(list);
-		return -1;
-	}
-	list->size = aligned_len;
-	list->addr = (void *)__pa(buf);
-	list->aaddr = (void *)(((unsigned int)(list->addr) + (align - 1)) &
-			~(align - 1));
-
-	if (!pmem[id].cached)
-		list->vaddr = ioremap(__pa(buf), aligned_len);
-	else
-		list->vaddr = ioremap_cached(__pa(buf), aligned_len);
-
-	INIT_LIST_HEAD(&list->allocs);
-	list_add(&list->allocs, &pmem[id].allocator.system_mem.alist);
-
-	return (int)list;
-}
-
-static pgprot_t pmem_phys_mem_access_prot(struct file *file, pgprot_t vma_prot)
-{
-	int id = get_id(file);
-#ifdef pgprot_writecombine
-	if (pmem[id].cached == 0 || file->f_flags & O_SYNC)
-		/* on ARMv6 and ARMv7 this expands to Normal Noncached */
-		return pgprot_writecombine(vma_prot);
-#endif
-#ifdef pgprot_ext_buffered
-	else if (pmem[id].buffered)
-		return pgprot_ext_buffered(vma_prot);
-#endif
-	return vma_prot;
-}
-
-static unsigned long pmem_start_addr_all_or_nothing(int id,
-		struct pmem_data *data)
-{
-	return PMEM_START_ADDR(id, 0);
-}
-
-static unsigned long pmem_start_addr_buddy_bestfit(int id,
-		struct pmem_data *data)
-{
-	return PMEM_START_ADDR(id, data->index);
-}
-
-static unsigned long pmem_start_addr_bitmap(int id, struct pmem_data *data)
-{
-	return data->index * pmem[id].quantum + pmem[id].base;
-}
-
-static unsigned long pmem_start_addr_system(int id, struct pmem_data *data)
-{
-	return (unsigned long)(((struct alloc_list *)(data->index))->aaddr);
-}
-
-static void *pmem_start_vaddr(int id, struct pmem_data *data)
-{
-	if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_SYSTEM)
-		return ((struct alloc_list *)(data->index))->vaddr;
-	else
-	return pmem[id].start_addr(id, data) - pmem[id].base + pmem[id].vbase;
-}
-
-static unsigned long pmem_len_all_or_nothing(int id, struct pmem_data *data)
-{
-	return data->index;
-}
-
-static unsigned long pmem_len_buddy_bestfit(int id, struct pmem_data *data)
-{
-	return PMEM_BUDDY_LEN(id, data->index);
-}
-
-static unsigned long pmem_len_bitmap(int id, struct pmem_data *data)
-{
-	int i;
-	unsigned long ret = 0;
-
-	mutex_lock(&pmem[id].arena_mutex);
-
-	for (i = 0; i < pmem[id].allocator.bitmap.bitmap_allocs; i++)
-		if (pmem[id].allocator.bitmap.bitm_alloc[i].bit ==
-				data->index) {
-			ret = pmem[id].allocator.bitmap.bitm_alloc[i].quanta *
-				pmem[id].quantum;
-			break;
-		}
-
-	mutex_unlock(&pmem[id].arena_mutex);
-#if PMEM_DEBUG
-	if (i >= pmem[id].allocator.bitmap.bitmap_allocs)
-		pr_alert("pmem: %s: can't find bitnum %d in "
-			"alloc'd array!\n", __func__, data->index);
-#endif
-	return ret;
-}
-
-static unsigned long pmem_len_system(int id, struct pmem_data *data)
-{
-	unsigned long ret = 0;
-
-	mutex_lock(&pmem[id].arena_mutex);
-
-	ret = ((struct alloc_list *)data->index)->size;
-	mutex_unlock(&pmem[id].arena_mutex);
-
-	return ret;
-}
-
-static int pmem_map_garbage(int id, struct vm_area_struct *vma,
-			    struct pmem_data *data, unsigned long offset,
-			    unsigned long len)
-{
-	int i, garbage_pages = len >> PAGE_SHIFT;
-
-	vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP | VM_SHARED | VM_WRITE;
-	for (i = 0; i < garbage_pages; i++) {
-		if (vm_insert_pfn(vma, vma->vm_start + offset + (i * PAGE_SIZE),
-		    pmem[id].garbage_pfn))
-			return -EAGAIN;
-	}
-	return 0;
-}
-
-static int pmem_unmap_pfn_range(int id, struct vm_area_struct *vma,
-				struct pmem_data *data, unsigned long offset,
-				unsigned long len)
-{
-	int garbage_pages;
-	DLOG("unmap offset %lx len %lx\n", offset, len);
-
-	BUG_ON(!PMEM_IS_PAGE_ALIGNED(len));
-
-	garbage_pages = len >> PAGE_SHIFT;
-	zap_page_range(vma, vma->vm_start + offset, len, NULL);
-	pmem_map_garbage(id, vma, data, offset, len);
-	return 0;
-}
-
-static int pmem_map_pfn_range(int id, struct vm_area_struct *vma,
-			      struct pmem_data *data, unsigned long offset,
-			      unsigned long len)
-{
-	int ret;
-	DLOG("map offset %lx len %lx\n", offset, len);
-	BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_start));
-	BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_end));
-	BUG_ON(!PMEM_IS_PAGE_ALIGNED(len));
-	BUG_ON(!PMEM_IS_PAGE_ALIGNED(offset));
-
-	ret = io_remap_pfn_range(vma, vma->vm_start + offset,
-		(pmem[id].start_addr(id, data) + offset) >> PAGE_SHIFT,
-		len, vma->vm_page_prot);
-	if (ret) {
-#if PMEM_DEBUG
-		pr_alert("pmem: %s: io_remap_pfn_range fails with "
-			"return value: %d!\n",	__func__, ret);
-#endif
-
-		ret = -EAGAIN;
-	}
-	return ret;
-}
-
-static int pmem_remap_pfn_range(int id, struct vm_area_struct *vma,
-			      struct pmem_data *data, unsigned long offset,
-			      unsigned long len)
-{
-	/* hold the mm semp for the vma you are modifying when you call this */
-	BUG_ON(!vma);
-	zap_page_range(vma, vma->vm_start + offset, len, NULL);
-	return pmem_map_pfn_range(id, vma, data, offset, len);
-}
-
-static void pmem_vma_open(struct vm_area_struct *vma)
-{
-	struct file *file = vma->vm_file;
-	struct pmem_data *data = file->private_data;
-	int id = get_id(file);
-
-#if PMEM_DEBUG_MSGS
-	char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-	DLOG("Dev %s(id: %d) pid %u(%s) ppid %u file %p count %ld\n",
-		get_name(file), id, current->pid,
-		get_task_comm(currtask_name, current),
-		current->parent->pid, file, file_count(file));
-	/* this should never be called as we don't support copying pmem
-	 * ranges via fork */
-	down_read(&data->sem);
-	BUG_ON(!has_allocation(file));
-	/* remap the garbage pages, forkers don't get access to the data */
-	pmem_unmap_pfn_range(id, vma, data, 0, vma->vm_start - vma->vm_end);
-	up_read(&data->sem);
-}
-
-static void pmem_vma_close(struct vm_area_struct *vma)
-{
-	struct file *file = vma->vm_file;
-	struct pmem_data *data = file->private_data;
-
-#if PMEM_DEBUG_MSGS
-	char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-	DLOG("Dev %s(id: %d) pid %u(%s) ppid %u file %p count %ld\n",
-		get_name(file), get_id(file), current->pid,
-		get_task_comm(currtask_name, current),
-		current->parent->pid, file, file_count(file));
-
-	if (unlikely(!is_pmem_file(file))) {
-		pr_warning("pmem: something is very wrong, you are "
-		       "closing a vm backing an allocation that doesn't "
-		       "exist!\n");
-		return;
-	}
-
-	down_write(&data->sem);
-	if (unlikely(!has_allocation(file))) {
-		up_write(&data->sem);
-		pr_warning("pmem: something is very wrong, you are "
-		       "closing a vm backing an allocation that doesn't "
-		       "exist!\n");
-		return;
-	}
-	if (data->vma == vma) {
-		data->vma = NULL;
-		if ((data->flags & PMEM_FLAGS_CONNECTED) &&
-		    (data->flags & PMEM_FLAGS_SUBMAP))
-			data->flags |= PMEM_FLAGS_UNSUBMAP;
-	}
-	/* the kernel is going to free this vma now anyway */
-	up_write(&data->sem);
-}
-
-static struct vm_operations_struct vm_ops = {
-	.open = pmem_vma_open,
-	.close = pmem_vma_close,
-};
-
-static int pmem_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct pmem_data *data = file->private_data;
-	int index = -1;
-	unsigned long vma_size =  vma->vm_end - vma->vm_start;
-	int ret = 0, id = get_id(file);
-#if PMEM_DEBUG_MSGS
-	char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-
-	if (!data) {
-		pr_err("pmem: Invalid file descriptor, no private data\n");
-		return -EINVAL;
-	}
-	DLOG("pid %u(%s) mmap vma_size %lu on dev %s(id: %d)\n", current->pid,
-		get_task_comm(currtask_name, current), vma_size,
-		get_name(file), id);
-	if (vma->vm_pgoff || !PMEM_IS_PAGE_ALIGNED(vma_size)) {
-#if PMEM_DEBUG
-		pr_err("pmem: mmaps must be at offset zero, aligned"
-				" and a multiple of pages_size.\n");
-#endif
-		return -EINVAL;
-	}
-
-	down_write(&data->sem);
-	/* check this file isn't already mmaped, for submaps check this file
-	 * has never been mmaped */
-	if ((data->flags & PMEM_FLAGS_SUBMAP) ||
-	    (data->flags & PMEM_FLAGS_UNSUBMAP)) {
-#if PMEM_DEBUG
-		pr_err("pmem: you can only mmap a pmem file once, "
-		       "this file is already mmaped. %x\n", data->flags);
-#endif
-		ret = -EINVAL;
-		goto error;
-	}
-	/* if file->private_data == unalloced, alloc*/
-	if (data->index == -1) {
-		mutex_lock(&pmem[id].arena_mutex);
-		index = pmem_allocate_from_id(id,
-				vma->vm_end - vma->vm_start,
-				SZ_4K);
-		mutex_unlock(&pmem[id].arena_mutex);
-		/* either no space was available or an error occured */
-		if (index == -1) {
-			pr_err("pmem: mmap unable to allocate memory"
-				"on %s\n", get_name(file));
-			ret = -ENOMEM;
-			goto error;
-		}
-		/* store the index of a successful allocation */
-		data->index = index;
-	}
-
-	if (pmem[id].len(id, data) < vma_size) {
-#if PMEM_DEBUG
-		pr_err("pmem: mmap size [%lu] does not match"
-		       " size of backing region [%lu].\n", vma_size,
-		       pmem[id].len(id, data));
-#endif
-		ret = -EINVAL;
-		goto error;
-	}
-
-	vma->vm_pgoff = pmem[id].start_addr(id, data) >> PAGE_SHIFT;
-
-	vma->vm_page_prot = pmem_phys_mem_access_prot(file, vma->vm_page_prot);
-
-	if (data->flags & PMEM_FLAGS_CONNECTED) {
-		struct pmem_region_node *region_node;
-		struct list_head *elt;
-		if (pmem_map_garbage(id, vma, data, 0, vma_size)) {
-			pr_alert("pmem: mmap failed in kernel!\n");
-			ret = -EAGAIN;
-			goto error;
-		}
-		list_for_each(elt, &data->region_list) {
-			region_node = list_entry(elt, struct pmem_region_node,
-						 list);
-			DLOG("remapping file: %p %lx %lx\n", file,
-				region_node->region.offset,
-				region_node->region.len);
-			if (pmem_remap_pfn_range(id, vma, data,
-						 region_node->region.offset,
-						 region_node->region.len)) {
-				ret = -EAGAIN;
-				goto error;
-			}
-		}
-		data->flags |= PMEM_FLAGS_SUBMAP;
-		get_task_struct(current->group_leader);
-		data->task = current->group_leader;
-		data->vma = vma;
-#if PMEM_DEBUG
-		data->pid = current->pid;
-#endif
-		DLOG("submmapped file %p vma %p pid %u\n", file, vma,
-		     current->pid);
-	} else {
-		if (pmem_map_pfn_range(id, vma, data, 0, vma_size)) {
-			pr_err("pmem: mmap failed in kernel!\n");
-			ret = -EAGAIN;
-			goto error;
-		}
-		data->flags |= PMEM_FLAGS_MASTERMAP;
-		data->pid = current->pid;
-	}
-	vma->vm_ops = &vm_ops;
-error:
-	up_write(&data->sem);
-	return ret;
-}
-
-/* the following are the api for accessing pmem regions by other drivers
- * from inside the kernel */
-int get_pmem_user_addr(struct file *file, unsigned long *start,
-		   unsigned long *len)
-{
-	int ret = -1;
-
-	if (is_pmem_file(file)) {
-		struct pmem_data *data = file->private_data;
-
-		down_read(&data->sem);
-		if (has_allocation(file)) {
-			if (data->vma) {
-				*start = data->vma->vm_start;
-				*len = data->vma->vm_end - data->vma->vm_start;
-			} else {
-				*start = *len = 0;
-#if PMEM_DEBUG
-				pr_err("pmem: %s: no vma present.\n",
-					__func__);
-#endif
-			}
-			ret = 0;
-		}
-		up_read(&data->sem);
-	}
-
-#if PMEM_DEBUG
-	if (ret)
-		pr_err("pmem: %s: requested pmem data from invalid"
-			"file.\n", __func__);
-#endif
-	return ret;
-}
-
-int get_pmem_addr(struct file *file, unsigned long *start,
-		  unsigned long *vstart, unsigned long *len)
-{
-	int ret = -1;
-
-	if (is_pmem_file(file)) {
-		struct pmem_data *data = file->private_data;
-
-		down_read(&data->sem);
-		if (has_allocation(file)) {
-			int id = get_id(file);
-
-			*start = pmem[id].start_addr(id, data);
-			*len = pmem[id].len(id, data);
-			*vstart = (unsigned long)
-				pmem_start_vaddr(id, data);
-			up_read(&data->sem);
-#if PMEM_DEBUG
-			down_write(&data->sem);
-			data->ref++;
-			up_write(&data->sem);
-#endif
-			DLOG("returning start %#lx len %lu "
-				"vstart %#lx\n",
-				*start, *len, *vstart);
-			ret = 0;
-		} else {
-			up_read(&data->sem);
-		}
-	}
-	return ret;
-}
-
-int get_pmem_file(unsigned int fd, unsigned long *start, unsigned long *vstart,
-		  unsigned long *len, struct file **filp)
-{
-	int ret = -1;
-	struct file *file = fget(fd);
-
-	if (unlikely(file == NULL)) {
-		pr_err("pmem: %s: requested data from file "
-			"descriptor that doesn't exist.\n", __func__);
-	} else {
-#if PMEM_DEBUG_MSGS
-		char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-		DLOG("filp %p rdev %d pid %u(%s) file %p(%ld)"
-			" dev %s(id: %d)\n", filp,
-			file->f_dentry->d_inode->i_rdev,
-			current->pid, get_task_comm(currtask_name, current),
-			file, file_count(file), get_name(file), get_id(file));
-
-		if (!get_pmem_addr(file, start, vstart, len)) {
-			if (filp)
-				*filp = file;
-			ret = 0;
-		} else {
-			fput(file);
-		}
-	}
-	return ret;
-}
-EXPORT_SYMBOL(get_pmem_file);
-
-int get_pmem_fd(int fd, unsigned long *start, unsigned long *len)
-{
-	unsigned long vstart;
-	return get_pmem_file(fd, start, &vstart, len, NULL);
-}
-EXPORT_SYMBOL(get_pmem_fd);
-
-void put_pmem_file(struct file *file)
-{
-#if PMEM_DEBUG_MSGS
-	char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-	DLOG("rdev %d pid %u(%s) file %p(%ld)" " dev %s(id: %d)\n",
-		file->f_dentry->d_inode->i_rdev, current->pid,
-		get_task_comm(currtask_name, current), file,
-		file_count(file), get_name(file), get_id(file));
-	if (is_pmem_file(file)) {
-#if PMEM_DEBUG
-		struct pmem_data *data = file->private_data;
-
-		down_write(&data->sem);
-		if (!data->ref--) {
-			data->ref++;
-			pr_alert("pmem: pmem_put > pmem_get %s "
-				"(pid %d)\n",
-			       pmem[get_id(file)].dev.name, data->pid);
-			BUG();
-		}
-		up_write(&data->sem);
-#endif
-		fput(file);
-	}
-}
-EXPORT_SYMBOL(put_pmem_file);
-
-void put_pmem_fd(int fd)
-{
-	int put_needed;
-	struct file *file = fget_light(fd, &put_needed);
-
-	if (file) {
-		put_pmem_file(file);
-		fput_light(file, put_needed);
-	}
-}
-
-void flush_pmem_fd(int fd, unsigned long offset, unsigned long len)
-{
-	int fput_needed;
-	struct file *file = fget_light(fd, &fput_needed);
-
-	if (file) {
-		flush_pmem_file(file, offset, len);
-		fput_light(file, fput_needed);
-	}
-}
-
-void flush_pmem_file(struct file *file, unsigned long offset, unsigned long len)
-{
-	struct pmem_data *data;
-	int id;
-	void *vaddr;
-	struct pmem_region_node *region_node;
-	struct list_head *elt;
-	void *flush_start, *flush_end;
-#ifdef CONFIG_OUTER_CACHE
-	unsigned long phy_start, phy_end;
-#endif
-	if (!is_pmem_file(file))
-		return;
-
-	id = get_id(file);
-	if (!pmem[id].cached)
-		return;
-
-	/* is_pmem_file fails if !file */
-	data = file->private_data;
-
-	down_read(&data->sem);
-	if (!has_allocation(file))
-		goto end;
-
-	vaddr = pmem_start_vaddr(id, data);
-
-	if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_SYSTEM) {
-		dmac_flush_range(vaddr,
-			(void *)((unsigned long)vaddr +
-				 ((struct alloc_list *)(data->index))->size));
-#ifdef CONFIG_OUTER_CACHE
-		phy_start = pmem_start_addr_system(id, data);
-
-		phy_end = phy_start +
-			((struct alloc_list *)(data->index))->size;
-
-		outer_flush_range(phy_start, phy_end);
-#endif
-		goto end;
-	}
-	/* if this isn't a submmapped file, flush the whole thing */
-	if (unlikely(!(data->flags & PMEM_FLAGS_CONNECTED))) {
-		dmac_flush_range(vaddr, vaddr + pmem[id].len(id, data));
-#ifdef CONFIG_OUTER_CACHE
-		phy_start = (unsigned long)vaddr -
-				(unsigned long)pmem[id].vbase + pmem[id].base;
-
-		phy_end  =  phy_start + pmem[id].len(id, data);
-
-		outer_flush_range(phy_start, phy_end);
-#endif
-		goto end;
-	}
-	/* otherwise, flush the region of the file we are drawing */
-	list_for_each(elt, &data->region_list) {
-		region_node = list_entry(elt, struct pmem_region_node, list);
-		if ((offset >= region_node->region.offset) &&
-		    ((offset + len) <= (region_node->region.offset +
-			region_node->region.len))) {
-			flush_start = vaddr + region_node->region.offset;
-			flush_end = flush_start + region_node->region.len;
-			dmac_flush_range(flush_start, flush_end);
-#ifdef CONFIG_OUTER_CACHE
-
-			phy_start = (unsigned long)flush_start -
-				(unsigned long)pmem[id].vbase + pmem[id].base;
-
-			phy_end  =  phy_start + region_node->region.len;
-
-			outer_flush_range(phy_start, phy_end);
-#endif
-			break;
-		}
-	}
-end:
-	up_read(&data->sem);
-}
-
-int pmem_cache_maint(struct file *file, unsigned int cmd,
-		struct pmem_addr *pmem_addr)
-{
-	struct pmem_data *data;
-	int id;
-	unsigned long vaddr, paddr, length, offset,
-		      pmem_len, pmem_start_addr;
-
-	/* Called from kernel-space so file may be NULL */
-	if (!file)
-		return -EBADF;
-
-	/*
-	 * check that the vaddr passed for flushing is valid
-	 * so that you don't crash the kernel
-	 */
-	if (!pmem_addr->vaddr)
-		return -EINVAL;
-
-	data = file->private_data;
-	id = get_id(file);
-
-	if (!pmem[id].cached)
-		return 0;
-
-	offset = pmem_addr->offset;
-	length = pmem_addr->length;
-
-	down_read(&data->sem);
-	if (!has_allocation(file)) {
-		up_read(&data->sem);
-		return -EINVAL;
-	}
-	pmem_len = pmem[id].len(id, data);
-	pmem_start_addr = pmem[id].start_addr(id, data);
-	up_read(&data->sem);
-
-	if (offset + length > pmem_len)
-		return -EINVAL;
-
-	vaddr = pmem_addr->vaddr;
-	paddr = pmem_start_addr + offset;
-
-	DLOG("pmem cache maint on dev %s(id: %d)"
-		"(vaddr %lx paddr %lx len %lu bytes)\n",
-		get_name(file), id, vaddr, paddr, length);
-	if (cmd == PMEM_CLEAN_INV_CACHES)
-		clean_and_invalidate_caches(vaddr,
-				length, paddr);
-	else if (cmd == PMEM_CLEAN_CACHES)
-		clean_caches(vaddr, length, paddr);
-	else if (cmd == PMEM_INV_CACHES)
-		invalidate_caches(vaddr, length, paddr);
-
-	return 0;
-}
-EXPORT_SYMBOL(pmem_cache_maint);
-
-static int pmem_connect(unsigned long connect, struct file *file)
-{
-	int ret = 0, put_needed;
-	struct file *src_file;
-
-	if (!file) {
-		pr_err("pmem: %s: NULL file pointer passed in, "
-			"bailing out!\n", __func__);
-		ret = -EINVAL;
-		goto leave;
-	}
-
-	src_file = fget_light(connect, &put_needed);
-
-	if (!src_file) {
-		pr_err("pmem: %s: src file not found!\n", __func__);
-		ret = -EBADF;
-		goto leave;
-	}
-
-	if (src_file == file) { /* degenerative case, operator error */
-		pr_err("pmem: %s: src_file and passed in file are "
-			"the same; refusing to connect to self!\n", __func__);
-		ret = -EINVAL;
-		goto put_src_file;
-	}
-
-	if (unlikely(!is_pmem_file(src_file))) {
-		pr_err("pmem: %s: src file is not a pmem file!\n",
-			__func__);
-		ret = -EINVAL;
-		goto put_src_file;
-	} else {
-		struct pmem_data *src_data = src_file->private_data;
-
-		if (!src_data) {
-			pr_err("pmem: %s: src file pointer has no"
-				"private data, bailing out!\n", __func__);
-			ret = -EINVAL;
-			goto put_src_file;
-		}
-
-		down_read(&src_data->sem);
-
-		if (unlikely(!has_allocation(src_file))) {
-			up_read(&src_data->sem);
-			pr_err("pmem: %s: src file has no allocation!\n",
-				__func__);
-			ret = -EINVAL;
-		} else {
-			struct pmem_data *data;
-			int src_index = src_data->index;
-
-			up_read(&src_data->sem);
-
-			data = file->private_data;
-			if (!data) {
-				pr_err("pmem: %s: passed in file "
-					"pointer has no private data, bailing"
-					" out!\n", __func__);
-				ret = -EINVAL;
-				goto put_src_file;
-			}
-
-			down_write(&data->sem);
-			if (has_allocation(file) &&
-					(data->index != src_index)) {
-				up_write(&data->sem);
-
-				pr_err("pmem: %s: file is already "
-					"mapped but doesn't match this "
-					"src_file!\n", __func__);
-				ret = -EINVAL;
-			} else {
-				data->index = src_index;
-				data->flags |= PMEM_FLAGS_CONNECTED;
-				data->master_fd = connect;
-				data->master_file = src_file;
-
-				up_write(&data->sem);
-
-				DLOG("connect %p to %p\n", file, src_file);
-			}
-		}
-	}
-put_src_file:
-	fput_light(src_file, put_needed);
-leave:
-	return ret;
-}
-
-static void pmem_unlock_data_and_mm(struct pmem_data *data,
-				    struct mm_struct *mm)
-{
-	up_write(&data->sem);
-	if (mm != NULL) {
-		up_write(&mm->mmap_sem);
-		mmput(mm);
-	}
-}
-
-static int pmem_lock_data_and_mm(struct file *file, struct pmem_data *data,
-				 struct mm_struct **locked_mm)
-{
-	int ret = 0;
-	struct mm_struct *mm = NULL;
-#if PMEM_DEBUG_MSGS
-	char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-	DLOG("pid %u(%s) file %p(%ld)\n",
-		current->pid, get_task_comm(currtask_name, current),
-		file, file_count(file));
-
-	*locked_mm = NULL;
-lock_mm:
-	down_read(&data->sem);
-	if (PMEM_IS_SUBMAP(data)) {
-		mm = get_task_mm(data->task);
-		if (!mm) {
-			up_read(&data->sem);
-#if PMEM_DEBUG
-			pr_alert("pmem: can't remap - task is gone!\n");
-#endif
-			return -1;
-		}
-	}
-	up_read(&data->sem);
-
-	if (mm)
-		down_write(&mm->mmap_sem);
-
-	down_write(&data->sem);
-	/* check that the file didn't get mmaped before we could take the
-	 * data sem, this should be safe b/c you can only submap each file
-	 * once */
-	if (PMEM_IS_SUBMAP(data) && !mm) {
-		pmem_unlock_data_and_mm(data, mm);
-		DLOG("mapping contention, repeating mmap op\n");
-		goto lock_mm;
-	}
-	/* now check that vma.mm is still there, it could have been
-	 * deleted by vma_close before we could get the data->sem */
-	if ((data->flags & PMEM_FLAGS_UNSUBMAP) && (mm != NULL)) {
-		/* might as well release this */
-		if (data->flags & PMEM_FLAGS_SUBMAP) {
-			put_task_struct(data->task);
-			data->task = NULL;
-			/* lower the submap flag to show the mm is gone */
-			data->flags &= ~(PMEM_FLAGS_SUBMAP);
-		}
-		pmem_unlock_data_and_mm(data, mm);
-#if PMEM_DEBUG
-		pr_alert("pmem: vma.mm went away!\n");
-#endif
-		return -1;
-	}
-	*locked_mm = mm;
-	return ret;
-}
-
-int pmem_remap(struct pmem_region *region, struct file *file,
-		      unsigned operation)
-{
-	int ret;
-	struct pmem_region_node *region_node;
-	struct mm_struct *mm = NULL;
-	struct list_head *elt, *elt2;
-	int id = get_id(file);
-	struct pmem_data *data;
-
-	DLOG("operation %#x, region offset %ld, region len %ld\n",
-		operation, region->offset, region->len);
-
-	if (!is_pmem_file(file)) {
-#if PMEM_DEBUG
-		pr_err("pmem: remap request for non-pmem file descriptor\n");
-#endif
-		return -EINVAL;
-	}
-
-	/* is_pmem_file fails if !file */
-	data = file->private_data;
-
-	/* pmem region must be aligned on a page boundry */
-	if (unlikely(!PMEM_IS_PAGE_ALIGNED(region->offset) ||
-		 !PMEM_IS_PAGE_ALIGNED(region->len))) {
-#if PMEM_DEBUG
-		pr_err("pmem: request for unaligned pmem"
-			"suballocation %lx %lx\n",
-			region->offset, region->len);
-#endif
-		return -EINVAL;
-	}
-
-	/* if userspace requests a region of len 0, there's nothing to do */
-	if (region->len == 0)
-		return 0;
-
-	/* lock the mm and data */
-	ret = pmem_lock_data_and_mm(file, data, &mm);
-	if (ret)
-		return 0;
-
-	/* only the owner of the master file can remap the client fds
-	 * that back in it */
-	if (!is_master_owner(file)) {
-#if PMEM_DEBUG
-		pr_err("pmem: remap requested from non-master process\n");
-#endif
-		ret = -EINVAL;
-		goto err;
-	}
-
-	/* check that the requested range is within the src allocation */
-	if (unlikely((region->offset > pmem[id].len(id, data)) ||
-		     (region->len > pmem[id].len(id, data)) ||
-		     (region->offset + region->len > pmem[id].len(id, data)))) {
-#if PMEM_DEBUG
-		pr_err("pmem: suballoc doesn't fit in src_file!\n");
-#endif
-		ret = -EINVAL;
-		goto err;
-	}
-
-	if (operation == PMEM_MAP) {
-		region_node = kmalloc(sizeof(struct pmem_region_node),
-			      GFP_KERNEL);
-		if (!region_node) {
-			ret = -ENOMEM;
-#if PMEM_DEBUG
-			pr_alert("pmem: No space to allocate remap metadata!");
-#endif
-			goto err;
-		}
-		region_node->region = *region;
-		list_add(&region_node->list, &data->region_list);
-	} else if (operation == PMEM_UNMAP) {
-		int found = 0;
-		list_for_each_safe(elt, elt2, &data->region_list) {
-			region_node = list_entry(elt, struct pmem_region_node,
-				      list);
-			if (region->len == 0 ||
-			    (region_node->region.offset == region->offset &&
-			    region_node->region.len == region->len)) {
-				list_del(elt);
-				kfree(region_node);
-				found = 1;
-			}
-		}
-		if (!found) {
-#if PMEM_DEBUG
-			pr_err("pmem: Unmap region does not map any"
-				" mapped region!");
-#endif
-			ret = -EINVAL;
-			goto err;
-		}
-	}
-
-	if (data->vma && PMEM_IS_SUBMAP(data)) {
-		if (operation == PMEM_MAP)
-			ret = pmem_remap_pfn_range(id, data->vma, data,
-				   region->offset, region->len);
-		else if (operation == PMEM_UNMAP)
-			ret = pmem_unmap_pfn_range(id, data->vma, data,
-				   region->offset, region->len);
-	}
-
-err:
-	pmem_unlock_data_and_mm(data, mm);
-	return ret;
-}
-
-static void pmem_revoke(struct file *file, struct pmem_data *data)
-{
-	struct pmem_region_node *region_node;
-	struct list_head *elt, *elt2;
-	struct mm_struct *mm = NULL;
-	int id = get_id(file);
-	int ret = 0;
-
-	data->master_file = NULL;
-	ret = pmem_lock_data_and_mm(file, data, &mm);
-	/* if lock_data_and_mm fails either the task that mapped the fd, or
-	 * the vma that mapped it have already gone away, nothing more
-	 * needs to be done */
-	if (ret)
-		return;
-	/* unmap everything */
-	/* delete the regions and region list nothing is mapped any more */
-	if (data->vma)
-		list_for_each_safe(elt, elt2, &data->region_list) {
-			region_node = list_entry(elt, struct pmem_region_node,
-						 list);
-			pmem_unmap_pfn_range(id, data->vma, data,
-					     region_node->region.offset,
-					     region_node->region.len);
-			list_del(elt);
-			kfree(region_node);
-	}
-	/* delete the master file */
-	pmem_unlock_data_and_mm(data, mm);
-}
-
-static void pmem_get_size(struct pmem_region *region, struct file *file)
-{
-	/* called via ioctl file op, so file guaranteed to be not NULL */
-	struct pmem_data *data = file->private_data;
-	int id = get_id(file);
-
-	down_read(&data->sem);
-	if (!has_allocation(file)) {
-		region->offset = 0;
-		region->len = 0;
-	} else {
-		region->offset = pmem[id].start_addr(id, data);
-		region->len = pmem[id].len(id, data);
-	}
-	up_read(&data->sem);
-	DLOG("offset 0x%lx len 0x%lx\n", region->offset, region->len);
-}
-
-
-static long pmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	/* called from user space as file op, so file guaranteed to be not
-	 * NULL
-	 */
-	struct pmem_data *data = file->private_data;
-	int id = get_id(file);
-#if PMEM_DEBUG_MSGS
-	char currtask_name[
-		FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-
-	DLOG("pid %u(%s) file %p(%ld) cmd %#x, dev %s(id: %d)\n",
-		current->pid, get_task_comm(currtask_name, current),
-		file, file_count(file), cmd, get_name(file), id);
-
-	switch (cmd) {
-	case PMEM_GET_PHYS:
-		{
-			struct pmem_region region;
-
-			DLOG("get_phys\n");
-			down_read(&data->sem);
-			if (!has_allocation(file)) {
-				region.offset = 0;
-				region.len = 0;
-			} else {
-				region.offset = pmem[id].start_addr(id, data);
-				region.len = pmem[id].len(id, data);
-			}
-			up_read(&data->sem);
-
-			if (copy_to_user((void __user *)arg, &region,
-						sizeof(struct pmem_region)))
-				return -EFAULT;
-
-			DLOG("pmem: successful request for "
-				"physical address of pmem region id %d, "
-				"offset 0x%lx, len 0x%lx\n",
-				id, region.offset, region.len);
-
-			break;
-		}
-	case PMEM_MAP:
-		{
-			struct pmem_region region;
-			DLOG("map\n");
-			if (copy_from_user(&region, (void __user *)arg,
-						sizeof(struct pmem_region)))
-				return -EFAULT;
-			return pmem_remap(&region, file, PMEM_MAP);
-		}
-		break;
-	case PMEM_UNMAP:
-		{
-			struct pmem_region region;
-			DLOG("unmap\n");
-			if (copy_from_user(&region, (void __user *)arg,
-						sizeof(struct pmem_region)))
-				return -EFAULT;
-			return pmem_remap(&region, file, PMEM_UNMAP);
-			break;
-		}
-	case PMEM_GET_SIZE:
-		{
-			struct pmem_region region;
-			DLOG("get_size\n");
-			pmem_get_size(&region, file);
-			if (copy_to_user((void __user *)arg, &region,
-						sizeof(struct pmem_region)))
-				return -EFAULT;
-			break;
-		}
-	case PMEM_GET_TOTAL_SIZE:
-		{
-			struct pmem_region region;
-			DLOG("get total size\n");
-			region.offset = 0;
-			get_id(file);
-			region.len = pmem[id].size;
-			if (copy_to_user((void __user *)arg, &region,
-						sizeof(struct pmem_region)))
-				return -EFAULT;
-			break;
-		}
-	case PMEM_GET_FREE_SPACE:
-		{
-			struct pmem_freespace fs;
-			DLOG("get freespace on %s(id: %d)\n",
-				get_name(file), id);
-
-			mutex_lock(&pmem[id].arena_mutex);
-			pmem[id].free_space(id, &fs);
-			mutex_unlock(&pmem[id].arena_mutex);
-
-			DLOG("%s(id: %d) total free %lu, largest %lu\n",
-				get_name(file), id, fs.total, fs.largest);
-
-			if (copy_to_user((void __user *)arg, &fs,
-				sizeof(struct pmem_freespace)))
-				return -EFAULT;
-			break;
-	}
-
-	case PMEM_ALLOCATE:
-		{
-			int ret = 0;
-			DLOG("allocate, id %d\n", id);
-			down_write(&data->sem);
-			if (has_allocation(file)) {
-				pr_err("pmem: Existing allocation found on "
-					"this file descrpitor\n");
-				up_write(&data->sem);
-				return -EINVAL;
-			}
-
-			mutex_lock(&pmem[id].arena_mutex);
-			data->index = pmem_allocate_from_id(id,
-					arg,
-					SZ_4K);
-			mutex_unlock(&pmem[id].arena_mutex);
-			ret = data->index == -1 ? -ENOMEM :
-				data->index;
-			up_write(&data->sem);
-			return ret;
-		}
-	case PMEM_ALLOCATE_ALIGNED:
-		{
-			struct pmem_allocation alloc;
-			int ret = 0;
-
-			if (copy_from_user(&alloc, (void __user *)arg,
-						sizeof(struct pmem_allocation)))
-				return -EFAULT;
-			DLOG("allocate id align %d %u\n", id, alloc.align);
-			down_write(&data->sem);
-			if (has_allocation(file)) {
-				pr_err("pmem: Existing allocation found on "
-					"this file descrpitor\n");
-				up_write(&data->sem);
-				return -EINVAL;
-			}
-
-			if (alloc.align & (alloc.align - 1)) {
-				pr_err("pmem: Alignment is not a power of 2\n");
-				return -EINVAL;
-			}
-
-			if (alloc.align != SZ_4K &&
-					(pmem[id].allocator_type !=
-						PMEM_ALLOCATORTYPE_BITMAP)) {
-				pr_err("pmem: Non 4k alignment requires bitmap"
-					" allocator on %s\n", pmem[id].name);
-				return -EINVAL;
-			}
-
-			if (alloc.align > SZ_1M ||
-				alloc.align < SZ_4K) {
-				pr_err("pmem: Invalid Alignment (%u) "
-					"specified\n", alloc.align);
-				return -EINVAL;
-			}
-
-			mutex_lock(&pmem[id].arena_mutex);
-			data->index = pmem_allocate_from_id(id,
-				alloc.size,
-				alloc.align);
-			mutex_unlock(&pmem[id].arena_mutex);
-			ret = data->index == -1 ? -ENOMEM :
-				data->index;
-			up_write(&data->sem);
-			return ret;
-		}
-	case PMEM_CONNECT:
-		DLOG("connect\n");
-		return pmem_connect(arg, file);
-	case PMEM_CLEAN_INV_CACHES:
-	case PMEM_CLEAN_CACHES:
-	case PMEM_INV_CACHES:
-		{
-			struct pmem_addr pmem_addr;
-
-			if (copy_from_user(&pmem_addr, (void __user *)arg,
-						sizeof(struct pmem_addr)))
-				return -EFAULT;
-
-			return pmem_cache_maint(file, cmd, &pmem_addr);
-		}
-	default:
-		if (pmem[id].ioctl)
-			return pmem[id].ioctl(file, cmd, arg);
-
-		DLOG("ioctl invalid (%#x)\n", cmd);
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static void ioremap_pmem(int id)
-{
-	unsigned long addr;
-	const struct mem_type *type;
-
-	DLOG("PMEMDEBUG: ioremaping for %s\n", pmem[id].name);
-	if (pmem[id].map_on_demand) {
-		addr = (unsigned long)pmem[id].area->addr;
-		if (pmem[id].cached)
-			type = get_mem_type(MT_DEVICE_CACHED);
-		else
-			type = get_mem_type(MT_DEVICE);
-		DLOG("PMEMDEBUG: Remap phys %lx to virt %lx on %s\n",
-			pmem[id].base, addr, pmem[id].name);
-		if (ioremap_pages(addr, pmem[id].base,  pmem[id].size, type)) {
-				pr_err("pmem: Failed to map pages\n");
-				BUG();
-		}
-		pmem[id].vbase = pmem[id].area->addr;
-		/* Flush the cache after installing page table entries to avoid
-		 * aliasing when these pages are remapped to user space.
-		 */
-		flush_cache_vmap(addr, addr + pmem[id].size);
-	} else {
-		if (pmem[id].cached)
-			pmem[id].vbase = ioremap_cached(pmem[id].base,
-						pmem[id].size);
-	#ifdef ioremap_ext_buffered
-		else if (pmem[id].buffered)
-			pmem[id].vbase = ioremap_ext_buffered(pmem[id].base,
-						pmem[id].size);
-	#endif
-		else
-			pmem[id].vbase = ioremap(pmem[id].base, pmem[id].size);
-	}
-}
-
-int pmem_setup(struct android_pmem_platform_data *pdata,
-	       long (*ioctl)(struct file *, unsigned int, unsigned long),
-	       int (*release)(struct inode *, struct file *))
-{
-	int i, index = 0, id;
-	struct vm_struct *pmem_vma = NULL;
-	struct page *page;
-
-	if (id_count >= PMEM_MAX_DEVICES) {
-		pr_alert("pmem: %s: unable to register driver(%s) - no more "
-			"devices available!\n", __func__, pdata->name);
-		goto err_no_mem;
-	}
-
-	if (!pdata->size) {
-		pr_alert("pmem: %s: unable to register pmem driver(%s) - zero "
-			"size passed in!\n", __func__, pdata->name);
-		goto err_no_mem;
-	}
-
-	id = id_count++;
-
-	pmem[id].id = id;
-
-	if (pmem[id].allocate) {
-		pr_alert("pmem: %s: unable to register pmem driver - "
-			"duplicate registration of %s!\n",
-			__func__, pdata->name);
-		goto err_no_mem;
-	}
-
-	pmem[id].allocator_type = pdata->allocator_type;
-
-	/* 'quantum' is a "hidden" variable that defaults to 0 in the board
-	 * files */
-	pmem[id].quantum = pdata->quantum ?: PMEM_MIN_ALLOC;
-	if (pmem[id].quantum < PMEM_MIN_ALLOC ||
-		!is_power_of_2(pmem[id].quantum)) {
-		pr_alert("pmem: %s: unable to register pmem driver %s - "
-			"invalid quantum value (%#x)!\n",
-			__func__, pdata->name, pmem[id].quantum);
-		goto err_reset_pmem_info;
-	}
-
-	if (pdata->size % pmem[id].quantum) {
-		/* bad alignment for size! */
-		pr_alert("pmem: %s: Unable to register driver %s - "
-			"memory region size (%#lx) is not a multiple of "
-			"quantum size(%#x)!\n", __func__, pdata->name,
-			pdata->size, pmem[id].quantum);
-		goto err_reset_pmem_info;
-	}
-
-	pmem[id].cached = pdata->cached;
-	pmem[id].buffered = pdata->buffered;
-	pmem[id].size = pdata->size;
-	pmem[id].memory_type = pdata->memory_type;
-	strlcpy(pmem[id].name, pdata->name, PMEM_NAME_SIZE);
-
-	pmem[id].num_entries = pmem[id].size / pmem[id].quantum;
-
-	memset(&pmem[id].kobj, 0, sizeof(pmem[0].kobj));
-	pmem[id].kobj.kset = pmem_kset;
-
-	switch (pmem[id].allocator_type) {
-	case PMEM_ALLOCATORTYPE_ALLORNOTHING:
-		pmem[id].allocate = pmem_allocator_all_or_nothing;
-		pmem[id].free = pmem_free_all_or_nothing;
-		pmem[id].free_space = pmem_free_space_all_or_nothing;
-		pmem[id].len = pmem_len_all_or_nothing;
-		pmem[id].start_addr = pmem_start_addr_all_or_nothing;
-		pmem[id].num_entries = 1;
-		pmem[id].quantum = pmem[id].size;
-		pmem[id].allocator.all_or_nothing.allocated = 0;
-
-		if (kobject_init_and_add(&pmem[id].kobj,
-				&pmem_allornothing_ktype, NULL,
-				"%s", pdata->name))
-			goto out_put_kobj;
-
-		break;
-
-	case PMEM_ALLOCATORTYPE_BUDDYBESTFIT:
-		pmem[id].allocator.buddy_bestfit.buddy_bitmap = kmalloc(
-			pmem[id].num_entries * sizeof(struct pmem_bits),
-			GFP_KERNEL);
-		if (!pmem[id].allocator.buddy_bestfit.buddy_bitmap)
-			goto err_reset_pmem_info;
-
-		memset(pmem[id].allocator.buddy_bestfit.buddy_bitmap, 0,
-			sizeof(struct pmem_bits) * pmem[id].num_entries);
-
-		for (i = sizeof(pmem[id].num_entries) * 8 - 1; i >= 0; i--)
-			if ((pmem[id].num_entries) &  1<<i) {
-				PMEM_BUDDY_ORDER(id, index) = i;
-				index = PMEM_BUDDY_NEXT_INDEX(id, index);
-			}
-		pmem[id].allocate = pmem_allocator_buddy_bestfit;
-		pmem[id].free = pmem_free_buddy_bestfit;
-		pmem[id].free_space = pmem_free_space_buddy_bestfit;
-		pmem[id].len = pmem_len_buddy_bestfit;
-		pmem[id].start_addr = pmem_start_addr_buddy_bestfit;
-		if (kobject_init_and_add(&pmem[id].kobj,
-				&pmem_buddy_bestfit_ktype, NULL,
-				"%s", pdata->name))
-			goto out_put_kobj;
-
-		break;
-
-	case PMEM_ALLOCATORTYPE_BITMAP: /* 0, default if not explicit */
-		pmem[id].allocator.bitmap.bitm_alloc = kmalloc(
-			PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS *
-				sizeof(*pmem[id].allocator.bitmap.bitm_alloc),
-			GFP_KERNEL);
-		if (!pmem[id].allocator.bitmap.bitm_alloc) {
-			pr_alert("pmem: %s: Unable to register pmem "
-					"driver %s - can't allocate "
-					"bitm_alloc!\n",
-					__func__, pdata->name);
-			goto err_reset_pmem_info;
-		}
-
-		if (kobject_init_and_add(&pmem[id].kobj,
-				&pmem_bitmap_ktype, NULL,
-				"%s", pdata->name))
-			goto out_put_kobj;
-
-		for (i = 0; i < PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS; i++) {
-			pmem[id].allocator.bitmap.bitm_alloc[i].bit = -1;
-			pmem[id].allocator.bitmap.bitm_alloc[i].quanta = 0;
-		}
-
-		pmem[id].allocator.bitmap.bitmap_allocs =
-			PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS;
-
-		pmem[id].allocator.bitmap.bitmap =
-			kcalloc((pmem[id].num_entries + 31) / 32,
-				sizeof(unsigned int), GFP_KERNEL);
-		if (!pmem[id].allocator.bitmap.bitmap) {
-			pr_alert("pmem: %s: Unable to register pmem "
-				"driver - can't allocate bitmap!\n",
-				__func__);
-			goto err_cant_register_device;
-		}
-		pmem[id].allocator.bitmap.bitmap_free = pmem[id].num_entries;
-
-		pmem[id].allocate = pmem_allocator_bitmap;
-		pmem[id].free = pmem_free_bitmap;
-		pmem[id].free_space = pmem_free_space_bitmap;
-		pmem[id].len = pmem_len_bitmap;
-		pmem[id].start_addr = pmem_start_addr_bitmap;
-
-		DLOG("bitmap allocator id %d (%s), num_entries %u, raw size "
-			"%lu, quanta size %u\n",
-			id, pdata->name, pmem[id].allocator.bitmap.bitmap_free,
-			pmem[id].size, pmem[id].quantum);
-		break;
-
-	case PMEM_ALLOCATORTYPE_SYSTEM:
-
-		INIT_LIST_HEAD(&pmem[id].allocator.system_mem.alist);
-
-		pmem[id].allocator.system_mem.used = 0;
-		pmem[id].vbase = NULL;
-
-		if (kobject_init_and_add(&pmem[id].kobj,
-				&pmem_system_ktype, NULL,
-				"%s", pdata->name))
-			goto out_put_kobj;
-
-		pmem[id].allocate = pmem_allocator_system;
-		pmem[id].free = pmem_free_system;
-		pmem[id].free_space = pmem_free_space_system;
-		pmem[id].len = pmem_len_system;
-		pmem[id].start_addr = pmem_start_addr_system;
-		pmem[id].num_entries = 0;
-		pmem[id].quantum = PAGE_SIZE;
-
-		DLOG("system allocator id %d (%s), raw size %lu\n",
-			id, pdata->name, pmem[id].size);
-		break;
-
-	default:
-		pr_alert("Invalid allocator type (%d) for pmem driver\n",
-			pdata->allocator_type);
-		goto err_reset_pmem_info;
-	}
-
-	pmem[id].ioctl = ioctl;
-	pmem[id].release = release;
-	mutex_init(&pmem[id].arena_mutex);
-	mutex_init(&pmem[id].data_list_mutex);
-	INIT_LIST_HEAD(&pmem[id].data_list);
-
-	pmem[id].dev.name = pdata->name;
-	pmem[id].dev.minor = id;
-	pmem[id].dev.fops = &pmem_fops;
-	pmem[id].reusable = pdata->reusable;
-	pr_info("pmem: Initializing %s as %s\n",
-		pdata->name, pdata->cached ? "cached" : "non-cached");
-
-	if (misc_register(&pmem[id].dev)) {
-		pr_alert("Unable to register pmem driver!\n");
-		goto err_cant_register_device;
-	}
-
-	if (!pmem[id].reusable) {
-		pmem[id].base = allocate_contiguous_memory_nomap(pmem[id].size,
-			pmem[id].memory_type, PAGE_SIZE);
-		if (!pmem[id].base) {
-			pr_err("pmem: Cannot allocate from reserved memory for %s\n",
-				pdata->name);
-			goto err_misc_deregister;
-		}
-	}
-
-	/* reusable pmem requires map on demand */
-	pmem[id].map_on_demand = pdata->map_on_demand || pdata->reusable;
-	if (pmem[id].map_on_demand) {
-		if (pmem[id].reusable) {
-			const struct fmem_data *fmem_info = fmem_get_info();
-			pmem[id].area = fmem_info->area;
-			pmem[id].base = fmem_info->phys;
-		} else {
-			pmem_vma = get_vm_area(pmem[id].size, VM_IOREMAP);
-			if (!pmem_vma) {
-				pr_err("pmem: Failed to allocate virtual space for "
-					"%s\n", pdata->name);
-				goto err_free;
-			}
-			pr_err("pmem: Reserving virtual address range %lx - %lx for"
-				" %s\n", (unsigned long) pmem_vma->addr,
-				(unsigned long) pmem_vma->addr + pmem[id].size,
-				pdata->name);
-			pmem[id].area = pmem_vma;
-		}
-	} else
-		pmem[id].area = NULL;
-
-	page = alloc_page(GFP_KERNEL);
-	if (!page) {
-		pr_err("pmem: Failed to allocate page for %s\n", pdata->name);
-		goto cleanup_vm;
-	}
-	pmem[id].garbage_pfn = page_to_pfn(page);
-	atomic_set(&pmem[id].allocation_cnt, 0);
-
-	if (pdata->setup_region)
-		pmem[id].region_data = pdata->setup_region();
-
-	if (pdata->request_region)
-		pmem[id].mem_request = pdata->request_region;
-
-	if (pdata->release_region)
-		pmem[id].mem_release = pdata->release_region;
-
-	pr_info("allocating %lu bytes at %lx physical for %s\n",
-		pmem[id].size, pmem[id].base, pmem[id].name);
-
-	return 0;
-
-cleanup_vm:
-	if (!pmem[id].reusable)
-		remove_vm_area(pmem_vma);
-err_free:
-	if (!pmem[id].reusable)
-		free_contiguous_memory_by_paddr(pmem[id].base);
-err_misc_deregister:
-	misc_deregister(&pmem[id].dev);
-err_cant_register_device:
-out_put_kobj:
-	kobject_put(&pmem[id].kobj);
-	if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BUDDYBESTFIT)
-		kfree(pmem[id].allocator.buddy_bestfit.buddy_bitmap);
-	else if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BITMAP) {
-		kfree(pmem[id].allocator.bitmap.bitmap);
-		kfree(pmem[id].allocator.bitmap.bitm_alloc);
-	}
-err_reset_pmem_info:
-	pmem[id].allocate = 0;
-	pmem[id].dev.minor = -1;
-err_no_mem:
-	return -1;
-}
-
-static int pmem_probe(struct platform_device *pdev)
-{
-	struct android_pmem_platform_data *pdata;
-
-	if (!pdev || !pdev->dev.platform_data) {
-		pr_alert("Unable to probe pmem!\n");
-		return -1;
-	}
-	pdata = pdev->dev.platform_data;
-
-	pm_runtime_set_active(&pdev->dev);
-	pm_runtime_enable(&pdev->dev);
-
-	return pmem_setup(pdata, NULL, NULL);
-}
-
-static int pmem_remove(struct platform_device *pdev)
-{
-	int id = pdev->id;
-	__free_page(pfn_to_page(pmem[id].garbage_pfn));
-	pm_runtime_disable(&pdev->dev);
-	if (pmem[id].vbase)
-		iounmap(pmem[id].vbase);
-	if (pmem[id].map_on_demand && !pmem[id].reusable && pmem[id].area)
-		free_vm_area(pmem[id].area);
-	if (pmem[id].base)
-		free_contiguous_memory_by_paddr(pmem[id].base);
-	kobject_put(&pmem[id].kobj);
-	if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BUDDYBESTFIT)
-		kfree(pmem[id].allocator.buddy_bestfit.buddy_bitmap);
-	else if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BITMAP) {
-		kfree(pmem[id].allocator.bitmap.bitmap);
-		kfree(pmem[id].allocator.bitmap.bitm_alloc);
-	}
-	misc_deregister(&pmem[id].dev);
-	return 0;
-}
-
-static int pmem_runtime_suspend(struct device *dev)
-{
-	dev_dbg(dev, "pm_runtime: suspending...\n");
-	return 0;
-}
-
-static int pmem_runtime_resume(struct device *dev)
-{
-	dev_dbg(dev, "pm_runtime: resuming...\n");
-	return 0;
-}
-
-static const struct dev_pm_ops pmem_dev_pm_ops = {
-	.runtime_suspend = pmem_runtime_suspend,
-	.runtime_resume = pmem_runtime_resume,
-};
-
-static struct platform_driver pmem_driver = {
-	.probe = pmem_probe,
-	.remove = pmem_remove,
-	.driver = { .name = "android_pmem",
-		    .pm = &pmem_dev_pm_ops,
-  }
-};
-
-
-static int __init pmem_init(void)
-{
-	/* create /sys/kernel/<PMEM_SYSFS_DIR_NAME> directory */
-	pmem_kset = kset_create_and_add(PMEM_SYSFS_DIR_NAME,
-		NULL, kernel_kobj);
-	if (!pmem_kset) {
-		pr_err("pmem(%s):kset_create_and_add fail\n", __func__);
-		return -ENOMEM;
-	}
-
-	return platform_driver_register(&pmem_driver);
-}
-
-static void __exit pmem_exit(void)
-{
-	platform_driver_unregister(&pmem_driver);
-}
-
-module_init(pmem_init);
-module_exit(pmem_exit);
-
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 9f12142..21e65b9 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -228,6 +228,7 @@
 	md = mmc_blk_get(dev_to_disk(dev));
 	card = md->queue.card;
 
+	mmc_rpm_hold(card->host, &card->dev);
 	mmc_claim_host(card->host);
 
 	ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
@@ -240,6 +241,7 @@
 		card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
 
 	mmc_release_host(card->host);
+	mmc_rpm_release(card->host, &card->dev);
 
 	if (!ret) {
 		pr_info("%s: Locking boot partition ro until next power on\n",
@@ -602,7 +604,7 @@
 	md = mmc_blk_get(bdev->bd_disk);
 	if (!md) {
 		err = -EINVAL;
-		goto cmd_done;
+		goto blk_err;
 	}
 
 	card = md->queue.card;
@@ -707,6 +709,7 @@
 
 cmd_done:
 	mmc_blk_put(md);
+blk_err:
 	kfree(idata->buf);
 	kfree(idata);
 	return err;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 73a1b41..9fc599b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2864,6 +2864,40 @@
 	return ret;
 }
 
+static int mmc_clk_update_freq(struct mmc_host *host,
+		unsigned long freq, enum mmc_load state)
+{
+	int err = 0;
+
+	if (host->ops->notify_load) {
+		err = host->ops->notify_load(host, state);
+		if (err)
+			goto out;
+	}
+
+	if (freq != host->clk_scaling.curr_freq) {
+		if (!mmc_is_vaild_state_for_clk_scaling(host)) {
+			err = -EAGAIN;
+			goto error;
+		}
+
+		err = host->bus_ops->change_bus_speed(host, &freq);
+		if (!err)
+			host->clk_scaling.curr_freq = freq;
+		else
+			pr_err("%s: %s: failed (%d) at freq=%lu\n",
+				mmc_hostname(host), __func__, err, freq);
+	}
+error:
+	if (err) {
+		/* restore previous state */
+		if (host->ops->notify_load)
+			host->ops->notify_load(host, host->clk_scaling.state);
+	}
+out:
+	return err;
+}
+
 /**
  * mmc_clk_scaling() - clock scaling decision algorithm
  * @host:	pointer to mmc host structure
@@ -2889,6 +2923,7 @@
 	unsigned int up_threshold = host->clk_scaling.up_threshold;
 	unsigned int down_threshold = host->clk_scaling.down_threshold;
 	bool queue_scale_down_work = false;
+	enum mmc_load state;
 
 	if (!card || !host->bus_ops || !host->bus_ops->change_bus_speed) {
 		pr_err("%s: %s: invalid entry\n", mmc_hostname(host), __func__);
@@ -2916,6 +2951,7 @@
 	busy_time_ms = host->clk_scaling.busy_time_us / USEC_PER_MSEC;
 
 	freq = host->clk_scaling.curr_freq;
+	state = host->clk_scaling.state;
 
 	/*
 	 * Note that the max. and min. frequency should be based
@@ -2924,28 +2960,24 @@
 	 */
 	if ((busy_time_ms * 100 > total_time_ms * up_threshold)) {
 		freq = mmc_get_max_frequency(host);
+		state = MMC_LOAD_HIGH;
 	} else if ((busy_time_ms * 100 < total_time_ms * down_threshold)) {
 		if (!from_wq)
 			queue_scale_down_work = true;
 		freq = mmc_get_min_frequency(host);
+		state = MMC_LOAD_LOW;
 	}
 
-	if (freq != host->clk_scaling.curr_freq) {
+	if (state != host->clk_scaling.state) {
 		if (!queue_scale_down_work) {
 			if (!from_wq)
 				cancel_delayed_work_sync(
 						&host->clk_scaling.work);
-
-			if (!mmc_is_vaild_state_for_clk_scaling(host))
-				goto bypass_scaling;
-
-			err = host->bus_ops->change_bus_speed(host, &freq);
+			err = mmc_clk_update_freq(host, freq, state);
 			if (!err)
-				host->clk_scaling.curr_freq = freq;
-			else
-				pr_err("%s: %s: failed (%d) at freq=%lu\n",
-					mmc_hostname(host), __func__, err,
-					freq);
+				host->clk_scaling.state = state;
+			else if (err == -EAGAIN)
+				goto no_reset_stats;
 		} else {
 			/*
 			 * We hold claim host while queueing the scale down
@@ -2954,13 +2986,12 @@
 			 */
 			queue_delayed_work(system_nrt_wq,
 					&host->clk_scaling.work, 1);
-			host->clk_scaling.in_progress = false;
-			goto out;
+			goto no_reset_stats;
 		}
 	}
 
 	mmc_reset_clk_scale_stats(host);
-bypass_scaling:
+no_reset_stats:
 	host->clk_scaling.in_progress = false;
 out:
 	return;
@@ -3007,6 +3038,9 @@
 
 	INIT_DELAYED_WORK(&host->clk_scaling.work, mmc_clk_scale_work);
 	host->clk_scaling.curr_freq = mmc_get_max_frequency(host);
+	if (host->ops->notify_load)
+		host->ops->notify_load(host, MMC_LOAD_HIGH);
+	host->clk_scaling.state = MMC_LOAD_HIGH;
 	mmc_reset_clk_scale_stats(host);
 	host->clk_scaling.enable = true;
 	host->clk_scaling.initialized = true;
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 8b7e0bd..903decf 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -176,9 +176,11 @@
 	if (val > host->f_max)
 		return -EINVAL;
 
+	mmc_rpm_hold(host, &host->class_dev);
 	mmc_claim_host(host);
 	mmc_set_clock(host, (unsigned int) val);
 	mmc_release_host(host);
+	mmc_rpm_release(host, &host->class_dev);
 
 	return 0;
 }
@@ -208,6 +210,7 @@
 	if (!host || (val < host->f_min))
 		goto out;
 
+	mmc_rpm_hold(host, &host->class_dev);
 	mmc_claim_host(host);
 	if (host->bus_ops && host->bus_ops->change_bus_speed) {
 		old_freq = host->f_max;
@@ -219,6 +222,7 @@
 			host->f_max = old_freq;
 	}
 	mmc_release_host(host);
+	mmc_rpm_release(host, &host->class_dev);
 out:
 	return err;
 }
@@ -286,6 +290,7 @@
 	u32		status;
 	int		ret;
 
+	mmc_rpm_hold(card->host, &card->dev);
 	mmc_claim_host(card->host);
 
 	ret = mmc_send_status(data, &status);
@@ -293,6 +298,7 @@
 		*val = status;
 
 	mmc_release_host(card->host);
+	mmc_rpm_release(card->host, &card->dev);
 
 	return ret;
 }
@@ -319,9 +325,11 @@
 		goto out_free;
 	}
 
+	mmc_rpm_hold(card->host, &card->dev);
 	mmc_claim_host(card->host);
 	err = mmc_send_ext_csd(card, ext_csd);
 	mmc_release_host(card->host);
+	mmc_rpm_release(card->host, &card->dev);
 	if (err)
 		goto out_free;
 
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index c0a4cef..6c03bfc 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -466,12 +466,8 @@
 		goto err;
 
 	if (value && !mmc_can_scale_clk(host)) {
-		if (mmc_card_ddr_mode(host->card) ||
-				mmc_card_hs200(host->card) ||
-				mmc_card_uhs(host->card)) {
-			host->caps2 |= MMC_CAP2_CLK_SCALE;
-			mmc_init_clk_scaling(host);
-		}
+		host->caps2 |= MMC_CAP2_CLK_SCALE;
+		mmc_init_clk_scaling(host);
 
 		if (!mmc_can_scale_clk(host)) {
 			host->caps2 &= ~MMC_CAP2_CLK_SCALE;
@@ -487,6 +483,10 @@
 			if (host->bus_ops->change_bus_speed(host, &freq))
 				goto err;
 		}
+		if (host->ops->notify_load &&
+				host->ops->notify_load(host, MMC_LOAD_HIGH))
+			goto err;
+		host->clk_scaling.state = MMC_LOAD_HIGH;
 		host->clk_scaling.initialized = false;
 	}
 	retval = count;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 8a866cf..89f8c91 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1734,9 +1734,7 @@
 	if (err)
 		goto remove_card;
 
-	/* Initialize clock scaling only for high frequency modes */
-	if (mmc_card_hs200(host->card) || mmc_card_ddr_mode(host->card))
-		mmc_init_clk_scaling(host);
+	mmc_init_clk_scaling(host);
 
 	return 0;
 
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 60e0640..ddf9a87 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1415,9 +1415,7 @@
 	if (err)
 		goto remove_card;
 
-	/* Initialize clock scaling only for high frequency modes */
-	if (mmc_card_uhs(host->card))
-		mmc_init_clk_scaling(host);
+	mmc_init_clk_scaling(host);
 
 	return 0;
 
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 3f3687b..caf5fe4 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -958,7 +958,7 @@
 	struct msmsdcc_nc_dmadata *nc;
 	dmov_box *box;
 	uint32_t rows;
-	unsigned int n;
+	int n;
 	int i, err = 0, box_cmd_cnt = 0;
 	struct scatterlist *sg = data->sg;
 	unsigned int len, offset;
@@ -4393,6 +4393,39 @@
 	return data_cnt;
 }
 
+static int msmsdcc_notify_load(struct mmc_host *mmc, enum mmc_load state)
+{
+	int err = 0;
+	unsigned long rate;
+	struct msmsdcc_host *host = mmc_priv(mmc);
+
+	if (IS_ERR_OR_NULL(host->bus_clk))
+		goto out;
+
+	switch (state) {
+	case MMC_LOAD_HIGH:
+		rate = MSMSDCC_BUS_VOTE_MAX_RATE;
+		break;
+	case MMC_LOAD_LOW:
+		rate = MSMSDCC_BUS_VOTE_MIN_RATE;
+		break;
+	default:
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (rate != host->bus_clk_rate) {
+		err = clk_set_rate(host->bus_clk, rate);
+		if (err)
+			pr_err("%s: %s: bus clk set rate %lu Hz err %d\n",
+					mmc_hostname(mmc), __func__, rate, err);
+		else
+			host->bus_clk_rate = rate;
+	}
+out:
+	return err;
+}
+
 static const struct mmc_host_ops msmsdcc_ops = {
 	.enable		= msmsdcc_enable,
 	.disable	= msmsdcc_disable,
@@ -4407,6 +4440,7 @@
 	.hw_reset = msmsdcc_hw_reset,
 	.stop_request = msmsdcc_stop_request,
 	.get_xfer_remain = msmsdcc_get_xfer_remain,
+	.notify_load = msmsdcc_notify_load,
 };
 
 static void msmsdcc_enable_status_gpio(struct msmsdcc_host *host)
@@ -5975,12 +6009,13 @@
 	host->bus_clk = clk_get(&pdev->dev, "bus_clk");
 	if (!IS_ERR_OR_NULL(host->bus_clk)) {
 		/* Vote for max. clk rate for max. performance */
-		ret = clk_set_rate(host->bus_clk, INT_MAX);
+		ret = clk_set_rate(host->bus_clk, MSMSDCC_BUS_VOTE_MAX_RATE);
 		if (ret)
 			goto bus_clk_put;
 		ret = clk_prepare_enable(host->bus_clk);
 		if (ret)
 			goto bus_clk_put;
+		host->bus_clk_rate = MSMSDCC_BUS_VOTE_MAX_RATE;
 	}
 
 	/*
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 4ed2d96..bcfde57 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -260,6 +260,12 @@
 #define MMC_MAX_DMA_CMDS (MAX_NR_SG_DMA_PIO * (MMC_MAX_REQ_SIZE / \
 		MMC_MAX_DMA_BOX_LENGTH))
 
+/*
+ * Peripheral bus clock scaling vote rates
+ */
+#define MSMSDCC_BUS_VOTE_MAX_RATE	64000000 /* Hz */
+#define MSMSDCC_BUS_VOTE_MIN_RATE	32000000 /* Hz */
+
 struct clk;
 
 struct msmsdcc_nc_dmadata {
@@ -360,6 +366,7 @@
 	struct clk		*clk;		/* main MMC bus clock */
 	struct clk		*pclk;		/* SDCC peripheral bus clock */
 	struct clk		*bus_clk;	/* SDCC bus voter clock */
+	unsigned long		bus_clk_rate;	/* peripheral bus clk rate */
 	atomic_t		clks_on;	/* set if clocks are enabled */
 
 	unsigned int		eject;		/* eject state */
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 15e36a8..89730b0 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2137,6 +2137,7 @@
 	int ret = 0, dead = 0;
 	u32 vdd_max_current;
 	u16 host_version;
+	u32 pwr;
 
 	pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
 	msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
@@ -2245,7 +2246,21 @@
 	}
 
 	/* Set SW_RST bit in POWER register (Offset 0x0) */
-	writel_relaxed(CORE_SW_RST, msm_host->core_mem + CORE_POWER);
+	writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_POWER) |
+			CORE_SW_RST, msm_host->core_mem + CORE_POWER);
+	/*
+	 * SW reset can take upto 10HCLK + 15MCLK cycles.
+	 * Calculating based on min clk rates (hclk = 27MHz,
+	 * mclk = 400KHz) it comes to ~40us. Let's poll for
+	 * max. 1ms for reset completion.
+	 */
+	ret = readl_poll_timeout(msm_host->core_mem + CORE_POWER,
+			pwr, !(pwr & CORE_SW_RST), 100, 10);
+
+	if (ret) {
+		dev_err(&pdev->dev, "reset failed (%d)\n", ret);
+		goto vreg_deinit;
+	}
 	/* Set HC_MODE_EN bit in HC_MODE register */
 	writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
 
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index 1f50e1c..3c3a62b 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -49,18 +49,11 @@
 /**
  * struct ecm_ipa_dev - main driver context parameters
  * @net: network interface struct implemented by this driver
- * @folder: debugfs folder for various debuging switches
+ * @directory: debugfs directory for various debuging switches
  * @tx_enable: flag that enable/disable Tx path to continue to IPA
  * @rx_enable: flag that enable/disable Rx path to continue to IPA
  * @rm_enable: flag that enable/disable Resource manager request prior to Tx
  * @dma_enable: flag that allow on-the-fly DMA mode for IPA
- * @tx_file: saved debugfs entry to allow cleanup
- * @rx_file: saved debugfs entry to allow cleanup
- * @rm_file: saved debugfs entry to allow cleanup
- * @outstanding_file:  saved debugfs entry to allow cleanup
- * @outstanding_high_file saved debugfs entry to allow cleanup
- * @outstanding_low_file saved debugfs entry to allow cleanup
- * @dma_file: saved debugfs entry to allow cleanup
  * @eth_ipv4_hdr_hdl: saved handle for ipv4 header-insertion table
  * @eth_ipv6_hdr_hdl: saved handle for ipv6 header-insertion table
  * @usb_to_ipa_hdl: save handle for IPA pipe operations
@@ -72,18 +65,11 @@
  */
 struct ecm_ipa_dev {
 	struct net_device *net;
-	bool tx_enable;
-	bool rx_enable;
-	bool rm_enable;
+	u32 tx_enable;
+	u32 rx_enable;
+	u32  rm_enable;
 	bool dma_enable;
-	struct dentry *folder;
-	struct dentry *tx_file;
-	struct dentry *rx_file;
-	struct dentry *rm_file;
-	struct dentry *outstanding_high_file;
-	struct dentry *outstanding_low_file;
-	struct dentry *dma_file;
-	struct dentry *outstanding_file;
+	struct dentry *directory;
 	uint32_t eth_ipv4_hdr_hdl;
 	uint32_t eth_ipv6_hdr_hdl;
 	u32 usb_to_ipa_hdl;
@@ -127,9 +113,6 @@
 static void ecm_ipa_deregister_properties(void);
 static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev);
 static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev);
-static int ecm_ipa_debugfs_tx_open(struct inode *inode, struct file *file);
-static int ecm_ipa_debugfs_rx_open(struct inode *inode, struct file *file);
-static int ecm_ipa_debugfs_rm_open(struct inode *inode, struct file *file);
 static int ecm_ipa_debugfs_dma_open(struct inode *inode, struct file *file);
 static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file);
 static ssize_t ecm_ipa_debugfs_enable_read(struct file *file,
@@ -149,25 +132,12 @@
 	.ndo_start_xmit = ecm_ipa_start_xmit,
 	.ndo_set_mac_address = eth_mac_addr,
 };
+
 static const struct ethtool_ops ops = {
 	.get_drvinfo = eth_get_drvinfo,
 	.get_link = ethtool_op_get_link,
 };
-const struct file_operations ecm_ipa_debugfs_tx_ops = {
-	.open = ecm_ipa_debugfs_tx_open,
-	.read = ecm_ipa_debugfs_enable_read,
-	.write = ecm_ipa_debugfs_enable_write,
-};
-const struct file_operations ecm_ipa_debugfs_rx_ops = {
-	.open = ecm_ipa_debugfs_rx_open,
-	.read = ecm_ipa_debugfs_enable_read,
-	.write = ecm_ipa_debugfs_enable_write,
-};
-const struct file_operations ecm_ipa_debugfs_rm_ops = {
-	.open = ecm_ipa_debugfs_rm_open,
-	.read = ecm_ipa_debugfs_enable_read,
-	.write = ecm_ipa_debugfs_enable_write,
-};
+
 const struct file_operations ecm_ipa_debugfs_dma_ops = {
 	.open = ecm_ipa_debugfs_dma_open,
 	.read = ecm_ipa_debugfs_enable_read,
@@ -814,33 +784,6 @@
 	return;
 }
 
-static int ecm_ipa_debugfs_tx_open(struct inode *inode, struct file *file)
-{
-	struct ecm_ipa_dev *dev = inode->i_private;
-	ECM_IPA_LOG_ENTRY();
-	file->private_data = &(dev->tx_enable);
-	ECM_IPA_LOG_ENTRY();
-	return 0;
-}
-
-static int ecm_ipa_debugfs_rx_open(struct inode *inode, struct file *file)
-{
-	struct ecm_ipa_dev *dev = inode->i_private;
-	ECM_IPA_LOG_ENTRY();
-	file->private_data = &(dev->rx_enable);
-	ECM_IPA_LOG_EXIT();
-	return 0;
-}
-
-static int ecm_ipa_debugfs_rm_open(struct inode *inode, struct file *file)
-{
-	struct ecm_ipa_dev *dev = inode->i_private;
-	ECM_IPA_LOG_ENTRY();
-	file->private_data = &(dev->rm_enable);
-	ECM_IPA_LOG_EXIT();
-	return 0;
-}
-
 static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file)
 {
 	struct ecm_ipa_dev *dev = inode->i_private;
@@ -935,82 +878,74 @@
 
 static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev)
 {
-	const mode_t flags = S_IRUGO | S_IWUGO;
+	const mode_t flags_read_write = S_IRUGO | S_IWUGO;
 	const mode_t flags_read_only = S_IRUGO;
+	struct dentry *file;
 
-	int ret = -EINVAL;
 	ECM_IPA_LOG_ENTRY();
+
 	if (!dev)
 		return -EINVAL;
-	dev->folder = debugfs_create_dir("ecm_ipa", NULL);
-	if (!dev->folder) {
-		ECM_IPA_ERROR("could not create debugfs folder entry\n");
-		ret = -EFAULT;
-		goto fail_folder;
-	}
-	dev->tx_file = debugfs_create_file("tx_enable", flags, dev->folder, dev,
-		   &ecm_ipa_debugfs_tx_ops);
-	if (!dev->tx_file) {
-		ECM_IPA_ERROR("could not create debugfs tx file\n");
-		ret = -EFAULT;
-		goto fail_file;
-	}
-	dev->rx_file = debugfs_create_file("rx_enable", flags, dev->folder, dev,
-			&ecm_ipa_debugfs_rx_ops);
-	if (!dev->rx_file) {
-		ECM_IPA_ERROR("could not create debugfs rx file\n");
-		ret = -EFAULT;
-		goto fail_file;
-	}
-	dev->rm_file = debugfs_create_file("rm_enable", flags, dev->folder, dev,
-			&ecm_ipa_debugfs_rm_ops);
-	if (!dev->rm_file) {
-		ECM_IPA_ERROR("could not create debugfs rm file\n");
-		ret = -EFAULT;
-		goto fail_file;
-	}
-	dev->dma_file = debugfs_create_file("dma_enable", flags, dev->folder,
-			dev, &ecm_ipa_debugfs_dma_ops);
-	if (!dev->dma_file) {
-		ECM_IPA_ERROR("could not create debugfs dma file\n");
-		ret = -EFAULT;
-		goto fail_file;
-	}
 
-	dev->outstanding_high_file = debugfs_create_u8("outstanding_high",
-			flags, dev->folder, &dev->outstanding_high);
-	if (!dev->outstanding_high_file) {
+	dev->directory = debugfs_create_dir("ecm_ipa", NULL);
+	if (!dev->directory) {
+		ECM_IPA_ERROR("could not create debugfs directory entry\n");
+		goto fail_directory;
+	}
+	file = debugfs_create_bool("tx_enable", flags_read_write,
+			dev->directory, &dev->tx_enable);
+	if (!file) {
+		ECM_IPA_ERROR("could not create debugfs tx file\n");
+		goto fail_file;
+	}
+	file = debugfs_create_bool("rx_enable", flags_read_write,
+			dev->directory, &dev->rx_enable);
+	if (!file) {
+		ECM_IPA_ERROR("could not create debugfs rx file\n");
+		goto fail_file;
+	}
+	file = debugfs_create_bool("rm_enable", flags_read_write,
+			dev->directory, &dev->rm_enable);
+	if (!file) {
+		ECM_IPA_ERROR("could not create debugfs rm file\n");
+		goto fail_file;
+	}
+	file = debugfs_create_u8("outstanding_high", flags_read_write,
+			dev->directory, &dev->outstanding_high);
+	if (!file) {
 		ECM_IPA_ERROR("could not create outstanding_high file\n");
-		ret = -EFAULT;
 		goto fail_file;
 	}
-	dev->outstanding_low_file = debugfs_create_u8("outstanding_low",
-			flags, dev->folder, &dev->outstanding_low);
-	if (!dev->outstanding_low_file) {
+	file = debugfs_create_u8("outstanding_low", flags_read_write,
+			dev->directory, &dev->outstanding_low);
+	if (!file) {
 		ECM_IPA_ERROR("could not create outstanding_low file\n");
-		ret = -EFAULT;
 		goto fail_file;
 	}
-	dev->outstanding_file = debugfs_create_file("outstanding",
-			flags_read_only, dev->folder, dev,
-			&ecm_ipa_debugfs_atomic_ops);
-	if (!dev->outstanding_file) {
+	file = debugfs_create_file("dma_enable", flags_read_write,
+			dev->directory, dev, &ecm_ipa_debugfs_dma_ops);
+	if (!file) {
+		ECM_IPA_ERROR("could not create debugfs dma file\n");
+		goto fail_file;
+	}
+	file = debugfs_create_file("outstanding", flags_read_only,
+			dev->directory, dev, &ecm_ipa_debugfs_atomic_ops);
+	if (!file) {
 		ECM_IPA_ERROR("could not create outstanding file\n");
-		ret = -EFAULT;
 		goto fail_file;
 	}
 
 	ECM_IPA_LOG_EXIT();
 	return 0;
 fail_file:
-	debugfs_remove_recursive(dev->folder);
-fail_folder:
-	return ret;
+	debugfs_remove_recursive(dev->directory);
+fail_directory:
+	return -EFAULT;
 }
 
 static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev)
 {
-	debugfs_remove_recursive(dev->folder);
+	debugfs_remove_recursive(dev->directory);
 }
 
 static void eth_get_drvinfo(struct net_device *net,
diff --git a/drivers/platform/msm/ipa/a2_service.c b/drivers/platform/msm/ipa/a2_service.c
index 1b33dc0..26353ec 100644
--- a/drivers/platform/msm/ipa/a2_service.c
+++ b/drivers/platform/msm/ipa/a2_service.c
@@ -86,8 +86,10 @@
 	struct list_head bam_tx_pool;
 	spinlock_t bam_tx_pool_spinlock;
 	struct workqueue_struct *a2_mux_tx_workqueue;
+	struct workqueue_struct *a2_mux_rx_workqueue;
 	int a2_mux_initialized;
 	bool bam_is_connected;
+	bool bam_connect_in_progress;
 	int a2_mux_send_power_vote_on_init_once;
 	int a2_mux_sw_bridge_is_connected;
 	u32 a2_device_handle;
@@ -237,7 +239,6 @@
 		INIT_COMPLETION(a2_mux_ctx->ul_wakeup_ack_completion);
 		power_vote(0);
 	}
-	a2_mux_ctx->bam_is_connected = false;
 }
 
 static void ul_wakeup(void)
@@ -245,7 +246,8 @@
 	int ret;
 
 	mutex_lock(&a2_mux_ctx->wakeup_lock);
-	if (a2_mux_ctx->bam_is_connected) {
+	if (a2_mux_ctx->bam_is_connected &&
+				!a2_mux_ctx->bam_connect_in_progress) {
 		IPADBG("%s Already awake\n", __func__);
 		mutex_unlock(&a2_mux_ctx->wakeup_lock);
 		return;
@@ -259,7 +261,6 @@
 			grab_wakelock();
 		else
 			a2_mux_ctx->a2_pc_disabled_wakelock_skipped = 1;
-		a2_mux_ctx->bam_is_connected = true;
 		mutex_unlock(&a2_mux_ctx->wakeup_lock);
 		return;
 	}
@@ -298,7 +299,6 @@
 			goto bail;
 		}
 	}
-	a2_mux_ctx->bam_is_connected = true;
 	IPADBG("%s complete\n", __func__);
 	mutex_unlock(&a2_mux_ctx->wakeup_lock);
 	return;
@@ -367,26 +367,82 @@
 		dev_kfree_skb_any(skb);
 }
 
+static bool msm_bam_dmux_kickoff_ul_power_down(void)
+
+{
+	bool is_connected;
+
+	write_lock(&a2_mux_ctx->ul_wakeup_lock);
+	if (a2_mux_ctx->bam_connect_in_progress) {
+		a2_mux_ctx->bam_is_connected = false;
+		is_connected = true;
+	} else {
+		is_connected = a2_mux_ctx->bam_is_connected;
+		a2_mux_ctx->bam_is_connected = false;
+		if (is_connected) {
+			a2_mux_ctx->bam_connect_in_progress = true;
+			queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
+				&a2_mux_ctx->kickoff_ul_power_down);
+		}
+	}
+	write_unlock(&a2_mux_ctx->ul_wakeup_lock);
+	return is_connected;
+}
+
+static bool msm_bam_dmux_kickoff_ul_wakeup(void)
+{
+	bool is_connected;
+
+	write_lock(&a2_mux_ctx->ul_wakeup_lock);
+	if (a2_mux_ctx->bam_connect_in_progress) {
+		a2_mux_ctx->bam_is_connected = true;
+		is_connected = false;
+	} else {
+		is_connected = a2_mux_ctx->bam_is_connected;
+		a2_mux_ctx->bam_is_connected = true;
+		if (!is_connected) {
+			a2_mux_ctx->bam_connect_in_progress = true;
+			queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
+				&a2_mux_ctx->kickoff_ul_wakeup);
+		}
+	}
+	write_unlock(&a2_mux_ctx->ul_wakeup_lock);
+	return is_connected;
+}
+
 static void kickoff_ul_power_down_func(struct work_struct *work)
 {
-	unsigned long flags;
+	bool is_connected;
 
-	write_lock_irqsave(&a2_mux_ctx->ul_wakeup_lock, flags);
-	if (a2_mux_ctx->bam_is_connected) {
-		IPADBG("%s: UL active - forcing powerdown\n", __func__);
-		ul_powerdown();
-	}
-	write_unlock_irqrestore(&a2_mux_ctx->ul_wakeup_lock, flags);
-	ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
-			IPA_RM_RESOURCE_A2_CONS);
+	IPADBG("%s: UL active - forcing powerdown\n", __func__);
+	ul_powerdown();
+	write_lock(&a2_mux_ctx->ul_wakeup_lock);
+	is_connected = a2_mux_ctx->bam_is_connected;
+	a2_mux_ctx->bam_is_connected = false;
+	a2_mux_ctx->bam_connect_in_progress = false;
+	write_unlock(&a2_mux_ctx->ul_wakeup_lock);
+	if (is_connected)
+		msm_bam_dmux_kickoff_ul_wakeup();
+	else
+		ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
+						IPA_RM_RESOURCE_A2_CONS);
 }
 
 static void kickoff_ul_wakeup_func(struct work_struct *work)
 {
-	if (!a2_mux_ctx->bam_is_connected)
-		ul_wakeup();
-	ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
+	bool is_connected;
+
+	ul_wakeup();
+	write_lock(&a2_mux_ctx->ul_wakeup_lock);
+	is_connected = a2_mux_ctx->bam_is_connected;
+	a2_mux_ctx->bam_is_connected = true;
+	a2_mux_ctx->bam_connect_in_progress = false;
+	write_unlock(&a2_mux_ctx->ul_wakeup_lock);
+	if (is_connected)
+		ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
 			IPA_RM_RESOURCE_A2_CONS);
+	else
+		msm_bam_dmux_kickoff_ul_power_down();
 }
 
 static void kickoff_ul_request_resource_func(struct work_struct *work)
@@ -414,33 +470,6 @@
 	toggle_apps_ack();
 }
 
-static bool msm_bam_dmux_kickoff_ul_wakeup(void)
-{
-	bool is_connected;
-
-	read_lock(&a2_mux_ctx->ul_wakeup_lock);
-	is_connected = a2_mux_ctx->bam_is_connected;
-	read_unlock(&a2_mux_ctx->ul_wakeup_lock);
-	if (!is_connected)
-		queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
-			   &a2_mux_ctx->kickoff_ul_wakeup);
-	return is_connected;
-}
-
-static bool msm_bam_dmux_kickoff_ul_power_down(void)
-
-{
-	bool is_connected;
-
-	read_lock(&a2_mux_ctx->ul_wakeup_lock);
-	is_connected = a2_mux_ctx->bam_is_connected;
-	read_unlock(&a2_mux_ctx->ul_wakeup_lock);
-	if (is_connected)
-		queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
-			   &a2_mux_ctx->kickoff_ul_power_down);
-	return is_connected;
-}
-
 static void ipa_embedded_notify(void *priv,
 				enum ipa_dp_evt_type evt,
 				unsigned long data)
@@ -491,10 +520,6 @@
 				__func__);
 		return -EFAULT;
 	}
-	ret = sps_device_reset(a2_mux_ctx->a2_device_handle);
-	if (ret)
-		IPAERR("%s: device reset failed ret = %d\n",
-		       __func__, ret);
 	memset(&connect_params, 0, sizeof(struct ipa_sys_connect_params));
 	connect_params.client = IPA_CLIENT_A2_TETHERED_CONS;
 	connect_params.notify = ipa_tethered_notify;
@@ -606,12 +631,6 @@
 				__func__, ret);
 		return ret;
 	}
-	ret = sps_device_reset(a2_mux_ctx->a2_device_handle);
-	if (ret) {
-		IPAERR("%s: device reset failed ret = %d\n",
-			__func__, ret);
-		return ret;
-	}
 	verify_tx_queue_is_empty(__func__);
 	(void) ipa_rm_release_resource(IPA_RM_RESOURCE_A2_PROD);
 	if (a2_mux_ctx->disconnect_ack)
@@ -641,7 +660,7 @@
 		IPA_STATS_INC_CNT(ipa_ctx->stats.a2_power_on_reqs_in);
 		grab_wakelock();
 		(void) connect_to_bam();
-		queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
+		queue_work(a2_mux_ctx->a2_mux_rx_workqueue,
 			   &a2_mux_ctx->kickoff_ul_request_resource);
 	} else if (!(new_state & SMSM_A2_POWER_CONTROL)) {
 		IPADBG("%s: MODEM PWR CTRL 0\n", __func__);
@@ -936,7 +955,8 @@
 	}
 	spin_unlock_irqrestore(&a2_mux_ctx->bam_ch[id].lock, flags);
 	read_lock(&a2_mux_ctx->ul_wakeup_lock);
-	is_connected = a2_mux_ctx->bam_is_connected;
+	is_connected = a2_mux_ctx->bam_is_connected &&
+					!a2_mux_ctx->bam_connect_in_progress;
 	read_unlock(&a2_mux_ctx->ul_wakeup_lock);
 	if (!is_connected)
 		return -ENODEV;
@@ -1240,7 +1260,8 @@
 	a2_mux_ctx->bam_ch[lcid].use_wm = 0;
 	spin_unlock_irqrestore(&a2_mux_ctx->bam_ch[lcid].lock, flags);
 	read_lock(&a2_mux_ctx->ul_wakeup_lock);
-	is_connected = a2_mux_ctx->bam_is_connected;
+	is_connected = a2_mux_ctx->bam_is_connected &&
+					!a2_mux_ctx->bam_connect_in_progress;
 	read_unlock(&a2_mux_ctx->ul_wakeup_lock);
 	if (!is_connected)
 		return -ENODEV;
@@ -1309,7 +1330,8 @@
 	if (!a2_mux_ctx->a2_mux_initialized)
 		return -ENODEV;
 	read_lock(&a2_mux_ctx->ul_wakeup_lock);
-	is_connected = a2_mux_ctx->bam_is_connected;
+	is_connected = a2_mux_ctx->bam_is_connected &&
+					!a2_mux_ctx->bam_connect_in_progress;
 	read_unlock(&a2_mux_ctx->ul_wakeup_lock);
 	if (!is_connected && !bam_ch_is_in_reset(lcid))
 		return -ENODEV;
@@ -1456,6 +1478,13 @@
 		       __func__);
 		return -ENOMEM;
 	}
+	a2_mux_ctx->a2_mux_rx_workqueue =
+		create_singlethread_workqueue("a2_mux_rx");
+	if (!a2_mux_ctx->a2_mux_rx_workqueue) {
+		IPAERR("%s: a2_mux_rx_workqueue alloc failed\n",
+			__func__);
+		return -ENOMEM;
+	}
 	return 0;
 }
 
@@ -1581,5 +1610,7 @@
 				NULL);
 	if (a2_mux_ctx->a2_mux_tx_workqueue)
 		destroy_workqueue(a2_mux_ctx->a2_mux_tx_workqueue);
+	if (a2_mux_ctx->a2_mux_rx_workqueue)
+		destroy_workqueue(a2_mux_ctx->a2_mux_rx_workqueue);
 	return 0;
 }
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 466e694..35b2561 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -778,66 +778,6 @@
 	return ret;
 }
 
-static int ipa_handle_tx_poll_for_pipe(struct ipa_sys_context *sys,
-		bool process_all)
-{
-	struct ipa_tx_pkt_wrapper *tx_pkt, *t;
-	struct sps_iovec iov;
-	unsigned long irq_flags;
-	int ret;
-	int cnt = 0;
-
-	do {
-		iov.addr = 0;
-		ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
-		if (ret) {
-			pr_err("%s: sps_get_iovec failed %d\n", __func__, ret);
-			break;
-		}
-		if (!iov.addr)
-			break;
-		spin_lock_irqsave(&sys->spinlock, irq_flags);
-		tx_pkt = list_first_entry(&sys->head_desc_list,
-					  struct ipa_tx_pkt_wrapper, link);
-		spin_unlock_irqrestore(&sys->spinlock, irq_flags);
-
-		switch (tx_pkt->cnt) {
-		case 1:
-			ipa_wq_write_done(&tx_pkt->work);
-			++cnt;
-			break;
-		case 0xFFFF:
-			/* reached end of set */
-			spin_lock_irqsave(&sys->spinlock, irq_flags);
-			list_for_each_entry_safe(tx_pkt, t,
-						 &sys->wait_desc_list, link) {
-				list_del(&tx_pkt->link);
-				list_add(&tx_pkt->link, &sys->head_desc_list);
-			}
-			tx_pkt =
-			   list_first_entry(&sys->head_desc_list,
-					    struct ipa_tx_pkt_wrapper, link);
-			spin_unlock_irqrestore(&sys->spinlock, irq_flags);
-			ipa_wq_write_done(&tx_pkt->work);
-			++cnt;
-			break;
-		default:
-			/* keep looping till reach the end of the set */
-			spin_lock_irqsave(&sys->spinlock,
-					  irq_flags);
-			list_del(&tx_pkt->link);
-			list_add_tail(&tx_pkt->link,
-				      &sys->wait_desc_list);
-			spin_unlock_irqrestore(&sys->spinlock,
-					       irq_flags);
-			++cnt;
-			break;
-		}
-	} while (process_all);
-
-	return cnt;
-}
-
 static void ipa_poll_function(struct work_struct *work)
 {
 	int ret;
@@ -857,13 +797,15 @@
 
 		/* check all the system pipes for tx comp and rx avail */
 		if (ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep->valid)
-			cnt |= ipa_handle_rx_core(false, true);
+			cnt |= ipa_handle_rx_core(
+					&ipa_ctx->sys[IPA_A5_LAN_WAN_IN],
+					false, true);
 
 		for (i = 0; i < num_tx_pipes; i++)
 			if (ipa_ctx->sys[tx_pipes[i]].ep->valid)
-				cnt |= ipa_handle_tx_poll_for_pipe(
+				cnt |= ipa_handle_tx_core(
 						&ipa_ctx->sys[tx_pipes[i]],
-						false);
+						false, true);
 	} while (cnt);
 
 	/* re-post the poll work */
@@ -1666,10 +1608,6 @@
 
 	IPADBG("polling_mode=%u delay_ms=%u\n", polling_mode, polling_delay_ms);
 	ipa_ctx->polling_mode = polling_mode;
-	if (ipa_ctx->polling_mode)
-		atomic_set(&ipa_ctx->curr_polling_state, 1);
-	else
-		atomic_set(&ipa_ctx->curr_polling_state, 0);
 	IPADBG("hdr_lcl=%u ip4_rt=%u ip6_rt=%u ip4_flt=%u ip6_flt=%u\n",
 	       hdr_tbl_lcl, ip4_rt_tbl_lcl, ip6_rt_tbl_lcl, ip4_flt_tbl_lcl,
 	       ip6_flt_tbl_lcl);
@@ -1891,7 +1829,10 @@
 			ipa_ctx->sys[i].ep = &ipa_ctx->ep[i];
 		else
 			ipa_ctx->sys[i].ep = &ipa_ctx->ep[WLAN_AMPDU_TX_EP];
-		INIT_LIST_HEAD(&ipa_ctx->sys[i].wait_desc_list);
+		if (ipa_ctx->polling_mode)
+			atomic_set(&ipa_ctx->sys[i].curr_polling_state, 1);
+		else
+			atomic_set(&ipa_ctx->sys[i].curr_polling_state, 0);
 	}
 
 	ipa_ctx->rx_wq = create_singlethread_workqueue("ipa rx wq");
@@ -1901,7 +1842,8 @@
 		goto fail_rx_wq;
 	}
 
-	ipa_ctx->tx_wq = create_singlethread_workqueue("ipa tx wq");
+	ipa_ctx->tx_wq = alloc_workqueue("ipa tx wq", WQ_MEM_RECLAIM |
+			WQ_CPU_INTENSIVE, 2);
 	if (!ipa_ctx->tx_wq) {
 		IPAERR(":fail to create tx wq\n");
 		result = -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index a78879d..a95eafe 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -15,18 +15,14 @@
 
 static void ipa_enable_data_path(u32 clnt_hdl)
 {
-	struct ipa_ep_context *ep = &ipa_ctx->ep[clnt_hdl];
-
 	if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_VIRTUAL) {
 		/* IPA_HW_MODE_VIRTUAL lacks support for TAG IC & EP suspend */
 		return;
 	}
 
-	if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1 && ep->suspended) {
+	if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1)
 		ipa_write_reg(ipa_ctx->mmio,
 				IPA_ENDP_INIT_CTRL_n_OFST(clnt_hdl), 0);
-		ep->suspended = false;
-	}
 }
 
 static int ipa_disable_data_path(u32 clnt_hdl)
@@ -50,7 +46,7 @@
 		goto fail_alloc;
 	}
 
-	if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1 && !ep->suspended) {
+	if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1) {
 		ipa_write_reg(ipa_ctx->mmio,
 				IPA_ENDP_INIT_CTRL_n_OFST(clnt_hdl), 1);
 
@@ -85,7 +81,6 @@
 				ep->cfg.aggr.aggr_en == IPA_ENABLE_AGGR &&
 				ep->cfg.aggr.aggr_time_limit)
 			msleep(ep->cfg.aggr.aggr_time_limit);
-		ep->suspended = true;
 	}
 
 	return 0;
@@ -298,7 +293,9 @@
 	if (in->client == IPA_CLIENT_HSIC1_CONS ||
 			in->client == IPA_CLIENT_HSIC2_CONS ||
 			in->client == IPA_CLIENT_HSIC3_CONS ||
-			in->client == IPA_CLIENT_HSIC4_CONS) {
+			in->client == IPA_CLIENT_HSIC4_CONS ||
+			in->client == IPA_CLIENT_A2_TETHERED_CONS ||
+			in->client == IPA_CLIENT_A2_EMBEDDED_CONS) {
 		IPADBG("disable holb for ep=%d tmr=%d\n", ipa_ep_idx,
 			ipa_ctx->hol_timer);
 		ipa_write_reg(ipa_ctx->mmio,
@@ -367,6 +364,11 @@
 
 	ep = &ipa_ctx->ep[clnt_hdl];
 
+	if (ep->suspended) {
+		ipa_inc_client_enable_clks();
+		ep->suspended = false;
+	}
+
 	result = ipa_disable_data_path(clnt_hdl);
 	if (result) {
 		IPAERR("disable data path failed res=%d clnt=%d.\n", result,
@@ -422,55 +424,79 @@
 EXPORT_SYMBOL(ipa_disconnect);
 
 /**
- * ipa_connection_suspend() - suspend B2B connection to/from IPA
+ * ipa_resume() - low-level IPA client resume
  * @clnt_hdl:	[in] opaque client handle assigned by IPA to client
  *
- * Should be called by the driver of the peripheral that wants to suspend
- * its BAM-BAM connection to/from IPA in BAM-BAM mode. The pipe is not
- * disconnected and must later be resumed before data transfer can begin
+ * Should be called by the driver of the peripheral that wants to resume IPA
+ * connection. Resume IPA connection results in turning on IPA clocks in
+ * case they were off as a result of suspend.
+ * this api can be called only if a call to ipa_suspend() was
+ * made.
  *
  * Returns:	0 on success, negative on failure
  *
  * Note:	Should not be called from atomic context
  */
-int ipa_connection_suspend(u32 clnt_hdl)
+int ipa_resume(u32 clnt_hdl)
 {
-	int result;
+	struct ipa_ep_context *ep;
 
 	if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
-		IPAERR("bad parm.\n");
-		return -EINVAL;
-	}
-	result = ipa_disable_data_path(clnt_hdl);
-	if (result)
-		IPAERR("disable data path failed res=%d clnt=%d.\n", result,
-				clnt_hdl);
-
-	return result;
-}
-EXPORT_SYMBOL(ipa_connection_suspend);
-
-/**
- * ipa_connection_resume() - resume B2B connection to/from IPA
- * @clnt_hdl:	[in] opaque client handle assigned by IPA to client
- *
- * Should be called by the driver of the peripheral that wants to resume
- * its previously suspended BAM-BAM connection to/from IPA in BAM-BAM mode.
- *
- * Returns:	0 on success, negative on failure
- *
- * Note:	Should not be called from atomic context
- */
-int ipa_connection_resume(u32 clnt_hdl)
-{
-	if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
-		IPAERR("bad parm.\n");
+		IPAERR("bad parm. clnt_hdl %d\n", clnt_hdl);
 		return -EINVAL;
 	}
 
-	ipa_enable_data_path(clnt_hdl);
+	ep = &ipa_ctx->ep[clnt_hdl];
+
+	if (!ep->suspended) {
+		IPAERR("EP not suspended. clnt_hdl %d\n", clnt_hdl);
+		return -EPERM;
+	}
+
+	ipa_inc_client_enable_clks();
+	ep->suspended = false;
 
 	return 0;
 }
-EXPORT_SYMBOL(ipa_connection_resume);
+EXPORT_SYMBOL(ipa_resume);
 
+/**
+* ipa_suspend() - low-level IPA client suspend
+* @clnt_hdl:	[in] opaque client handle assigned by IPA to client
+*
+* Should be called by the driver of the peripheral that wants to suspend IPA
+* connection. Suspend IPA connection results in turning off IPA clocks in
+* case that there is no active clients using IPA. Pipes remains connected in
+* case of suspend.
+*
+* Returns:	0 on success, negative on failure
+*
+* Note:	Should not be called from atomic context
+*/
+int ipa_suspend(u32 clnt_hdl)
+{
+	struct ipa_ep_context *ep;
+
+	if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
+		IPAERR("bad parm. clnt_hdl %d\n", clnt_hdl);
+		return -EINVAL;
+	}
+
+	ep = &ipa_ctx->ep[clnt_hdl];
+
+	if (ep->suspended) {
+		IPAERR("EP already suspended. clnt_hdl %d\n", clnt_hdl);
+		return -EPERM;
+	}
+
+	if (IPA_CLIENT_IS_CONS(ep->client) &&
+				ep->cfg.aggr.aggr_en == IPA_ENABLE_AGGR &&
+				ep->cfg.aggr.aggr_time_limit)
+		msleep(ep->cfg.aggr.aggr_time_limit);
+
+	ipa_dec_client_disable_clks();
+	ep->suspended = true;
+
+	return 0;
+}
+EXPORT_SYMBOL(ipa_suspend);
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index fb69817..b11c7da 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -104,6 +104,7 @@
 static struct dentry *dfile_stats;
 static struct dentry *dfile_dbg_cnt;
 static struct dentry *dfile_msg;
+static struct dentry *dfile_ip4_nat;
 static char dbg_buff[IPA_MAX_MSG_LEN];
 static s8 ep_reg_idx;
 
@@ -608,6 +609,7 @@
 			"rx=%u\n"
 			"rx_repl_repost=%u\n"
 			"x_intr_repost=%u\n"
+			"x_intr_repost_tx=%u\n"
 			"rx_q_len=%u\n"
 			"act_clnt=%u\n"
 			"con_clnt_bmap=0x%x\n"
@@ -622,6 +624,7 @@
 			ipa_ctx->stats.rx_pkts,
 			ipa_ctx->stats.rx_repl_repost,
 			ipa_ctx->stats.x_intr_repost,
+			ipa_ctx->stats.x_intr_repost_tx,
 			ipa_ctx->stats.rx_q_len,
 			ipa_ctx->ipa_active_clients,
 			connect,
@@ -720,6 +723,238 @@
 	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
 }
 
+static ssize_t ipa_read_nat4(struct file *file,
+		char __user *ubuf, size_t count,
+		loff_t *ppos) {
+
+#define ENTRY_U32_FIELDS 8
+#define NAT_ENTRY_ENABLE 0x8000
+#define NAT_ENTRY_RST_FIN_BIT 0x4000
+#define BASE_TABLE 0
+#define EXPANSION_TABLE 1
+
+	u32 *base_tbl, *indx_tbl;
+	u32 tbl_size, *tmp;
+	u32 value, i, j, rule_id;
+	u16 enable, tbl_entry, flag;
+	int nbytes, cnt;
+
+	cnt = 0;
+	value = ipa_ctx->nat_mem.public_ip_addr;
+	nbytes = scnprintf(dbg_buff + cnt,
+				IPA_MAX_MSG_LEN,
+				"Table IP Address:%d.%d.%d.%d\n",
+				((value & 0xFF000000) >> 24),
+				((value & 0x00FF0000) >> 16),
+				((value & 0x0000FF00) >> 8),
+				((value & 0x000000FF)));
+	cnt += nbytes;
+
+	nbytes = scnprintf(dbg_buff + cnt,
+				IPA_MAX_MSG_LEN,
+				"Table Size:%d\n",
+				ipa_ctx->nat_mem.size_base_tables);
+	cnt += nbytes;
+
+	nbytes = scnprintf(dbg_buff + cnt,
+				IPA_MAX_MSG_LEN,
+				"Expansion Table Size:%d\n",
+				ipa_ctx->nat_mem.size_expansion_tables);
+	cnt += nbytes;
+
+	if (!ipa_ctx->nat_mem.is_sys_mem) {
+		nbytes = scnprintf(dbg_buff + cnt,
+					IPA_MAX_MSG_LEN,
+					"Not supported for local(shared) memory\n");
+		cnt += nbytes;
+
+		return simple_read_from_buffer(ubuf, count,
+						ppos, dbg_buff, cnt);
+	}
+
+
+	/* Print Base tables */
+	rule_id = 0;
+	for (j = 0; j < 2; j++) {
+		if (j == BASE_TABLE) {
+			tbl_size = ipa_ctx->nat_mem.size_base_tables;
+			base_tbl = (u32 *)ipa_ctx->nat_mem.ipv4_rules_addr;
+
+			nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+					"\nBase Table:\n");
+			cnt += nbytes;
+		} else {
+			tbl_size = ipa_ctx->nat_mem.size_expansion_tables;
+			base_tbl =
+			 (u32 *)ipa_ctx->nat_mem.ipv4_expansion_rules_addr;
+
+			nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+					"\nExpansion Base Table:\n");
+			cnt += nbytes;
+		}
+
+		if (base_tbl != NULL) {
+			for (i = 0; i <= tbl_size; i++, rule_id++) {
+				tmp = base_tbl;
+				value = tmp[4];
+				enable = ((value & 0xFFFF0000) >> 16);
+
+				if (enable & NAT_ENTRY_ENABLE) {
+					nbytes = scnprintf(dbg_buff + cnt,
+								IPA_MAX_MSG_LEN,
+								"Rule:%d ",
+								rule_id);
+					cnt += nbytes;
+
+					value = *tmp;
+					nbytes = scnprintf(dbg_buff + cnt,
+						IPA_MAX_MSG_LEN,
+						"Private_IP:%d.%d.%d.%d ",
+						((value & 0xFF000000) >> 24),
+						((value & 0x00FF0000) >> 16),
+						((value & 0x0000FF00) >> 8),
+						((value & 0x000000FF)));
+					cnt += nbytes;
+					tmp++;
+
+					value = *tmp;
+					nbytes = scnprintf(dbg_buff + cnt,
+						IPA_MAX_MSG_LEN,
+						"Target_IP:%d.%d.%d.%d ",
+						((value & 0xFF000000) >> 24),
+						((value & 0x00FF0000) >> 16),
+						((value & 0x0000FF00) >> 8),
+						((value & 0x000000FF)));
+					cnt += nbytes;
+					tmp++;
+
+					value = *tmp;
+					nbytes = scnprintf(dbg_buff + cnt,
+						IPA_MAX_MSG_LEN,
+						"Next_Index:%d  Public_Port:%d ",
+						(value & 0x0000FFFF),
+						((value & 0xFFFF0000) >> 16));
+					cnt += nbytes;
+					tmp++;
+
+					value = *tmp;
+					nbytes = scnprintf(dbg_buff + cnt,
+						IPA_MAX_MSG_LEN,
+						"Private_Port:%d  Target_Port:%d ",
+						(value & 0x0000FFFF),
+						((value & 0xFFFF0000) >> 16));
+					cnt += nbytes;
+					tmp++;
+
+					value = *tmp;
+					nbytes = scnprintf(dbg_buff + cnt,
+						IPA_MAX_MSG_LEN,
+						"IP-CKSM-delta:0x%x  ",
+						(value & 0x0000FFFF));
+					cnt += nbytes;
+
+					flag = ((value & 0xFFFF0000) >> 16);
+					if (flag & NAT_ENTRY_RST_FIN_BIT) {
+						nbytes =
+						 scnprintf(dbg_buff + cnt,
+							  IPA_MAX_MSG_LEN,
+								"IP_CKSM_delta:0x%x  Flags:%s ",
+							  (value & 0x0000FFFF),
+								"Direct_To_A5");
+						cnt += nbytes;
+					} else {
+						nbytes =
+						 scnprintf(dbg_buff + cnt,
+							IPA_MAX_MSG_LEN,
+							"IP_CKSM_delta:0x%x  Flags:%s ",
+							(value & 0x0000FFFF),
+							"Fwd_to_route");
+						cnt += nbytes;
+					}
+					tmp++;
+
+					value = *tmp;
+					nbytes = scnprintf(dbg_buff + cnt,
+						IPA_MAX_MSG_LEN,
+						"Time_stamp:0x%x Proto:%d ",
+						(value & 0x00FFFFFF),
+						((value & 0xFF000000) >> 27));
+					cnt += nbytes;
+					tmp++;
+
+					value = *tmp;
+					nbytes = scnprintf(dbg_buff + cnt,
+						IPA_MAX_MSG_LEN,
+						"Prev_Index:%d  Indx_tbl_entry:%d ",
+						(value & 0x0000FFFF),
+						((value & 0xFFFF0000) >> 16));
+					cnt += nbytes;
+					tmp++;
+
+					value = *tmp;
+					nbytes = scnprintf(dbg_buff + cnt,
+						IPA_MAX_MSG_LEN,
+						"TCP_UDP_cksum_delta:0x%x\n",
+						((value & 0xFFFF0000) >> 16));
+					cnt += nbytes;
+				}
+
+				base_tbl += ENTRY_U32_FIELDS;
+
+			}
+		}
+	}
+
+	/* Print Index tables */
+	rule_id = 0;
+	for (j = 0; j < 2; j++) {
+		if (j == BASE_TABLE) {
+			tbl_size = ipa_ctx->nat_mem.size_base_tables;
+			indx_tbl = (u32 *)ipa_ctx->nat_mem.index_table_addr;
+
+			nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+					"\nIndex Table:\n");
+			cnt += nbytes;
+		} else {
+			tbl_size = ipa_ctx->nat_mem.size_expansion_tables;
+			indx_tbl =
+			 (u32 *)ipa_ctx->nat_mem.index_table_expansion_addr;
+
+			nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+					"\nExpansion Index Table:\n");
+			cnt += nbytes;
+		}
+
+		if (indx_tbl != NULL) {
+			for (i = 0; i <= tbl_size; i++, rule_id++) {
+				tmp = indx_tbl;
+				value = *tmp;
+				tbl_entry = (value & 0x0000FFFF);
+
+				if (tbl_entry) {
+					nbytes = scnprintf(dbg_buff + cnt,
+								IPA_MAX_MSG_LEN,
+								"Rule:%d ",
+								rule_id);
+					cnt += nbytes;
+
+					value = *tmp;
+					nbytes = scnprintf(dbg_buff + cnt,
+						IPA_MAX_MSG_LEN,
+						"Table_Entry:%d  Next_Index:%d\n",
+						tbl_entry,
+						((value & 0xFFFF0000) >> 16));
+					cnt += nbytes;
+				}
+
+				indx_tbl++;
+			}
+		}
+	}
+
+	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
+}
+
 const struct file_operations ipa_gen_reg_ops = {
 	.read = ipa_read_gen_reg,
 };
@@ -763,6 +998,10 @@
 	.write = ipa_write_dbg_cnt,
 };
 
+const struct file_operations ipa_nat4_ops = {
+	.read = ipa_read_nat4,
+};
+
 void ipa_debugfs_init(void)
 {
 	const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
@@ -860,6 +1099,13 @@
 		goto fail;
 	}
 
+	dfile_ip4_nat = debugfs_create_file("ip4_nat", read_only_mode, dent,
+			0, &ipa_nat4_ops);
+	if (!dfile_ip4_nat || IS_ERR(dfile_ip4_nat)) {
+		IPAERR("fail to create file for debug_fs ip4 nat\n");
+		goto fail;
+	}
+
 	return;
 
 fail:
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index 228c77fe..67728c2 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -20,14 +20,15 @@
 #define list_next_entry(pos, member) \
 	list_entry(pos->member.next, typeof(*pos), member)
 #define IPA_LAST_DESC_CNT 0xFFFF
-#define POLLING_INACTIVITY 40
-#define POLLING_MIN_SLEEP 950
-#define POLLING_MAX_SLEEP 1050
+#define POLLING_INACTIVITY_RX 40
+#define POLLING_MIN_SLEEP_RX 950
+#define POLLING_MAX_SLEEP_RX 1050
+#define POLLING_INACTIVITY_TX 40
+#define POLLING_MIN_SLEEP_TX 400
+#define POLLING_MAX_SLEEP_TX 500
 
 static void replenish_rx_work_func(struct work_struct *work);
 static struct delayed_work replenish_rx_work;
-static void switch_to_intr_work_func(struct work_struct *work);
-static struct delayed_work switch_to_intr_work;
 static void ipa_wq_handle_rx(struct work_struct *work);
 static DECLARE_WORK(rx_work, ipa_wq_handle_rx);
 
@@ -47,57 +48,164 @@
 void ipa_wq_write_done(struct work_struct *work)
 {
 	struct ipa_tx_pkt_wrapper *tx_pkt;
-	struct ipa_tx_pkt_wrapper *next_pkt;
 	struct ipa_tx_pkt_wrapper *tx_pkt_expected;
 	unsigned long irq_flags;
-	struct ipa_mem_buffer mult = { 0 };
-	int i;
-	u32 cnt;
 
 	tx_pkt = container_of(work, struct ipa_tx_pkt_wrapper, work);
-	cnt = tx_pkt->cnt;
-	IPADBG("cnt=%d\n", cnt);
 
-	if (unlikely(cnt == 0))
+	if (unlikely(tx_pkt == NULL))
 		WARN_ON(1);
+	WARN_ON(tx_pkt->cnt != 1);
 
-	if (cnt > 1 && cnt != IPA_LAST_DESC_CNT)
-		mult = tx_pkt->mult;
+	spin_lock_irqsave(&tx_pkt->sys->spinlock, irq_flags);
+	tx_pkt_expected = list_first_entry(&tx_pkt->sys->head_desc_list,
+					   struct ipa_tx_pkt_wrapper,
+					   link);
+	if (unlikely(tx_pkt != tx_pkt_expected)) {
+		spin_unlock_irqrestore(&tx_pkt->sys->spinlock,
+				irq_flags);
+		WARN_ON(1);
+	}
+	list_del(&tx_pkt->link);
+	spin_unlock_irqrestore(&tx_pkt->sys->spinlock, irq_flags);
+	if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
+		dma_pool_free(ipa_ctx->dma_pool,
+				tx_pkt->bounce,
+				tx_pkt->mem.phys_base);
+	} else {
+		dma_unmap_single(NULL, tx_pkt->mem.phys_base,
+				tx_pkt->mem.size,
+				DMA_TO_DEVICE);
+	}
 
-	for (i = 0; i < cnt; i++) {
-		if (unlikely(tx_pkt == NULL))
-			WARN_ON(1);
-		spin_lock_irqsave(&tx_pkt->sys->spinlock, irq_flags);
-		tx_pkt_expected = list_first_entry(&tx_pkt->sys->head_desc_list,
-						   struct ipa_tx_pkt_wrapper,
-						   link);
-		if (unlikely(tx_pkt != tx_pkt_expected)) {
-			spin_unlock_irqrestore(&tx_pkt->sys->spinlock,
-					irq_flags);
-			WARN_ON(1);
+	if (tx_pkt->callback)
+		tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
+
+	kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+}
+
+int ipa_handle_tx_core(struct ipa_sys_context *sys, bool process_all,
+		bool in_poll_state)
+{
+	struct ipa_tx_pkt_wrapper *tx_pkt;
+	struct sps_iovec iov;
+	int ret;
+	int cnt = 0;
+	unsigned long irq_flags;
+
+	while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
+				!atomic_read(&sys->curr_polling_state))) {
+		if (cnt && !process_all)
+			break;
+		ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
+		if (ret) {
+			IPAERR("sps_get_iovec failed %d\n", ret);
+			break;
 		}
-		next_pkt = list_next_entry(tx_pkt, link);
+
+		if (iov.addr == 0)
+			break;
+
+		if (unlikely(list_empty(&sys->head_desc_list)))
+			continue;
+
+		spin_lock_irqsave(&sys->spinlock, irq_flags);
+		tx_pkt = list_first_entry(&sys->head_desc_list,
+					  struct ipa_tx_pkt_wrapper, link);
+
+		sys->len--;
 		list_del(&tx_pkt->link);
-		spin_unlock_irqrestore(&tx_pkt->sys->spinlock, irq_flags);
-		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
+		spin_unlock_irqrestore(&sys->spinlock, irq_flags);
+
+		IPADBG("--curr_cnt=%d\n", sys->len);
+
+		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
 			dma_pool_free(ipa_ctx->dma_pool,
 					tx_pkt->bounce,
 					tx_pkt->mem.phys_base);
-		} else {
+		else
 			dma_unmap_single(NULL, tx_pkt->mem.phys_base,
 					tx_pkt->mem.size,
 					DMA_TO_DEVICE);
-		}
 
 		if (tx_pkt->callback)
 			tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
 
+		if (tx_pkt->cnt > 1 && tx_pkt->cnt != IPA_LAST_DESC_CNT)
+			dma_pool_free(ipa_ctx->dma_pool, tx_pkt->mult.base,
+					tx_pkt->mult.phys_base);
+
 		kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
-		tx_pkt = next_pkt;
+		cnt++;
+	};
+
+	return cnt;
+}
+
+/**
+ * ipa_tx_switch_to_intr_mode() - Operate the Tx data path in interrupt mode
+ */
+static void ipa_tx_switch_to_intr_mode(struct ipa_sys_context *sys)
+{
+	int ret;
+
+	if (!atomic_read(&sys->curr_polling_state)) {
+		IPAERR("already in intr mode\n");
+		goto fail;
 	}
 
-	if (mult.phys_base)
-		dma_pool_free(ipa_ctx->dma_pool, mult.base, mult.phys_base);
+	ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
+	if (ret) {
+		IPAERR("sps_get_config() failed %d\n", ret);
+		goto fail;
+	}
+	sys->event.options = SPS_O_EOT;
+	ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
+	if (ret) {
+		IPAERR("sps_register_event() failed %d\n", ret);
+		goto fail;
+	}
+	sys->ep->connect.options =
+		SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_EOT;
+	ret = sps_set_config(sys->ep->ep_hdl, &sys->ep->connect);
+	if (ret) {
+		IPAERR("sps_set_config() failed %d\n", ret);
+		goto fail;
+	}
+	atomic_set(&sys->curr_polling_state, 0);
+	ipa_handle_tx_core(sys, true, false);
+	return;
+
+fail:
+	IPA_STATS_INC_CNT(ipa_ctx->stats.x_intr_repost_tx);
+	schedule_delayed_work(&sys->switch_to_intr_work, msecs_to_jiffies(1));
+	return;
+}
+
+static void ipa_handle_tx(struct ipa_sys_context *sys)
+{
+	int inactive_cycles = 0;
+	int cnt;
+
+	do {
+		cnt = ipa_handle_tx_core(sys, true, true);
+		if (cnt == 0) {
+			inactive_cycles++;
+			usleep_range(POLLING_MIN_SLEEP_TX,
+					POLLING_MAX_SLEEP_TX);
+		} else {
+			inactive_cycles = 0;
+		}
+	} while (inactive_cycles <= POLLING_INACTIVITY_TX);
+
+	ipa_tx_switch_to_intr_mode(sys);
+}
+
+static void ipa_wq_handle_tx(struct work_struct *work)
+{
+	struct ipa_tx_pkt_wrapper *tx_pkt;
+	tx_pkt = container_of(work, struct ipa_tx_pkt_wrapper, work);
+	ipa_handle_tx(tx_pkt->sys);
 }
 
 /**
@@ -165,7 +273,6 @@
 	}
 
 	INIT_LIST_HEAD(&tx_pkt->link);
-	INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
 	tx_pkt->type = desc->type;
 	tx_pkt->cnt = 1;    /* only 1 desc in this "set" */
 
@@ -187,10 +294,15 @@
 		IPADBG("sending cmd=%d pyld_len=%d sps_flags=%x\n",
 				desc->opcode, desc->len, sps_flags);
 		IPA_DUMP_BUFF(desc->pyld, dma_address, desc->len);
+		INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
 	} else {
 		len = desc->len;
+		INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
 	}
 
+	if (unlikely(ipa_ctx->polling_mode))
+		INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
+
 	spin_lock_irqsave(&sys->spinlock, irq_flags);
 	list_add_tail(&tx_pkt->link, &sys->head_desc_list);
 	result = sps_transfer_one(sys->ep->ep_hdl, dma_address, len, tx_pkt,
@@ -286,7 +398,7 @@
 			tx_pkt->mult.base = transfer.iovec;
 			tx_pkt->mult.size = size;
 			tx_pkt->cnt = num_desc;
-			INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
+			INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
 		}
 
 		iovec = &transfer.iovec[i];
@@ -475,6 +587,49 @@
 
 /**
  * ipa_sps_irq_tx_notify() - Callback function which will be called by
+ * the SPS driver to start a Tx poll operation.
+ * Called in an interrupt context.
+ * @notify:	SPS driver supplied notification struct
+ *
+ * This function defer the work for this event to the tx workqueue.
+ */
+static void ipa_sps_irq_tx_notify(struct sps_event_notify *notify)
+{
+	struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_OUT];
+	struct ipa_tx_pkt_wrapper *tx_pkt;
+	int ret;
+
+	IPADBG("event %d notified\n", notify->event_id);
+
+	switch (notify->event_id) {
+	case SPS_EVENT_EOT:
+		tx_pkt = notify->data.transfer.user;
+		if (!atomic_read(&sys->curr_polling_state)) {
+			ret = sps_get_config(sys->ep->ep_hdl,
+					&sys->ep->connect);
+			if (ret) {
+				IPAERR("sps_get_config() failed %d\n", ret);
+				break;
+			}
+			sys->ep->connect.options = SPS_O_AUTO_ENABLE |
+				SPS_O_ACK_TRANSFERS | SPS_O_POLL;
+			ret = sps_set_config(sys->ep->ep_hdl,
+					&sys->ep->connect);
+			if (ret) {
+				IPAERR("sps_set_config() failed %d\n", ret);
+				break;
+			}
+			atomic_set(&sys->curr_polling_state, 1);
+			queue_work(ipa_ctx->tx_wq, &tx_pkt->work);
+		}
+		break;
+	default:
+		IPAERR("recieved unexpected event id %d\n", notify->event_id);
+	}
+}
+
+/**
+ * ipa_sps_irq_tx_no_aggr_notify() - Callback function which will be called by
  * the SPS driver after a Tx operation is complete.
  * Called in an interrupt context.
  * @notify:	SPS driver supplied notification struct
@@ -482,7 +637,7 @@
  * This function defer the work for this event to the tx workqueue.
  * This event will be later handled by ipa_write_done.
  */
-static void ipa_sps_irq_tx_notify(struct sps_event_notify *notify)
+static void ipa_sps_irq_tx_no_aggr_notify(struct sps_event_notify *notify)
 {
 	struct ipa_tx_pkt_wrapper *tx_pkt;
 
@@ -512,7 +667,8 @@
  *  - Call the endpoints notify function, passing the skb in the parameters
  *  - Replenish the rx cache
  */
-int ipa_handle_rx_core(bool process_all, bool in_poll_state)
+int ipa_handle_rx_core(struct ipa_sys_context *sys, bool process_all,
+		bool in_poll_state)
 {
 	struct ipa_a5_mux_hdr *mux_hdr;
 	struct ipa_rx_pkt_wrapper *rx_pkt;
@@ -521,15 +677,14 @@
 	unsigned int pull_len;
 	unsigned int padding;
 	int ret;
-	struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
 	struct ipa_ep_context *ep;
 	int cnt = 0;
 	struct completion *compl;
 	struct ipa_tree_node *node;
 	unsigned int src_pipe;
 
-	while ((in_poll_state ? atomic_read(&ipa_ctx->curr_polling_state) :
-				!atomic_read(&ipa_ctx->curr_polling_state))) {
+	while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
+				!atomic_read(&sys->curr_polling_state))) {
 		if (cnt && !process_all)
 			break;
 
@@ -654,19 +809,15 @@
 /**
  * ipa_rx_switch_to_intr_mode() - Operate the Rx data path in interrupt mode
  */
-static void ipa_rx_switch_to_intr_mode(void)
+static void ipa_rx_switch_to_intr_mode(struct ipa_sys_context *sys)
 {
 	int ret;
-	struct ipa_sys_context *sys;
 
-	IPADBG("Enter");
-	if (!atomic_read(&ipa_ctx->curr_polling_state)) {
+	if (!atomic_read(&sys->curr_polling_state)) {
 		IPAERR("already in intr mode\n");
 		goto fail;
 	}
 
-	sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
-
 	ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
 	if (ret) {
 		IPAERR("sps_get_config() failed %d\n", ret);
@@ -685,15 +836,16 @@
 		IPAERR("sps_set_config() failed %d\n", ret);
 		goto fail;
 	}
-	atomic_set(&ipa_ctx->curr_polling_state, 0);
-	ipa_handle_rx_core(true, false);
+	atomic_set(&sys->curr_polling_state, 0);
+	ipa_handle_rx_core(sys, true, false);
 	return;
 
 fail:
 	IPA_STATS_INC_CNT(ipa_ctx->stats.x_intr_repost);
-	schedule_delayed_work(&switch_to_intr_work, msecs_to_jiffies(1));
+	schedule_delayed_work(&sys->switch_to_intr_work, msecs_to_jiffies(1));
 }
 
+
 /**
  * ipa_rx_notify() - Callback function which is called by the SPS driver when a
  * a packet is received
@@ -709,29 +861,29 @@
  */
 static void ipa_sps_irq_rx_notify(struct sps_event_notify *notify)
 {
-	struct ipa_ep_context *ep;
+	struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
 	int ret;
 
 	IPADBG("event %d notified\n", notify->event_id);
 
 	switch (notify->event_id) {
 	case SPS_EVENT_EOT:
-		if (!atomic_read(&ipa_ctx->curr_polling_state)) {
-			ep = ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep;
-
-			ret = sps_get_config(ep->ep_hdl, &ep->connect);
+		if (!atomic_read(&sys->curr_polling_state)) {
+			ret = sps_get_config(sys->ep->ep_hdl,
+					&sys->ep->connect);
 			if (ret) {
 				IPAERR("sps_get_config() failed %d\n", ret);
 				break;
 			}
-			ep->connect.options = SPS_O_AUTO_ENABLE |
+			sys->ep->connect.options = SPS_O_AUTO_ENABLE |
 				SPS_O_ACK_TRANSFERS | SPS_O_POLL;
-			ret = sps_set_config(ep->ep_hdl, &ep->connect);
+			ret = sps_set_config(sys->ep->ep_hdl,
+					&sys->ep->connect);
 			if (ret) {
 				IPAERR("sps_set_config() failed %d\n", ret);
 				break;
 			}
-			atomic_set(&ipa_ctx->curr_polling_state, 1);
+			atomic_set(&sys->curr_polling_state, 1);
 			queue_work(ipa_ctx->rx_wq, &rx_work);
 		}
 		break;
@@ -740,6 +892,51 @@
 	}
 }
 
+static void switch_to_intr_tx_work_func(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct ipa_sys_context *sys;
+	dwork = container_of(work, struct delayed_work, work);
+	sys = container_of(dwork, struct ipa_sys_context, switch_to_intr_work);
+	ipa_handle_tx(sys);
+}
+
+/**
+ * ipa_handle_rx() - handle packet reception. This function is executed in the
+ * context of a work queue.
+ * @work: work struct needed by the work queue
+ *
+ * ipa_handle_rx_core() is run in polling mode. After all packets has been
+ * received, the driver switches back to interrupt mode.
+ */
+static void ipa_handle_rx(struct ipa_sys_context *sys)
+{
+	int inactive_cycles = 0;
+	int cnt;
+
+	do {
+		cnt = ipa_handle_rx_core(sys, true, true);
+		if (cnt == 0) {
+			inactive_cycles++;
+			usleep_range(POLLING_MIN_SLEEP_RX,
+					POLLING_MAX_SLEEP_RX);
+		} else {
+			inactive_cycles = 0;
+		}
+	} while (inactive_cycles <= POLLING_INACTIVITY_RX);
+
+	ipa_rx_switch_to_intr_mode(sys);
+}
+
+static void switch_to_intr_rx_work_func(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct ipa_sys_context *sys;
+	dwork = container_of(work, struct delayed_work, work);
+	sys = container_of(dwork, struct ipa_sys_context, switch_to_intr_work);
+	ipa_handle_rx(sys);
+}
+
 /**
  * ipa_setup_sys_pipe() - Setup an IPA end-point in system-BAM mode and perform
  * IPA EP configuration
@@ -858,14 +1055,18 @@
 
 	switch (ipa_ep_idx) {
 	case 1:
-		/* fall through */
+		sys_idx = ipa_ep_idx;
+		break;
 	case 2:
-		/* fall through */
+		sys_idx = ipa_ep_idx;
+		INIT_DELAYED_WORK(&ipa_ctx->sys[sys_idx].switch_to_intr_work,
+				switch_to_intr_tx_work_func);
+		break;
 	case 3:
 		sys_idx = ipa_ep_idx;
 		INIT_DELAYED_WORK(&replenish_rx_work, replenish_rx_work_func);
-		INIT_DELAYED_WORK(&switch_to_intr_work,
-				switch_to_intr_work_func);
+		INIT_DELAYED_WORK(&ipa_ctx->sys[sys_idx].switch_to_intr_work,
+				switch_to_intr_rx_work_func);
 		break;
 	case WLAN_AMPDU_TX_EP:
 		sys_idx = IPA_A5_WLAN_AMPDU_OUT;
@@ -886,7 +1087,10 @@
 		ipa_ctx->sys[sys_idx].event.callback =
 				IPA_CLIENT_IS_CONS(sys_in->client) ?
 					ipa_sps_irq_rx_notify :
-					ipa_sps_irq_tx_notify;
+					(sys_in->client ==
+					 IPA_CLIENT_A5_LAN_WAN_PROD ?
+					ipa_sps_irq_tx_notify :
+					ipa_sps_irq_tx_no_aggr_notify);
 		result = sps_register_event(ipa_ctx->ep[ipa_ep_idx].ep_hdl,
 					  &ipa_ctx->sys[sys_idx].event);
 		if (result < 0) {
@@ -1078,37 +1282,9 @@
 }
 EXPORT_SYMBOL(ipa_tx_dp);
 
-static void ipa_handle_rx(void)
-{
-	int inactive_cycles = 0;
-	int cnt;
-
-	ipa_inc_client_enable_clks();
-	do {
-		cnt = ipa_handle_rx_core(true, true);
-		if (cnt == 0) {
-			inactive_cycles++;
-			usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
-		} else {
-			inactive_cycles = 0;
-		}
-	} while (inactive_cycles <= POLLING_INACTIVITY);
-
-	ipa_rx_switch_to_intr_mode();
-	ipa_dec_client_disable_clks();
-}
-
-/**
- * ipa_handle_rx() - handle packet reception. This function is executed in the
- * context of a work queue.
- * @work: work struct needed by the work queue
- *
- * ipa_handle_rx_core() is run in polling mode. After all packets has been
- * received, the driver switches back to interrupt mode.
- */
 static void ipa_wq_handle_rx(struct work_struct *work)
 {
-	ipa_handle_rx();
+	ipa_handle_rx(&ipa_ctx->sys[IPA_A5_LAN_WAN_IN]);
 }
 
 /**
@@ -1202,11 +1378,6 @@
 	ipa_replenish_rx_cache();
 }
 
-static void switch_to_intr_work_func(struct work_struct *work)
-{
-	ipa_handle_rx();
-}
-
 /**
  * ipa_cleanup_rx() - release RX queue resources
  *
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index cc3e630..b57194e 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -372,7 +372,6 @@
  * @spinlock: protects the list and its size
  * @event: used to request CALLBACK mode from SPS driver
  * @ep: IPA EP context
- * @wait_desc_list: used to hold completed Tx packets
  *
  * IPA context specific to the system-bam pipes a.k.a LAN IN/OUT and WAN
  */
@@ -382,7 +381,8 @@
 	spinlock_t spinlock;
 	struct sps_register_event event;
 	struct ipa_ep_context *ep;
-	struct list_head wait_desc_list;
+	atomic_t curr_polling_state;
+	struct delayed_work switch_to_intr_work;
 };
 
 /**
@@ -479,6 +479,14 @@
  * @is_sys_mem: flag indicating if NAT memory is sys memory
  * @is_dev_init: flag indicating if NAT device is initialized
  * @lock: NAT memory mutex
+ * @nat_base_address: nat table virutal address
+ * @ipv4_rules_addr: base nat table address
+ * @ipv4_expansion_rules_addr: expansion table address
+ * @index_table_addr: index table address
+ * @index_table_expansion_addr: index expansion table address
+ * @size_base_tables: base table size
+ * @size_expansion_tables: expansion table size
+ * @public_ip_addr: ip address of nat table
  */
 struct ipa_nat_mem {
 	struct class *class;
@@ -492,6 +500,14 @@
 	bool is_sys_mem;
 	bool is_dev_init;
 	struct mutex lock;
+	void *nat_base_address;
+	char *ipv4_rules_addr;
+	char *ipv4_expansion_rules_addr;
+	char *index_table_addr;
+	char *index_table_expansion_addr;
+	u32 size_base_tables;
+	u32 size_expansion_tables;
+	u32 public_ip_addr;
 };
 
 /**
@@ -530,6 +546,7 @@
 	u32 bridged_pkts[IPA_BRIDGE_TYPE_MAX][IPA_BRIDGE_DIR_MAX];
 	u32 rx_repl_repost;
 	u32 x_intr_repost;
+	u32 x_intr_repost_tx;
 	u32 rx_q_len;
 	u32 msg_w[IPA_EVENT_MAX];
 	u32 msg_r[IPA_EVENT_MAX];
@@ -641,7 +658,6 @@
 	uint aggregation_type;
 	uint aggregation_byte_limit;
 	uint aggregation_time_limit;
-	atomic_t curr_polling_state;
 	struct delayed_work poll_work;
 	bool hdr_tbl_lcl;
 	struct ipa_mem_buffer hdr_mem;
@@ -800,7 +816,10 @@
 void ipa_cleanup_rx(void);
 int ipa_cfg_filter(u32 disable);
 void ipa_wq_write_done(struct work_struct *work);
-int ipa_handle_rx_core(bool process_all, bool in_poll_state);
+int ipa_handle_rx_core(struct ipa_sys_context *sys, bool process_all,
+		bool in_poll_state);
+int ipa_handle_tx_core(struct ipa_sys_context *sys, bool process_all,
+		bool in_poll_state);
 int ipa_pipe_mem_init(u32 start_ofst, u32 size);
 int ipa_pipe_mem_alloc(u32 *ofst, u32 size);
 int ipa_pipe_mem_free(u32 ofst, u32 size);
diff --git a/drivers/platform/msm/ipa/ipa_nat.c b/drivers/platform/msm/ipa/ipa_nat.c
index befa2cf..e2c344f 100644
--- a/drivers/platform/msm/ipa/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_nat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -75,6 +75,7 @@
 			IPAERR("unable to map memory. Err:%d\n", result);
 			goto bail;
 		}
+		ipa_ctx->nat_mem.nat_base_address = nat_ctx->vaddr;
 	} else {
 		IPADBG("Mapping shared(local) memory\n");
 		IPADBG("map sz=0x%lx\n", vsize);
@@ -88,7 +89,7 @@
 			result = -EAGAIN;
 			goto bail;
 		}
-
+		ipa_ctx->nat_mem.nat_base_address = (void *)vma->vm_start;
 	}
 	nat_ctx->is_mapped = true;
 	vma->vm_ops = &ipa_nat_remap_vm_ops;
@@ -299,6 +300,35 @@
 		goto free_cmd;
 	}
 
+	ipa_ctx->nat_mem.public_ip_addr = init->ip_addr;
+	IPADBG("Table ip address:0x%x", ipa_ctx->nat_mem.public_ip_addr);
+
+	ipa_ctx->nat_mem.ipv4_rules_addr =
+	 (char *)ipa_ctx->nat_mem.nat_base_address + init->ipv4_rules_offset;
+	IPADBG("ipv4_rules_addr: 0x%p\n",
+				 ipa_ctx->nat_mem.ipv4_rules_addr);
+
+	ipa_ctx->nat_mem.ipv4_expansion_rules_addr =
+	 (char *)ipa_ctx->nat_mem.nat_base_address + init->expn_rules_offset;
+	IPADBG("ipv4_expansion_rules_addr: 0x%p\n",
+				 ipa_ctx->nat_mem.ipv4_expansion_rules_addr);
+
+	ipa_ctx->nat_mem.index_table_addr =
+		 (char *)ipa_ctx->nat_mem.nat_base_address + init->index_offset;
+	IPADBG("index_table_addr: 0x%p\n",
+				 ipa_ctx->nat_mem.index_table_addr);
+
+	ipa_ctx->nat_mem.index_table_expansion_addr =
+	 (char *)ipa_ctx->nat_mem.nat_base_address + init->index_expn_offset;
+	IPADBG("index_table_expansion_addr: 0x%p\n",
+				 ipa_ctx->nat_mem.index_table_expansion_addr);
+
+	IPADBG("size_base_tables: %d\n", init->table_entries);
+	ipa_ctx->nat_mem.size_base_tables  = init->table_entries;
+
+	IPADBG("size_expansion_tables: %d\n", init->expn_table_entries);
+	ipa_ctx->nat_mem.size_expansion_tables = init->expn_table_entries;
+
 	IPADBG("return\n");
 	result = 0;
 free_cmd:
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
index 1fdd300..88a49c4 100644
--- a/drivers/platform/msm/ipa/ipa_rm.c
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -21,6 +21,7 @@
 struct ipa_rm_context_type {
 	struct ipa_rm_dep_graph *dep_graph;
 	struct workqueue_struct *ipa_rm_wq;
+	rwlock_t lock;
 };
 static struct ipa_rm_context_type *ipa_rm_ctx;
 
@@ -41,10 +42,9 @@
 	struct ipa_rm_resource *resource;
 	int result;
 
-	if (!create_params) {
-		result = -EINVAL;
-		goto bail;
-	}
+	if (!create_params)
+		return -EINVAL;
+	write_lock(&ipa_rm_ctx->lock);
 	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
 					  create_params->name,
 					  &resource) == 0) {
@@ -59,11 +59,51 @@
 	if (result)
 		ipa_rm_resource_delete(resource);
 bail:
+	write_unlock(&ipa_rm_ctx->lock);
 	return result;
 }
 EXPORT_SYMBOL(ipa_rm_create_resource);
 
 /**
+ * ipa_rm_delete_resource() - delete resource
+ * @resource_name: name of resource to be deleted
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * This function is called by IPA RM client to delete client's resources.
+ *
+ */
+int ipa_rm_delete_resource(enum ipa_rm_resource_name resource_name)
+{
+	struct ipa_rm_resource *resource;
+	int result;
+
+	IPADBG("IPA RM ::ipa_rm_delete_resource num[%d] ENTER\n",
+			resource_name);
+	write_lock(&ipa_rm_ctx->lock);
+	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+					resource_name,
+						&resource) != 0) {
+		IPADBG("ipa_rm_delete_resource param are bad********\n");
+		result = -EINVAL;
+		goto bail;
+	}
+	result = ipa_rm_resource_delete(resource);
+	if (result) {
+		IPADBG("error in ipa_rm_resource_delete\n");
+		goto bail;
+	}
+	result = ipa_rm_dep_graph_remove(ipa_rm_ctx->dep_graph,
+								resource_name);
+	IPADBG("IPA RM ::ipa_rm_delete_resource [%d] SUCCESS\n",
+								resource_name);
+bail:
+	write_unlock(&ipa_rm_ctx->lock);
+	return result;
+}
+EXPORT_SYMBOL(ipa_rm_delete_resource);
+
+/**
  * ipa_rm_add_dependency() - create dependency
  *					between 2 resources
  * @resource_name: name of dependent resource
@@ -77,13 +117,19 @@
 int ipa_rm_add_dependency(enum ipa_rm_resource_name resource_name,
 			enum ipa_rm_resource_name depends_on_name)
 {
-	return ipa_rm_dep_graph_add_dependency(
-			ipa_rm_ctx->dep_graph,
-			resource_name,
-			depends_on_name);
+	int result;
+
+	read_lock(&ipa_rm_ctx->lock);
+	result = ipa_rm_dep_graph_add_dependency(
+						ipa_rm_ctx->dep_graph,
+						resource_name,
+						depends_on_name);
+	read_unlock(&ipa_rm_ctx->lock);
+	return result;
 }
 EXPORT_SYMBOL(ipa_rm_add_dependency);
 
+
 /**
  * ipa_rm_delete_dependency() - create dependency
  *					between 2 resources
@@ -98,10 +144,14 @@
 int ipa_rm_delete_dependency(enum ipa_rm_resource_name resource_name,
 			enum ipa_rm_resource_name depends_on_name)
 {
-	return ipa_rm_dep_graph_delete_dependency(
-			ipa_rm_ctx->dep_graph,
-			resource_name,
-			depends_on_name);
+	int result;
+	read_lock(&ipa_rm_ctx->lock);
+	result = ipa_rm_dep_graph_delete_dependency(
+			  ipa_rm_ctx->dep_graph,
+			  resource_name,
+			  depends_on_name);
+	read_unlock(&ipa_rm_ctx->lock);
+	return result;
 }
 EXPORT_SYMBOL(ipa_rm_delete_dependency);
 
@@ -120,10 +170,9 @@
 	int result;
 	IPADBG("IPA RM ::ipa_rm_request_resource ENTER\n");
 
-	if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
-			result = -EINVAL;
-			goto bail;
-	}
+	if (!IPA_RM_RESORCE_IS_PROD(resource_name))
+			return -EINVAL;
+	read_lock(&ipa_rm_ctx->lock);
 	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
 			resource_name,
 			&resource) != 0) {
@@ -136,6 +185,7 @@
 bail:
 	IPADBG("IPA RM ::ipa_rm_request_resource EXIT [%d]\n", result);
 
+	read_unlock(&ipa_rm_ctx->lock);
 	return result;
 }
 EXPORT_SYMBOL(ipa_rm_request_resource);
@@ -155,10 +205,9 @@
 	int result;
 	IPADBG("IPA RM ::ipa_rm_release_resource ENTER\n");
 
-	if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
-		result = -EINVAL;
-		goto bail;
-	}
+	if (!IPA_RM_RESORCE_IS_PROD(resource_name))
+		return -EINVAL;
+	read_lock(&ipa_rm_ctx->lock);
 	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
 					  resource_name,
 					  &resource) != 0) {
@@ -170,6 +219,7 @@
 
 bail:
 	IPADBG("IPA RM ::ipa_rm_release_resource EXIT [%d]\n", result);
+	read_unlock(&ipa_rm_ctx->lock);
 	return result;
 }
 EXPORT_SYMBOL(ipa_rm_release_resource);
@@ -189,10 +239,10 @@
 {
 	int result;
 	struct ipa_rm_resource *resource;
-	if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
-		result = -EINVAL;
-		goto bail;
-	}
+
+	if (!IPA_RM_RESORCE_IS_PROD(resource_name))
+		return -EINVAL;
+	read_lock(&ipa_rm_ctx->lock);
 	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
 				resource_name,
 				&resource) != 0) {
@@ -203,6 +253,7 @@
 			(struct ipa_rm_resource_prod *)resource,
 			reg_params);
 bail:
+	read_unlock(&ipa_rm_ctx->lock);
 	return result;
 }
 EXPORT_SYMBOL(ipa_rm_register);
@@ -222,10 +273,10 @@
 {
 	int result;
 	struct ipa_rm_resource *resource;
-	if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
-		result = -EINVAL;
-		goto bail;
-	}
+
+	if (!IPA_RM_RESORCE_IS_PROD(resource_name))
+		return -EINVAL;
+	read_lock(&ipa_rm_ctx->lock);
 	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
 			resource_name,
 			&resource) != 0) {
@@ -236,6 +287,7 @@
 			(struct ipa_rm_resource_prod *)resource,
 			reg_params);
 bail:
+	read_unlock(&ipa_rm_ctx->lock);
 	return result;
 }
 EXPORT_SYMBOL(ipa_rm_deregister);
@@ -278,25 +330,32 @@
 	case IPA_RM_WQ_NOTIFY_PROD:
 		if (!IPA_RM_RESORCE_IS_PROD(ipa_rm_work->resource_name))
 			return;
+		read_lock(&ipa_rm_ctx->lock);
 		if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
 						ipa_rm_work->resource_name,
-						&resource) != 0)
+						&resource) != 0){
+			read_unlock(&ipa_rm_ctx->lock);
 			return;
+		}
 		ipa_rm_resource_producer_notify_clients(
 				(struct ipa_rm_resource_prod *)resource,
 				ipa_rm_work->event);
-
+		read_unlock(&ipa_rm_ctx->lock);
 		break;
 	case IPA_RM_WQ_NOTIFY_CONS:
 		break;
 	case IPA_RM_WQ_RESOURCE_CB:
+		read_lock(&ipa_rm_ctx->lock);
 		if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
 						ipa_rm_work->resource_name,
-						&resource) != 0)
+						&resource) != 0){
+			read_unlock(&ipa_rm_ctx->lock);
 			return;
+		}
 		ipa_rm_resource_consumer_handle_cb(
 				(struct ipa_rm_resource_cons *)resource,
 				ipa_rm_work->event);
+		read_unlock(&ipa_rm_ctx->lock);
 		break;
 	default:
 		break;
@@ -351,6 +410,7 @@
 	result = ipa_rm_dep_graph_create(&(ipa_rm_ctx->dep_graph));
 	if (result)
 		goto graph_alloc_fail;
+	rwlock_init(&ipa_rm_ctx->lock);
 	IPADBG("IPA RM ipa_rm_initialize SUCCESS\n");
 	return 0;
 
diff --git a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
index 6afab42..8144a42 100644
--- a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
+++ b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
@@ -39,7 +39,6 @@
 		result = -ENOMEM;
 		goto bail;
 	}
-	rwlock_init(&((*dep_graph)->lock));
 bail:
 	return result;
 }
@@ -55,12 +54,10 @@
 	int resource_index;
 	if (!graph)
 		return;
-	write_lock(&graph->lock);
 	for (resource_index = 0;
 			resource_index < IPA_RM_RESOURCE_MAX;
 			resource_index++)
 		kfree(graph->resource_table[resource_index]);
-	write_unlock(&graph->lock);
 	memset(graph->resource_table, 0, sizeof(graph->resource_table));
 }
 
@@ -88,9 +85,7 @@
 		result = -EINVAL;
 		goto bail;
 	}
-	read_lock(&graph->lock);
 	*resource = graph->resource_table[resource_index];
-	read_unlock(&graph->lock);
 	if (!*resource) {
 		result = -EINVAL;
 		goto bail;
@@ -112,6 +107,7 @@
 {
 	int result = 0;
 	int resource_index;
+
 	if (!graph || !resource) {
 		result = -EINVAL;
 		goto bail;
@@ -121,14 +117,29 @@
 		result = -EINVAL;
 		goto bail;
 	}
-	write_lock(&graph->lock);
 	graph->resource_table[resource_index] = resource;
-	write_unlock(&graph->lock);
 bail:
 	return result;
 }
 
 /**
+ * ipa_rm_dep_graph_remove() - removes resource from graph
+ * @graph: [in] dependency graph
+ * @resource: [in] resource to add
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_dep_graph_remove(struct ipa_rm_dep_graph *graph,
+		enum ipa_rm_resource_name resource_name)
+{
+	if (!graph)
+		return -EINVAL;
+
+	graph->resource_table[resource_name] = NULL;
+	return 0;
+}
+
+/**
  * ipa_rm_dep_graph_add_dependency() - adds dependency between
  *				two nodes in graph
  * @graph: [in] dependency graph
diff --git a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
index 19d9461..4126819 100644
--- a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
+++ b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
@@ -19,7 +19,6 @@
 
 struct ipa_rm_dep_graph {
 	struct ipa_rm_resource *resource_table[IPA_RM_RESOURCE_MAX];
-	rwlock_t lock;
 };
 
 int ipa_rm_dep_graph_get_resource(
@@ -34,6 +33,9 @@
 int ipa_rm_dep_graph_add(struct ipa_rm_dep_graph *graph,
 			 struct ipa_rm_resource *resource);
 
+int ipa_rm_dep_graph_remove(struct ipa_rm_dep_graph *graph,
+				enum ipa_rm_resource_name resource_name);
+
 int ipa_rm_dep_graph_add_dependency(struct ipa_rm_dep_graph *graph,
 				enum ipa_rm_resource_name resource_name,
 				enum ipa_rm_resource_name depends_on_name);
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index 3615952..0fc4826 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -80,8 +80,8 @@
 	int result = 0;
 	int driver_result;
 	unsigned long flags;
-	IPADBG("IPA RM ::ipa_rm_resource_consumer_request %d ENTER\n",
-		consumer->resource.name);
+	IPADBG("IPA RM ::%s name %d ENTER\n",
+	       __func__, consumer->resource.name);
 	spin_lock_irqsave(&consumer->resource.state_lock, flags);
 	switch (consumer->resource.state) {
 	case IPA_RM_RELEASED:
@@ -115,8 +115,7 @@
 	consumer->usage_count++;
 bail:
 	spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
-	IPADBG("IPA RM ::ipa_rm_resource_consumer_request %d EXIT %d\n",
-		consumer->resource.name, result);
+	IPADBG("IPA RM ::ipa_rm_resource_consumer_request EXIT [%d]\n", result);
 	return result;
 }
 
@@ -127,8 +126,8 @@
 	int driver_result;
 	unsigned long flags;
 	enum ipa_rm_resource_state save_state;
-	IPADBG("IPA RM ::ipa_rm_resource_consumer_release %d ENTER\n",
-		consumer->resource.name);
+	IPADBG("IPA RM ::%s name %d ENTER\n",
+	       __func__, consumer->resource.name);
 	spin_lock_irqsave(&consumer->resource.state_lock, flags);
 	switch (consumer->resource.state) {
 	case IPA_RM_RELEASED:
@@ -163,8 +162,7 @@
 	}
 bail:
 	spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
-	IPADBG("IPA RM ::ipa_rm_resource_consumer_release %d EXIT %d\n",
-		consumer->resource.name, result);
+	IPADBG("IPA RM ::ipa_rm_resource_consumer_release EXIT [%d]\n", result);
 	return result;
 }
 
@@ -332,19 +330,56 @@
  * ipa_rm_resource_delete() - deletes resource
  * @resource: [in] resource
  *			for resource initialization with IPA RM
+ *
+ * Returns: 0 on success, negative on failure
  */
-void ipa_rm_resource_delete(struct ipa_rm_resource *resource)
+int ipa_rm_resource_delete(struct ipa_rm_resource *resource)
 {
-	if (!resource)
-		return;
-	if (resource->peers_list)
-		ipa_rm_peers_list_delete(resource->peers_list);
+	struct ipa_rm_resource *consumer, *producer;
+	int i, result = 0;
+
+	IPADBG("IPA RM: %s ENTER\n", __func__);
+
+	if (!resource) {
+		IPADBG("ipa_rm_resource_delete ENTER with invalid param\n");
+		return -EINVAL;
+	}
 	if (resource->type == IPA_RM_PRODUCER) {
+		if (resource->peers_list) {
+			for (i = IPA_RM_RESOURCE_PROD_MAX;
+					i < IPA_RM_RESOURCE_MAX;
+						++i) {
+				consumer = ipa_rm_peers_list_get_resource(
+						i,
+						resource->peers_list);
+				if (consumer) {
+					ipa_rm_resource_delete_dependency(
+						resource,
+						consumer);
+				}
+			}
+			ipa_rm_peers_list_delete(resource->peers_list);
+		}
 		ipa_rm_resource_producer_delete(
 				(struct ipa_rm_resource_prod *) resource);
 		kfree((struct ipa_rm_resource_prod *) resource);
-	} else
+	} else if (resource->type == IPA_RM_CONSUMER) {
+		if (resource->peers_list) {
+			for (i = 0; i < IPA_RM_RESOURCE_PROD_MAX; ++i) {
+				producer = ipa_rm_peers_list_get_resource(
+							i,
+							resource->peers_list);
+				if (producer)
+					ipa_rm_resource_delete_dependency(
+							producer,
+							resource);
+			}
+			ipa_rm_peers_list_delete(resource->peers_list);
+		}
 		kfree((struct ipa_rm_resource_cons *) resource);
+	}
+	IPADBG("ipa_rm_resource_delete SUCCESS\n");
+	return result;
 }
 
 /**
@@ -367,6 +402,8 @@
 		result = -EPERM;
 		goto bail;
 	}
+	IPADBG("IPA RM: %s name %d ENTER\n",
+	       __func__, producer->resource.name);
 	read_lock(&producer->event_listeners_lock);
 	list_for_each(pos, &(producer->event_listeners)) {
 		reg_info = list_entry(pos,
@@ -511,6 +548,10 @@
 	unsigned long flags;
 	if (!resource || !depends_on)
 		return -EINVAL;
+	IPADBG("IPA RM: %s from %d to %d ENTER\n",
+			__func__,
+	       resource->name,
+	       depends_on->name);
 	if (!ipa_rm_peers_list_check_dependency(resource->peers_list,
 			resource->name,
 			depends_on->peers_list,
@@ -539,8 +580,6 @@
 		goto bail;
 	}
 	spin_unlock_irqrestore(&resource->state_lock, flags);
-	(void) ipa_rm_resource_consumer_release(
-			(struct ipa_rm_resource_cons *)depends_on);
 	if (ipa_rm_peers_list_has_last_peer(resource->peers_list)) {
 		(void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
 				resource->name,
@@ -551,6 +590,12 @@
 			depends_on->name);
 	ipa_rm_peers_list_remove_peer(depends_on->peers_list,
 			resource->name);
+	(void) ipa_rm_resource_consumer_release(
+			(struct ipa_rm_resource_cons *)depends_on);
+	IPADBG("IPA RM: %s from %d to %d SUCCESS\n",
+		__func__,
+		resource->name,
+		depends_on->name);
 bail:
 	return result;
 }
@@ -568,7 +613,7 @@
 	unsigned long flags;
 	struct ipa_rm_resource *consumer;
 	int consumer_result;
-	IPADBG("IPA RM ::ipa_rm_resource_producer_request %d ENTER\n",
+	IPADBG("IPA RM ::ipa_rm_resource_producer_request [%d] ENTER\n",
 			producer->resource.name);
 	if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
 		spin_lock_irqsave(&producer->resource.state_lock, flags);
@@ -628,12 +673,11 @@
 	if (producer->pending_request == 0)
 		producer->resource.state = IPA_RM_GRANTED;
 	spin_unlock_irqrestore(&producer->resource.state_lock, flags);
-	return result;
+	goto bail;
 unlock_and_bail:
 	spin_unlock_irqrestore(&producer->resource.state_lock, flags);
 bail:
-	IPADBG("IPA RM ::ipa_rm_resource_producer_request %d EXIT %d\n",
-		producer->resource.name, result);
+	IPADBG("IPA RM ::ipa_rm_resource_producer_request EXIT[%d]\n", result);
 	return result;
 }
 
@@ -651,8 +695,9 @@
 	unsigned long flags;
 	struct ipa_rm_resource *consumer;
 	int consumer_result;
-	IPADBG("IPA RM ::ipa_rm_resource_producer_release %d ENTER\n",
-		producer->resource.name);
+	IPADBG("IPA RM: %s name %d ENTER\n",
+			__func__,
+			producer->resource.name);
 	if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
 		spin_lock_irqsave(&producer->resource.state_lock, flags);
 		producer->resource.state = IPA_RM_RELEASED;
@@ -708,8 +753,7 @@
 	return result;
 bail:
 	spin_unlock_irqrestore(&producer->resource.state_lock, flags);
-	IPADBG("IPA RM ::ipa_rm_resource_producer_release %d EXIT %d\n",
-		producer->resource.name, result);
+	IPADBG("IPA RM ::ipa_rm_resource_producer_release EXIT[%d]\n", result);
 	return result;
 }
 
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.h b/drivers/platform/msm/ipa/ipa_rm_resource.h
index b9c2e91..81ccc53 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.h
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.h
@@ -99,7 +99,7 @@
 		struct ipa_rm_create_params *create_params,
 		struct ipa_rm_resource **resource);
 
-void ipa_rm_resource_delete(struct ipa_rm_resource *resource);
+int ipa_rm_resource_delete(struct ipa_rm_resource *resource);
 
 int ipa_rm_resource_producer_register(struct ipa_rm_resource_prod *producer,
 				struct ipa_rm_register_params *reg_params);
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index 40c8fc7..9062ab8 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -69,6 +69,13 @@
 #define TETH_TOTAL_FLT_ENTRIES_IP 2
 #define TETH_IP_FAMILIES 2
 
+/**
+ * struct mac_addresses_type - store host PC and device MAC addresses
+ * @host_pc_mac_addr: MAC address of the host PC
+ * @host_pc_mac_addr_known: is the MAC address of the host PC known ?
+ * @device_mac_addr: MAC address of the device
+ * @device_mac_addr_known: is the MAC address of the device known ?
+ */
 struct mac_addresses_type {
 	u8 host_pc_mac_addr[ETH_ALEN];
 	bool host_pc_mac_addr_known;
@@ -76,12 +83,59 @@
 	bool device_mac_addr_known;
 };
 
+/**
+ * struct stats - driver statistics, viewable using debugfs
+ * @a2_to_usb_num_sw_tx_packets: number of packets bridged from A2 to USB using
+ * the SW bridge
+ * @usb_to_a2_num_sw_tx_packets: number of packets bridged from USB to A2 using
+ * the SW bridge
+ * @num_sw_tx_packets_during_resource_wakeup: number of packets bridged during a
+ * resource wakeup period, there is a special treatment for these kind of
+ * packets
+ */
 struct stats {
 	u64 a2_to_usb_num_sw_tx_packets;
 	u64 usb_to_a2_num_sw_tx_packets;
 	u64 num_sw_tx_packets_during_resource_wakeup;
 };
 
+/**
+ * struct teth_bridge_ctx - Tethering bridge driver context information
+ * @class: kernel class pointer
+ * @dev_num: kernel device number
+ * @dev: kernel device struct pointer
+ * @cdev: kernel character device struct
+ * @usb_ipa_pipe_hdl: USB to IPA pipe handle
+ * @ipa_usb_pipe_hdl: IPA to USB pipe handle
+ * @a2_ipa_pipe_hdl: A2 to IPA pipe handle
+ * @ipa_a2_pipe_hdl: IPA to A2 pipe handle
+ * @is_connected: is the tethered bridge connected ?
+ * @link_protocol: IP / Ethernet
+ * @mac_addresses: Struct which holds host pc and device MAC addresses, relevant
+ * in ethernet mode only
+ * @is_hw_bridge_complete: is HW bridge setup ?
+ * @aggr_params: aggregation parmeters
+ * @aggr_params_known: are the aggregation parameters known ?
+ * @tethering_mode: Rmnet / MBIM
+ * @is_bridge_prod_up: completion object signaled when the bridge producer
+ * finished its resource request procedure
+ * @is_bridge_prod_down: completion object signaled when the bridge producer
+ * finished its resource release procedure
+ * @comp_hw_bridge_work: used for setting up the HW bridge using a workqueue
+ * @comp_hw_bridge_in_progress: true when the HW bridge setup is in progress
+ * @aggr_caps: aggregation capabilities
+ * @stats: statistics, how many packets were transmitted using the SW bridge
+ * @teth_wq: dedicated workqueue, used for setting up the HW bridge and for
+ * sending packets using the SW bridge when the system is waking up from power
+ * collapse
+ * @a2_ipa_hdr_len: A2 to IPA header length, used to configure the A2 endpoint
+ * for header removal
+ * @hdr_del: array to store the headers handles in order to delete them later
+ * @routing_del: array of routing rules handles, one array for IPv4 and one for
+ * IPv6
+ * @filtering_del: array of routing rules handles, one array for IPv4 and one
+ * for IPv6
+ */
 struct teth_bridge_ctx {
 	struct class *class;
 	dev_t dev_num;
@@ -117,6 +171,12 @@
 	TETH_A2_TO_USB,
 };
 
+/**
+ * struct teth_work - wrapper for an skb which is sent using a workqueue
+ * @work: used by the workqueue
+ * @skb: pointer to the skb to be sent
+ * @dir: direction of send, A2 to USB or USB to A2
+ */
 struct teth_work {
 	struct work_struct work;
 	struct sk_buff *skb;
@@ -128,6 +188,15 @@
 static char dbg_buff[TETH_MAX_MSG_LEN];
 #endif
 
+/**
+ * add_eth_hdrs() - add Ethernet headers to IPA
+ * @hdr_name_ipv4: header name for IPv4
+ * @hdr_name_ipv6: header name for IPv6
+ * @src_mac_addr: source MAC address
+ * @dst_mac_addr: destination MAC address
+ *
+ * This function is called only when link protocol is Ethernet
+ */
 static int add_eth_hdrs(char *hdr_name_ipv4, char *hdr_name_ipv6,
 			u8 *src_mac_addr, u8 *dst_mac_addr)
 {
@@ -269,6 +338,12 @@
 	return res;
 }
 
+/**
+ * configure_ipa_header_block() - adds headers and configures endpoint registers
+ *
+ * - For IP link protocol and MBIM aggregation, configure MBIM header
+ * - For Ethernet link protocol, configure Ethernet headers
+ */
 static int configure_ipa_header_block(void)
 {
 	int res;
@@ -412,6 +487,14 @@
 	return res;
 }
 
+/**
+ * configure_ipa_routing_block() - Configure the IPA routing block
+ *
+ * This function configures IPA for:
+ * - Route all packets from USB to A2
+ * - Route all packets from A2 to USB
+ * - Use the correct headers in Ethernet or MBIM cases
+ */
 static int configure_ipa_routing_block(void)
 {
 	int res;
@@ -547,6 +630,13 @@
 	return res;
 }
 
+/**
+ * configure_ipa_filtering_block() - Configures IPA filtering block
+ *
+ * This function configures IPA for:
+ * - Filter all traffic coming from USB to A2 pointing routing table
+ * - Filter all traffic coming from A2 to USB pointing routing table
+ */
 static int configure_ipa_filtering_block(void)
 {
 	int res;
@@ -663,6 +753,11 @@
 	}
 }
 
+/**
+ * teth_set_aggregation() - set aggregation parameters to IPA
+ *
+ * The parameters to this function are passed in the context variable ipa_ctx.
+ */
 static int teth_set_aggregation(void)
 {
 	int res;
@@ -727,6 +822,14 @@
 	return res;
 }
 
+/**
+ * teth_request_resource() - wrapper function to
+ * ipa_rm_inactivity_timer_request_resource()
+ *
+ * - initialize the is_bridge_prod_up completion object
+ * - request the resource
+ * - error handling
+ */
 static int teth_request_resource(void)
 {
 	int res;
@@ -744,6 +847,10 @@
 	return 0;
 }
 
+/**
+ * complete_hw_bridge() - setup the HW bridge from USB to A2 and back through
+ * IPA
+ */
 static void complete_hw_bridge(struct work_struct *work)
 {
 	int res;
@@ -812,6 +919,20 @@
 		  mac_addr[4], mac_addr[5]);
 }
 
+/**
+ * check_to_complete_hw_bridge() - can HW bridge be set up ?
+ * @param skb: pointer to socket buffer
+ * @param my_mac_addr: pointer to write 'my' extracted MAC address to
+ * @param my_mac_addr_known: pointer to update whether 'my' extracted MAC
+ * address is known
+ * @param peer_mac_addr_known: pointer to update whether the 'peer' extracted
+ * MAC address is known
+ *
+ * This function is used by both A2 and USB callback functions, therefore the
+ * meaning of 'my' and 'peer' changes according to the context.
+ * Extracts MAC address from the packet in Ethernet link protocol,
+ * Sets up the HW bridge in case all conditions are met.
+ */
 static void check_to_complete_hw_bridge(struct sk_buff *skb,
 					u8 *my_mac_addr,
 					bool *my_mac_addr_known,
@@ -841,6 +962,9 @@
 	}
 }
 
+/**
+ * teth_send_skb_work() - workqueue function for sending a packet
+ */
 static void teth_send_skb_work(struct work_struct *work)
 {
 	struct teth_work *work_data =
@@ -887,6 +1011,15 @@
 	kfree(work_data);
 }
 
+/**
+ * defer_skb_send() - defer sending an skb using the SW bridge to a workqueue
+ * @param skb: pointer to the socket buffer
+ * @param dir: direction of send
+ *
+ * In case where during a packet send, the A2 or USB needs to wake up from power
+ * collapse, defer the send and return the context to IPA driver. This is
+ * important since IPA driver has a single threaded Rx path.
+ */
 static void defer_skb_send(struct sk_buff *skb, enum teth_packet_direction dir)
 {
 	struct teth_work *work = kmalloc(sizeof(struct teth_work), GFP_KERNEL);
@@ -909,6 +1042,30 @@
 	queue_work(teth_ctx->teth_wq, &work->work);
 }
 
+/**
+ * usb_notify_cb() - callback function for sending packets from USB to A2
+ * @param priv: private data
+ * @param evt: event - RECEIVE or WRITE_DONE
+ * @param data: pointer to skb to be sent
+ *
+ * This callback function is installed by the IPA driver, it is invoked in 2
+ * cases:
+ * 1. When a packet comes from the USB pipe and is routed to A5 (SW bridging)
+ * 2. After a packet has been bridged from USB to A2 and its skb should be freed
+ *
+ * Invocation: sps driver --> IPA driver --> bridge driver
+ *
+ * In the event of IPA_RECEIVE:
+ * - Checks whether the HW bridge can be set up..
+ * - Requests the BRIDGE_PROD resource so that A2 and USB are not in power
+ * collapse. In case where the resource is waking up, defer the send operation
+ * to a workqueue in order to not block the IPA driver single threaded Rx path.
+ * - Sends the packets to A2 using a2_service driver API.
+ * - Releases the BRIDGE_PROD resource.
+ *
+ * In the event of IPA_WRITE_DONE:
+ * - Frees the skb memory
+ */
 static void usb_notify_cb(void *priv,
 			  enum ipa_dp_evt_type evt,
 			  unsigned long data)
@@ -969,6 +1126,30 @@
 	return;
 }
 
+/**
+ * a2_notify_cb() - callback function for sending packets from A2 to USB
+ * @param user_data: private data
+ * @param event: event - RECEIVE or WRITE_DONE
+ * @param data: pointer to skb to be sent
+ *
+ * This callback function is installed by the IPA driver, it is invoked in 2
+ * cases:
+ * 1. When a packet comes from the A2 pipe and is routed to A5 (SW bridging)
+ * 2. After a packet has been bridged from A2 to USB and its skb should be freed
+ *
+ * Invocation: sps driver --> IPA driver --> a2_service driver --> bridge driver
+ *
+ * In the event of A2_MUX_RECEIVE:
+ * - Checks whether the HW bridge can be set up..
+ * - Requests the BRIDGE_PROD resource so that A2 and USB are not in power
+ * collapse. In case where the resource is waking up, defer the send operation
+ * to a workqueue in order to not block the IPA driver single threaded Rx path.
+ * - Sends the packets to USB using IPA drivers ipa_tx_dp() API.
+ * - Releases the BRIDGE_PROD resource.
+ *
+ * In the event of A2_MUX_WRITE_DONE:
+ * - Frees the skb memory
+ */
 static void a2_notify_cb(void *user_data,
 			 enum a2_mux_event_type event,
 			 unsigned long data)
@@ -1031,6 +1212,15 @@
 	return;
 }
 
+/**
+ * bridge_prod_notify_cb() - IPA Resource Manager callback function
+ * @param notify_cb_data: private data
+ * @param event: RESOURCE_GRANTED / RESOURCE_RELEASED
+ * @param data: not used in this case
+ *
+ * This callback function is called by IPA resource manager to notify the
+ * BRIDGE_PROD entity of events like RESOURCE_GRANTED and RESOURCE_RELEASED.
+ */
 static void bridge_prod_notify_cb(void *notify_cb_data,
 				  enum ipa_rm_event event,
 				  unsigned long data)
@@ -1075,10 +1265,17 @@
 
 /**
 * teth_bridge_init() - Initialize the Tethering bridge driver
-* @usb_notify_cb_ptr:	Callback function which should be used
-*			by the caller. Output parameter.
-* @private_data_ptr:	Data for the callback function. Should
-*			be used by the caller. Output parameter.
+* @usb_notify_cb_ptr:	Callback function which should be used by the caller.
+* Output parameter.
+* @private_data_ptr:	Data for the callback function. Should be used by the
+* caller. Output parameter.
+*
+* USB driver gets a pointer to a callback function (usb_notify_cb) and an
+* associated data. USB driver installs this callback function in the call to
+* ipa_connect().
+*
+* Builds IPA resource manager dependency graph.
+*
 * Return codes: 0: success,
 *		-EINVAL - Bad parameter
 *		Other negative value - Failure
@@ -1145,6 +1342,9 @@
 }
 EXPORT_SYMBOL(teth_bridge_init);
 
+/**
+ * initialize_context() - Initialize the ipa_ctx struct
+ */
 static void initialize_context(void)
 {
 	TETH_DBG_FUNC_ENTRY();
@@ -1198,10 +1398,6 @@
 
 /**
 * teth_bridge_disconnect() - Disconnect tethering bridge module
-*
-* Return codes:	0: success
-*		-EPERM: Operation not permitted as the bridge is already
-*		disconnected
 */
 int teth_bridge_disconnect(void)
 {
@@ -1214,19 +1410,38 @@
 		goto bail;
 	}
 
-	/* Request the BRIDGE_PROD resource */
+	/*
+	 * Delete part of IPA resource manager dependency graph. Only the
+	 * BRIDGE_PROD <-> A2 dependency remains intact
+	 */
+	res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
+				       IPA_RM_RESOURCE_USB_CONS);
+	if ((res != 0) && (res != -EINPROGRESS))
+		TETH_ERR(
+			"Failed deleting ipa_rm dependency BRIDGE_PROD <-> USB_CONS\n");
+	res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
+				       IPA_RM_RESOURCE_A2_CONS);
+	if ((res != 0) && (res != -EINPROGRESS))
+		TETH_ERR(
+			"Failed deleting ipa_rm dependency USB_PROD <-> A2_CONS\n");
+	res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_A2_PROD,
+				       IPA_RM_RESOURCE_USB_CONS);
+	if ((res != 0) && (res != -EINPROGRESS))
+		TETH_ERR(
+			"Failed deleting ipa_rm dependency A2_PROD <-> USB_CONS\n");
+
+	/* Request the BRIDGE_PROD resource, A2 and IPA should power up */
 	res = teth_request_resource();
 	if (res) {
 		TETH_ERR("request_resource() failed.\n");
 		goto bail;
 	}
 
-	teth_ctx->is_connected = false;
-
 	/* Close the channel to A2 */
 	if (a2_mux_close_channel(A2_MUX_TETHERED_0))
 		TETH_ERR("a2_mux_close_channel() failed\n");
 
+	/* Teardown the IPA HW bridge */
 	if (teth_ctx->is_hw_bridge_complete) {
 		/* Delete header entries */
 		if (ipa_del_hdr(teth_ctx->hdr_del))
@@ -1256,27 +1471,14 @@
 
 	ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
 
-	/* Delete IPA Resource manager dependency graph */
-	res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
-				       IPA_RM_RESOURCE_USB_CONS);
-	if ((res != 0) && (res != -EINPROGRESS))
-		TETH_ERR(
-			"Failed deleting ipa_rm dependency BRIDGE_PROD <-> USB_CONS\n");
+	/* Delete the last ipa_rm dependency - BRIDGE_PROD <-> A2 */
 	res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
 				       IPA_RM_RESOURCE_A2_CONS);
 	if ((res != 0) && (res != -EINPROGRESS))
 		TETH_ERR(
 			"Failed deleting ipa_rm dependency BRIDGE_PROD <-> A2_CONS\n");
-	res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
-				       IPA_RM_RESOURCE_A2_CONS);
-	if ((res != 0) && (res != -EINPROGRESS))
-		TETH_ERR(
-			"Failed deleting ipa_rm dependency USB_PROD <-> A2_CONS\n");
-	res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_A2_PROD,
-				       IPA_RM_RESOURCE_USB_CONS);
-	if ((res != 0) && (res != -EINPROGRESS))
-		TETH_ERR(
-			"Failed deleting ipa_rm dependency A2_PROD <-> USB_CONS\n");
+
+	teth_ctx->is_connected = false;
 bail:
 	TETH_DBG_FUNC_EXIT();
 
@@ -1384,6 +1586,9 @@
 		   TETH_AGGR_MAX_AGGR_PACKET_SIZE_DEFAULT;
 }
 
+/**
+ * teth_set_bridge_mode() - set the link protocol (IP / Ethernet)
+ */
 static void teth_set_bridge_mode(enum teth_link_protocol_type link_protocol)
 {
 	teth_ctx->link_protocol = link_protocol;
@@ -1391,6 +1596,14 @@
 	memset(&teth_ctx->mac_addresses, 0, sizeof(teth_ctx->mac_addresses));
 }
 
+/**
+ * teth_bridge_set_aggr_params() - kernel API to set aggregation parameters
+ * @param aggr_params: aggregation parmeters for uplink and downlink
+ *
+ * Besides setting the aggregation parameters, the function enforces max tranfer
+ * size which is less then 8K and also forbids Ethernet link protocol with MBIM
+ * aggregation which is not supported by HW.
+ */
 int teth_bridge_set_aggr_params(struct teth_aggr_params *aggr_params)
 {
 	int res;
@@ -1540,6 +1753,10 @@
 	return res;
 }
 
+/**
+ * set_aggr_capabilities() - allocates and fills the aggregation capabilities
+ * struct
+ */
 static int set_aggr_capabilities(void)
 {
 	u16 NUM_PROTOCOLS = 2;
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index fd42c47..866b921 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -375,7 +375,7 @@
 
 #define CC_READING_RESOLUTION_N	542535
 #define CC_READING_RESOLUTION_D	100000
-static int cc_reading_to_uv(int16_t reading)
+static s64 cc_reading_to_uv(s64 reading)
 {
 	return div_s64(reading * CC_READING_RESOLUTION_N,
 					CC_READING_RESOLUTION_D);
@@ -582,7 +582,7 @@
 	return false;
 }
 
-static bool is_batfet_open(struct qpnp_bms_chip *chip)
+static bool is_battery_full(struct qpnp_bms_chip *chip)
 {
 	union power_supply_propval ret = {0,};
 
@@ -610,18 +610,32 @@
 
 	iadc_channel = chip->use_external_rsense ?
 				EXTERNAL_RSENSE : INTERNAL_RSENSE;
-	rc = qpnp_iadc_vadc_sync_read(iadc_channel, &i_result,
-				VBAT_SNS, &v_result);
-	if (rc) {
-		pr_err("vadc read failed with rc: %d\n", rc);
-		return rc;
+	if (is_battery_full(chip)) {
+		rc = get_battery_current(chip, ibat_ua);
+		if (rc) {
+			pr_err("bms current read failed with rc: %d\n", rc);
+			return rc;
+		}
+		rc = qpnp_vadc_read(VBAT_SNS, &v_result);
+		if (rc) {
+			pr_err("vadc read failed with rc: %d\n", rc);
+			return rc;
+		}
+		*vbat_uv = (int)v_result.physical;
+	} else {
+		rc = qpnp_iadc_vadc_sync_read(iadc_channel, &i_result,
+					VBAT_SNS, &v_result);
+		if (rc) {
+			pr_err("adc sync read failed with rc: %d\n", rc);
+			return rc;
+		}
+		/*
+		* reverse the current read by the iadc, since the bms uses
+		* flipped battery current polarity.
+		*/
+		*ibat_ua = -1 * (int)i_result.result_ua;
+		*vbat_uv = (int)v_result.physical;
 	}
-	/*
-	 * reverse the current read by the iadc, since the bms uses
-	 * flipped battery current polarity.
-	 */
-	*ibat_ua = -1 * (int)i_result.result_ua;
-	*vbat_uv = (int)v_result.physical;
 
 	return 0;
 }
@@ -774,14 +788,6 @@
 	return (fcc_uah * pc) / 100;
 }
 
-#define CC_RESOLUTION_N		542535
-#define CC_RESOLUTION_D		100000
-
-static s64 cc_to_uv(s64 cc)
-{
-	return div_s64(cc * CC_RESOLUTION_N, CC_RESOLUTION_D);
-}
-
 #define CC_READING_TICKS	56
 #define SLEEP_CLK_HZ		32764
 #define SECONDS_PER_HOUR	3600
@@ -817,7 +823,7 @@
 
 	qpnp_iadc_get_gain_and_offset(&calibration);
 	pr_debug("cc = %lld\n", cc);
-	cc_voltage_uv = cc_to_uv(cc);
+	cc_voltage_uv = cc_reading_to_uv(cc);
 	cc_voltage_uv = cc_adjust_for_gain(cc_voltage_uv,
 					calibration.gain_raw
 					- calibration.offset_raw);
@@ -1409,7 +1415,7 @@
 		goto out;
 	}
 
-	if (ibat_ua < 0 && !is_batfet_open(chip)) {
+	if (ibat_ua < 0 && !is_battery_full(chip)) {
 		soc = charging_adjustments(chip, params, soc, vbat_uv, ibat_ua,
 				batt_temp);
 		goto out;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 6a2ce8d..993b2cb 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -546,6 +546,9 @@
 	/* Don't run on battery for batteryless hardware */
 	if (chip->use_default_batt_values)
 		return 0;
+	/* Don't force on battery if battery is not present */
+	if (!qpnp_chg_is_batt_present(chip))
+		return 0;
 
 	/* This bit forces the charger to run off of the battery rather
 	 * than a connected charger */
@@ -1564,9 +1567,9 @@
 
 			rc |= devm_request_irq(chip->dev, chip->chg_failed_irq,
 				qpnp_chg_chgr_chg_failed_irq_handler,
-				IRQF_TRIGGER_RISING, "chg_failed", chip);
+				IRQF_TRIGGER_RISING, "chg-failed", chip);
 			if (rc < 0) {
-				pr_err("Can't request %d chg_failed chg: %d\n",
+				pr_err("Can't request %d chg-failed: %d\n",
 						chip->chg_failed_irq, rc);
 				return rc;
 			}
@@ -1584,7 +1587,7 @@
 			rc |= devm_request_irq(chip->dev, chip->chg_trklchg_irq,
 				qpnp_chg_chgr_chg_trklchg_irq_handler,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-				"fast-chg-on", chip);
+				"trkl-chg-on", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d trkl-chg-on: %d\n",
 						chip->chg_trklchg_irq, rc);
@@ -1607,7 +1610,7 @@
 			rc = devm_request_irq(chip->dev, chip->batt_pres_irq,
 				qpnp_chg_bat_if_batt_pres_irq_handler,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-				"bat_if_batt_pres", chip);
+				"batt-pres", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d batt-pres irq: %d\n",
 						chip->batt_pres_irq, rc);
@@ -1628,9 +1631,9 @@
 			rc = devm_request_irq(chip->dev, chip->usbin_valid_irq,
 				qpnp_chg_usb_usbin_valid_irq_handler,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-					"chg_usbin_valid", chip);
+					"usbin-valid", chip);
 			if (rc < 0) {
-				pr_err("Can't request %d usbinvalid: %d\n",
+				pr_err("Can't request %d usbin-valid: %d\n",
 						chip->usbin_valid_irq, rc);
 				return rc;
 			}
@@ -1644,9 +1647,9 @@
 			rc = devm_request_irq(chip->dev, chip->chg_gone_irq,
 				qpnp_chg_usb_chg_gone_irq_handler,
 				IRQF_TRIGGER_RISING,
-					"chg_gone_irq", chip);
+					"chg-gone", chip);
 			if (rc < 0) {
-				pr_err("Can't request %d chg_gone: %d\n",
+				pr_err("Can't request %d chg-gone: %d\n",
 						chip->chg_gone_irq, rc);
 				return rc;
 			}
@@ -1663,9 +1666,9 @@
 			rc = devm_request_irq(chip->dev, chip->dcin_valid_irq,
 				qpnp_chg_dc_dcin_valid_irq_handler,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-				"chg_dcin_valid", chip);
+				"dcin-valid", chip);
 			if (rc < 0) {
-				pr_err("Can't request %d dcinvalid: %d\n",
+				pr_err("Can't request %d dcin-valid: %d\n",
 						chip->dcin_valid_irq, rc);
 				return rc;
 			}
@@ -2120,9 +2123,10 @@
 		}
 		INIT_WORK(&chip->adc_measure_work,
 			qpnp_bat_if_adc_measure_work);
-		INIT_DELAYED_WORK(&chip->arb_stop_work, qpnp_arb_stop_work);
 	}
 
+	INIT_DELAYED_WORK(&chip->arb_stop_work, qpnp_arb_stop_work);
+
 	if (chip->dc_chgpth_base) {
 		chip->dc_psy.name = "qpnp-dc";
 		chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
@@ -2245,7 +2249,7 @@
 	return rc;
 }
 
-static const struct dev_pm_ops qpnp_bms_pm_ops = {
+static const struct dev_pm_ops qpnp_chg_pm_ops = {
 	.resume		= qpnp_chg_resume,
 	.suspend	= qpnp_chg_suspend,
 };
@@ -2254,9 +2258,10 @@
 	.probe		= qpnp_charger_probe,
 	.remove		= __devexit_p(qpnp_charger_remove),
 	.driver		= {
-		.name	= QPNP_CHARGER_DEV_NAME,
-		.owner  = THIS_MODULE,
-		.of_match_table = qpnp_charger_match_table,
+		.name		= QPNP_CHARGER_DEV_NAME,
+		.owner		= THIS_MODULE,
+		.of_match_table	= qpnp_charger_match_table,
+		.pm		= &qpnp_chg_pm_ops,
 	},
 };
 
diff --git a/drivers/power/smb350_charger.c b/drivers/power/smb350_charger.c
index 21d7aea..11fff43 100644
--- a/drivers/power/smb350_charger.c
+++ b/drivers/power/smb350_charger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -263,6 +263,9 @@
 
 	if (!chg_enabled) {
 		pr_warn("Charging not enabled.\n");
+		/* release the wake-lock when DC power removed */
+		if (wake_lock_active(&dev->chg_wake_lock))
+			wake_unlock(&dev->chg_wake_lock);
 		return POWER_SUPPLY_CHARGE_TYPE_NONE;
 	}
 
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 42119aa..2b9af47 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -28,6 +28,7 @@
 #include <linux/of.h>
 #include <linux/sysfs.h>
 #include <linux/types.h>
+#include <linux/android_alarm.h>
 #include <mach/cpufreq.h>
 #include <mach/rpm-regulator.h>
 #include <mach/rpm-regulator-smd.h>
@@ -41,6 +42,10 @@
 static bool core_control_enabled;
 static uint32_t cpus_offlined;
 static DEFINE_MUTEX(core_control_mutex);
+static uint32_t wakeup_ms;
+static struct alarm thermal_rtc;
+static struct kobject *tt_kobj;
+static struct work_struct timer_work;
 
 static int enabled;
 static int rails_cnt;
@@ -58,6 +63,7 @@
 static bool psm_enabled;
 static bool psm_nodes_called;
 static bool psm_probed;
+static int *tsens_id_map;
 static DEFINE_MUTEX(vdd_rstr_mutex);
 static DEFINE_MUTEX(psm_mutex);
 
@@ -66,7 +72,7 @@
 	uint32_t freq_req;
 	uint32_t min_level;
 	uint32_t num_levels;
-	uint32_t curr_level;
+	int32_t curr_level;
 	uint32_t levels[3];
 	struct kobj_attribute value_attr;
 	struct kobj_attribute level_attr;
@@ -153,6 +159,7 @@
 {
 	int cpu = 0;
 	int ret = 0;
+	struct cpufreq_policy *policy = NULL;
 
 	if (!freq_table_get) {
 		ret = check_freq_table();
@@ -168,16 +175,20 @@
 
 	for_each_possible_cpu(cpu) {
 		ret = msm_cpufreq_set_freq_limits(cpu, min, limited_max_freq);
-
 		if (ret) {
 			pr_err("%s:Fail to set limits for cpu%d\n",
 					__func__, cpu);
 			return ret;
 		}
 
-		if (cpufreq_update_policy(cpu))
-			pr_debug("%s: Cannot update policy for cpu%d\n",
-					__func__, cpu);
+		if (cpu_online(cpu)) {
+			policy = cpufreq_cpu_get(cpu);
+			if (!policy)
+				continue;
+			cpufreq_driver_target(policy, policy->cur,
+					CPUFREQ_RELATION_L);
+			cpufreq_cpu_put(policy);
+		}
 	}
 
 	return ret;
@@ -187,6 +198,9 @@
 {
 	int ret = 0;
 
+	if (level == r->curr_level)
+		return ret;
+
 	/* level = -1: disable, level = 0,1,2..n: enable */
 	if (level == -1) {
 		ret = update_cpu_min_freq_all(r->min_level);
@@ -217,6 +231,9 @@
 				r->name);
 		return -EFAULT;
 	}
+	if (level == r->curr_level)
+		return ret;
+
 	/* level = -1: disable, level = 0,1,2..n: enable */
 	if (level == -1) {
 		ret = regulator_set_voltage(r->reg, r->min_level,
@@ -235,32 +252,6 @@
 
 	return ret;
 }
-/* 1:enable, 0:disable */
-static int vdd_restriction_apply_all(int en)
-{
-	int i = 0;
-	int fail_cnt = 0;
-	int ret = 0;
-
-	for (i = 0; i < rails_cnt; i++) {
-		if (rails[i].freq_req == 1 && freq_table_get)
-			ret = vdd_restriction_apply_freq(&rails[i],
-					en ? 0 : -1);
-		else
-			ret = vdd_restriction_apply_voltage(&rails[i],
-					en ? 0 : -1);
-		if (ret) {
-			pr_err("Cannot set voltage for %s", rails[i].name);
-			fail_cnt++;
-		}
-	}
-	/* Check fail_cnt again to make sure all of the rails are applied
-	 * restriction successfully or not */
-	if (fail_cnt)
-		return -EFAULT;
-
-	return ret;
-}
 
 /* Setting all rails the same mode */
 static int psm_set_mode_all(int mode)
@@ -322,8 +313,10 @@
 			ret = vdd_restriction_apply_voltage(&rails[i],
 			(val) ? 0 : -1);
 
-		/* Even if fail to set one rail, still try to set the
-		 * others. Continue the loop */
+		/*
+		 * Even if fail to set one rail, still try to set the
+		 * others. Continue the loop
+		 */
 		if (ret)
 			pr_err("Set vdd restriction for %s failed\n",
 					rails[i].name);
@@ -373,7 +366,7 @@
 	else
 		val = reg->levels[reg->curr_level];
 
-	return snprintf(buf, PAGE_SIZE, "%d\n", reg->levels[reg->curr_level]);
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
 }
 
 static int vdd_rstr_reg_level_show(
@@ -395,7 +388,7 @@
 	if (vdd_rstr_en.enabled == 0)
 		goto done_store_level;
 
-	ret = kstrtoint(buf, 10, &val);
+	ret = kstrtouint(buf, 10, &val);
 	if (ret) {
 		pr_err("Invalid input %s for level\n", buf);
 		goto done_store_level;
@@ -468,6 +461,103 @@
 	return count;
 }
 
+static int check_sensor_id(int sensor_id)
+{
+	int i = 0;
+	bool hw_id_found;
+	int ret = 0;
+
+	for (i = 0; i < max_tsens_num; i++) {
+		if (sensor_id == tsens_id_map[i]) {
+			hw_id_found = true;
+			break;
+		}
+	}
+	if (!hw_id_found) {
+		pr_err("%s: Invalid sensor hw id :%d\n", __func__, sensor_id);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int create_sensor_id_map(void)
+{
+	int i = 0;
+	int ret = 0;
+
+	tsens_id_map = kzalloc(sizeof(int) * max_tsens_num,
+			GFP_KERNEL);
+	if (!tsens_id_map) {
+		pr_err("%s: Cannot allocate memory for tsens_id_map\n",
+				__func__);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < max_tsens_num; i++) {
+		ret = tsens_get_hw_id_mapping(i, &tsens_id_map[i]);
+		/* If return -ENXIO, hw_id is default in sequence */
+		if (ret) {
+			if (ret == -ENXIO) {
+				tsens_id_map[i] = i;
+				ret = 0;
+			} else {
+				pr_err( \
+				"%s: Failed to get hw id for sw id %d\n",
+				__func__, i);
+				goto fail;
+			}
+		}
+	}
+
+	return ret;
+fail:
+	kfree(tsens_id_map);
+	return ret;
+}
+
+/* 1:enable, 0:disable */
+static int vdd_restriction_apply_all(int en)
+{
+	int i = 0;
+	int en_cnt = 0;
+	int dis_cnt = 0;
+	int fail_cnt = 0;
+	int ret = 0;
+
+	for (i = 0; i < rails_cnt; i++) {
+		if (rails[i].freq_req == 1 && freq_table_get)
+			ret = vdd_restriction_apply_freq(&rails[i],
+					en ? 0 : -1);
+		else
+			ret = vdd_restriction_apply_voltage(&rails[i],
+					en ? 0 : -1);
+		if (ret) {
+			pr_err("Cannot set voltage for %s", rails[i].name);
+			fail_cnt++;
+		} else {
+			if (en)
+				en_cnt++;
+			else
+				dis_cnt++;
+		}
+	}
+
+	/* As long as one rail is enabled, vdd rstr is enabled */
+	if (en && en_cnt)
+		vdd_rstr_en.enabled = 1;
+	else if (!en && (dis_cnt == rails_cnt))
+		vdd_rstr_en.enabled = 0;
+
+	/*
+	 * Check fail_cnt again to make sure all of the rails are applied
+	 * restriction successfully or not
+	 */
+	if (fail_cnt)
+		return -EFAULT;
+	return ret;
+}
+
 static int msm_thermal_get_freq_table(void)
 {
 	int ret = 0;
@@ -545,7 +635,8 @@
 			cpus_offlined &= ~BIT(i);
 			pr_info("%s: Allow Online CPU%d Temp: %ld\n",
 					KBUILD_MODNAME, i, temp);
-			/* If this core is already online, then bring up the
+			/*
+			 * If this core is already online, then bring up the
 			 * next offlined core.
 			 */
 			if (cpu_online(i))
@@ -578,7 +669,7 @@
 
 	mutex_lock(&vdd_rstr_mutex);
 	for (i = 0; i < max_tsens_num; i++) {
-		tsens_dev.sensor_num = i;
+		tsens_dev.sensor_num = tsens_id_map[i];
 		ret = tsens_get_temp(&tsens_dev, &temp);
 		if (ret) {
 			pr_debug("%s: Unable to read TSENS sensor %d\n",
@@ -586,18 +677,15 @@
 			dis_cnt++;
 			continue;
 		}
-		if (temp <=  msm_thermal_info.vdd_rstr_temp_hyst_degC &&
-				vdd_rstr_en.enabled == 0) {
+		if (temp <=  msm_thermal_info.vdd_rstr_temp_degC) {
 			ret = vdd_restriction_apply_all(1);
 			if (ret) {
 				pr_err( \
 				"Enable vdd rstr votlage for all failed\n");
 				goto exit;
 			}
-			vdd_rstr_en.enabled = 1;
 			goto exit;
-		} else if (temp > msm_thermal_info.vdd_rstr_temp_degC &&
-				vdd_rstr_en.enabled == 1)
+		} else if (temp > msm_thermal_info.vdd_rstr_temp_hyst_degC)
 			dis_cnt++;
 	}
 	if (dis_cnt == max_tsens_num) {
@@ -606,7 +694,6 @@
 			pr_err("Disable vdd rstr votlage for all failed\n");
 			goto exit;
 		}
-		vdd_rstr_en.enabled = 0;
 	}
 exit:
 	mutex_unlock(&vdd_rstr_mutex);
@@ -623,7 +710,7 @@
 
 	mutex_lock(&psm_mutex);
 	for (i = 0; i < max_tsens_num; i++) {
-		tsens_dev.sensor_num = i;
+		tsens_dev.sensor_num = tsens_id_map[i];
 		ret = tsens_get_temp(&tsens_dev, &temp);
 		if (ret) {
 			pr_debug("%s: Unable to read TSENS sensor %d\n",
@@ -632,9 +719,11 @@
 			continue;
 		}
 
-		/* As long as one sensor is above the threshold, set PWM mode
+		/*
+		 * As long as one sensor is above the threshold, set PWM mode
 		 * on all rails, and loop stops. Set auto mode when all rails
-		 * are below thershold */
+		 * are below thershold
+		 */
 		if (temp >  msm_thermal_info.psm_temp_degC) {
 			ret = psm_set_mode_all(PMIC_PWM_MODE);
 			if (ret) {
@@ -749,7 +838,40 @@
 	.notifier_call = msm_thermal_cpu_callback,
 };
 
-/**
+static void thermal_rtc_setup(void)
+{
+	ktime_t wakeup_time;
+	ktime_t curr_time;
+
+	curr_time = alarm_get_elapsed_realtime();
+	wakeup_time = ktime_add_us(curr_time,
+			(wakeup_ms * USEC_PER_MSEC));
+	alarm_start_range(&thermal_rtc, wakeup_time,
+			wakeup_time);
+	pr_debug("%s: Current Time: %ld %ld, Alarm set to: %ld %ld\n",
+			KBUILD_MODNAME,
+			ktime_to_timeval(curr_time).tv_sec,
+			ktime_to_timeval(curr_time).tv_usec,
+			ktime_to_timeval(wakeup_time).tv_sec,
+			ktime_to_timeval(wakeup_time).tv_usec);
+
+}
+
+static void timer_work_fn(struct work_struct *work)
+{
+	sysfs_notify(tt_kobj, NULL, "wakeup_ms");
+}
+
+static void thermal_rtc_callback(struct alarm *al)
+{
+	struct timeval ts;
+	ts = ktime_to_timeval(alarm_get_elapsed_realtime());
+	schedule_work(&timer_work);
+	pr_debug("%s: Time on alarm expiry: %ld %ld\n", KBUILD_MODNAME,
+			ts.tv_sec, ts.tv_usec);
+}
+
+/*
  * We will reset the cpu frequencies limits here. The core online/offline
  * status will be carried over to the process stopping the msm_thermal, as
  * we dont want to online a core and bring in the thermal issues.
@@ -905,6 +1027,52 @@
 	.attrs = cc_attrs,
 };
 
+static ssize_t show_wakeup_ms(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", wakeup_ms);
+}
+
+static ssize_t store_wakeup_ms(struct kobject *kobj,
+		struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int ret;
+	ret = kstrtouint(buf, 10, &wakeup_ms);
+
+	if (ret) {
+		pr_err("%s: Trying to set invalid wakeup timer\n",
+				KBUILD_MODNAME);
+		return ret;
+	}
+
+	if (wakeup_ms > 0) {
+		thermal_rtc_setup();
+		pr_debug("%s: Timer started for %ums\n", KBUILD_MODNAME,
+				wakeup_ms);
+	} else {
+		ret = alarm_cancel(&thermal_rtc);
+		if (ret)
+			pr_debug("%s: Timer canceled\n", KBUILD_MODNAME);
+		else
+			pr_debug("%s: No active timer present to cancel\n",
+					KBUILD_MODNAME);
+
+	}
+	return count;
+}
+
+static __cpuinitdata struct kobj_attribute timer_attr =
+__ATTR(wakeup_ms, 0644, show_wakeup_ms, store_wakeup_ms);
+
+static __cpuinitdata struct attribute *tt_attrs[] = {
+	&timer_attr.attr,
+	NULL,
+};
+
+static __cpuinitdata struct attribute_group tt_attr_group = {
+	.attrs = tt_attrs,
+};
+
 static __init int msm_thermal_add_cc_nodes(void)
 {
 	struct kobject *module_kobj = NULL;
@@ -941,15 +1109,54 @@
 	return ret;
 }
 
+static __init int msm_thermal_add_timer_nodes(void)
+{
+	struct kobject *module_kobj = NULL;
+	int ret = 0;
+
+	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!module_kobj) {
+		pr_err("%s: cannot find kobject for module\n",
+			KBUILD_MODNAME);
+		ret = -ENOENT;
+		goto failed;
+	}
+
+	tt_kobj = kobject_create_and_add("thermal_timer", module_kobj);
+	if (!tt_kobj) {
+		pr_err("%s: cannot create timer kobj\n",
+				KBUILD_MODNAME);
+		ret = -ENOMEM;
+		goto failed;
+	}
+
+	ret = sysfs_create_group(tt_kobj, &tt_attr_group);
+	if (ret) {
+		pr_err("%s: cannot create group\n", KBUILD_MODNAME);
+		goto failed;
+	}
+
+	return 0;
+
+failed:
+	if (tt_kobj)
+		kobject_del(tt_kobj);
+	return ret;
+}
+
 int __devinit msm_thermal_init(struct msm_thermal_data *pdata)
 {
 	int ret = 0;
 
 	BUG_ON(!pdata);
 	tsens_get_max_sensor_num(&max_tsens_num);
-	BUG_ON(msm_thermal_info.sensor_id >= max_tsens_num);
 	memcpy(&msm_thermal_info, pdata, sizeof(struct msm_thermal_data));
 
+	if (create_sensor_id_map())
+		return -EINVAL;
+	if (check_sensor_id(msm_thermal_info.sensor_id))
+		return -EINVAL;
+
 	enabled = 1;
 	core_control_enabled = 1;
 	INIT_DELAYED_WORK(&check_temp_work, check_temp);
@@ -969,8 +1176,10 @@
 		if (rails[i].freq_req == 1) {
 			usefreq |= BIT(i);
 			check_freq_table();
-			/* Restrict frequency by default until we have made
-			 * our first temp reading */
+			/*
+			 * Restrict frequency by default until we have made
+			 * our first temp reading
+			 */
 			if (freq_table_get)
 				ret = vdd_restriction_apply_freq(&rails[i], 0);
 			else
@@ -991,8 +1200,10 @@
 				}
 				return ret;
 			}
-			/* Restrict votlage by default until we have made
-			 * our first temp reading */
+			/*
+			 * Restrict votlage by default until we have made
+			 * our first temp reading
+			 */
 			ret = vdd_restriction_apply_voltage(&rails[i], 0);
 		}
 	}
@@ -1396,9 +1607,11 @@
 	key = "qcom,core-control-mask";
 	ret = of_property_read_u32(node, key, &data.core_control_mask);
 
-	/* Probe optional properties below. Call probe_psm before
+	/*
+	 * Probe optional properties below. Call probe_psm before
 	 * probe_vdd_rstr because rpm_regulator_get has to be called
-	 * before devm_regulator_get*/
+	 * before devm_regulator_get
+	 */
 	ret = probe_psm(node, &data, pdev);
 	if (ret == -EPROBE_DEFER)
 		goto fail;
@@ -1406,8 +1619,10 @@
 	if (ret == -EPROBE_DEFER)
 		goto fail;
 
-	/* In case sysfs add nodes get called before probe function.
-	 * Need to make sure sysfs node is created again */
+	/*
+	 * In case sysfs add nodes get called before probe function.
+	 * Need to make sure sysfs node is created again
+	 */
 	if (psm_nodes_called) {
 		msm_thermal_add_psm_nodes();
 		psm_nodes_called = false;
@@ -1452,6 +1667,10 @@
 	msm_thermal_add_cc_nodes();
 	msm_thermal_add_psm_nodes();
 	msm_thermal_add_vdd_rstr_nodes();
+	alarm_init(&thermal_rtc, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+			thermal_rtc_callback);
+	INIT_WORK(&timer_work, timer_work_fn);
+	msm_thermal_add_timer_nodes();
 
 	return 0;
 }
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index ede2ef1..1d02e32 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -110,6 +110,34 @@
 		wake_up_interruptible(&vt_event_waitqueue);
 }
 
+static void __vt_event_queue(struct vt_event_wait *vw)
+{
+	unsigned long flags;
+	/* Prepare the event */
+	INIT_LIST_HEAD(&vw->list);
+	vw->done = 0;
+	/* Queue our event */
+	spin_lock_irqsave(&vt_event_lock, flags);
+	list_add(&vw->list, &vt_events);
+	spin_unlock_irqrestore(&vt_event_lock, flags);
+}
+
+static void __vt_event_wait(struct vt_event_wait *vw)
+{
+	/* Wait for it to pass */
+	wait_event_interruptible(vt_event_waitqueue, vw->done);
+}
+
+static void __vt_event_dequeue(struct vt_event_wait *vw)
+{
+	unsigned long flags;
+
+	/* Dequeue it */
+	spin_lock_irqsave(&vt_event_lock, flags);
+	list_del(&vw->list);
+	spin_unlock_irqrestore(&vt_event_lock, flags);
+}
+
 /**
  *	vt_event_wait		-	wait for an event
  *	@vw: our event
@@ -121,20 +149,9 @@
 
 static void vt_event_wait(struct vt_event_wait *vw)
 {
-	unsigned long flags;
-	/* Prepare the event */
-	INIT_LIST_HEAD(&vw->list);
-	vw->done = 0;
-	/* Queue our event */
-	spin_lock_irqsave(&vt_event_lock, flags);
-	list_add(&vw->list, &vt_events);
-	spin_unlock_irqrestore(&vt_event_lock, flags);
-	/* Wait for it to pass */
-	wait_event_interruptible(vt_event_waitqueue, vw->done);
-	/* Dequeue it */
-	spin_lock_irqsave(&vt_event_lock, flags);
-	list_del(&vw->list);
-	spin_unlock_irqrestore(&vt_event_lock, flags);
+	__vt_event_queue(vw);
+	__vt_event_wait(vw);
+	__vt_event_dequeue(vw);
 }
 
 /**
@@ -177,10 +194,14 @@
 {
 	struct vt_event_wait vw;
 	do {
-		if (n == fg_console + 1)
-			break;
 		vw.event.event = VT_EVENT_SWITCH;
-		vt_event_wait(&vw);
+		__vt_event_queue(&vw);
+		if (n == fg_console + 1) {
+			__vt_event_dequeue(&vw);
+			break;
+		}
+		__vt_event_wait(&vw);
+		__vt_event_dequeue(&vw);
 		if (vw.done == 0)
 			return -EINTR;
 	} while (vw.event.newev != n);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index b8e02d2..a27eb09 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1309,8 +1309,14 @@
 	data |= (0x7F | (1 << 14));
 	dwc3_msm_ssusb_write_phycreg(msm->base, 0x1002, data);
 
-	/* Set LOS_BIAS to 0x5 */
-	dwc3_msm_write_readback(msm->base, SS_PHY_PARAM_CTRL_1, 0x07, 0x5);
+	/*
+	 * Set the QSCRATCH SS_PHY_PARAM_CTRL1 parameters as follows
+	 * TX_FULL_SWING [26:20] amplitude to 127
+	 * TX_DEEMPH_3_5DB [13:8] to 22
+	 * LOS_BIAS [2:0] to 0x5
+	 */
+	dwc3_msm_write_readback(msm->base, SS_PHY_PARAM_CTRL_1,
+				0x07f03f07, 0x07f01605);
 }
 
 /* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 8d2ec97..bb0b2fb 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -751,6 +751,9 @@
 	dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
 
 	r = next_request(&ep0->request_list);
+	if (r == NULL)
+		return;
+
 	ur = &r->request;
 	if ((epnum & 1) && ur->zero &&
 		(ur->length % ep0->endpoint.maxpacket == 0)) {
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index f68527c..54b772b 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -181,7 +181,7 @@
 
 struct dsi_panel_cmds_list {
 	struct dsi_cmd_desc *buf;
-	char size;
+	int size;
 	char ctrl_state;
 };
 
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 8c4c021..5d56df4 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -414,6 +414,8 @@
 	/* disable DSI controller */
 	mdss_dsi_controller_cfg(0, pdata);
 
+	/* disable DSI phy */
+	mdss_dsi_phy_enable(ctrl_pdata->ctrl_base, 0);
 	ret = mdss_dsi_panel_power_on(pdata, 0);
 	if (ret) {
 		pr_err("%s: Panel power off failed\n", __func__);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 97a07ed..72ad67e 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -627,12 +627,7 @@
 static int mdss_fb_blank(int blank_mode, struct fb_info *info)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
-	if (blank_mode == FB_BLANK_POWERDOWN) {
-		struct fb_event event;
-		event.info = info;
-		event.data = &blank_mode;
-		fb_notifier_call_chain(FB_EVENT_BLANK, &event);
-	}
+
 	mdss_fb_pan_idle(mfd);
 	if (mfd->op_enable == 0) {
 		if (blank_mode == FB_BLANK_UNBLANK)
@@ -957,6 +952,7 @@
 		result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
 					   mfd->op_enable);
 		if (result) {
+			pm_runtime_put(info->dev);
 			pr_err("mdss_fb_open: can't turn on display!\n");
 			return result;
 		}
diff --git a/drivers/video/msm/mdss/mdss_hdmi_mhl.h b/drivers/video/msm/mdss/mdss_hdmi_mhl.h
index 8fef63e..8a9d4fc 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_mhl.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_mhl.h
@@ -19,9 +19,9 @@
 struct msm_hdmi_mhl_ops {
 	u8 (*tmds_enabled)(struct platform_device *pdev);
 	int (*set_mhl_max_pclk)(struct platform_device *pdev, u32 max_val);
+	int (*set_upstream_hpd)(struct platform_device *pdev, uint8_t on);
 };
 
 int msm_hdmi_register_mhl(struct platform_device *pdev,
-			  struct msm_hdmi_mhl_ops *ops);
-
+			  struct msm_hdmi_mhl_ops *ops, void *data);
 #endif /* __MDSS_HDMI_MHL_H__ */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index dc51b1b..ad4cbd2 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -81,6 +81,7 @@
 	struct hdmi_tx_audio_acr lut[AUDIO_SAMPLE_RATE_MAX];
 };
 
+static int hdmi_tx_set_mhl_hpd(struct platform_device *pdev, uint8_t on);
 static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on);
 static irqreturn_t hdmi_tx_isr(int irq, void *data);
 static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl);
@@ -1950,7 +1951,7 @@
 }
 
 int msm_hdmi_register_mhl(struct platform_device *pdev,
-		struct msm_hdmi_mhl_ops *ops)
+			  struct msm_hdmi_mhl_ops *ops, void *data)
 {
 	struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
 
@@ -1966,6 +1967,8 @@
 
 	ops->tmds_enabled = hdmi_tx_tmds_enabled;
 	ops->set_mhl_max_pclk = hdmi_tx_set_mhl_max_pclk;
+	ops->set_upstream_hpd = hdmi_tx_set_mhl_hpd;
+
 	return 0;
 }
 
@@ -2438,6 +2441,41 @@
 	return rc;
 } /* hdmi_tx_sysfs_enable_hpd */
 
+static int hdmi_tx_set_mhl_hpd(struct platform_device *pdev, uint8_t on)
+{
+	int rc = 0;
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+	hdmi_ctrl = platform_get_drvdata(pdev);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!on && hdmi_ctrl->hpd_feature_on) {
+		rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
+	} else if (on && !hdmi_ctrl->hpd_feature_on) {
+		rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
+	} else {
+		DEV_DBG("%s: hpd is already '%s'. return\n", __func__,
+			hdmi_ctrl->hpd_feature_on ? "enabled" : "disabled");
+		return rc;
+	}
+
+	if (!rc) {
+		hdmi_ctrl->hpd_feature_on =
+			(~hdmi_ctrl->hpd_feature_on) & BIT(0);
+		DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_feature_on);
+	} else {
+		DEV_ERR("%s: failed to '%s' hpd. rc = %d\n", __func__,
+			on ? "enable" : "disable", rc);
+	}
+
+	return rc;
+
+}
+
 static irqreturn_t hdmi_tx_isr(int irq, void *data)
 {
 	struct dss_io_data *io = NULL;
@@ -2868,7 +2906,7 @@
 
 	switch (module_type) {
 	case HDMI_TX_HPD_PM:
-		mp->num_clk = 2;
+		mp->num_clk = 3;
 		mp->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) *
 			mp->num_clk, GFP_KERNEL);
 		if (!mp->clk_config) {
@@ -2884,6 +2922,16 @@
 		snprintf(mp->clk_config[1].clk_name, 32, "%s", "core_clk");
 		mp->clk_config[1].type = DSS_CLK_OTHER;
 		mp->clk_config[1].rate = 19200000;
+
+		/*
+		 * This clock is required to clock MDSS interrupt registers
+		 * when HDMI is the only block turned on within MDSS. Since
+		 * rate for this clock is controlled by MDP driver, treat this
+		 * similar to AHB clock and do not set rate for it.
+		 */
+		snprintf(mp->clk_config[2].clk_name, 32, "%s", "mdp_core_clk");
+		mp->clk_config[2].type = DSS_CLK_AHB;
+		mp->clk_config[2].rate = 0;
 		break;
 
 	case HDMI_TX_CORE_PM:
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 22de7e4..b9457be 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -388,12 +388,11 @@
 
 		bus_idx = (current_bus_idx % (num_cases - 1)) + 1;
 
-		/* aligning to avoid performing updates for small changes */
-		ab_quota = ALIGN(ab_quota, SZ_64M);
-		ib_quota = ALIGN(ib_quota, SZ_64M);
-
 		vect = mdp_bus_scale_table.usecase[current_bus_idx].vectors;
-		if ((ab_quota == vect->ab) && (ib_quota == vect->ib)) {
+
+		/* avoid performing updates for small changes */
+		if ((ALIGN(ab_quota, SZ_64M) == ALIGN(vect->ab, SZ_64M)) &&
+			(ALIGN(ib_quota, SZ_64M) == ALIGN(vect->ib, SZ_64M))) {
 			pr_debug("skip bus scaling, no change in vectors\n");
 			return 0;
 		}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 6be2b73..e18722c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -110,8 +110,8 @@
 typedef void (*mdp_vsync_handler_t)(struct mdss_mdp_ctl *, ktime_t);
 
 struct mdss_mdp_vsync_handler {
+	bool enabled;
 	mdp_vsync_handler_t vsync_handler;
-	u32 ref_cnt;
 	struct list_head list;
 };
 
@@ -385,7 +385,7 @@
 
 irqreturn_t mdss_mdp_isr(int irq, void *ptr);
 int mdss_iommu_attach(struct mdss_data_type *mdata);
-int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata);
+int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata);
 void mdss_mdp_irq_clear(struct mdss_data_type *mdata,
 		u32 intr_type, u32 intf_num);
 int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
@@ -415,6 +415,10 @@
 
 struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
 					struct msm_fb_data_type *mfd);
+int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata);
+void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata);
+int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
 		struct mdss_panel_data *pdata);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index eef41b5..b2147c3 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -451,6 +451,29 @@
 	return 0;
 }
 
+void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata)
+{
+	switch (pdata->panel_info.type) {
+	case MIPI_VIDEO_PANEL:
+		mdss_mdp_video_copy_splash_screen(pdata);
+		break;
+	case MIPI_CMD_PANEL:
+	default:
+		break;
+	}
+}
+
+int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl)
+{
+	switch (ctl->panel_data->panel_info.type) {
+	case MIPI_VIDEO_PANEL:
+		return mdss_mdp_video_reconfigure_splash_done(ctl);
+	case MIPI_CMD_PANEL:
+	default:
+		return 0;
+	}
+}
+
 static inline int mdss_mdp_set_split_ctl(struct mdss_mdp_ctl *ctl,
 		struct mdss_mdp_ctl *split_ctl)
 {
@@ -938,7 +961,7 @@
 	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_RESET, NULL);
 	if (ret) {
 		pr_err("panel power on failed ctl=%d\n", ctl->num);
-		return ret;
+		goto error;
 	}
 
 	ret = mdss_mdp_ctl_start_sub(ctl);
@@ -961,6 +984,7 @@
 	}
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+error:
 	mutex_unlock(&ctl->lock);
 
 	return ret;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index d68a3d4..72cbed9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -14,6 +14,8 @@
 #define pr_fmt(fmt)	"%s: " fmt, __func__
 
 #include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
 
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
@@ -201,13 +203,13 @@
 }
 
 
-static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl)
+static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl, bool clear)
 {
 	struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
 
 	if (atomic_inc_return(&ctx->vsync_ref) == 1)
 		mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
-	else
+	else if (clear)
 		mdss_mdp_irq_clear(ctl->mdata, MDSS_MDP_IRQ_INTF_VSYNC,
 				ctl->intf_num);
 }
@@ -225,9 +227,8 @@
 {
 	struct mdss_mdp_video_ctx *ctx;
 	unsigned long flags;
-	struct mdss_mdp_vsync_handler *tmp;
-	bool exist = false;
 	int ret = 0;
+	bool irq_en = false;
 
 	if (!handle || !(handle->vsync_handler)) {
 		ret = -EINVAL;
@@ -242,32 +243,24 @@
 	}
 
 	spin_lock_irqsave(&ctx->vsync_lock, flags);
-	list_for_each_entry(tmp, &(ctx->vsync_handlers), list) {
-		if (tmp->vsync_handler == handle->vsync_handler) {
-			exist = true;
-			tmp->ref_cnt++;
-		}
-	}
-	if (!exist) {
-		handle->ref_cnt = 1;
+	if (!handle->enabled) {
+		handle->enabled = true;
 		list_add(&handle->list, &ctx->vsync_handlers);
+		irq_en = true;
 	}
-
-	video_vsync_irq_enable(ctl);
 	spin_unlock_irqrestore(&ctx->vsync_lock, flags);
+	if (irq_en)
+		video_vsync_irq_enable(ctl, false);
 exit:
 	return ret;
 }
 
-/* passing NULL as handle or vsync_handler will clear all handlers */
 static int mdss_mdp_video_remove_vsync_handler(struct mdss_mdp_ctl *ctl,
 		struct mdss_mdp_vsync_handler *handle)
 {
 	struct mdss_mdp_video_ctx *ctx;
 	unsigned long flags;
-	struct mdss_mdp_vsync_handler *tmp, *q;
-	bool exist = true;
-	bool used = false;
+	bool irq_dis = false;
 
 	ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
 	if (!ctx) {
@@ -276,26 +269,21 @@
 	}
 
 	spin_lock_irqsave(&ctx->vsync_lock, flags);
-	list_for_each_entry_safe(tmp, q, &ctx->vsync_handlers, list) {
-		if (handle && handle->vsync_handler)
-			exist = (tmp->vsync_handler == handle->vsync_handler);
-		if (exist) {
-			tmp->ref_cnt--;
-			if (handle && handle->vsync_handler)
-				used = (tmp->ref_cnt != 0);
-			if (!used) {
-				video_vsync_irq_disable(ctl);
-				list_del_init(&tmp->list);
-			}
-		}
+	if (handle->enabled) {
+		handle->enabled = false;
+		list_del_init(&handle->list);
+		irq_dis = true;
 	}
 	spin_unlock_irqrestore(&ctx->vsync_lock, flags);
+	if (irq_dis)
+		video_vsync_irq_disable(ctl);
 	return 0;
 }
 
 static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_mdp_video_ctx *ctx;
+	struct mdss_mdp_vsync_handler *tmp, *handle;
 	int rc;
 
 	pr_debug("stop ctl=%d\n", ctl->num);
@@ -326,7 +314,8 @@
 			ctl->intf_num);
 	}
 
-	mdss_mdp_video_remove_vsync_handler(ctl, NULL);
+	list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list)
+		mdss_mdp_video_remove_vsync_handler(ctl, handle);
 
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
 				   NULL, NULL);
@@ -429,6 +418,8 @@
 					ctl->num);
 			ctx->polling_en++;
 			rc = mdss_mdp_video_pollwait(ctl);
+		} else {
+			rc = 0;
 		}
 	}
 
@@ -466,7 +457,7 @@
 
 	if (!ctx->wait_pending) {
 		ctx->wait_pending++;
-		video_vsync_irq_enable(ctl);
+		video_vsync_irq_enable(ctl, true);
 		INIT_COMPLETION(ctx->vsync_comp);
 	} else {
 		WARN(1, "commit without wait! ctl=%d", ctl->num);
@@ -474,7 +465,13 @@
 
 	if (!ctx->timegen_en) {
 		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);
-		WARN(rc, "intf %d unblank error (%d)\n", ctl->intf_num, rc);
+		if (rc) {
+			pr_warn("intf #%d unblank error (%d)\n",
+					ctl->intf_num, rc);
+			video_vsync_irq_disable(ctl);
+			ctx->wait_pending = 0;
+			return rc;
+		}
 
 		pr_debug("enabling timing gen for intf=%d\n", ctl->intf_num);
 
@@ -497,6 +494,92 @@
 	return 0;
 }
 
+int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata)
+{
+	void *virt = NULL;
+	unsigned long bl_fb_addr = 0;
+	unsigned long *bl_fb_addr_va;
+	unsigned long  pipe_addr, pipe_src_size;
+	u32 height, width, rgb_size, bpp;
+	size_t size;
+	static struct ion_handle *ihdl;
+	struct ion_client *iclient = mdss_get_ionclient();
+	static ion_phys_addr_t phys;
+
+	pipe_addr = MDSS_MDP_REG_SSPP_OFFSET(3) +
+		MDSS_MDP_REG_SSPP_SRC0_ADDR;
+	pipe_src_size =
+		MDSS_MDP_REG_SSPP_OFFSET(3) + MDSS_MDP_REG_SSPP_SRC_SIZE;
+
+	bpp        = 3;
+	rgb_size   = MDSS_MDP_REG_READ(pipe_src_size);
+	bl_fb_addr = MDSS_MDP_REG_READ(pipe_addr);
+
+	height = (rgb_size >> 16) & 0xffff;
+	width  = rgb_size & 0xffff;
+	size = PAGE_ALIGN(height * width * bpp);
+	pr_debug("%s:%d splash_height=%d splash_width=%d Buffer size=%d\n",
+			__func__, __LINE__, height, width, size);
+
+	ihdl = ion_alloc(iclient, size, SZ_1M,
+			ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+	if (IS_ERR_OR_NULL(ihdl)) {
+		pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
+		return -ENOMEM;
+	}
+
+	pdata->panel_info.splash_ihdl = ihdl;
+
+	virt = ion_map_kernel(iclient, ihdl);
+	ion_phys(iclient, ihdl, &phys, &size);
+
+	pr_debug("%s %d Allocating %u bytes at 0x%lx (%pa phys)\n",
+			__func__, __LINE__, size,
+			(unsigned long int)virt, &phys);
+
+	bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
+
+	memcpy(virt, bl_fb_addr_va, size);
+
+	MDSS_MDP_REG_WRITE(pipe_addr, phys);
+	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_CTL_FLUSH + MDSS_MDP_REG_CTL_OFFSET(0),
+			0x48);
+
+	return 0;
+}
+
+int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
+{
+	struct ion_client *iclient = mdss_get_ionclient();
+	struct mdss_panel_data *pdata;
+	int ret = 0, off;
+	int mdss_mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
+	int mdss_v2_intf_off = 0;
+
+	off = 0;
+
+	pdata = ctl->panel_data;
+
+	pdata->panel_info.cont_splash_enabled = 0;
+
+
+	mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
+	off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
+
+	if (mdss_mdp_rev == MDSS_MDP_HW_REV_102)
+		mdss_v2_intf_off =  0xEC00;
+
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN -
+			mdss_v2_intf_off, 0);
+	/* wait for 1 VSYNC for the pipe to be unstaged */
+	msleep(20);
+	ion_free(iclient, pdata->panel_info.splash_ihdl);
+	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
+			NULL);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	return ret;
+}
+
 int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_data_type *mdata;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index af47d0f..ac1c4ce 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -39,6 +39,7 @@
 static atomic_t ov_active_panels = ATOMIC_INIT(0);
 static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd);
 static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd);
+static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd);
 
 static int mdss_mdp_overlay_get(struct msm_fb_data_type *mfd,
 				struct mdp_overlay *req)
@@ -179,6 +180,14 @@
 			       req->src_rect.h, req->dst_rect.h);
 			return -EINVAL;
 		}
+
+		if (req->flags & MDP_BWC_EN) {
+			if ((req->src.width != req->src_rect.w) ||
+			    (req->src.height != req->src_rect.h)) {
+				pr_err("BWC: unequal src img and rect w,h\n");
+				return -EINVAL;
+			}
+		}
 	}
 
 	if (fmt->is_yuv) {
@@ -189,6 +198,13 @@
 		}
 	}
 
+	if (req->flags & MDP_DEINTERLACE) {
+		if ((req->src.width % 4 != 0) || (req->src.height % 4 != 0)) {
+			pr_err("interlaced fmt w,h need to be even post div\n");
+			return -EINVAL;
+		}
+	}
+
 	return 0;
 }
 
@@ -322,7 +338,7 @@
 	if (pipe && pipe->ndx != req->id) {
 		pr_debug("replacing pnum=%d at stage=%d mux=%d\n",
 				pipe->num, req->z_order, mixer_mux);
-		pipe->params_changed = true;
+		mdss_mdp_mixer_pipe_unstage(pipe);
 	}
 
 	mixer = mdss_mdp_mixer_get(mdp5_data->ctl, mixer_mux);
@@ -588,7 +604,7 @@
 	return 0;
 }
 
-static int mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
+static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
 {
 	struct mdss_mdp_pipe *pipe, *tmp;
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
@@ -613,96 +629,6 @@
 	mutex_unlock(&mfd->lock);
 	list_for_each_entry_safe(pipe, tmp, &destroy_pipes, cleanup_list)
 		mdss_mdp_pipe_destroy(pipe);
-
-	return 0;
-}
-
-int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata)
-{
-	void *virt = NULL;
-	unsigned long bl_fb_addr = 0;
-	unsigned long *bl_fb_addr_va;
-	unsigned long  pipe_addr, pipe_src_size;
-	u32 height, width, rgb_size, bpp;
-	size_t size;
-	static struct ion_handle *ihdl;
-	struct ion_client *iclient = mdss_get_ionclient();
-	static ion_phys_addr_t phys;
-
-	pipe_addr = MDSS_MDP_REG_SSPP_OFFSET(3) +
-		MDSS_MDP_REG_SSPP_SRC0_ADDR;
-	pipe_src_size =
-		MDSS_MDP_REG_SSPP_OFFSET(3) + MDSS_MDP_REG_SSPP_SRC_SIZE;
-
-	bpp        = 3;
-	rgb_size   = MDSS_MDP_REG_READ(pipe_src_size);
-	bl_fb_addr = MDSS_MDP_REG_READ(pipe_addr);
-
-	height = (rgb_size >> 16) & 0xffff;
-	width  = rgb_size & 0xffff;
-	size = PAGE_ALIGN(height * width * bpp);
-	pr_debug("%s:%d splash_height=%d splash_width=%d Buffer size=%d\n",
-			__func__, __LINE__, height, width, size);
-
-	ihdl = ion_alloc(iclient, size, SZ_1M,
-			ION_HEAP(ION_QSECOM_HEAP_ID), 0);
-	if (IS_ERR_OR_NULL(ihdl)) {
-		pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
-		return -ENOMEM;
-	}
-
-	pdata->panel_info.splash_ihdl = ihdl;
-
-	virt = ion_map_kernel(iclient, ihdl);
-	ion_phys(iclient, ihdl, &phys, &size);
-
-	pr_debug("%s %d Allocating %u bytes at 0x%lx (%pa phys)\n",
-			__func__, __LINE__, size,
-			(unsigned long int)virt, &phys);
-
-	bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
-
-	memcpy(virt, bl_fb_addr_va, size);
-
-	MDSS_MDP_REG_WRITE(pipe_addr, phys);
-	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_CTL_FLUSH + MDSS_MDP_REG_CTL_OFFSET(0),
-			0x48);
-
-	return 0;
-
-}
-
-int mdss_mdp_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
-{
-	struct ion_client *iclient = mdss_get_ionclient();
-	struct mdss_panel_data *pdata;
-	int ret = 0, off;
-	int mdss_mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
-	int mdss_v2_intf_off = 0;
-
-	off = 0;
-
-	pdata = ctl->panel_data;
-
-	pdata->panel_info.cont_splash_enabled = 0;
-
-	ion_free(iclient, pdata->panel_info.splash_ihdl);
-
-	mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
-	off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
-
-	if (mdss_mdp_rev == MDSS_MDP_HW_REV_102)
-		mdss_v2_intf_off =  0xEC00;
-
-	/* wait for 1 VSYNC for the pipe to be unstaged */
-	msleep(20);
-	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN -
-			mdss_v2_intf_off, 0);
-	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
-			NULL);
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-	mdss_mdp_footswitch_ctrl_splash(0);
-	return ret;
 }
 
 static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd)
@@ -721,8 +647,10 @@
 		return rc;
 	}
 
-	if (mfd->panel_info->cont_splash_enabled)
-		mdss_mdp_reconfigure_splash_done(mdp5_data->ctl);
+	if (mfd->panel_info->cont_splash_enabled) {
+		mdss_mdp_ctl_splash_finish(mdp5_data->ctl);
+		mdss_mdp_footswitch_ctrl_splash(0);
+	}
 
 	if (!is_mdss_iommu_attached()) {
 		mdss_iommu_attach(mdss_res);
@@ -811,7 +739,7 @@
 	mutex_unlock(&mfd->no_update.lock);
 
 commit_fail:
-	ret = mdss_mdp_overlay_cleanup(mfd);
+	mdss_mdp_overlay_cleanup(mfd);
 
 	mutex_unlock(&mdp5_data->ov_lock);
 
@@ -1006,7 +934,7 @@
 	return ret;
 }
 
-static int mdss_mdp_overlay_force_cleanup(struct msm_fb_data_type *mfd)
+static void mdss_mdp_overlay_force_cleanup(struct msm_fb_data_type *mfd)
 {
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
@@ -1024,9 +952,7 @@
 			mdss_mdp_display_wait4comp(ctl);
 	}
 
-	ret = mdss_mdp_overlay_cleanup(mfd);
-
-	return ret;
+	mdss_mdp_overlay_cleanup(mfd);
 }
 
 static void mdss_mdp_overlay_force_dma_cleanup(struct mdss_data_type *mdata)
@@ -1899,7 +1825,10 @@
 			return rc;
 	}
 
-	if (!IS_ERR_VALUE(rc) && mdp5_data->vsync_pending) {
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("Failed to turn on fb%d\n", mfd->index);
+		mdss_mdp_overlay_off(mfd);
+	} else if (mdp5_data->vsync_pending) {
 		mdp5_data->vsync_pending = 0;
 		mdss_mdp_overlay_vsync_ctrl(mfd, mdp5_data->vsync_pending);
 	}
@@ -1956,7 +1885,7 @@
 	if (pdata->panel_info.cont_splash_enabled) {
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 		mdss_mdp_footswitch_ctrl_splash(1);
-		mdss_mdp_copy_splash_screen(pdata);
+		mdss_mdp_ctl_splash_start(pdata);
 	}
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 12ff943..ce4c47c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -671,7 +671,7 @@
 			else
 				scale_config |= /* RGB, A */
 					(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
-					(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+					(MDSS_MDP_SCALE_FILTER_PCMN << 18);
 		}
 
 		phasey_step = mdss_mdp_scale_phase_step(
@@ -728,7 +728,7 @@
 			else
 				scale_config |= /* RGB, A */
 					(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
-					(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+					(MDSS_MDP_SCALE_FILTER_PCMN << 16);
 		}
 
 		phasex_step = mdss_mdp_scale_phase_step(
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 016c973..5d9396a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -367,6 +367,7 @@
 
 int mdss_mdp_rotator_release(u32 ndx)
 {
+	int rc = 0;
 	struct mdss_mdp_rotator_session *rot;
 	mutex_lock(&rotator_lock);
 	rot = mdss_mdp_rotator_session_get(ndx);
@@ -374,11 +375,11 @@
 		mdss_mdp_rotator_finish(rot);
 	} else {
 		pr_warn("unknown session id=%x\n", ndx);
-		return -ENOENT;
+		rc = -ENOENT;
 	}
 	mutex_unlock(&rotator_lock);
 
-	return 0;
+	return rc;
 }
 
 int mdss_mdp_rotator_release_all(void)
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 7ccf1b9..1f8244d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -194,6 +194,7 @@
 {
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
+	int rc = 0;
 
 	mutex_lock(&mdss_mdp_wb_buf_lock);
 	if (wb == NULL) {
@@ -202,7 +203,8 @@
 		mdp5_data->wb = wb;
 	} else if (mfd->index != wb->fb_ndx) {
 		pr_err("only one writeback intf supported at a time\n");
-		return -EMLINK;
+		rc = -EMLINK;
+		goto error;
 	} else {
 		pr_debug("writeback already initialized\n");
 	}
@@ -217,8 +219,9 @@
 	init_waitqueue_head(&wb->wait_q);
 
 	mdp5_data->wb = wb;
+error:
 	mutex_unlock(&mdss_mdp_wb_buf_lock);
-	return 0;
+	return rc;
 }
 
 static int mdss_mdp_wb_terminate(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index d230100..9e8cfa7 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -55,8 +55,35 @@
 	MAX_PHYS_TARGET_NUM,
 };
 
+/**
+ * enum mdss_intf_events - Different events generated by MDP core
+ *
+ * @MDSS_EVENT_RESET:		MDP control path is being (re)initialized.
+ * @MDSS_EVENT_UNBLANK:		Sent before first frame update from MDP is
+ *				sent to panel.
+ * @MDSS_EVENT_PANEL_ON:	After first frame update from MDP.
+ * @MDSS_EVENT_BLANK:		MDP has no contents to display only blank screen
+ *				is shown in panel. Sent before panel off.
+ * @MDSS_EVENT_PANEL_OFF:	MDP has suspended frame updates, panel should be
+ *				completely shutdown after this call.
+ * @MDSS_EVENT_CLOSE:		MDP has tore down entire session.
+ * @MDSS_EVENT_SUSPEND:		Propagation of power suspend event.
+ * @MDSS_EVENT_RESUME:		Propagation of power resume event.
+ * @MDSS_EVENT_CHECK_PARAMS:	Event generated when a panel reconfiguration is
+ *				requested including when resolution changes.
+ *				The event handler receives pointer to
+ *				struct mdss_panel_info and should return one of:
+ *				 - negative if the configuration is invalid
+ *				 - 0 if there is no panel reconfig needed
+ *				 - 1 if reconfig is needed to take effect
+ * @MDSS_EVENT_CONT_SPLASH_FINISH: Special event used to handle transition of
+ *				display state from boot loader to panel driver.
+ * @MDSS_EVENT_FB_REGISTERED:	Called after fb dev driver has been registered,
+ *				panel driver gets ptr to struct fb_info which
+ *				holds fb dev information.
+ */
 enum mdss_intf_events {
-	MDSS_EVENT_RESET,
+	MDSS_EVENT_RESET = 1,
 	MDSS_EVENT_UNBLANK,
 	MDSS_EVENT_PANEL_ON,
 	MDSS_EVENT_BLANK,
@@ -214,7 +241,18 @@
 	void (*set_backlight) (struct mdss_panel_data *pdata, u32 bl_level);
 	unsigned char *mmss_cc_base;
 
-	/* function entry chain */
+	/**
+	 * event_handler() - callback handler for MDP core events
+	 * @pdata:	Pointer refering to the panel struct associated to this
+	 *		event. Can be used to retrieve panel info.
+	 * @e:		Event being generated, see enum mdss_intf_events
+	 * @arg:	Optional argument to pass some info from some events.
+	 *
+	 * Used to register handler to be used to propagate different events
+	 * happening in MDP core driver. Panel driver can listen for any of
+	 * these events to perform appropriate actions for panel initialization
+	 * and teardown.
+	 */
 	int (*event_handler) (struct mdss_panel_data *pdata, int e, void *arg);
 
 	struct mdss_panel_data *next;
diff --git a/drivers/video/msm/mdss/mhl_msc.c b/drivers/video/msm/mdss/mhl_msc.c
index 96e8b67..08d0693 100644
--- a/drivers/video/msm/mdss/mhl_msc.c
+++ b/drivers/video/msm/mdss/mhl_msc.c
@@ -169,6 +169,7 @@
 	cmd_env = vmalloc(sizeof(struct msc_cmd_envelope));
 	if (!cmd_env) {
 		pr_err("%s: out of memory!\n", __func__);
+		mutex_unlock(&msc_send_workqueue_mutex);
 		return -ENOMEM;
 	}
 
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index a3a1a4e..21b6f24 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -190,7 +190,7 @@
 
 static irqreturn_t mhl_tx_isr(int irq, void *dev_id);
 static void switch_mode(struct mhl_tx_ctrl *mhl_ctrl,
-			enum mhl_st_type to_mode);
+			enum mhl_st_type to_mode, bool hpd_off);
 static void mhl_init_reg_settings(struct mhl_tx_ctrl *mhl_ctrl,
 				  bool mhl_disc_en);
 
@@ -703,9 +703,18 @@
 }
 
 
-static void switch_mode(struct mhl_tx_ctrl *mhl_ctrl, enum mhl_st_type to_mode)
+static void switch_mode(struct mhl_tx_ctrl *mhl_ctrl, enum mhl_st_type to_mode,
+			bool hpd_off)
 {
 	struct i2c_client *client = mhl_ctrl->i2c_handle;
+	unsigned long flags;
+	int rc;
+	struct msm_hdmi_mhl_ops *hdmi_mhl_ops = mhl_ctrl->hdmi_mhl_ops;
+
+	pr_debug("%s: tx pwr on\n", __func__);
+	spin_lock_irqsave(&mhl_ctrl->lock, flags);
+	mhl_ctrl->tx_powered_off = false;
+	spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
 
 	switch (to_mode) {
 	case POWER_STATE_D0_NO_MHL:
@@ -722,8 +731,11 @@
 		mhl_ctrl->cur_state = to_mode;
 		break;
 	case POWER_STATE_D3:
-		if (mhl_ctrl->cur_state == POWER_STATE_D3)
+		if (mhl_ctrl->cur_state == POWER_STATE_D3) {
+			pr_debug("%s: mhl tx already in low power mode\n",
+				__func__);
 			break;
+		}
 
 		/* Force HPD to 0 when not in MHL mode.  */
 		mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
@@ -736,7 +748,19 @@
 		msleep(50);
 		if (!mhl_ctrl->disc_enabled)
 			MHL_SII_REG_NAME_MOD(REG_DISC_CTRL1, BIT1 | BIT0, 0x00);
-		MHL_SII_PAGE3_MOD(0x003D, BIT0, 0x00);
+
+		spin_lock_irqsave(&mhl_ctrl->lock, flags);
+		mhl_ctrl->tx_powered_off = true;
+		spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
+		if (hdmi_mhl_ops && hpd_off) {
+			rc = hdmi_mhl_ops->set_upstream_hpd(
+				mhl_ctrl->pdata->hdmi_pdev, 0);
+			pr_debug("%s: hdmi unset hpd %s\n", __func__,
+				 rc ? "failed" : "passed");
+		}
+		msleep(200);
+		MHL_SII_PAGE1_MOD(0x003D, BIT0, 0x00);
 		mhl_ctrl->cur_state = POWER_STATE_D3;
 		break;
 	default:
@@ -744,6 +768,22 @@
 	}
 }
 
+static bool is_mhl_powered(void *mhl_ctx)
+{
+	struct mhl_tx_ctrl *mhl_ctrl = (struct mhl_tx_ctrl *)mhl_ctx;
+	unsigned long flags;
+	bool r = false;
+
+	spin_lock_irqsave(&mhl_ctrl->lock, flags);
+	if (mhl_ctrl->tx_powered_off)
+		r = false;
+	else
+		r = true;
+	spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
+	pr_debug("%s: ret pwr state as %x\n", __func__, r);
+	return r;
+}
 
 void mhl_tmds_ctrl(struct mhl_tx_ctrl *mhl_ctrl, uint8_t on)
 {
@@ -759,6 +799,7 @@
 void mhl_drive_hpd(struct mhl_tx_ctrl *mhl_ctrl, uint8_t to_state)
 {
 	struct i2c_client *client = mhl_ctrl->i2c_handle;
+	unsigned long flags;
 
 	pr_debug("%s: To state=[0x%x]\n", __func__, to_state);
 	if (to_state == HPD_UP) {
@@ -769,10 +810,13 @@
 		 * propogate to src let HPD float by clearing
 		 * HPD OUT OVRRD EN
 		 */
-		MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, 0x00);
+		spin_lock_irqsave(&mhl_ctrl->lock, flags);
+		mhl_ctrl->tx_powered_off = false;
+		spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+		MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, 0);
 	} else {
 		/* Drive HPD to DOWN state */
-		MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, BIT4);
+		MHL_SII_REG_NAME_MOD(REG_INT_CTRL, (BIT4 | BIT5), BIT4);
 	}
 }
 
@@ -789,9 +833,7 @@
 		pr_err("%s: cur st not D0\n", __func__);
 		return;
 	}
-	/* spin_lock_irqsave(&mhl_state_lock, flags); */
-	switch_mode(mhl_ctrl, POWER_STATE_D0_MHL);
-	/* spin_unlock_irqrestore(&mhl_state_lock, flags); */
+	switch_mode(mhl_ctrl, POWER_STATE_D0_MHL, true);
 
 	MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0x10);
 	MHL_SII_CBUS_WR(0x07, 0xF2);
@@ -823,19 +865,29 @@
 static void mhl_msm_disconnection(struct mhl_tx_ctrl *mhl_ctrl)
 {
 	struct i2c_client *client = mhl_ctrl->i2c_handle;
-	/*
-	 * MHL TX CTL1
-	 * Disabling Tx termination
-	 */
-	MHL_SII_PAGE3_WR(0x30, 0xD0);
+	unsigned long flags;
 
-	switch_mode(mhl_ctrl, POWER_STATE_D3);
+	spin_lock_irqsave(&mhl_ctrl->lock, flags);
+	mhl_ctrl->dwnstream_hpd &= ~BIT6;
+	spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
+	/* disabling Tx termination */
+	MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0xD0);
+	switch_mode(mhl_ctrl, POWER_STATE_D3, true);
 }
 
 static int  mhl_msm_read_rgnd_int(struct mhl_tx_ctrl *mhl_ctrl)
 {
 	uint8_t rgnd_imp;
 	struct i2c_client *client = mhl_ctrl->i2c_handle;
+	struct msm_hdmi_mhl_ops *hdmi_mhl_ops = mhl_ctrl->hdmi_mhl_ops;
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&mhl_ctrl->lock, flags);
+	mhl_ctrl->tx_powered_off = false;
+	spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
 	/* DISC STATUS REG 2 */
 	rgnd_imp = (mhl_i2c_reg_read(client, TX_PAGE_3, 0x001C) &
 		    (BIT1 | BIT0));
@@ -843,6 +895,12 @@
 
 	if (0x02 == rgnd_imp) {
 		pr_debug("%s: mhl sink\n", __func__);
+		if (hdmi_mhl_ops) {
+			rc = hdmi_mhl_ops->set_upstream_hpd(
+				mhl_ctrl->pdata->hdmi_pdev, 1);
+			pr_debug("%s: hdmi set hpd %s\n", __func__,
+				 rc ? "failed" : "passed");
+		}
 		mhl_ctrl->mhl_mode = 1;
 		power_supply_changed(&mhl_ctrl->mhl_psy);
 		if (mhl_ctrl->notify_usb_online)
@@ -850,7 +908,7 @@
 	} else {
 		pr_debug("%s: non-mhl sink\n", __func__);
 		mhl_ctrl->mhl_mode = 0;
-		switch_mode(mhl_ctrl, POWER_STATE_D3);
+		switch_mode(mhl_ctrl, POWER_STATE_D3, true);
 	}
 	complete(&mhl_ctrl->rgnd_done);
 	return mhl_ctrl->mhl_mode ?
@@ -904,9 +962,9 @@
 }
 
 
-static void dev_detect_isr(struct mhl_tx_ctrl *mhl_ctrl)
+static int dev_detect_isr(struct mhl_tx_ctrl *mhl_ctrl)
 {
-	uint8_t status, reg ;
+	uint8_t status, reg;
 	struct i2c_client *client = mhl_ctrl->i2c_handle;
 
 	/* INTR_STATUS4 */
@@ -916,13 +974,13 @@
 	if ((0x00 == status) &&\
 	    (mhl_ctrl->cur_state == POWER_STATE_D3)) {
 		pr_err("%s: invalid intr\n", __func__);
-		return;
+		return 0;
 	}
 
 	if (0xFF == status) {
 		pr_debug("%s: invalid intr 0xff\n", __func__);
 		MHL_SII_REG_NAME_WR(REG_INTR4, status);
-		return;
+		return 0;
 	}
 
 	if ((status & BIT0) && (mhl_ctrl->chip_rev_id < 1)) {
@@ -940,31 +998,35 @@
 		mhl_msm_connection(mhl_ctrl);
 	} else if (status & BIT3) {
 		pr_debug("%s: uUSB-a type dev detct\n", __func__);
+
 		/* Short RGND */
 		MHL_SII_REG_NAME_MOD(REG_DISC_STAT2, BIT0 | BIT1, 0x00);
 		mhl_msm_disconnection(mhl_ctrl);
 		power_supply_changed(&mhl_ctrl->mhl_psy);
 		if (mhl_ctrl->notify_usb_online)
 			mhl_ctrl->notify_usb_online(0);
+		return -EACCES;
 	}
 
 	if (status & BIT5) {
 		/* clr intr - reg int4 */
 		pr_debug("%s: mhl discon: int4 st=%02X\n", __func__,
 			 (int)status);
+
 		reg = MHL_SII_REG_NAME_RD(REG_INTR4);
 		MHL_SII_REG_NAME_WR(REG_INTR4, reg);
 		mhl_msm_disconnection(mhl_ctrl);
 		power_supply_changed(&mhl_ctrl->mhl_psy);
 		if (mhl_ctrl->notify_usb_online)
 			mhl_ctrl->notify_usb_online(0);
+		return -EACCES;
 	}
 
 	if ((mhl_ctrl->cur_state != POWER_STATE_D0_NO_MHL) &&\
 	    (status & BIT6)) {
 		/* rgnd rdy Intr */
 		pr_debug("%s: rgnd ready intr\n", __func__);
-		switch_mode(mhl_ctrl, POWER_STATE_D0_NO_MHL);
+		switch_mode(mhl_ctrl, POWER_STATE_D0_NO_MHL, true);
 		mhl_msm_read_rgnd_int(mhl_ctrl);
 	}
 
@@ -981,6 +1043,7 @@
 		release_usb_switch_open(mhl_ctrl);
 	}
 	MHL_SII_REG_NAME_WR(REG_INTR4, status);
+	return 0;
 }
 
 static void mhl_misc_isr(struct mhl_tx_ctrl *mhl_ctrl)
@@ -1000,10 +1063,13 @@
 
 static void mhl_hpd_stat_isr(struct mhl_tx_ctrl *mhl_ctrl)
 {
-	uint8_t intr_1_stat;
-	uint8_t cbus_stat;
+	uint8_t intr_1_stat, cbus_stat, t;
+	unsigned long flags;
 	struct i2c_client *client = mhl_ctrl->i2c_handle;
 
+	if (!is_mhl_powered(mhl_ctrl))
+		return;
+
 	/* INTR STATUS 1 */
 	intr_1_stat = MHL_SII_PAGE0_RD(0x0071);
 
@@ -1012,6 +1078,7 @@
 
 	/* Clear interrupts */
 	MHL_SII_PAGE0_WR(0x0071, intr_1_stat);
+
 	if (BIT6 & intr_1_stat) {
 		/*
 		 * HPD status change event is pending
@@ -1019,11 +1086,21 @@
 		 * MSC REQ ABRT REASON
 		 */
 		cbus_stat = MHL_SII_CBUS_RD(0x0D);
-		if (BIT6 & cbus_stat)
-			mhl_drive_hpd(mhl_ctrl, HPD_UP);
-		else
-			mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
+		pr_debug("%s: cbus_stat=[0x%02x] cur_pwr=[%u]\n",
+			 __func__, cbus_stat, mhl_ctrl->cur_state);
 
+		spin_lock_irqsave(&mhl_ctrl->lock, flags);
+		t = mhl_ctrl->dwnstream_hpd;
+		spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
+		if (BIT6 & (cbus_stat ^ t)) {
+			u8 status = cbus_stat & BIT6;
+			mhl_drive_hpd(mhl_ctrl, status ? HPD_UP : HPD_DOWN);
+
+			spin_lock_irqsave(&mhl_ctrl->lock, flags);
+			mhl_ctrl->dwnstream_hpd = cbus_stat;
+			spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+		}
 	}
 }
 
@@ -1257,122 +1334,9 @@
 
 }
 
-static void clear_all_intrs(struct i2c_client *client)
-{
-	uint8_t regval = 0x00;
-
-	pr_debug_intr("********* exiting isr mask check ?? *************\n");
-	pr_debug_intr("int1 mask = %02X\n",
-		(int) MHL_SII_REG_NAME_RD(REG_INTR1));
-	pr_debug_intr("int3 mask = %02X\n",
-		(int) MHL_SII_PAGE0_RD(0x0077));
-	pr_debug_intr("int4 mask = %02X\n",
-		(int) MHL_SII_REG_NAME_RD(REG_INTR4));
-	pr_debug_intr("int5 mask = %02X\n",
-		(int) MHL_SII_REG_NAME_RD(REG_INTR5));
-	pr_debug_intr("cbus1 mask = %02X\n",
-		(int) MHL_SII_CBUS_RD(0x0009));
-	pr_debug_intr("cbus2 mask = %02X\n",
-		(int) MHL_SII_CBUS_RD(0x001F));
-	pr_debug_intr("********* end of isr mask check *************\n");
-
-	regval = MHL_SII_REG_NAME_RD(REG_INTR1);
-	pr_debug_intr("int1 st = %02X\n", (int)regval);
-	MHL_SII_REG_NAME_WR(REG_INTR1, regval);
-
-	regval =  MHL_SII_REG_NAME_RD(REG_INTR2);
-	pr_debug_intr("int2 st = %02X\n", (int)regval);
-	MHL_SII_REG_NAME_WR(REG_INTR2, regval);
-
-	regval =  MHL_SII_PAGE0_RD(0x0073);
-	pr_debug_intr("int3 st = %02X\n", (int)regval);
-	MHL_SII_PAGE0_WR(0x0073, regval);
-
-	regval =  MHL_SII_REG_NAME_RD(REG_INTR4);
-	pr_debug_intr("int4 st = %02X\n", (int)regval);
-	MHL_SII_REG_NAME_WR(REG_INTR4, regval);
-
-	regval =  MHL_SII_REG_NAME_RD(REG_INTR5);
-	pr_debug_intr("int5 st = %02X\n", (int)regval);
-	MHL_SII_REG_NAME_WR(REG_INTR5, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x0008);
-	pr_debug_intr("cbusInt st = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x0008, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x001E);
-	pr_debug_intr("CBUS intR_2: %d\n", (int)regval);
-	MHL_SII_CBUS_WR(0x001E, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00A0);
-	pr_debug_intr("A0 int set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00A0, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00A1);
-	pr_debug_intr("A1 int set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00A1, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00A2);
-	pr_debug_intr("A2 int set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00A2, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00A3);
-	pr_debug_intr("A3 int set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00A3, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00B0);
-	pr_debug_intr("B0 st set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00B0, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00B1);
-	pr_debug_intr("B1 st set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00B1, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00B2);
-	pr_debug_intr("B2 st set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00B2, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00B3);
-	pr_debug_intr("B3 st set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00B3, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00E0);
-	pr_debug_intr("E0 st set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00E0, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00E1);
-	pr_debug_intr("E1 st set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00E1, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00E2);
-	pr_debug_intr("E2 st set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00E2, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00E3);
-	pr_debug_intr("E3 st set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00E3, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00F0);
-	pr_debug_intr("F0 int set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00F0, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00F1);
-	pr_debug_intr("F1 int set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00F1, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00F2);
-	pr_debug_intr("F2 int set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00F2, regval);
-
-	regval =  MHL_SII_CBUS_RD(0x00F3);
-	pr_debug_intr("F3 int set = %02X\n", (int)regval);
-	MHL_SII_CBUS_WR(0x00F3, regval);
-	pr_debug_intr("********* end of exiting in isr *************\n");
-}
-
-
 static irqreturn_t mhl_tx_isr(int irq, void *data)
 {
+	int rc;
 	struct mhl_tx_ctrl *mhl_ctrl = (struct mhl_tx_ctrl *)data;
 	pr_debug("%s: Getting Interrupts\n", __func__);
 
@@ -1380,7 +1344,11 @@
 	 * Check RGND, MHL_EST, CBUS_LOCKOUT, SCDT
 	 * interrupts. In D3, we get only RGND
 	 */
-	dev_detect_isr(mhl_ctrl);
+	rc = dev_detect_isr(mhl_ctrl);
+	if (rc) {
+		pr_info("%s: dev_detect_isr rc=[%d]\n", __func__, rc);
+		return IRQ_HANDLED;
+	}
 
 	pr_debug("%s: cur pwr state is [0x%x]\n",
 		 __func__, mhl_ctrl->cur_state);
@@ -1401,8 +1369,6 @@
 		mhl_hpd_stat_isr(mhl_ctrl);
 	}
 
-	clear_all_intrs(mhl_ctrl->i2c_handle);
-
 	return IRQ_HANDLED;
 }
 
@@ -1410,6 +1376,13 @@
 {
 	uint8_t chip_rev_id = 0x00;
 	struct i2c_client *client = mhl_ctrl->i2c_handle;
+	unsigned long flags;
+
+
+	spin_lock_irqsave(&mhl_ctrl->lock, flags);
+	mhl_ctrl->dwnstream_hpd = 0;
+	mhl_ctrl->tx_powered_off = false;
+	spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
 
 	/* Reset the TX chip */
 	mhl_sii_reset_pin(mhl_ctrl, 0);
@@ -1428,7 +1401,7 @@
 	 * MHL-USB handshake is implemented
 	 */
 	mhl_init_reg_settings(mhl_ctrl, true);
-	switch_mode(mhl_ctrl, POWER_STATE_D3);
+	switch_mode(mhl_ctrl, POWER_STATE_D0_NO_MHL, false);
 	return 0;
 }
 
@@ -1710,6 +1683,7 @@
 	mhl_ctrl->cur_state = POWER_STATE_D0_MHL;
 	INIT_LIST_HEAD(&mhl_ctrl->list_cmd);
 	init_completion(&mhl_ctrl->msc_cmd_done);
+	spin_lock_init(&mhl_ctrl->lock);
 	mhl_ctrl->msc_send_workqueue = create_singlethread_workqueue
 		("mhl_msc_cmd_queue");
 
@@ -1813,7 +1787,7 @@
 	pr_debug("%s: i2c client addr is [%x]\n", __func__, client->addr);
 	if (mhl_ctrl->pdata->hdmi_pdev) {
 		rc = msm_hdmi_register_mhl(mhl_ctrl->pdata->hdmi_pdev,
-					   hdmi_mhl_ops);
+					   hdmi_mhl_ops, mhl_ctrl);
 		if (rc) {
 			pr_err("%s: register with hdmi failed\n", __func__);
 			rc = -EPROBE_DEFER;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 2b07e43..5564ceb 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -275,8 +275,8 @@
 
 	} else {
 		MIPI_OUTP(ctrl_base + 0x0220, 0x006);
-		usleep(10);
 		MIPI_OUTP(ctrl_base + 0x0470, 0x000);
+		MIPI_OUTP(ctrl_base + 0x0598, 0x000);
 		wmb();
 	}
 }
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index c219725..aa1eba5 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -229,7 +229,15 @@
 	DMX_EVENT_MARKER = 0x00000100,
 
 	/* New indexing entry is ready */
-	DMX_EVENT_NEW_INDEX_ENTRY = 0x00000200
+	DMX_EVENT_NEW_INDEX_ENTRY = 0x00000200,
+
+	/*
+	 * Section filter timer expired. This is notified
+	 * when timeout is configured to section filter
+	 * (dmx_sct_filter_params) and no sections were
+	 * received for the given time.
+	 */
+	DMX_EVENT_SECTION_TIMEOUT = 0x00000400
 };
 
 enum dmx_oob_cmd {
@@ -706,6 +714,46 @@
 	__u64 types;
 };
 
+struct dmx_set_ts_insertion {
+	/*
+	 * Unique identifier managed by the caller.
+	 * This identifier can be used later to remove the
+	 * insertion using DMX_ABORT_TS_INSERTION ioctl.
+	 */
+	__u32 identifier;
+
+	/*
+	 * Repetition time in msec, minimum allowed value is 25msec.
+	 * 0 repetition time means one-shot insertion is done.
+	 * Insertion done based on wall-clock.
+	 */
+	__u32 repetition_time;
+
+	/*
+	 * TS packets buffer to be inserted.
+	 * The buffer is inserted as-is to the recording buffer
+	 * without any modification.
+	 * It is advised to set discontinuity flag in the very
+	 * first TS packet in the buffer.
+	 */
+	const __u8 *ts_packets;
+
+	/*
+	 * Size in bytes of the TS packets buffer to be inserted.
+	 * Should be in multiples of 188 or 192 bytes
+	 * depending on recording filter output format.
+	 */
+	size_t size;
+};
+
+struct dmx_abort_ts_insertion {
+	/*
+	 * Identifier of the insertion buffer previously set
+	 * using DMX_SET_TS_INSERTION.
+	 */
+	__u32 identifier;
+};
+
 #define DMX_START                _IO('o', 41)
 #define DMX_STOP                 _IO('o', 42)
 #define DMX_SET_FILTER           _IOW('o', 43, struct dmx_sct_filter_params)
@@ -734,5 +782,7 @@
 #define DMX_GET_EVENTS_MASK	_IOR('o', 67, struct dmx_events_mask)
 #define DMX_PUSH_OOB_COMMAND	_IOW('o', 68, struct dmx_oob_command)
 #define DMX_SET_INDEXING_PARAMS _IOW('o', 69, struct dmx_indexing_params)
+#define DMX_SET_TS_INSERTION _IOW('o', 70, struct dmx_set_ts_insertion)
+#define DMX_ABORT_TS_INSERTION _IOW('o', 71, struct dmx_abort_ts_insertion)
 
 #endif /*_DVBDMX_H_*/
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index d8eb494..a66a411 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -158,6 +158,9 @@
 	int scrpd_busy;
 	int wr_burst_pending;
 	struct completion req_write_done;
+	spinlock_t lock;
+	bool tx_powered_off;
+	uint8_t dwnstream_hpd;
 };
 
 int mhl_i2c_reg_read(struct i2c_client *client,
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 9eef3a0..48be19a 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -82,6 +82,12 @@
 #define MMC_SET_DRIVER_TYPE_D	3
 };
 
+/* states to represent load on the host */
+enum mmc_load {
+	MMC_LOAD_HIGH,
+	MMC_LOAD_LOW,
+};
+
 struct mmc_host_ops {
 	/*
 	 * 'enable' is called when the host is claimed and 'disable' is called
@@ -140,6 +146,7 @@
 	void	(*hw_reset)(struct mmc_host *host);
 	unsigned long (*get_max_frequency)(struct mmc_host *host);
 	unsigned long (*get_min_frequency)(struct mmc_host *host);
+	int	(*notify_load)(struct mmc_host *, enum mmc_load);
 	int	(*stop_request)(struct mmc_host *host);
 	unsigned int	(*get_xfer_remain)(struct mmc_host *host);
 };
@@ -401,6 +408,7 @@
 		bool		initialized;
 		bool		in_progress;
 		struct delayed_work work;
+		enum mmc_load	state;
 	} clk_scaling;
 	unsigned long		private[0] ____cacheline_aligned;
 };
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ca7a586..d63232a 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -72,11 +72,9 @@
 #ifdef CONFIG_CMA
 bool is_cma_pageblock(struct page *page);
 #  define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA)
-#  define cma_wmark_pages(zone)	zone->min_cma_pages
 #else
 #  define is_cma_pageblock(page) false
 #  define is_migrate_cma(migratetype) false
-#  define cma_wmark_pages(zone) 0
 #endif
 
 #define for_each_migratetype_order(order, type) \
@@ -385,11 +383,6 @@
 	seqlock_t		span_seqlock;
 #endif
 #ifdef CONFIG_CMA
-	/*
-	 * CMA needs to increase watermark levels during the allocation
-	 * process to make sure that the system is not starved.
-	 */
-	unsigned long		min_cma_pages;
 	bool			cma_alloc;
 #endif
 	struct free_area	free_area[MAX_ORDER];
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 15e5dc9..13d0b80 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -197,15 +197,18 @@
 /**
  * enum qpnp_adc_scale_fn_type - Scaling function for pm8941 pre calibrated
  *				   digital data relative to ADC reference.
- * %ADC_SCALE_DEFAULT: Default scaling to convert raw adc code to voltage.
- * %ADC_SCALE_BATT_THERM: Conversion to temperature based on btm parameters.
- * %ADC_SCALE_THERM_100K_PULLUP: Returns temperature in degC.
+ * %SCALE_DEFAULT: Default scaling to convert raw adc code to voltage (uV).
+ * %SCALE_BATT_THERM: Conversion to temperature(decidegC) based on btm
+ *			parameters.
+ * %SCALE_THERM_100K_PULLUP: Returns temperature in degC.
  *				 Uses a mapping table with 100K pullup.
- * %ADC_SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
- * %ADC_SCALE_XOTHERM: Returns XO thermistor voltage in degree's Centigrade.
- * %ADC_SCALE_THERM_150K_PULLUP: Returns temperature in degC.
+ * %SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
+ * %SCALE_XOTHERM: Returns XO thermistor voltage in degree's Centigrade.
+ * %SCALE_THERM_150K_PULLUP: Returns temperature in degC.
  *				 Uses a mapping table with 150K pullup.
- * %ADC_SCALE_NONE: Do not use this scaling type.
+ * %SCALE_QRD_BATT_THERM: Conversion to temperature(decidegC) based on
+ *			btm parameters.
+ * %SCALE_NONE: Do not use this scaling type.
  */
 enum qpnp_adc_scale_fn_type {
 	SCALE_DEFAULT = 0,
@@ -214,6 +217,7 @@
 	SCALE_PMIC_THERM,
 	SCALE_XOTHERM,
 	SCALE_THERM_150K_PULLUP,
+	SCALE_QRD_BATT_THERM,
 	SCALE_NONE,
 };
 
@@ -1039,7 +1043,7 @@
 /**
  * qpnp_adc_scale_batt_therm() - Scales the pre-calibrated digital output
  *		of an ADC to the ADC reference and compensates for the
- *		gain and offset. Returns the temperature in degC.
+ *		gain and offset. Returns the temperature in decidegC.
  * @adc_code:	pre-calibrated digital ouput of the ADC.
  * @adc_prop:	adc properties of the pm8xxx adc such as bit resolution,
  *		reference voltage.
@@ -1052,6 +1056,21 @@
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt);
 /**
+ * qpnp_adc_scale_qrd_batt_therm() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset. Returns the temperature in decidegC.
+ * @adc_code:	pre-calibrated digital ouput of the ADC.
+ * @adc_prop:	adc properties of the pm8xxx adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	physical result to be stored.
+ */
+int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
  * qpnp_adc_scale_batt_id() - Scales the pre-calibrated digital output
  *		of an ADC to the ADC reference and compensates for the
  *		gain and offset.
@@ -1257,6 +1276,11 @@
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt)
 { return -ENXIO; }
+static inline int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+{ return -ENXIO; }
 static inline int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
 			const struct qpnp_adc_properties *adc_prop,
 			const struct qpnp_vadc_chan_properties *chan_prop,
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 74b09cb..4bce95c 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -700,6 +700,7 @@
 #define V4L2_QCOM_BUF_FLAG_CODECCONFIG  0x4000
 #define V4L2_QCOM_BUF_FLAG_EOSEQ  0x8000
 #define V4L2_QCOM_BUF_TIMESTAMP_INVALID 0x10000
+#define V4L2_QCOM_BUF_FLAG_DECODEONLY 0x40000
 
 /*
  *	O V E R L A Y   P R E V I E W
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index bf6b23b..3775ddd 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -64,6 +64,7 @@
 	EVERY_8FRAME,
 	EVERY_16FRAME,
 	EVERY_32FRAME,
+	SKIP_ALL,
 	MAX_SKIP,
 };
 
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 87730b1..f064837 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -6516,6 +6516,11 @@
 #define AANC_HW_BLOCK_VERSION_1				(1)
 #define AANC_HW_BLOCK_VERSION_2				(2)
 
+/*Clip bank selection*/
+#define AFE_API_VERSION_CLIP_BANK_SEL_CFG 0x1
+#define AFE_CLIP_MAX_BANKS		4
+#define AFE_PARAM_ID_CLIP_BANK_SEL_CFG 0x00010242
+
 struct afe_param_aanc_port_cfg {
 	/* Minor version used for tracking the version of the module's
 	* source port configuration.
@@ -6550,6 +6555,18 @@
 	uint32_t aanc_hw_version;
 } __packed;
 
+struct afe_param_id_clip_bank_sel {
+	/* Minor version used for tracking the version of the module's
+	* hw version
+	*/
+	uint32_t minor_version;
+
+	/* Number of banks to be read */
+	uint32_t num_banks;
+
+	uint32_t bank_map[AFE_CLIP_MAX_BANKS];
+} __packed;
+
 /* ERROR CODES */
 /* Success. The operation completed with no errors. */
 #define ADSP_EOK          0x00000000
@@ -6782,6 +6799,8 @@
 	AFE_SLIMBUS_SLAVE_CONFIG,
 	AFE_CDC_REGISTERS_CONFIG,
 	AFE_AANC_VERSION,
+	AFE_CDC_CLIP_REGISTERS_CONFIG,
+	AFE_CLIP_BANK_SEL,
 	AFE_MAX_CONFIG_TYPES,
 };
 
@@ -6903,4 +6922,10 @@
 /* Dolby DAP topology */
 #define DOLBY_ADM_COPP_TOPOLOGY_ID	0x0001033B
 
+struct afe_svc_cmd_set_clip_bank_selection {
+	struct apr_hdr hdr;
+	struct afe_svc_cmd_set_param param;
+	struct afe_port_param_data_v2 pdata;
+	struct afe_param_id_clip_bank_sel bank_sel;
+} __packed;
 #endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 40b0e1e..81636a3 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -1453,6 +1453,23 @@
 	u32                read_format;
 } __attribute__((packed));
 
+#define ASM_STREAM_CMD_OPEN_LOOPBACK	0x00010D6E
+struct asm_stream_cmd_open_loopback {
+	struct apr_hdr         hdr;
+	u32                    mode_flags;
+/* Mode flags.
+ * Bit 0-31: reserved; client should set these bits to 0
+ */
+	u16                    src_endpointype;
+	/* Endpoint type. 0 = Tx Matrix */
+	u16                    sink_endpointype;
+	/* Endpoint type. 0 = Rx Matrix */
+	u32                    postprocopo_id;
+/* Postprocessor topology ID. Specifies the topology of
+ * postprocessing algorithms.
+ */
+} __packed;
+
 #define ADM_CMD_CONNECT_AFE_PORT 0x00010320
 #define ADM_CMD_DISCONNECT_AFE_PORT 0x00010321
 
@@ -1909,5 +1926,4 @@
 
 int srs_ss3d_open(int port_id, int srs_tech_id, void *srs_params);
 /* SRS Studio Sound 3D end */
-
 #endif /*_APR_AUDIO_H_*/
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 406407d..41f875b 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -207,6 +207,8 @@
 			uint32_t rd_format,
 			uint32_t wr_format);
 
+int q6asm_open_loopack(struct audio_client *ac);
+
 int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
 				uint32_t lsw_ts, uint32_t flags);
 int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index e6a2e35..edd656c 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -224,13 +224,10 @@
 		raw_spin_unlock(&base->cpu_base->lock);
 		raw_spin_lock(&new_base->cpu_base->lock);
 
-		this_cpu = smp_processor_id();
-
-		if (cpu != this_cpu && (hrtimer_check_target(timer, new_base)
-			|| !cpu_online(cpu))) {
+		if (cpu != this_cpu && hrtimer_check_target(timer, new_base)) {
+			cpu = this_cpu;
 			raw_spin_unlock(&new_base->cpu_base->lock);
 			raw_spin_lock(&base->cpu_base->lock);
-			cpu = smp_processor_id();
 			timer->base = base;
 			goto again;
 		}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 69b9521..798c750 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -785,6 +785,10 @@
 	set_pageblock_migratetype(page, MIGRATE_CMA);
 	__free_pages(page, pageblock_order);
 	totalram_pages += pageblock_nr_pages;
+#ifdef CONFIG_HIGHMEM
+	if (PageHighMem(page))
+		totalhigh_pages += pageblock_nr_pages;
+#endif
 }
 #endif
 
@@ -5199,10 +5203,6 @@
 		zone->watermark[WMARK_LOW]  = min_wmark_pages(zone) + (tmp >> 2);
 		zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + (tmp >> 1);
 
-		zone->watermark[WMARK_MIN] += cma_wmark_pages(zone);
-		zone->watermark[WMARK_LOW] += cma_wmark_pages(zone);
-		zone->watermark[WMARK_HIGH] += cma_wmark_pages(zone);
-
 		setup_zone_migrate_reserve(zone);
 		spin_unlock_irqrestore(&zone->lock, flags);
 	}
@@ -5820,54 +5820,6 @@
 	return ret > 0 ? 0 : ret;
 }
 
-/*
- * Update zone's cma pages counter used for watermark level calculation.
- */
-static inline void __update_cma_watermarks(struct zone *zone, int count)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&zone->lock, flags);
-	zone->min_cma_pages += count;
-	spin_unlock_irqrestore(&zone->lock, flags);
-	setup_per_zone_wmarks();
-}
-
-/*
- * Trigger memory pressure bump to reclaim some pages in order to be able to
- * allocate 'count' pages in single page units. Does similar work as
- *__alloc_pages_slowpath() function.
- */
-static int __reclaim_pages(struct zone *zone, gfp_t gfp_mask, int count)
-{
-	enum zone_type high_zoneidx = gfp_zone(gfp_mask);
-	struct zonelist *zonelist = node_zonelist(0, gfp_mask);
-	int did_some_progress = 0;
-	int order = 1;
-
-	/*
-	 * Increase level of watermarks to force kswapd do his job
-	 * to stabilise at new watermark level.
-	 */
-	__update_cma_watermarks(zone, count);
-
-	/* Obey watermarks as if the page was being allocated */
-	while (!zone_watermark_ok(zone, 0, low_wmark_pages(zone), 0, 0)) {
-		wake_all_kswapd(order, zonelist, high_zoneidx, zone_idx(zone));
-
-		did_some_progress = __perform_reclaim(gfp_mask, order, zonelist,
-						      NULL);
-		if (!did_some_progress) {
-			/* Exhausted what can be done so it's blamo time */
-			out_of_memory(zonelist, gfp_mask, order, NULL, false);
-		}
-	}
-
-	/* Restore original watermark levels. */
-	__update_cma_watermarks(zone, -count);
-
-	return count;
-}
-
 /**
  * alloc_contig_range() -- tries to allocate given range of pages
  * @start:	start PFN to allocate
@@ -5968,11 +5920,6 @@
 		goto done;
 	}
 
-	/*
-	 * Reclaim enough pages to make sure that contiguous allocation
-	 * will not starve the system.
-	 */
-	__reclaim_pages(zone, GFP_HIGHUSER_MOVABLE, end-start);
 
 	/* Grab isolated pages from freelists. */
 	outer_end = isolate_freepages_range(outer_start, end);
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index c8647fb1..e1a904f 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -34,6 +34,7 @@
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/tlv.h>
+#include <mach/qdsp6v2/apr.h>
 #include "msm8x10-wcd.h"
 #include "wcd9xxx-resmgr.h"
 #include "msm8x10_wcd_registers.h"
@@ -52,7 +53,7 @@
 
 #define MAX_MSM8X10_WCD_DEVICE	4
 #define CODEC_DT_MAX_PROP_SIZE	40
-#define MSM8X10_WCD_I2C_GSBI_SLAVE_ID "1-000d"
+#define MSM8X10_WCD_I2C_GSBI_SLAVE_ID "5-000d"
 
 enum {
 	MSM8X10_WCD_I2C_TOP_LEVEL = 0,
@@ -82,6 +83,12 @@
 static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[];
 static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
 
+#define MSM8X10_WCD_ACQUIRE_LOCK(x) do { \
+	mutex_lock_nested(&x, SINGLE_DEPTH_NESTING); \
+} while (0)
+#define MSM8X10_WCD_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
+
+
 /* Codec supports 2 IIR filters */
 enum {
 	IIR1 = 0,
@@ -99,6 +106,12 @@
 	BAND_MAX,
 };
 
+enum msm8x10_wcd_bandgap_type {
+	MSM8X10_WCD_BANDGAP_OFF = 0,
+	MSM8X10_WCD_BANDGAP_AUDIO_MODE,
+	MSM8X10_WCD_BANDGAP_MBHC_MODE,
+};
+
 struct hpf_work {
 	struct msm8x10_wcd_priv *msm8x10_wcd;
 	u32 decimator;
@@ -113,11 +126,14 @@
 	u32 adc_count;
 	u32 rx_bias_count;
 	s32 dmic_1_2_clk_cnt;
-
+	enum msm8x10_wcd_bandgap_type bandgap_type;
+	bool mclk_enabled;
+	bool clock_active;
+	bool config_mode_active;
+	bool mbhc_polling_active;
+	struct mutex codec_resource_lock;
 	/* resmgr module */
 	struct wcd9xxx_resmgr resmgr;
-	/* mbhc module */
-	struct wcd9xxx_mbhc mbhc;
 };
 
 static unsigned short rx_digital_gain_reg[] = {
@@ -139,8 +155,8 @@
 };
 
 static char *msm8x10_wcd_supplies[] = {
-	"cdc-vdd-mic-bias", "cdc-vdda-h", "cdc-vdd-1p2", "cdc-vdd-px",
-	"cdc-vdda-cp",
+	"cdc-vdda-cp", "cdc-vdda-h", "cdc-vdd-px", "cdc-vdd-1p2v",
+	"cdc-vdd-mic-bias",
 };
 
 static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
@@ -158,7 +174,6 @@
 {
 	int rtn = 0;
 	int value = ((reg & 0x0f00) >> 8) & 0x000f;
-	pr_debug("%s: reg(0x%x) value(%d)\n", __func__, reg, value);
 	switch (value) {
 	case 0:
 	case 1:
@@ -171,7 +186,7 @@
 	return rtn;
 }
 
-static int msm8x10_wcd_abh_write_device(u16 reg, unsigned int *value, u32 bytes)
+static int msm8x10_wcd_abh_write_device(u16 reg, u8 *value, u32 bytes)
 {
 	u32 temp = ((u32)(*value)) & 0x000000FF;
 	u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
@@ -179,11 +194,13 @@
 	return 0;
 }
 
-static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, unsigned int *value)
+static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, u8 *value)
 {
+	u32 temp;
 	u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
-	*value = ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
+	temp = ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
 				      offset, 4));
+	*value = (u8)temp;
 	return 0;
 }
 
@@ -274,7 +291,7 @@
 			}
 		}
 	}
-	pr_debug("%s: Reg 0x%x = 0x%x\n", __func__, reg, *dest);
+	pr_debug("%s: reg 0x%x = 0x%x\n", __func__, reg, *dest);
 	return 0;
 }
 
@@ -292,20 +309,22 @@
 				u16 reg, unsigned int *val)
 {
 	int ret = -EINVAL;
+	u8 temp;
 
 	/* check if use I2C interface for Helicon or AHB for Dino */
 	mutex_lock(&msm8x10_wcd->io_lock);
 	if (MSM8X10_WCD_IS_HELICON_REG(reg))
-		ret = msm8x10_wcd_i2c_read(reg, 1, val);
+		ret = msm8x10_wcd_i2c_read(reg, 1, &temp);
 	else if (MSM8X10_WCD_IS_DINO_REG(reg))
-		ret = msm8x10_wcd_abh_read_device(reg, 1, val);
+		ret = msm8x10_wcd_abh_read_device(reg, 1, &temp);
 	mutex_unlock(&msm8x10_wcd->io_lock);
+	*val = temp;
 	return ret;
 }
 
 
 static int msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd, u16  reg,
-				 unsigned int val)
+				 u8 val)
 {
 	int ret = -EINVAL;
 
@@ -393,7 +412,7 @@
 				reg, ret);
 	}
 
-	return msm8x10_wcd_reg_write(codec->control_data, reg, value);
+	return msm8x10_wcd_reg_write(codec->control_data, reg, (u8)value);
 }
 
 static unsigned int msm8x10_wcd_read(struct snd_soc_codec *codec,
@@ -438,10 +457,14 @@
 	regnode = of_parse_phandle(dev->of_node, prop_name, 0);
 
 	if (!regnode) {
-		dev_err(dev, "Looking up %s property in node %s failed",
+		dev_err(dev, "Looking up %s property in node %s failed\n",
 			prop_name, dev->of_node->full_name);
 		return -ENODEV;
 	}
+
+	dev_dbg(dev, "Looking up %s property in node %s\n",
+		prop_name, dev->of_node->full_name);
+
 	vreg->name = vreg_name;
 
 	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
@@ -481,17 +504,7 @@
 	u32 prop_val;
 
 	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
-		 "qcom,cdc-micbias-ldoh-v");
-	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
-	if (ret) {
-		dev_err(dev, "Looking up %s property in node %s failed",
-			prop_name, dev->of_node->full_name);
-		return -ENODEV;
-	}
-	micbias->ldoh_v = (u8)prop_val;
-
-	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
-		 "qcom,cdc-micbias-cfilt1-mv");
+		 "qcom,cdc-micbias-cfilt-mv");
 	ret = of_property_read_u32(dev->of_node, prop_name,
 				   &micbias->cfilt1_mv);
 	if (ret) {
@@ -501,7 +514,7 @@
 	}
 
 	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
-		 "qcom,cdc-micbias1-cfilt-sel");
+		 "qcom,cdc-micbias-cfilt-sel");
 	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
 	if (ret) {
 		dev_err(dev, "Looking up %s property in node %s failed",
@@ -559,23 +572,14 @@
 		if (ret)
 			goto err;
 	}
-
 	ret = msm8x10_wcd_dt_parse_micbias_info(dev, &pdata->micbias);
 	if (ret)
 		goto err;
-
-	pdata->reset_gpio = of_get_named_gpio(dev->of_node,
-				"qcom,cdc-reset-gpio", 0);
-	if (pdata->reset_gpio < 0) {
-		dev_err(dev, "Looking up %s property in node %s failed %d\n",
-			"qcom, cdc-reset-gpio", dev->of_node->full_name,
-			pdata->reset_gpio);
-		goto err;
-	}
-	dev_dbg(dev, "%s: reset gpio %d", __func__, pdata->reset_gpio);
 	return pdata;
 err:
 	devm_kfree(dev, pdata);
+	dev_err(dev, "%s: Failed to populate DT data ret = %d\n",
+		__func__, ret);
 	return NULL;
 }
 
@@ -611,6 +615,9 @@
 				    MSM8X10_WCD_A_CDC_CLK_OTHR_CTL, 0x01,
 				    0x00);
 		snd_soc_update_bits(codec,
+				    MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
+				    0x01, 0x01);
+		snd_soc_update_bits(codec,
 				    MSM8X10_WCD_A_CP_STATIC, 0x08, 0x00);
 		break;
 	}
@@ -846,7 +853,7 @@
 	SOC_ENUM_EXT("EAR PA Gain", msm8x10_wcd_ear_pa_gain_enum[0],
 		msm8x10_wcd_pa_gain_get, msm8x10_wcd_pa_gain_put),
 
-	SOC_SINGLE_TLV("LINEOUT1 Volume", MSM8X10_WCD_A_RX_LINE_1_GAIN,
+	SOC_SINGLE_TLV("LINEOUT Volume", MSM8X10_WCD_A_RX_LINE_1_GAIN,
 		       0, 12, 1, line_gain),
 
 	SOC_SINGLE_TLV("HPHL Volume", MSM8X10_WCD_A_RX_HPH_L_GAIN,
@@ -1102,9 +1109,6 @@
 	switch (decimator) {
 	case 1:
 	case 2:
-		if (dec_mux == 1)
-			adc_dmic_sel = 0x1;
-		else
 			adc_dmic_sel = 0x0;
 		break;
 	default:
@@ -1148,68 +1152,6 @@
 	SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
 };
 
-/* virtual port entries */
-static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
-			     struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-
-	ucontrol->value.integer.value[0] = widget->value;
-	return 0;
-}
-
-static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
-			     struct snd_ctl_elem_value *ucontrol)
-{
-	return 0;
-}
-
-static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
-			   struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-
-	ucontrol->value.enumerated.item[0] = widget->value;
-	return 0;
-}
-
-static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
-			   struct snd_ctl_elem_value *ucontrol)
-{
-	return 0;
-}
-
-
-static const char *const slim_rx_mux_text[] = {
-	"ZERO", "AIF1_PB"
-};
-
-static const struct soc_enum slim_rx_mux_enum =
-	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
-
-static const struct snd_kcontrol_new slim_rx_mux[MSM8X10_WCD_RX_MAX] = {
-	SOC_DAPM_ENUM_EXT("I2S RX1 Mux", slim_rx_mux_enum,
-			  slim_rx_mux_get, slim_rx_mux_put),
-	SOC_DAPM_ENUM_EXT("I2S RX2 Mux", slim_rx_mux_enum,
-			  slim_rx_mux_get, slim_rx_mux_put),
-	SOC_DAPM_ENUM_EXT("I2S RX3 Mux", slim_rx_mux_enum,
-			  slim_rx_mux_get, slim_rx_mux_put),
-};
-
-static const struct snd_kcontrol_new aif_cap_mixer[] = {
-	SOC_SINGLE_EXT("I2S TX1", SND_SOC_NOPM, MSM8X10_WCD_TX1, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("I2S TX2", SND_SOC_NOPM, MSM8X10_WCD_TX2, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("I2S TX3", SND_SOC_NOPM, MSM8X10_WCD_TX3, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("I2S TX4", SND_SOC_NOPM, MSM8X10_WCD_TX4, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-};
-
-
 static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
 					 int enable)
 {
@@ -1243,7 +1185,7 @@
 
 	if (w->reg == MSM8X10_WCD_A_TX_1_EN)
 		init_bit_shift = 7;
-	else if (adc_reg == MSM8X10_WCD_A_TX_2_EN)
+	else if (w->reg == MSM8X10_WCD_A_TX_2_EN)
 		init_bit_shift = 6;
 	else {
 		dev_err(codec->dev, "%s: Error, invalid adc register\n",
@@ -1365,54 +1307,36 @@
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
-	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
 	u16 micb_int_reg;
-	u8 cfilt_sel_val = 0;
 	char *internal1_text = "Internal1";
 	char *internal2_text = "Internal2";
 	char *internal3_text = "Internal3";
-	enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
 
 	dev_dbg(codec->dev, "%s %d\n", __func__, event);
 	switch (w->reg) {
 	case MSM8X10_WCD_A_MICB_1_CTL:
 		micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
-		cfilt_sel_val =
-			msm8x10_wcd->resmgr.pdata->micbias.bias1_cfilt_sel;
-		e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
-		e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
-		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
 		break;
 	default:
 		dev_err(codec->dev,
-			"%s: Error, invalid micbias register\n", __func__);
+			"%s: Error, invalid micbias register 0x%x\n",
+			__func__, w->reg);
 		return -EINVAL;
 	}
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		/* Let MBHC module know so micbias switch to be off */
-		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
-
-		/* Get cfilt */
-		wcd9xxx_resmgr_cfilt_get(&msm8x10_wcd->resmgr, cfilt_sel_val);
-
 		if (strnstr(w->name, internal1_text, 30))
-			snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
+			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
 		else if (strnstr(w->name, internal2_text, 30))
-			snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
+			snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
 		else if (strnstr(w->name, internal3_text, 30))
-			snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
+			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		usleep_range(20000, 20100);
-		/* Let MBHC module know so micbias is on */
-		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_on);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		/* Let MBHC module know so micbias switch to be off */
-		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
-
 		if (strnstr(w->name, internal1_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
 		else if (strnstr(w->name, internal2_text, 30))
@@ -1420,14 +1344,36 @@
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
 
-		/* Put cfilt */
-		wcd9xxx_resmgr_cfilt_put(&msm8x10_wcd->resmgr, cfilt_sel_val);
 		break;
 	}
-
 	return 0;
 }
 
+static void tx_hpf_corner_freq_callback(struct work_struct *work)
+{
+	struct delayed_work *hpf_delayed_work;
+	struct hpf_work *hpf_work;
+	struct msm8x10_wcd_priv *msm8x10_wcd;
+	struct snd_soc_codec *codec;
+	u16 tx_mux_ctl_reg;
+	u8 hpf_cut_of_freq;
+
+	hpf_delayed_work = to_delayed_work(work);
+	hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
+	msm8x10_wcd = hpf_work->msm8x10_wcd;
+	codec = hpf_work->msm8x10_wcd->codec;
+	hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
+
+	tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
+			(hpf_work->decimator - 1) * 32;
+
+	dev_info(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
+		 __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
+
+	snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
+}
+
+
 #define  TX_MUX_CTL_CUT_OFF_FREQ_MASK	0x30
 #define  CF_MIN_3DB_4HZ			0x0
 #define  CF_MIN_3DB_75HZ		0x1
@@ -1582,6 +1528,7 @@
 {
 	struct snd_soc_codec *codec = w->codec;
 	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+	msm8x10_wcd->resmgr.codec = codec;
 
 	dev_dbg(codec->dev, "%s %d\n", __func__, event);
 
@@ -1697,21 +1644,12 @@
 
 	{"I2S TX1", NULL, "TX_I2S_CLK"},
 	{"I2S TX2", NULL, "TX_I2S_CLK"},
-	{"I2S TX3", NULL, "TX_I2S_CLK"},
-	{"I2S TX4", NULL, "TX_I2S_CLK"},
 
-	{"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
+	{"DEC1 MUX", NULL, "TX CLK"},
+	{"DEC2 MUX", NULL, "TX CLK"},
 
-	{"AIF1_CAP Mixer", "I2S TX1", "I2S TX1 MUX"},
-	{"AIF1_CAP Mixer", "I2S TX2", "I2S TX2 MUX"},
-	{"AIF1_CAP Mixer", "I2S TX3", "I2S TX3 MUX"},
-	{"AIF1_CAP Mixer", "I2S TX4", "I2S TX4 MUX"},
-
-	{"I2S TX1 MUX", NULL, "DEC1 MUX"},
-	{"I2S TX2 MUX", NULL, "DEC2 MUX"},
-	{"I2S TX3 MUX", NULL, "RX1 MIX1"},
-	{"I2S TX4 MUX", "RMIX2", "RX1 MIX2"},
-	{"I2S TX4 MUX", "RMIX3", "RX1 MIX3"},
+	{"I2S TX1", NULL, "DEC1 MUX"},
+	{"I2S TX2", NULL, "DEC2 MUX"},
 
 	/* Earpiece (RX MIX1) */
 	{"EAR", NULL, "EAR PA"},
@@ -1725,33 +1663,32 @@
 	{"HPHL", NULL, "HPHL DAC"},
 
 	{"HPHR", NULL, "HPHR DAC"},
-	{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
 
 	{"HPHL DAC", NULL, "CP"},
 
 	{"HPHR DAC", NULL, "CP"},
+	{"SPK DAC", NULL, "CP"},
 
 	{"DAC1", "Switch", "RX1 CHAIN"},
 	{"HPHL DAC", "Switch", "RX1 CHAIN"},
 	{"HPHR DAC", NULL, "RX2 CHAIN"},
 
-	{"LINEOUT1", NULL, "LINEOUT1 PA"},
+	{"LINEOUT", NULL, "LINEOUT PA"},
 	{"SPK_OUT", NULL, "SPK PA"},
 
-	{"LINEOUT1 PA", NULL, "CP"},
-	{"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
+	{"LINEOUT PA", NULL, "CP"},
+	{"LINEOUT PA", NULL, "LINEOUT DAC"},
 
-	{"LINEOUT1 DAC", "RX2 INPUT", "RX2 MIX1"},
-	{"LINEOUT1 DAC", "RX3 INPUT", "RX3 MIX1"},
-
+	{"CP", NULL, "RX_BIAS"},
 	{"SPK PA", NULL, "SPK DAC"},
-	{"SPK DAC", NULL, "RX7 MIX2"},
+	{"SPK DAC", NULL, "RX3 CHAIN"},
 
+	{"RX1 CHAIN", NULL, "RX1 CLK"},
+	{"RX2 CHAIN", NULL, "RX2 CLK"},
+	{"RX3 CHAIN", NULL, "RX3 CLK"},
 	{"RX1 CHAIN", NULL, "RX1 MIX2"},
 	{"RX2 CHAIN", NULL, "RX2 MIX2"},
-
-	{"LINEOUT1 DAC", NULL, "RX_BIAS"},
-	{"SPK DAC", NULL, "RX_BIAS"},
+	{"RX3 CHAIN", NULL, "RX3 MIX1"},
 
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
@@ -1761,19 +1698,7 @@
 	{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
 	{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
 	{"RX1 MIX2", NULL, "RX1 MIX1"},
-	{"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
-	{"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
 	{"RX2 MIX2", NULL, "RX2 MIX1"},
-	{"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
-	{"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
-
-	{"I2S RX1 MUX", "AIF1_PB", "AIF1 PB"},
-	{"I2S RX2 MUX", "AIF1_PB", "AIF1 PB"},
-	{"I2S RX3 MUX", "AIF1_PB", "AIF1 PB"},
-
-	{"I2S RX1", NULL, "I2S RX1 MUX"},
-	{"I2S RX2", NULL, "I2S RX2 MUX"},
-	{"I2S RX3", NULL, "I2S RX3 MUX"},
 
 	{"RX1 MIX1 INP1", "RX1", "I2S RX1"},
 	{"RX1 MIX1 INP1", "RX2", "I2S RX2"},
@@ -1825,41 +1750,109 @@
 	{"IIR1", NULL, "IIR1 INP1 MUX"},
 	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
 	{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
-
-	/* There is no LDO_H in Helicon */
-	{"MIC BIAS1 Internal1", NULL, "LDO_H"},
-	{"MIC BIAS1 Internal2", NULL, "LDO_H"},
-	{"MIC BIAS1 External", NULL, "LDO_H"},
+	{"MIC BIAS Internal2", NULL, "INT_LDO_H"},
+	{"MIC BIAS External", NULL, "INT_LDO_H"},
 };
 
 static int msm8x10_wcd_startup(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
-	struct msm8x10_wcd *msm8x10_wcd_core =
-		dev_get_drvdata(dai->codec->dev);
 	dev_dbg(dai->codec->dev, "%s(): substream = %s  stream = %d\n",
 		__func__,
 		substream->name, substream->stream);
-	if ((msm8x10_wcd_core != NULL) &&
-	    (msm8x10_wcd_core->dev != NULL))
-		pm_runtime_get_sync(msm8x10_wcd_core->dev);
-
 	return 0;
 }
 
 static void msm8x10_wcd_shutdown(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
-	struct msm8x10_wcd *msm8x10_wcd_core =
-		dev_get_drvdata(dai->codec->dev);
 	dev_dbg(dai->codec->dev,
 		"%s(): substream = %s  stream = %d\n" , __func__,
 		substream->name, substream->stream);
-	if ((msm8x10_wcd_core != NULL) &&
-	    (msm8x10_wcd_core->dev != NULL)) {
-		pm_runtime_mark_last_busy(msm8x10_wcd_core->dev);
-		pm_runtime_put(msm8x10_wcd_core->dev);
+}
+
+static int msm8x10_wcd_codec_enable_clock_block(struct snd_soc_codec *codec,
+						int enable)
+{
+	if (enable) {
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+				    0x01, 0x01);
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
+				    0x03, 0x03);
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+				    0x0f, 0x0d);
+	} else {
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+				    0x0f, 0x00);
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+				    0x01, 0x01);
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+				    0x03, 0x00);
 	}
+	return 0;
+}
+
+static void msm8x10_wcd_codec_enable_audio_mode_bandgap(struct snd_soc_codec
+							*codec)
+{
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
+		0x80);
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x04,
+		0x04);
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x01,
+		0x01);
+	usleep_range(1000, 1000);
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
+		0x00);
+}
+
+static void msm8x10_wcd_codec_enable_bandgap(struct snd_soc_codec *codec,
+	enum msm8x10_wcd_bandgap_type choice)
+{
+	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+
+	/* TODO lock resources accessed by audio streams and threaded
+	 * interrupt handlers
+	 */
+
+	dev_dbg(codec->dev, "%s, choice is %d, current is %d\n",
+		__func__, choice,
+		msm8x10_wcd->bandgap_type);
+
+	if (msm8x10_wcd->bandgap_type == choice)
+		return;
+
+	if ((msm8x10_wcd->bandgap_type == MSM8X10_WCD_BANDGAP_OFF) &&
+		(choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
+		msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
+	} else if (choice == MSM8X10_WCD_BANDGAP_MBHC_MODE) {
+		/* bandgap mode becomes fast,
+		 * mclk should be off or clk buff source souldn't be VBG
+		 * Let's turn off mclk always */
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+				    0x2, 0x2);
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+				    0x80, 0x80);
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+				    0x4, 0x4);
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+				    0x01, 0x01);
+		usleep_range(1000, 1000);
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+				    0x80, 0x00);
+	} else if ((msm8x10_wcd->bandgap_type ==
+		    MSM8X10_WCD_BANDGAP_MBHC_MODE) &&
+		    (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
+		snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
+		usleep_range(100, 100);
+		msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
+	} else if (choice == MSM8X10_WCD_BANDGAP_OFF) {
+		snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
+	} else {
+		dev_err(codec->dev,
+			"%s: Error, Invalid bandgap settings\n", __func__);
+	}
+	msm8x10_wcd->bandgap_type = choice;
 }
 
 int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec,
@@ -1867,24 +1860,30 @@
 {
 	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
 
-	dev_dbg(codec->dev,
-		"%s: mclk_enable = %u, dapm = %d\n", __func__,
-		mclk_enable, dapm);
-	WCD9XXX_BCL_LOCK(&msm8x10_wcd->resmgr);
+	dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
+		__func__, mclk_enable, dapm);
+	if (dapm)
+		MSM8X10_WCD_ACQUIRE_LOCK(msm8x10_wcd->codec_resource_lock);
 	if (mclk_enable) {
-		wcd9xxx_resmgr_get_bandgap(&msm8x10_wcd->resmgr,
-					   WCD9XXX_BANDGAP_AUDIO_MODE);
-		wcd9xxx_resmgr_get_clk_block(&msm8x10_wcd->resmgr,
-					     WCD9XXX_CLK_MCLK);
+		msm8x10_wcd->mclk_enabled = true;
+		msm8x10_wcd_codec_enable_bandgap(codec,
+					   MSM8X10_WCD_BANDGAP_AUDIO_MODE);
+		msm8x10_wcd_codec_enable_clock_block(codec, 1);
 	} else {
-		/* Put clock and BG */
-		wcd9xxx_resmgr_put_clk_block(&msm8x10_wcd->resmgr,
-					     WCD9XXX_CLK_MCLK);
-		wcd9xxx_resmgr_put_bandgap(&msm8x10_wcd->resmgr,
-					   WCD9XXX_BANDGAP_AUDIO_MODE);
+		if (!msm8x10_wcd->mclk_enabled) {
+			if (dapm)
+				MSM8X10_WCD_RELEASE_LOCK(
+				  msm8x10_wcd->codec_resource_lock);
+			dev_err(codec->dev, "Error, MCLK already diabled\n");
+			return -EINVAL;
+		}
+		msm8x10_wcd->mclk_enabled = false;
+		msm8x10_wcd_codec_enable_clock_block(codec, 0);
+		msm8x10_wcd_codec_enable_bandgap(codec,
+						   MSM8X10_WCD_BANDGAP_OFF);
 	}
-	WCD9XXX_BCL_UNLOCK(&msm8x10_wcd->resmgr);
-
+	if (dapm)
+		MSM8X10_WCD_RELEASE_LOCK(msm8x10_wcd->codec_resource_lock);
 	return 0;
 }
 
@@ -2027,7 +2026,7 @@
 			.rate_max = 192000,
 			.rate_min = 8000,
 			.channels_min = 1,
-			.channels_max = 4,
+			.channels_max = 3,
 		},
 		.ops = &msm8x10_wcd_dai_ops,
 	},
@@ -2077,23 +2076,16 @@
 	SND_SOC_DAPM_MIXER("DAC1", MSM8X10_WCD_A_RX_EAR_EN, 6, 0, dac1_switch,
 		ARRAY_SIZE(dac1_switch)),
 
-	SND_SOC_DAPM_AIF_IN("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
-				AIF1_PB, 0),
+	SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
 
-	SND_SOC_DAPM_MUX("I2S RX1 MUX", SND_SOC_NOPM, MSM8X10_WCD_RX1, 0,
-				&slim_rx_mux[MSM8X10_WCD_RX1]),
-	SND_SOC_DAPM_MUX("I2S RX2 MUX", SND_SOC_NOPM, MSM8X10_WCD_RX2, 0,
-				&slim_rx_mux[MSM8X10_WCD_RX2]),
-	SND_SOC_DAPM_MUX("I2S RX3 MUX", SND_SOC_NOPM, MSM8X10_WCD_RX3, 0,
-				&slim_rx_mux[MSM8X10_WCD_RX3]),
+	SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
 
-	SND_SOC_DAPM_MIXER("I2S RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("I2S RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("I2S RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("I2S RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("I2S RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
 
-	/* Headphone */
+	SND_SOC_DAPM_SUPPLY("TX CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+			4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
+
 	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
 	SND_SOC_DAPM_PGA_E("HPHL", MSM8X10_WCD_A_RX_HPH_CNP_EN,
 		5, 0, NULL, 0,
@@ -2114,10 +2106,10 @@
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
 	/* Speaker */
-	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT"),
 	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
 
-	SND_SOC_DAPM_PGA_E("LINEOUT1 PA", MSM8X10_WCD_A_RX_LINE_CNP_EN,
+	SND_SOC_DAPM_PGA_E("LINEOUT PA", MSM8X10_WCD_A_RX_LINE_CNP_EN,
 			0, 0, NULL, 0, msm8x10_wcd_codec_enable_lineout,
 			SND_SOC_DAPM_PRE_PMU |
 			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -2127,7 +2119,7 @@
 			SND_SOC_DAPM_PRE_PMU |
 			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL,
+	SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL,
 		MSM8X10_WCD_A_RX_LINE_1_DAC_CTL, 7, 0,
 		msm8x10_wcd_lineout_dac_event,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
@@ -2152,10 +2144,18 @@
 		0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 
+	SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+		1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+		2, 0, NULL, 0),
 	SND_SOC_DAPM_MIXER("RX1 CHAIN", MSM8X10_WCD_A_CDC_RX1_B6_CTL,
 		5, 0, NULL, 0),
 	SND_SOC_DAPM_MIXER("RX2 CHAIN", MSM8X10_WCD_A_CDC_RX2_B6_CTL,
 		5, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX3 CHAIN", MSM8X10_WCD_A_CDC_RX3_B6_CTL,
+		5, 0, NULL, 0),
 
 	SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
 		&rx_mix1_inp1_mux),
@@ -2191,26 +2191,28 @@
 
 
 	SND_SOC_DAPM_INPUT("AMIC1"),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External",
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1",
 		MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
 		msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1",
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal2",
 		MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
 		msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2",
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal3",
 		MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
 		msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
 		msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
+	SND_SOC_DAPM_ADC_E("ADC2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
 		msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
+	SND_SOC_DAPM_MICBIAS("MIC BIAS External", MSM8X10_WCD_A_MICB_1_CTL,
+			     7, 0),
+
 	SND_SOC_DAPM_INPUT("AMIC3"),
 
 	SND_SOC_DAPM_MUX_E("DEC1 MUX",
@@ -2226,11 +2228,13 @@
 		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_INPUT("AMIC2"),
-	SND_SOC_DAPM_AIF_OUT("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
-		AIF1_CAP, 0),
 
-	SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
-		aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
+	SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM,
+		0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM,
+		0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM,
+		0, 0),
 
 	/* Digital Mic Inputs */
 	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
@@ -2254,7 +2258,7 @@
 static const struct msm8x10_wcd_reg_mask_val msm8x10_wcd_reg_defaults[] = {
 
 	/* set MCLk to 9.6 */
-	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CHIP_CTL, 0x0A),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CHIP_CTL, 0x00),
 
 	/* EAR PA deafults  */
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_CMBUFF, 0x05),
@@ -2280,7 +2284,12 @@
 
 
 	/* Disable TX7 internal biasing path which can cause leakage */
-	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_SUP_SWITCH_CTRL_1, 0xBF),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x82),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
 };
 
 static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
@@ -2338,12 +2347,36 @@
 
 static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
 {
+	struct msm8x10_wcd_priv *msm8x10_wcd;
+	int i;
 	dev_dbg(codec->dev, "%s()\n", __func__);
 
+	msm8x10_wcd = kzalloc(sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
+	if (!msm8x10_wcd) {
+		dev_err(codec->dev, "Failed to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0 ; i < NUM_DECIMATORS; i++) {
+		tx_hpf_work[i].msm8x10_wcd = msm8x10_wcd;
+		tx_hpf_work[i].decimator = i + 1;
+		INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
+			tx_hpf_corner_freq_callback);
+	}
+
 	codec->control_data = dev_get_drvdata(codec->dev);
+	snd_soc_codec_set_drvdata(codec, msm8x10_wcd);
+	msm8x10_wcd->codec = codec;
 	msm8x10_wcd_codec_init_reg(codec);
 	msm8x10_wcd_update_reg_defaults(codec);
 
+	msm8x10_wcd->mclk_enabled = false;
+	msm8x10_wcd->bandgap_type = MSM8X10_WCD_BANDGAP_OFF;
+	msm8x10_wcd->clock_active = false;
+	msm8x10_wcd->config_mode_active = false;
+	msm8x10_wcd->mbhc_polling_active = false;
+	mutex_init(&msm8x10_wcd->codec_resource_lock);
+	msm8x10_wcd->codec = codec;
 
 	return 0;
 }
@@ -2353,18 +2386,6 @@
 	return 0;
 }
 
-static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
-{
-
-	mutex_init(&msm8x10->io_lock);
-	mutex_init(&msm8x10->xfer_lock);
-	mutex_init(&msm8x10->pm_lock);
-	msm8x10->wlock_holders = 0;
-
-	return 0;
-}
-
-
 static struct snd_soc_codec_driver soc_codec_dev_msm8x10_wcd = {
 	.probe	= msm8x10_wcd_codec_probe,
 	.remove	= msm8x10_wcd_codec_remove,
@@ -2387,6 +2408,124 @@
 	.num_dapm_routes = ARRAY_SIZE(audio_map),
 };
 
+static int msm8x10_wcd_enable_supplies(struct msm8x10_wcd *msm8x10,
+				struct msm8x10_wcd_pdata *pdata)
+{
+	int ret;
+	int i;
+	msm8x10->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
+				   ARRAY_SIZE(pdata->regulator),
+				   GFP_KERNEL);
+	if (!msm8x10->supplies) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	msm8x10->num_of_supplies = 0;
+
+	if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
+		dev_err(msm8x10->dev, "%s: Array Size out of bound\n",
+			__func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		if (pdata->regulator[i].name) {
+			msm8x10->supplies[i].supply = pdata->regulator[i].name;
+			msm8x10->num_of_supplies++;
+		}
+	}
+
+	ret = regulator_bulk_get(msm8x10->dev, msm8x10->num_of_supplies,
+				 msm8x10->supplies);
+	if (ret != 0) {
+		dev_err(msm8x10->dev, "Failed to get supplies: err = %d\n",
+							ret);
+		goto err_supplies;
+	}
+
+	for (i = 0; i < msm8x10->num_of_supplies; i++) {
+		ret = regulator_set_voltage(msm8x10->supplies[i].consumer,
+			pdata->regulator[i].min_uV, pdata->regulator[i].max_uV);
+		if (ret) {
+			dev_err(msm8x10->dev, "%s: Setting regulator voltage failed for regulator %s err = %d\n",
+				__func__, msm8x10->supplies[i].supply, ret);
+			goto err_get;
+		}
+
+		ret = regulator_set_optimum_mode(msm8x10->supplies[i].consumer,
+			pdata->regulator[i].optimum_uA);
+		if (ret < 0) {
+			dev_err(msm8x10->dev, "%s: Setting regulator optimum mode failed for regulator %s err = %d\n",
+				__func__, msm8x10->supplies[i].supply, ret);
+			goto err_get;
+		}
+	}
+
+	ret = regulator_bulk_enable(msm8x10->num_of_supplies,
+				    msm8x10->supplies);
+	if (ret != 0) {
+		dev_err(msm8x10->dev, "Failed to enable supplies: err = %d\n",
+				ret);
+		goto err_configure;
+	}
+	return ret;
+
+err_configure:
+	for (i = 0; i < msm8x10->num_of_supplies; i++) {
+		regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
+			pdata->regulator[i].max_uV);
+		regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
+	}
+err_get:
+	regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
+err_supplies:
+	kfree(msm8x10->supplies);
+err:
+	return ret;
+}
+
+static void msm8x10_wcd_disable_supplies(struct msm8x10_wcd *msm8x10,
+				     struct msm8x10_wcd_pdata *pdata)
+{
+	int i;
+
+	regulator_bulk_disable(msm8x10->num_of_supplies,
+				    msm8x10->supplies);
+	for (i = 0; i < msm8x10->num_of_supplies; i++) {
+		regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
+			pdata->regulator[i].max_uV);
+		regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
+	}
+	regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
+	kfree(msm8x10->supplies);
+}
+
+static int msm8x10_wcd_bringup(struct msm8x10_wcd *msm8x10)
+{
+	msm8x10->read_dev = msm8x10_wcd_reg_read;
+	msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CDC_RST_CTL, 0x02);
+	msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CHIP_CTL, 0x00);
+	usleep_range(5000, 5000);
+	msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CDC_RST_CTL, 0x03);
+	return 0;
+}
+
+static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
+{
+	mutex_init(&msm8x10->io_lock);
+	mutex_init(&msm8x10->xfer_lock);
+	mutex_init(&msm8x10->pm_lock);
+	msm8x10->wlock_holders = 0;
+
+	iowrite32(0x03C00000, ioremap(0xFD512050, 4));
+	usleep_range(5000, 5000);
+
+	msm8x10_wcd_bringup(msm8x10);
+	return 0;
+}
+
 static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
@@ -2401,7 +2540,7 @@
 
 	if (device_id > 0) {
 		msm8x10_wcd_modules[device_id++].client = client;
-		return ret;
+		goto rtn;
 	}
 
 	dev = &client->dev;
@@ -2421,19 +2560,25 @@
 		dev_err(&client->dev,
 			"%s: error, allocation failed\n", __func__);
 		ret = -ENOMEM;
-		goto fail;
+		goto rtn;
 	}
 
 	msm8x10->dev = &client->dev;
 	msm8x10_wcd_modules[device_id++].client = client;
 	msm8x10->read_dev = msm8x10_wcd_reg_read;
 	msm8x10->write_dev = msm8x10_wcd_reg_write;
+	ret = msm8x10_wcd_enable_supplies(msm8x10, pdata);
+	if (ret) {
+		dev_err(&client->dev, "%s: Fail to enable Codec supplies\n",
+			__func__);
+		goto err_codec;
+	}
 	ret = msm8x10_wcd_device_init(msm8x10);
 	if (ret) {
 		dev_err(&client->dev,
 			"%s:msm8x10_wcd_device_init failed with error %d\n",
 			__func__, ret);
-		goto fail;
+		goto err_supplies;
 	}
 	dev_set_drvdata(&client->dev, msm8x10);
 	ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_msm8x10_wcd,
@@ -2443,7 +2588,14 @@
 		dev_err(&client->dev,
 			"%s:snd_soc_register_codec failed with error %d\n",
 			__func__, ret);
-fail:
+	else
+		goto rtn;
+
+err_supplies:
+	msm8x10_wcd_disable_supplies(msm8x10, pdata);
+err_codec:
+	kfree(msm8x10);
+rtn:
 	return ret;
 }
 
diff --git a/sound/soc/codecs/msm8x10-wcd.h b/sound/soc/codecs/msm8x10-wcd.h
index 44e8a6d..d250e0a 100644
--- a/sound/soc/codecs/msm8x10-wcd.h
+++ b/sound/soc/codecs/msm8x10-wcd.h
@@ -199,7 +199,7 @@
 	int (*read_dev)(struct msm8x10_wcd *msm8x10,
 			unsigned short reg, unsigned int *val);
 	int (*write_dev)(struct msm8x10_wcd *msm8x10,
-			 unsigned short reg, unsigned int val);
+			 unsigned short reg, u8 val);
 
 	u32 num_of_supplies;
 	struct regulator_bulk_data *supplies;
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 67674f3..b71dd65 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -461,8 +461,8 @@
 					kcontrol->private_value)->shift;
 
 	ucontrol->value.integer.value[0] =
-		snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
-		(1 << band_idx);
+		(snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
+		(1 << band_idx)) != 0;
 
 	dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
 		iir_idx, band_idx,
@@ -485,23 +485,54 @@
 	snd_soc_update_bits(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx),
 		(1 << band_idx), (value << band_idx));
 
-	dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
-		iir_idx, band_idx, value);
+	pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
+		iir_idx, band_idx,
+		((snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
+		(1 << band_idx)) != 0));
 	return 0;
 }
 static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
 				int iir_idx, int band_idx,
 				int coeff_idx)
 {
+	uint32_t value = 0;
+
 	/* Address does not automatically update if reading */
 	snd_soc_write(codec,
 		(TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
-		(band_idx * BAND_MAX + coeff_idx) & 0x1F);
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t)) & 0x7F);
+
+	value |= snd_soc_read(codec,
+		(TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx));
+
+	snd_soc_write(codec,
+		(TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 1) & 0x7F);
+
+	value |= (snd_soc_read(codec,
+		(TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 8);
+
+	snd_soc_write(codec,
+		(TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 2) & 0x7F);
+
+	value |= (snd_soc_read(codec,
+		(TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 16);
+
+	snd_soc_write(codec,
+		(TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 3) & 0x7F);
 
 	/* Mask bits top 2 bits since they are reserved */
-	return ((snd_soc_read(codec,
-		(TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24)) &
-		0x3FFFFFFF;
+	value |= ((snd_soc_read(codec,
+		(TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) & 0x3F) << 24);
+
+	return value;
+
 }
 
 static int tapan_get_iir_band_audio_mixer(
@@ -545,13 +576,19 @@
 
 static void set_iir_band_coeff(struct snd_soc_codec *codec,
 				int iir_idx, int band_idx,
-				int coeff_idx, uint32_t value)
+				uint32_t value)
 {
-	/* Mask top 3 bits, 6-8 are reserved */
-	/* Update address manually each time */
 	snd_soc_write(codec,
-		(TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
-		(band_idx * BAND_MAX + coeff_idx) & 0x1F);
+		(TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+		(value & 0xFF));
+
+	snd_soc_write(codec,
+		(TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+		(value >> 8) & 0xFF);
+
+	snd_soc_write(codec,
+		(TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+		(value >> 16) & 0xFF);
 
 	/* Mask top 2 bits, 7-8 are reserved */
 	snd_soc_write(codec,
@@ -570,15 +607,21 @@
 	int band_idx = ((struct soc_multi_mixer_control *)
 					kcontrol->private_value)->shift;
 
-	set_iir_band_coeff(codec, iir_idx, band_idx, 0,
+	/* Mask top bit it is reserved */
+	/* Updates addr automatically for each B2 write */
+	snd_soc_write(codec,
+		(TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+		(band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
+
+	set_iir_band_coeff(codec, iir_idx, band_idx,
 				ucontrol->value.integer.value[0]);
-	set_iir_band_coeff(codec, iir_idx, band_idx, 1,
+	set_iir_band_coeff(codec, iir_idx, band_idx,
 				ucontrol->value.integer.value[1]);
-	set_iir_band_coeff(codec, iir_idx, band_idx, 2,
+	set_iir_band_coeff(codec, iir_idx, band_idx,
 				ucontrol->value.integer.value[2]);
-	set_iir_band_coeff(codec, iir_idx, band_idx, 3,
+	set_iir_band_coeff(codec, iir_idx, band_idx,
 				ucontrol->value.integer.value[3]);
-	set_iir_band_coeff(codec, iir_idx, band_idx, 4,
+	set_iir_band_coeff(codec, iir_idx, band_idx,
 				ucontrol->value.integer.value[4]);
 
 	dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 43a1042..845f1a2 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -110,6 +110,15 @@
 	AANC_FF_GAIN_ADAPTIVE,
 	AANC_FFGAIN_ADAPTIVE_EN,
 	AANC_GAIN_CONTROL,
+	SPKR_CLIP_PIPE_BANK_SEL,
+	SPKR_CLIPDET_VAL0,
+	SPKR_CLIPDET_VAL1,
+	SPKR_CLIPDET_VAL2,
+	SPKR_CLIPDET_VAL3,
+	SPKR_CLIPDET_VAL4,
+	SPKR_CLIPDET_VAL5,
+	SPKR_CLIPDET_VAL6,
+	SPKR_CLIPDET_VAL7,
 	MAX_CFG_REGISTERS,
 };
 
@@ -182,6 +191,74 @@
 		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_ANC1_GAIN_CTL),
 		AANC_GAIN_CONTROL, 0xFF, 8, 0
 	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_DESTN3),
+		MAD_CLIP_INT_DEST_SELECT_REG, 0x8, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_MASK3),
+		MAD_CLIP_INT_MASK_REG, 0x8, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_STATUS3),
+		MAD_CLIP_INT_STATUS_REG, 0x8, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_CLEAR3),
+		MAD_CLIP_INT_CLEAR_REG, 0x8, 8, 0
+	},
+};
+
+static struct afe_param_cdc_reg_cfg clip_reg_cfg[] = {
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_B1_CTL),
+		SPKR_CLIP_PIPE_BANK_SEL, 0x3, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL0),
+		SPKR_CLIPDET_VAL0, 0xff, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL1),
+		SPKR_CLIPDET_VAL1, 0xff, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL2),
+		SPKR_CLIPDET_VAL2, 0xff, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL3),
+		SPKR_CLIPDET_VAL3, 0xff, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL4),
+		SPKR_CLIPDET_VAL4, 0xff, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL5),
+		SPKR_CLIPDET_VAL5, 0xff, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL6),
+		SPKR_CLIPDET_VAL6, 0xff, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL7),
+		SPKR_CLIPDET_VAL7, 0xff, 8, 0
+	},
 };
 
 static struct afe_param_cdc_reg_cfg_data taiko_audio_reg_cfg = {
@@ -189,11 +266,22 @@
 	.reg_data = audio_reg_cfg,
 };
 
+static struct afe_param_cdc_reg_cfg_data taiko_clip_reg_cfg = {
+	.num_registers = ARRAY_SIZE(clip_reg_cfg),
+	.reg_data = clip_reg_cfg,
+};
+
 static struct afe_param_id_cdc_aanc_version taiko_cdc_aanc_version = {
 	.cdc_aanc_minor_version = AFE_API_VERSION_CDC_AANC_VERSION,
 	.aanc_hw_version        = AANC_HW_BLOCK_VERSION_2,
 };
 
+static struct afe_param_id_clip_bank_sel clip_bank_sel = {
+	.minor_version = AFE_API_VERSION_CLIP_BANK_SEL_CFG,
+	.num_banks = AFE_CLIP_MAX_BANKS,
+	.bank_map = {0, 1, 2, 3},
+};
+
 module_param_cb(spkr_drv_wrnd, &spkr_drv_wrnd_param_ops, &spkr_drv_wrnd, 0644);
 MODULE_PARM_DESC(spkr_drv_wrnd,
 	       "Run software workaround to avoid leakage on the speaker drive");
@@ -4620,9 +4708,6 @@
 	dai = &taiko_p->dai[w->shift];
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		/*Enable Clip Detection*/
-		snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_CLIP_DET,
-				0x8, 0x8);
 		/*Enable V&I sensing*/
 		snd_soc_update_bits(codec, TAIKO_A_SPKR_PROT_EN,
 				0x88, 0x88);
@@ -4635,6 +4720,7 @@
 		/*Enable Current Decimator*/
 		snd_soc_update_bits(codec,
 		TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x1F, 0x13);
+		(void) taiko_codec_enable_slim_chmask(dai, true);
 		ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
 					dai->rate, dai->bit_width,
 					&dai->grph);
@@ -4657,9 +4743,6 @@
 		/*Disable V&I sensing*/
 		snd_soc_update_bits(codec, TAIKO_A_SPKR_PROT_EN,
 				0x88, 0x00);
-		/*Disable clip detection*/
-		snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_CLIP_DET,
-				0x8, 0x0);
 		break;
 	}
 out_vi:
@@ -5949,6 +6032,7 @@
 			   enum afe_config_type config_type)
 {
 	struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *taiko_core = dev_get_drvdata(codec->dev->parent);
 
 	switch (config_type) {
 	case AFE_SLIMBUS_SLAVE_CONFIG:
@@ -5959,6 +6043,16 @@
 		return &taiko_slimbus_slave_port_cfg;
 	case AFE_AANC_VERSION:
 		return &taiko_cdc_aanc_version;
+	case AFE_CLIP_BANK_SEL:
+		if (!TAIKO_IS_1_0(taiko_core->version))
+			return &clip_bank_sel;
+		else
+			return NULL;
+	case AFE_CDC_CLIP_REGISTERS_CONFIG:
+		if (!TAIKO_IS_1_0(taiko_core->version))
+			return &taiko_clip_reg_cfg;
+		else
+			return NULL;
 	default:
 		pr_err("%s: Unknown config_type 0x%x\n", __func__, config_type);
 		return NULL;
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index daba6d5..a37b4eb 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -2786,6 +2786,7 @@
 	wcd9xxx_turn_onoff_rel_detection(codec, true);
 
 	pr_debug("%s: leave\n", __func__);
+	return;
 
 gen_err:
 	pr_err("%s: Error returned, ret: %d\n", __func__, ret);
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index ebde90b..7ab4811 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -55,8 +55,7 @@
 # for MSM 8960 sound card driver
 
 obj-$(CONFIG_SND_SOC_MSM_QDSP6_INTF) += qdsp6/
-
-snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
+snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-loopback.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
 obj-$(CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO) += msm-dai-q6-hdmi.o
 obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o msm-pcm-dtmf.o msm-pcm-host-voice.o
 snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 8db13f6..1b51595 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -236,6 +236,17 @@
 			.rate_min =	8000,
 			.rate_max = 192000,
 		},
+		.capture = {
+			.stream_name = "MultiMedia6 Capture",
+			.aif_name = "MM_UL6",
+			.rates = (SNDRV_PCM_RATE_8000_48000|
+					SNDRV_PCM_RATE_KNOT),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =     8000,
+			.rate_max =	48000,
+		},
 		.ops = &msm_fe_Multimedia_dai_ops,
 		.name = "MultiMedia6",
 	},
@@ -549,6 +560,34 @@
 		.name = "SEC_I2S_RX_HOSTLESS",
 	},
 	{
+		.capture = {
+			.stream_name = "Primary MI2S_TX Hostless Capture",
+			.aif_name = "PRI_MI2S_UL_HL",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min = 8000,
+			.rate_max = 48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "PRI_MI2S_TX_HOSTLESS",
+	},
+	{
+		.playback = {
+			.stream_name = "Secondary MI2S_RX Hostless Playback",
+			.aif_name = "SEC_MI2S_DL_HL",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =	8000,
+			.rate_max =    48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "SEC_MI2S_RX_HOSTLESS",
+	},
+	{
 		.playback = {
 			.stream_name = "Voice2 Playback",
 			.aif_name = "VOICE2_DL",
diff --git a/sound/soc/msm/msm-pcm-loopback.c b/sound/soc/msm/msm-pcm-loopback.c
new file mode 100644
index 0000000..84ea9c6
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-loopback.c
@@ -0,0 +1,362 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*/
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/apr_audio.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/q6asm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm-routing.h"
+
+struct msm_pcm_loopback {
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+
+	int instance;
+
+	struct mutex lock;
+
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+
+	int playback_start;
+	int capture_start;
+	int session_id;
+	struct audio_client *audio_client;
+};
+
+static void stop_pcm(struct msm_pcm_loopback *pcm);
+
+static const struct snd_pcm_hardware dummy_pcm_hardware = {
+	.formats                = 0xffffffff,
+	.channels_min           = 1,
+	.channels_max           = UINT_MAX,
+
+	/* Random values to keep userspace happy when checking constraints */
+	.info                   = SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.buffer_bytes_max       = 128*1024,
+	.period_bytes_min       = 1024,
+	.period_bytes_max       = 1024*2,
+	.periods_min            = 2,
+	.periods_max            = 128,
+};
+
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+					void *priv_data)
+{
+	struct msm_pcm_loopback *pcm = priv_data;
+
+	BUG_ON(!pcm);
+
+	pr_debug("%s: event %x\n", __func__, event);
+
+	switch (event) {
+	case MSM_PCM_RT_EVT_DEVSWITCH:
+		q6asm_cmd(pcm->audio_client, CMD_PAUSE);
+		q6asm_cmd(pcm->audio_client, CMD_FLUSH);
+		q6asm_run(pcm->audio_client, 0, 0, 0);
+	default:
+		break;
+	}
+}
+
+static void msm_pcm_loopback_event_handler(uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv)
+{
+	pr_debug("%s\n", __func__);
+	switch (opcode) {
+	case APR_BASIC_RSP_RESULT: {
+		switch (payload[0]) {
+			break;
+		default:
+			break;
+		}
+	}
+	break;
+	default:
+		pr_err("Not Supported Event opcode[0x%x]\n", opcode);
+		break;
+	}
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct msm_pcm_loopback *pcm;
+	int ret = 0;
+	struct msm_pcm_routing_evt event;
+
+	pcm = dev_get_drvdata(rtd->platform->dev);
+	mutex_lock(&pcm->lock);
+
+	snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		pcm->playback_substream = substream;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		pcm->capture_substream = substream;
+
+	pcm->instance++;
+	dev_dbg(rtd->platform->dev, "%s: pcm out open: %d,%d\n", __func__,
+			pcm->instance, substream->stream);
+	if (pcm->instance == 2) {
+		struct snd_soc_pcm_runtime *soc_pcm_rx =
+				pcm->playback_substream->private_data;
+		struct snd_soc_pcm_runtime *soc_pcm_tx =
+				pcm->capture_substream->private_data;
+		if (pcm->audio_client != NULL)
+			stop_pcm(pcm);
+
+		pcm->audio_client = q6asm_audio_client_alloc(
+				(app_cb)msm_pcm_loopback_event_handler, pcm);
+		if (!pcm->audio_client) {
+			dev_err(rtd->platform->dev,
+				"%s: Could not allocate memory\n", __func__);
+			mutex_unlock(&pcm->lock);
+			return -ENOMEM;
+		}
+		pcm->session_id = pcm->audio_client->session;
+		pcm->audio_client->perf_mode = false;
+		ret = q6asm_open_loopack(pcm->audio_client);
+		if (ret < 0) {
+			dev_err(rtd->platform->dev,
+				"%s: pcm out open failed\n", __func__);
+			q6asm_audio_client_free(pcm->audio_client);
+			mutex_unlock(&pcm->lock);
+			return -ENOMEM;
+		}
+		event.event_func = msm_pcm_route_event_handler;
+		event.priv_data = (void *) pcm;
+		msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->be_id,
+			pcm->audio_client->perf_mode,
+			pcm->session_id, pcm->capture_substream->stream);
+		msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->be_id,
+			pcm->audio_client->perf_mode,
+			pcm->session_id, pcm->playback_substream->stream,
+			event);
+	}
+	dev_info(rtd->platform->dev, "%s: Instance = %d, Stream ID = %s\n",
+			__func__ , pcm->instance, substream->pcm->id);
+	runtime->private_data = pcm;
+
+	mutex_unlock(&pcm->lock);
+
+	return 0;
+}
+
+static void stop_pcm(struct msm_pcm_loopback *pcm)
+{
+	struct snd_soc_pcm_runtime *soc_pcm_rx =
+		pcm->playback_substream->private_data;
+	struct snd_soc_pcm_runtime *soc_pcm_tx =
+		pcm->capture_substream->private_data;
+
+	if (pcm->audio_client == NULL)
+		return;
+	q6asm_cmd(pcm->audio_client, CMD_CLOSE);
+
+	msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
+			SNDRV_PCM_STREAM_PLAYBACK);
+	msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
+			SNDRV_PCM_STREAM_CAPTURE);
+	q6asm_audio_client_free(pcm->audio_client);
+	pcm->audio_client = NULL;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm_loopback *pcm = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	int ret = 0;
+
+	mutex_lock(&pcm->lock);
+
+	dev_dbg(rtd->platform->dev, "%s: end pcm call:%d\n",
+		__func__, substream->stream);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		pcm->playback_start = 0;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		pcm->capture_start = 0;
+
+	pcm->instance--;
+	if (!pcm->playback_start || !pcm->capture_start) {
+		dev_dbg(rtd->platform->dev, "%s: end pcm call\n", __func__);
+		stop_pcm(pcm);
+	}
+
+	mutex_unlock(&pcm->lock);
+	return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm_loopback *pcm = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+	mutex_lock(&pcm->lock);
+
+	dev_dbg(rtd->platform->dev, "%s: ASM loopback stream:%d\n",
+		__func__, substream->stream);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (!pcm->playback_start)
+			pcm->playback_start = 1;
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (!pcm->capture_start)
+			pcm->capture_start = 1;
+	}
+	mutex_unlock(&pcm->lock);
+
+	return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm_loopback *pcm = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		dev_dbg(rtd->platform->dev,
+			"%s: playback_start:%d,capture_start:%d\n", __func__,
+			pcm->playback_start, pcm->capture_start);
+		if (pcm->playback_start && pcm->capture_start)
+			q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_STOP:
+		dev_dbg(rtd->platform->dev,
+			"%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
+			__func__, pcm->playback_start, pcm->capture_start);
+		if (pcm->playback_start && pcm->capture_start)
+			q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+	dev_dbg(rtd->platform->dev, "%s: ASM loopback\n", __func__);
+
+	return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+		params_buffer_bytes(params));
+}
+
+static int msm_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.hw_params	= msm_pcm_hw_params,
+	.hw_free	= msm_pcm_hw_free,
+	.close          = msm_pcm_close,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+};
+
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_pcm_ops,
+	.pcm_new	= msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	struct msm_pcm_loopback *pcm;
+
+	dev_dbg(&pdev->dev, "%s: dev name %s\n",
+		__func__, dev_name(&pdev->dev));
+
+	pcm = kzalloc(sizeof(struct msm_pcm_loopback), GFP_KERNEL);
+	if (!pcm) {
+		dev_err(&pdev->dev, "%s Failed to allocate memory for pcm\n",
+			__func__);
+		return -ENOMEM;
+	} else {
+		mutex_init(&pcm->lock);
+		dev_set_drvdata(&pdev->dev, pcm);
+	}
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	struct msm_pcm_loopback *pcm;
+
+	pcm = dev_get_drvdata(&pdev->dev);
+	mutex_destroy(&pcm->lock);
+
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-pcm-loopback",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM loopback platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index e74a0dd..2c3c6df 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -658,6 +658,11 @@
 				msm_bedais[reg].sample_rate, channels,
 				DEFAULT_COPP_TOPOLOGY);
 
+			if (session_type == SESSION_TYPE_RX &&
+				fdai->event_info.event_func)
+					fdai->event_info.event_func(
+						MSM_PCM_RT_EVT_DEVSWITCH,
+						fdai->event_info.priv_data);
 
 			msm_pcm_routing_build_matrix(val,
 				fdai->strm_id, path_type);
@@ -976,10 +981,8 @@
 static int msm_routing_set_fm_vol_mixer(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	afe_loopback_gain(INT_FM_TX , ucontrol->value.integer.value[0]);
-
+	afe_loopback_gain(INT_FM_TX, ucontrol->value.integer.value[0]);
 	msm_route_fm_vol_control = ucontrol->value.integer.value[0];
-
 	return 0;
 }
 
@@ -1660,6 +1663,9 @@
 	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),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -1696,6 +1702,9 @@
 	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),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -1714,6 +1723,9 @@
 	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),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
@@ -1810,6 +1822,12 @@
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
 	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
 	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -2715,6 +2733,7 @@
 	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
@@ -2828,6 +2847,8 @@
 	mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -3008,6 +3029,7 @@
 	{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
@@ -3026,6 +3048,7 @@
 	{"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"},
+	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
 
 	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3040,12 +3063,14 @@
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"AFE_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"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"},
+	{"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 
 	{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
@@ -3054,12 +3079,14 @@
 	{"MM_UL2", NULL, "MultiMedia2 Mixer"},
 	{"MM_UL4", NULL, "MultiMedia4 Mixer"},
 	{"MM_UL5", NULL, "MultiMedia5 Mixer"},
+	{"MM_UL6", NULL, "MultiMedia6 Mixer"},
 
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
 
 	{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index c42e155..e25a44a 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -117,6 +117,7 @@
 
 enum msm_pcm_routing_event {
 	MSM_PCM_RT_EVT_BUF_RECFG,
+	MSM_PCM_RT_EVT_DEVSWITCH,
 	MSM_PCM_RT_EVT_MAX,
 };
 /* dai_id: front-end ID,
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index 737317c..dd92e34 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -1143,6 +1143,22 @@
 		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
 	},
+	{
+		.name = "MSM8960 FM",
+		.stream_name = "MultiMedia6",
+		.cpu_dai_name	= "MultiMedia6",
+		.platform_name  = "msm-pcm-loopback",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+	},
 	/* Backend DAI Links */
 	{
 		.name = LPASS_BE_SLIMBUS_0_RX,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index a458713..51334f2 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -1424,7 +1424,26 @@
 			__func__, err);
 		goto out;
 	}
-
+	config_data = taiko_get_afe_config(codec,
+				AFE_CDC_CLIP_REGISTERS_CONFIG);
+	if (config_data) {
+		err = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
+					config_data, 0);
+		if (err) {
+			pr_err("%s: Failed to set clip registers %d\n",
+				__func__, err);
+			return err;
+		}
+	}
+	config_data = taiko_get_afe_config(codec, AFE_CLIP_BANK_SEL);
+	if (config_data) {
+		err = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0);
+		if (err) {
+			pr_err("%s: Failed to set AFE bank selection %d\n",
+				__func__, err);
+			return err;
+		}
+	}
 	/* start mbhc */
 	mbhc_cfg.calibration = def_taiko_mbhc_cal();
 	if (mbhc_cfg.calibration) {
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 4dd85fc..1f7712f 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/qpnp/clkdiv.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -26,8 +27,196 @@
 #include <asm/mach-types.h>
 #include <mach/socinfo.h>
 #include <qdsp6v2/msm-pcm-routing-v2.h>
+#include <sound/q6afe-v2.h>
 #include <linux/module.h>
+#include "../codecs/msm8x10-wcd.h"
 #define DRV_NAME "msm8x10-asoc-wcd"
+#define BTSCO_RATE_8KHZ 8000
+#define BTSCO_RATE_16KHZ 16000
+
+static int msm_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm_btsco_ch = 1;
+
+static int msm_proxy_rx_ch = 2;
+
+#define MSM8X10_DINO_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL	0xFE03B004
+#define MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR			0xFE02C000
+#define MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR			0xFE02C004
+#define MSM8X10_DINO_LPASS_DIGCODEC_M				0xFE02C008
+#define MSM8X10_DINO_LPASS_DIGCODEC_N				0xFE02C00C
+#define MSM8X10_DINO_LPASS_DIGCODEC_D				0xFE02C010
+#define MSM8X10_DINO_LPASS_DIGCODEC_CBCR			0xFE02C014
+#define MSM8X10_DINO_LPASS_DIGCODEC_AHB_CBCR			0xFE02C018
+
+/*
+ * There is limitation for the clock root selection from
+ * either MI2S or DIG_CODEC.
+ * If DIG_CODEC root can only provide 9.6MHz clock
+ * to codec while MI2S only can provide
+ * 12.288MHz.
+ */
+enum {
+	DIG_CDC_CLK_SEL_DIG_CODEC,
+	DIG_CDC_CLK_SEL_PRI_MI2S,
+	DIG_CDC_CLK_SEL_SEC_MI2S,
+};
+
+static struct afe_clk_cfg mi2s_rx_clk = {
+	AFE_API_VERSION_I2S_CONFIG,
+	Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+	Q6AFE_LPASS_OSR_CLK_12_P288_MHZ,
+	Q6AFE_LPASS_CLK_SRC_INTERNAL,
+	Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+	Q6AFE_LPASS_MODE_BOTH_VALID,
+	0,
+};
+
+static struct afe_clk_cfg mi2s_tx_clk = {
+	AFE_API_VERSION_I2S_CONFIG,
+	Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+	Q6AFE_LPASS_OSR_CLK_12_P288_MHZ,
+	Q6AFE_LPASS_CLK_SRC_INTERNAL,
+	Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+	Q6AFE_LPASS_MODE_BOTH_VALID,
+	0,
+};
+
+static struct afe_digital_clk_cfg digital_cdc_clk = {
+	AFE_API_VERSION_I2S_CONFIG,
+	9600000,
+	5,  /* Digital Codec root */
+	0,
+};
+
+static atomic_t aud_init_rsc_ref;
+
+static int msm8x10_mclk_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event);
+
+static const struct snd_soc_dapm_route msm8x10_common_audio_map[] = {
+	{"RX_BIAS", NULL, "MCLK"},
+	{"INT_LDO_H", NULL, "MCLK"},
+	{"MIC BIAS External", NULL, "Handset Mic"},
+	{"MIC BIAS Internal2", NULL, "Headset Mic"},
+	{"AMIC1", NULL, "MIC BIAS External"},
+	{"AMIC2", NULL, "MIC BIAS Internal2"},
+
+};
+
+static const struct snd_soc_dapm_widget msm8x10_dapm_widgets[] = {
+
+	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
+	msm8x10_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIC("Handset Mic", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+
+};
+
+/*
+ * This function will be replaced by
+ * afe_set_lpass_internal_digital_codec_clock(port_id, cfg)
+ * in the future after LPASS API fix
+ */
+static int msm_enable_lpass_mclk(void)
+{
+	/* Select the codec root */
+	iowrite32(DIG_CDC_CLK_SEL_DIG_CODEC,
+		  ioremap(MSM8X10_DINO_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL,
+		  4));
+	/* Div-2 */
+	iowrite32(0x3, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4));
+	iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4));
+	iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4));
+	iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4));
+	/* Digital codec clock enable */
+	iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+	/* AHB clock enable */
+	iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_AHB_CBCR, 4));
+	/* Set the update bit to make the settings go through */
+	iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4));
+
+	return 0;
+}
+
+static int msm_enable_mclk_root(u16 port_id, struct afe_digital_clk_cfg *cfg)
+{
+	int ret = 0;
+	/*
+	  * msm_enable_lpass_mclk() function call will be replaced by
+	  * ret =  afe_set_lpass_internal_digital_codec_clock(port_id, cfg)
+	  * in the future. Currentlt there is a bug in LPASS plan which
+	  * doesn't consider the digital codec clock. It will be fixed soon
+	  * in new Q6 image
+	  */
+	msm_enable_lpass_mclk();
+	pr_debug("%s(): return = %d\n", __func__, ret);
+	return ret;
+}
+
+static int msm_config_mclk(u16 port_id, struct afe_digital_clk_cfg *cfg)
+{
+	/* Select the codec root */
+	iowrite32(DIG_CDC_CLK_SEL_DIG_CODEC,
+		  ioremap(MSM8X10_DINO_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL,
+		  4));
+	/* Div-2 */
+	iowrite32(0x3, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4));
+	iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4));
+	iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4));
+	iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4));
+	/* Digital codec clock enable */
+	if (cfg->clk_val == 0) {
+		iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+		pr_debug("%s(line %d)\n", __func__, __LINE__);
+	} else {
+		iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+		pr_debug("%s(line %d)\n", __func__, __LINE__);
+	}
+	iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+	/* AHB clock enable */
+	iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_AHB_CBCR, 4));
+	/* Set the update bit to make the settings go through */
+	iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4));
+
+	return 0;
+
+}
+
+static int msm_config_mi2s_clk(int enable)
+{
+	int ret = 0;
+	pr_debug("%s(line %d):enable = %x\n", __func__, __LINE__, enable);
+	if (enable) {
+		digital_cdc_clk.clk_val = 9600000;
+		mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+		mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+		ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+					  &mi2s_rx_clk);
+		mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+		mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+		ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+					  &mi2s_tx_clk);
+		if (ret < 0)
+			pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+	} else {
+		digital_cdc_clk.clk_val = 0;
+		mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+		mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+		ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+					  &mi2s_rx_clk);
+		mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+		mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+		ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+					  &mi2s_tx_clk);
+		if (ret < 0)
+			pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+	}
+	ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX, &digital_cdc_clk);
+	return ret;
+}
+
 
 static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 				struct snd_pcm_hw_params *params)
@@ -41,13 +230,22 @@
 	return 0;
 }
 
-static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
 {
-	pr_info("%s(), dev_name%s\n", __func__, dev_name(rtd->cpu_dai->dev));
+	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_snd_hw_params(struct snd_pcm_substream *substream,
+static int msm_mi2s_snd_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params)
 {
 	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
@@ -55,34 +253,184 @@
 	return 0;
 }
 
-static int msm_snd_startup(struct snd_pcm_substream *substream)
+static int mi2s_clk_ctl(struct snd_pcm_substream *substream, bool enable)
 {
+	int ret = 0;
+	if (enable) {
+		digital_cdc_clk.clk_val = 9600000;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+			mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+			ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+						  &mi2s_rx_clk);
+		} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+			mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+			mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+			ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+						  &mi2s_tx_clk);
+		} else
+			pr_err("%s:Not valid substream.\n", __func__);
+
+		if (ret < 0)
+			pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+	} else {
+		digital_cdc_clk.clk_val = 0;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+			mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+			ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+						  &mi2s_rx_clk);
+		} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+			mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+			mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+			ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+						  &mi2s_tx_clk);
+		} else
+			pr_err("%s:Not valid substream.\n", __func__);
+
+		if (ret < 0)
+			pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+	}
+	ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX, &digital_cdc_clk);
+	return ret;
+}
+
+static int msm8x10_enable_codec_ext_clk(struct snd_soc_codec *codec,
+					int enable, bool dapm)
+{
+	int ret = 0;
+
+	pr_debug("%s: enable = %d  codec name %s enable %x\n",
+		   __func__, enable, codec->name, enable);
+	if (enable) {
+		digital_cdc_clk.clk_val = 9600000;
+		msm_config_mi2s_clk(1);
+		ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX,
+					   &digital_cdc_clk);
+		msm8x10_wcd_mclk_enable(codec, 1, dapm);
+	} else {
+		msm8x10_wcd_mclk_enable(codec, 0, dapm);
+		ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX,
+					   &digital_cdc_clk);
+		msm_config_mi2s_clk(0);
+	}
+	return ret;
+}
+
+static int msm8x10_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:
+		return msm8x10_enable_codec_ext_clk(w->codec, 1, true);
+	case SND_SOC_DAPM_POST_PMD:
+		return msm8x10_enable_codec_ext_clk(w->codec, 0, true);
+	default:
+		return -EINVAL;
+	}
+}
+
+static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+	int ret;
+
 	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
 		 substream->name, substream->stream);
+	ret = mi2s_clk_ctl(substream, false);
+	if (ret < 0)
+		pr_err("%s:clock disable failed\n", __func__);
+}
+
+static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+
+	ret = mi2s_clk_ctl(substream, true);
+
+	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		pr_err("set fmt cpu dai failed\n");
+
+	return ret;
+}
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+
+	pr_debug("%s(),dev_name%s\n", __func__, dev_name(cpu_dai->dev));
+
+	pr_debug("%s(): aud_init_rsc_ref counter = %d\n",
+		__func__, atomic_read(&aud_init_rsc_ref));
+	if (atomic_inc_return(&aud_init_rsc_ref) != 1)
+		goto exit;
+
+	snd_soc_dapm_new_controls(dapm, msm8x10_dapm_widgets,
+				ARRAY_SIZE(msm8x10_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, msm8x10_common_audio_map,
+		ARRAY_SIZE(msm8x10_common_audio_map));
+
+	snd_soc_dapm_sync(dapm);
+	ret =  msm_enable_mclk_root(AFE_PORT_ID_SECONDARY_MI2S_RX,
+				    &digital_cdc_clk);
+exit:
+	return ret;
+}
+
+static int msm_proxy_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: msm_proxy_rx_ch =%d\n", __func__, msm_proxy_rx_ch);
+
+	if (channels->max < 2)
+		channels->min = channels->max = 2;
+	channels->min = channels->max = msm_proxy_rx_ch;
+	rate->min = rate->max = 48000;
 	return 0;
 }
 
-
-static void msm_snd_shutdown(struct snd_pcm_substream *substream)
+static int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
 {
-	pr_debug("%s(): substream = %s stream = %d\n", __func__,
-		 substream->name, substream->stream);
-}
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
 
-static struct snd_soc_ops msm8x10_be_ops = {
-	.startup = msm_snd_startup,
-	.hw_params = msm_snd_hw_params,
-	.shutdown = msm_snd_shutdown,
+	rate->min = rate->max = 48000;
+	return 0;
+}
+static struct snd_soc_ops msm8x10_mi2s_be_ops = {
+	.startup = msm_mi2s_snd_startup,
+	.hw_params = msm_mi2s_snd_hw_params,
+	.shutdown = msm_mi2s_snd_shutdown,
 };
 
 /* Digital audio interface glue - connects codec <---> CPU */
 static struct snd_soc_dai_link msm8x10_dai[] = {
 	/* FrontEnd DAI Links */
-	{
+	{/* hw:x,0 */
 		.name = "MSM8X10 Media1",
 		.stream_name = "MultiMedia1",
 		.cpu_dai_name	= "MultiMedia1",
-		.platform_name  = "msm-pcm-dsp",
+		.platform_name  = "msm-pcm-dsp.0",
 		.dynamic = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -93,11 +441,11 @@
 		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
 	},
-	{
+	{/* hw:x,1 */
 		.name = "MSM8X10 Media2",
 		.stream_name = "MultiMedia2",
 		.cpu_dai_name   = "MultiMedia2",
-		.platform_name  = "msm-pcm-dsp",
+		.platform_name  = "msm-pcm-dsp.0",
 		.dynamic = 1,
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
@@ -108,31 +456,347 @@
 		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
 	},
+	{/* hw:x,2 */
+		.name = "Circuit-Switch Voice",
+		.stream_name = "CS-Voice",
+		.cpu_dai_name   = "CS-VOICE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_CS_VOICE,
+	},
+	{/* hw:x,3 */
+		.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,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_VOIP,
+	},
+	{/* hw:x,4 */
+		.name = "MSM8X10 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,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+	},
+	/* Hostless PCM purpose */
+	{/* hw:x,5 */
+		.name = "Secondary MI2S RX Hostless",
+		.stream_name = "Secondary MI2S_RX Hostless Playback",
+		.cpu_dai_name = "SEC_MI2S_RX_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,
+		 /* This dainlink has MI2S support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{/* hw:x,6 */
+		.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,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{/* hw:x,7 */
+		.name = "MSM AFE-PCM RX",
+		.stream_name = "AFE-PROXY RX",
+		.cpu_dai_name = "msm-dai-q6-dev.241",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+	},
+	{/* hw:x,8 */
+		.name = "MSM AFE-PCM TX",
+		.stream_name = "AFE-PROXY TX",
+		.cpu_dai_name = "msm-dai-q6-dev.240",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+	},
+	{/* hw:x,9 */
+		.name = "MSM8X10 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,
+		 /* this dainlink has playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+	},
+	{/* hw:x,10 */
+		.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,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{/* hw:x,11 */
+		.name = "Primary MI2S TX Hostless",
+		.stream_name = "Primary MI2S_TX Hostless Capture",
+		.cpu_dai_name = "PRI_MI2S_TX_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,
+		 /* This dainlink has MI2S support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{/* hw:x,12 */
+		.name = "MSM8x10 LowLatency",
+		.stream_name = "MultiMedia5",
+		.cpu_dai_name   = "MultiMedia5",
+		.platform_name  = "msm-pcm-dsp.1",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+	},
 	/* Backend I2S DAI Links */
 	{
-		.name = LPASS_BE_MI2S_RX,
-		.stream_name = "Primary MI2S Playback",
-		.cpu_dai_name = "msm-dai-q6-mi2s.0",
-		.platform_name = "msm-pcm-routing",
-		.codec_name     = "msm8x10-wcd-i2c-core.1-000d",
-		.codec_dai_name = "msm8x10_wcd_i2s_rx1",
-		.no_pcm = 1,
-		.be_id = MSM_BACKEND_DAI_MI2S_RX,
-		.init = &msm_audrx_init,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ops = &msm8x10_be_ops,
-	},
-	{
-		.name = LPASS_BE_SEC_MI2S_TX,
-		.stream_name = "Secondary MI2S Capture",
+		.name = LPASS_BE_SEC_MI2S_RX,
+		.stream_name = "Secondary MI2S Playback",
 		.cpu_dai_name = "msm-dai-q6-mi2s.1",
 		.platform_name = "msm-pcm-routing",
-		.codec_name     = "msm8x10-wcd-i2c-core.1-000d",
+		.codec_name     = "msm8x10-wcd-i2c-core.5-000d",
+		.codec_dai_name = "msm8x10_wcd_i2s_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+		.init = &msm_audrx_init,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm8x10_mi2s_be_ops,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_PRI_MI2S_TX,
+		.stream_name = "Primary MI2S Capture",
+		.cpu_dai_name = "msm-dai-q6-mi2s.0",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm8x10-wcd-i2c-core.5-000d",
 		.codec_dai_name = "msm8x10_wcd_i2s_tx1",
 		.no_pcm = 1,
-		.be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+		.be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
+		.init = &msm_audrx_init,
 		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ops = &msm8x10_be_ops,
+		.ops = &msm8x10_mi2s_be_ops,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_INT_BT_SCO_RX,
+		.stream_name = "Internal BT-SCO Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.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,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_INT_BT_SCO_TX,
+		.stream_name = "Internal BT-SCO Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.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,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_INT_FM_RX,
+		.stream_name = "Internal FM Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.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,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_INT_FM_TX,
+		.stream_name = "Internal FM Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.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,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_AFE_PCM_RX,
+		.stream_name = "AFE Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.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_rx_be_hw_params_fixup,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_AFE_PCM_TX,
+		.stream_name = "AFE Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.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_tx_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Incall Record Uplink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_TX,
+		.stream_name = "Voice Uplink Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.32772",
+		.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_INCALL_RECORD_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Incall Record Downlink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_RX,
+		.stream_name = "Voice Downlink Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.32771",
+		.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_INCALL_RECORD_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Incall Music BACK END DAI Link */
+	{
+		.name = LPASS_BE_VOICE_PLAYBACK_TX,
+		.stream_name = "Voice Farend Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.32773",
+		.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_VOICE_PLAYBACK_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Incall Record Uplink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_TX,
+		.stream_name = "Voice Uplink Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.32772",
+		.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_INCALL_RECORD_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Incall Record Downlink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_RX,
+		.stream_name = "Voice Downlink Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.32771",
+		.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_INCALL_RECORD_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Incall Music BACK END DAI Link */
+	{
+		.name = LPASS_BE_VOICE_PLAYBACK_TX,
+		.stream_name = "Voice Farend Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.32773",
+		.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_VOICE_PLAYBACK_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
 	},
 };
 
@@ -165,6 +829,8 @@
 		goto err;
 	}
 
+	atomic_set(&aud_init_rsc_ref, 0);
+
 	return 0;
 err:
 	return ret;
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index f15f4d1..659d5a2 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -912,6 +912,7 @@
 		case ASM_STREAM_CMD_OPEN_WRITE:
 		case ASM_STREAM_CMD_OPEN_WRITE_V2_1:
 		case ASM_STREAM_CMD_OPEN_READWRITE:
+		case ASM_STREAM_CMD_OPEN_LOOPBACK:
 		case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
 		case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
@@ -1852,6 +1853,45 @@
 	return -EINVAL;
 }
 
+int q6asm_open_loopack(struct audio_client *ac)
+{
+	int rc = 0x00;
+	struct asm_stream_cmd_open_loopback open;
+
+	if ((ac == NULL) || (ac->apr == NULL)) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d]", __func__, ac->session);
+
+	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK;
+
+	open.mode_flags = 0;
+	open.src_endpointype = 0;
+	open.sink_endpointype = 0;
+	/* source endpoint : matrix */
+	open.postprocopo_id = get_asm_topology();
+	if (open.postprocopo_id == 0)
+		open.postprocopo_id = DEFAULT_POPP_TOPOLOGY;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("open failed op[0x%x]rc[%d]\n", \
+						open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for OPEN_WRITE rc[%d]\n", rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
 int q6asm_run(struct audio_client *ac, uint32_t flags,
 		uint32_t msw_ts, uint32_t lsw_ts)
 {
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 7d9cc16..04b090a 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -1482,7 +1482,7 @@
 	case SNDRV_PCM_STREAM_PLAYBACK:
 		switch (mi2s_id) {
 		case MSM_PRIM_MI2S:
-			*port_id = MI2S_RX;
+			*port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
 			break;
 		case MSM_SEC_MI2S:
 			*port_id = AFE_PORT_ID_SECONDARY_MI2S_RX;
@@ -1502,7 +1502,7 @@
 	case SNDRV_PCM_STREAM_CAPTURE:
 		switch (mi2s_id) {
 		case MSM_PRIM_MI2S:
-			*port_id = MI2S_TX;
+			*port_id = AFE_PORT_ID_PRIMARY_MI2S_TX;
 			break;
 		case MSM_SEC_MI2S:
 			*port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 717e63b..9fbf749 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -420,6 +420,12 @@
 	}
 
 	data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size, &idx);
+	if (size < fbytes) {
+		pr_err("%s: size mismatch error size %d fbytes %d\n",
+		__func__ , size , fbytes);
+		ret = -EFAULT;
+		goto fail;
+	}
 	bufptr = data;
 	if (bufptr) {
 		pr_debug("%s:fbytes =%d: xfer=%d size=%d\n",
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index e7c4a8a..fa476ee 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -1406,6 +1406,9 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = {
@@ -1421,6 +1424,18 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mi2s_hl_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+	MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+	MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = {
@@ -1436,6 +1451,9 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_MI2S_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
@@ -1571,6 +1589,9 @@
 	SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
 		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
 		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
 	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
 		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
 		msm_routing_put_audio_mixer),
@@ -1646,6 +1667,9 @@
 	SOC_SINGLE_EXT("SEC_AUX_PCM_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
@@ -1684,6 +1708,24 @@
 	msm_routing_put_voice_mixer),
 };
 
+static const struct snd_kcontrol_new sec_mi2s_rx_voice_mixer_controls[] = {
+	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+	MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
 static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
 	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_0_RX,
 	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -1865,6 +1907,9 @@
 	SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voice", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
 	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("PRI_MI2S_TX_Voice", MSM_BACKEND_DAI_PRI_MI2S_TX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new tx_voice2_mixer_controls[] = {
@@ -1934,6 +1979,9 @@
 	SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voip", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("PRI_MI2S_TX_Voip", MSM_BACKEND_DAI_PRI_MI2S_TX,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = {
@@ -2516,12 +2564,19 @@
 	SND_SOC_DAPM_AIF_IN("HDMI_DL_HL", "HDMI_HOSTLESS Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SEC_I2S_DL_HL", "SEC_I2S_RX_HOSTLESS Playback",
 		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SEC_MI2S_DL_HL",
+		"Secondary MI2S_RX Hostless Playback",
+		0, 0, 0, 0),
+
 	SND_SOC_DAPM_AIF_IN("AUXPCM_DL_HL", "AUXPCM_HOSTLESS Playback",
 		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("AUXPCM_UL_HL", "AUXPCM_HOSTLESS Capture",
 		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MI2S_UL_HL", "MI2S_TX_HOSTLESS Capture",
 		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("PRI_MI2S_UL_HL",
+		"Primary MI2S_TX Hostless Capture",
+		0, 0, 0, 0),
 
 	SND_SOC_DAPM_AIF_OUT("MI2S_DL_HL", "MI2S_RX_HOSTLESS Playback",
 		0, 0, 0, 0),
@@ -2549,6 +2604,8 @@
 	SND_SOC_DAPM_AIF_IN("MI2S_TX", "MI2S Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("QUAT_MI2S_TX", "Quaternary MI2S Capture",
 						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PRI_MI2S_TX", "Primary MI2S Capture",
+			    0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SEC_MI2S_TX", "Secondary MI2S Capture",
 			    0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
@@ -2627,6 +2684,9 @@
 	SND_SOC_DAPM_MIXER("SEC_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 			   secondary_mi2s_rx_mixer_controls,
 			   ARRAY_SIZE(secondary_mi2s_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+			   mi2s_hl_mixer_controls,
+			   ARRAY_SIZE(mi2s_hl_mixer_controls)),
 	SND_SOC_DAPM_MIXER("PRI_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 			   primary_mi2s_rx_mixer_controls,
 			   ARRAY_SIZE(primary_mi2s_rx_mixer_controls)),
@@ -2657,6 +2717,10 @@
 				SND_SOC_NOPM, 0, 0,
 				sec_i2s_rx_voice_mixer_controls,
 				ARRAY_SIZE(sec_i2s_rx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_MI2S_RX_Voice Mixer",
+				SND_SOC_NOPM, 0, 0,
+				sec_mi2s_rx_voice_mixer_controls,
+				ARRAY_SIZE(sec_mi2s_rx_voice_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SLIM_0_RX_Voice Mixer",
 				SND_SOC_NOPM, 0, 0,
 				slimbus_rx_voice_mixer_controls,
@@ -2805,6 +2869,7 @@
 	{"QUAT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"QUAT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"QUAT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"QUAT_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Audio Mixer"},
 
 
@@ -2812,17 +2877,23 @@
 	{"SEC_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"SEC_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"SEC_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"SEC_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Audio Mixer"},
 
+	{"SEC_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"SEC_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+
 	{"PRI_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"PRI_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"PRI_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"PRI_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"PRI_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
 	{"MultiMedia1 Mixer", "MI2S_TX", "MI2S_TX"},
 	{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
+	{"MultiMedia5 Mixer", "MI2S_TX", "MI2S_TX"},
 	{"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
 	{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
@@ -2831,6 +2902,7 @@
 	{"MultiMedia5 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
 	{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+	{"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -2901,6 +2973,13 @@
 	{"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
 
+	{"SEC_MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"SEC_MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+	{"SEC_MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"SEC_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"SEC_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+	{"SEC_MI2S_RX", NULL, "SEC_MI2S_RX_Voice Mixer"},
+
 	{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"SLIM_0_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
 	{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
@@ -2951,6 +3030,7 @@
 	{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
 
 	{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
+	{"Voice_Tx Mixer", "PRI_MI2S_TX_Voice", "PRI_MI2S_TX"},
 	{"Voice_Tx Mixer", "MI2S_TX_Voice", "MI2S_TX"},
 	{"Voice_Tx Mixer", "SLIM_0_TX_Voice", "SLIMBUS_0_TX"},
 	{"Voice_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice", "INT_BT_SCO_TX"},
@@ -2982,6 +3062,7 @@
 	{"Voip_Tx Mixer", "AFE_PCM_TX_Voip", "PCM_TX"},
 	{"Voip_Tx Mixer", "AUX_PCM_TX_Voip", "AUX_PCM_TX"},
 	{"Voip_Tx Mixer", "SEC_AUX_PCM_TX_Voip", "SEC_AUX_PCM_TX"},
+	{"Voip_Tx Mixer", "PRI_MI2S_TX_Voip", "PRI_MI2S_TX"},
 
 	{"VOIP_UL", NULL, "Voip_Tx Mixer"},
 	{"SLIMBUS_DL_HL", "Switch", "SLIM0_DL_HL"},
@@ -3014,6 +3095,9 @@
 	{"PCM_RX", NULL, "PCM_RX_DL_HL"},
 	{"MI2S_UL_HL", NULL, "MI2S_TX"},
 	{"SEC_I2S_RX", NULL, "SEC_I2S_DL_HL"},
+	{"PRI_MI2S_UL_HL", NULL, "PRI_MI2S_TX"},
+	{"SEC_MI2S_RX", NULL, "SEC_MI2S_DL_HL"},
+
 	{"SLIMBUS_0_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"SLIMBUS_0_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"SLIMBUS_0_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
@@ -3098,6 +3182,7 @@
 	{"PRI_I2S_TX", NULL, "BE_IN"},
 	{"MI2S_TX", NULL, "BE_IN"},
 	{"QUAT_MI2S_TX", NULL, "BE_IN"},
+	{"PRI_MI2S_TX", NULL, "BE_IN"},
 	{"SEC_MI2S_TX", NULL, "BE_IN"},
 	{"SLIMBUS_0_TX", NULL, "BE_IN" },
 	{"SLIMBUS_1_TX", NULL, "BE_IN" },
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 3598977..5b4244e 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -899,6 +899,44 @@
 	return ret;
 }
 
+static int afe_send_bank_selection_clip(
+		struct afe_param_id_clip_bank_sel *param)
+{
+	int ret;
+	struct afe_svc_cmd_set_clip_bank_selection config;
+	if (!param) {
+		pr_err("%s: Invalid params", __func__);
+		return -EINVAL;
+	}
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = IDX_GLOBAL_CFG;
+	config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+	config.param.payload_size = sizeof(struct afe_port_param_data_v2) +
+				sizeof(struct afe_param_id_clip_bank_sel);
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+
+	config.pdata.module_id = AFE_MODULE_CDC_DEV_CFG;
+	config.pdata.param_id = AFE_PARAM_ID_CLIP_BANK_SEL_CFG;
+	config.pdata.param_size =
+		sizeof(struct afe_param_id_clip_bank_sel);
+	config.bank_sel = *param;
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+	if (ret) {
+		pr_err("%s: AFE_PARAM_ID_CLIP_BANK_SEL_CFG failed %d\n",
+		__func__, ret);
+	} else if (atomic_read(&this_afe.status) != 0) {
+		pr_err("%s: config cmd failed\n", __func__);
+		ret = -EAGAIN;
+	}
+	return ret;
+}
 int afe_send_aanc_version(
 	struct afe_param_id_cdc_aanc_version *version_cfg)
 {
@@ -991,6 +1029,12 @@
 	case AFE_AANC_VERSION:
 		ret = afe_send_aanc_version(config_data);
 		break;
+	case AFE_CLIP_BANK_SEL:
+		ret = afe_send_bank_selection_clip(config_data);
+		break;
+	case AFE_CDC_CLIP_REGISTERS_CONFIG:
+		ret = afe_send_codec_reg_config(config_data);
+		break;
 	default:
 		pr_err("%s: unknown configuration type", __func__);
 		ret = -EINVAL;
@@ -1149,21 +1193,20 @@
 	config.hdr.token = index;
 
 	switch (port_id) {
-	case PRIMARY_I2S_RX:
-	case PRIMARY_I2S_TX:
-		cfg_type = AFE_PARAM_ID_PCM_CONFIG;
-		break;
 	case AFE_PORT_ID_PRIMARY_PCM_RX:
 	case AFE_PORT_ID_PRIMARY_PCM_TX:
 	case AFE_PORT_ID_SECONDARY_PCM_RX:
 	case AFE_PORT_ID_SECONDARY_PCM_TX:
 		cfg_type = AFE_PARAM_ID_PCM_CONFIG;
 		break;
+	case PRIMARY_I2S_RX:
+	case PRIMARY_I2S_TX:
 	case SECONDARY_I2S_RX:
 	case SECONDARY_I2S_TX:
 	case MI2S_RX:
 	case MI2S_TX:
 	case AFE_PORT_ID_PRIMARY_MI2S_RX:
+	case AFE_PORT_ID_PRIMARY_MI2S_TX:
 	case AFE_PORT_ID_SECONDARY_MI2S_RX:
 	case AFE_PORT_ID_SECONDARY_MI2S_TX:
 	case AFE_PORT_ID_TERTIARY_MI2S_RX:
@@ -1288,6 +1331,8 @@
 	case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX;
 	case AFE_PORT_ID_PRIMARY_MI2S_RX:
 		return IDX_AFE_PORT_ID_PRIMARY_MI2S_RX;
+	case AFE_PORT_ID_PRIMARY_MI2S_TX:
+		return IDX_AFE_PORT_ID_PRIMARY_MI2S_TX;
 	case AFE_PORT_ID_QUATERNARY_MI2S_RX:
 		return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
 	case AFE_PORT_ID_QUATERNARY_MI2S_TX:
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index 3cb7a1f..dae1ebd 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -60,6 +60,8 @@
 	case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
 	case AFE_PORT_ID_PRIMARY_MI2S_RX:
 		return IDX_AFE_PORT_ID_PRIMARY_MI2S_RX;
+	case AFE_PORT_ID_PRIMARY_MI2S_TX:
+		return IDX_AFE_PORT_ID_PRIMARY_MI2S_TX;
 	case AFE_PORT_ID_QUATERNARY_MI2S_RX:
 		return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
 	case AFE_PORT_ID_QUATERNARY_MI2S_TX:
@@ -76,8 +78,8 @@
 int q6audio_get_port_id(u16 port_id)
 {
 	switch (port_id) {
-	case PRIMARY_I2S_RX: return AFE_PORT_ID_PRIMARY_MI2S_RX;
-	case PRIMARY_I2S_TX: return AFE_PORT_ID_PRIMARY_MI2S_TX;
+	case PRIMARY_I2S_RX: return PRIMARY_I2S_RX;
+	case PRIMARY_I2S_TX: return PRIMARY_I2S_TX;
 	case AFE_PORT_ID_PRIMARY_PCM_RX:
 			return AFE_PORT_ID_PRIMARY_PCM_RX;
 	case AFE_PORT_ID_PRIMARY_PCM_TX:
@@ -114,6 +116,8 @@
 	case RT_PROXY_PORT_001_TX: return AFE_PORT_ID_RT_PROXY_PORT_001_TX;
 	case AFE_PORT_ID_PRIMARY_MI2S_RX:
 			     return AFE_PORT_ID_PRIMARY_MI2S_RX;
+	case AFE_PORT_ID_PRIMARY_MI2S_TX:
+			     return AFE_PORT_ID_PRIMARY_MI2S_TX;
 	case AFE_PORT_ID_QUATERNARY_MI2S_RX:
 			     return AFE_PORT_ID_QUATERNARY_MI2S_RX;
 	case AFE_PORT_ID_QUATERNARY_MI2S_TX:
@@ -168,6 +172,10 @@
 	case AFE_PORT_ID_TERTIARY_MI2S_RX:
 	case AFE_PORT_ID_QUATERNARY_MI2S_RX:
 	case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+	case AFE_PORT_ID_PRIMARY_MI2S_RX:
+	case AFE_PORT_ID_PRIMARY_MI2S_TX:
+	case AFE_PORT_ID_SECONDARY_MI2S_RX:
+	case AFE_PORT_ID_SECONDARY_MI2S_TX:
 		break;
 	default:
 		ret = -EINVAL;
@@ -214,6 +222,7 @@
 	case RT_PROXY_PORT_001_RX:
 	case RT_PROXY_PORT_001_TX:
 	case AFE_PORT_ID_PRIMARY_MI2S_RX:
+	case AFE_PORT_ID_PRIMARY_MI2S_TX:
 	case AFE_PORT_ID_QUATERNARY_MI2S_RX:
 	case AFE_PORT_ID_QUATERNARY_MI2S_TX:
 	case AFE_PORT_ID_SECONDARY_MI2S_RX: