Merge "ARM: dts: msm: Add new mdm9650 device tree file"
diff --git a/Documentation/devicetree/bindings/arm/msm/bcl.txt b/Documentation/devicetree/bindings/arm/msm/bcl.txt
index 86e3858..0aa35ad 100644
--- a/Documentation/devicetree/bindings/arm/msm/bcl.txt
+++ b/Documentation/devicetree/bindings/arm/msm/bcl.txt
@@ -149,7 +149,9 @@
 micro-amps.
 
 Required Parameters:
-- compatible: must be qcom,msm-bcl
+- compatible: must be either
+	1. 'qcom,msm-bcl' for bcl peripheral without LMH DCVSh interface.
+	2. 'qcom,msm-bcl-lmh' for bcl peripheral with LMH DCVSh interface.
 - reg: <a b> where 'a' is the starting register address of the PMIC
 	peripheral and 'b' is the size of the peripheral address space.
 	If the BCL inhibit current derating feature is enabled, this must also
@@ -164,13 +166,17 @@
 - interrupt-names: user defined names for the interrupts. These
 		interrupt names will be used by the drivers to identify the
 		interrupts, instead of specifying the ID's.
+- qcom,ibat-polling-delay-ms: Software polling interval for monitoring ibat
+		low threshold.
+- qcom,vbat-polling-delay-ms: Software polling interval for monitoring vbat
+		high threshold.
+
+optional Parameters for peripheral with LMH DCVSh interface:
 - qcom,vbat-scaling-factor: The scaling factor to be used for converting
 		the raw vbat ADC value to milli-volt.
 - qcom,vbat-gain-numerator: The numerator of the vbat gain correction factor.
 - qcom,vbat-gain-denominator: The denominator of the vbat gain correction
 		factor.
-- qcom,vbat-polling-delay-ms: Software polling interval for monitoring vbat
-		high threshold.
 - qcom,ibat-scaling-factor: The scaling factor to be used for converting
 		the raw ibat ADC value to micro-amps.
 - qcom, ibat-gain-numerator: The numerator of the ibat gain correction factor.
@@ -180,8 +186,7 @@
 		factor.
 - qcom, ibat-offset-denominator: The denominator of the ibat offset
 		correction factor.
-- qcom,ibat-polling-delay-ms: Software polling interval for monitoring ibat
-		low threshold.
+
 Optional Parameters:
 - qcom,inhibit-derating-ua: The amount that the bcl current high trip threshold
 		should be lowered by when the bcl peripheral is operating in a
diff --git a/Documentation/devicetree/bindings/leds/leds-tlc591xx.txt b/Documentation/devicetree/bindings/leds/leds-tlc591xx.txt
new file mode 100644
index 0000000..3bbbf70
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-tlc591xx.txt
@@ -0,0 +1,40 @@
+LEDs connected to tlc59116 or tlc59108
+
+Required properties
+- compatible: should be "ti,tlc59116" or "ti,tlc59108"
+- #address-cells: must be 1
+- #size-cells: must be 0
+- reg: typically 0x68
+
+Each led is represented as a sub-node of the ti,tlc59116.
+See Documentation/devicetree/bindings/leds/common.txt
+
+LED sub-node properties:
+- reg: number of LED line, 0 to 15 or 0 to 7
+- label: (optional) name of LED
+- linux,default-trigger : (optional)
+
+Examples:
+
+tlc59116@68 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	compatible = "ti,tlc59116";
+	reg = <0x68>;
+
+	wan@0 {
+		label = "wrt1900ac:amber:wan";
+		reg = <0x0>;
+	};
+
+	2g@2 {
+		label = "wrt1900ac:white:2g";
+		reg = <0x2>;
+	};
+
+	alive@9 {
+		label = "wrt1900ac:green:alive";
+		reg = <0x9>;
+		linux,default_trigger = "heartbeat";
+	};
+};
diff --git a/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt b/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt
index fe3c261..3017468 100644
--- a/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt
+++ b/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt
@@ -25,6 +25,7 @@
 		between host and device.
   - qcom,mhi-config-iatu: If property is present map the control and data region
 		between host and device using iatu.
+  - qcom,mhi-interrupt: If property is present register for mhi interrupt.
   - qcom,mhi-local-pa-base: The physical base address on the device used by the
 		MHI device driver to map the control and data region with the
 		MHI driver on the host. This property is required if iatu
diff --git a/Documentation/devicetree/bindings/net/can/k61-can.txt b/Documentation/devicetree/bindings/net/can/k61-can.txt
index 57e8581..ea4a7b4 100644
--- a/Documentation/devicetree/bindings/net/can/k61-can.txt
+++ b/Documentation/devicetree/bindings/net/can/k61-can.txt
@@ -3,15 +3,20 @@
 This driver implements SPI slave protocol for Freescale K61 CAN controller.
 
 Required properties:
-  - compatible: Should be "fsl,k61".
+  - compatible: Should be "fsl,k61" or "nxp,mpc5746c".
   - reg: Should contain SPI chip select.
   - interrupt-parent: Should specify interrupt controller for the interrupt.
   - interrupts: Should contain IRQ line for the CAN controller.
+
+Optional properties:
   - reset-gpio: Reference to the GPIO connected to the reset input.
   - pinctrl-names : Names corresponding to the numbered pinctrl states.
   - pinctrl-0 : This explains the active state of the GPIO line.
   - pinctrl-1 : This explains the suspend state of the GPIO line.
-
+  - bits-per-word: Indicate how many bits are in a SPI frame. e.g.: 8, 16, 32.
+                   Default to 16.
+  - reset-delay-msec: Delay in milliseconds to be applied after resetting the chip.
+                      Default to 1 ms.
 
 Example:
 
@@ -24,4 +29,6 @@
 		pinctrl-names = "active", "sleep";
 		pinctrl-0 = <&can_rst_on>;
 		pinctrl-1 = <&can_rst_off>;
+		bits-per-word = <8>;
+		reset-delay-msec = <100>;
 	};
diff --git a/Documentation/devicetree/bindings/pci/msm_ep_pcie.txt b/Documentation/devicetree/bindings/pci/msm_ep_pcie.txt
index 6930ee5..1f6d79dd 100644
--- a/Documentation/devicetree/bindings/pci/msm_ep_pcie.txt
+++ b/Documentation/devicetree/bindings/pci/msm_ep_pcie.txt
@@ -50,6 +50,7 @@
   - qcom,pcie-active-config: boolean type; active configuration of PCIe
     addressing.
   - qcom,pcie-aggregated-irq: boolean type; interrupts are aggregated.
+  - qcom,pcie-mhi-a7-irq: boolean type; MHI a7 has separate irq.
   - qcom,pcie-perst-enum: Link enumeration will be triggered by PERST
     deassertion.
   - mdm2apstatus-gpio: GPIO used by PCIe endpoint side to notify the host side.
@@ -117,6 +118,7 @@
 		qcom,pcie-link-speed = <1>;
 		qcom,pcie-active-config;
 		qcom,pcie-aggregated-irq;
+		qcom,pcie-mhi-a7-irq;
 		qcom,pcie-perst-enum;
 		qcom,phy-status-reg = <0x728>;
 		qcom,dbi-base-reg = <0x168>;
diff --git a/arch/arm/boot/dts/qcom/apq8009w-bg-wtp-v2.dts b/arch/arm/boot/dts/qcom/apq8009w-bg-wtp-v2.dts
index 46a3878..940ac88 100644
--- a/arch/arm/boot/dts/qcom/apq8009w-bg-wtp-v2.dts
+++ b/arch/arm/boot/dts/qcom/apq8009w-bg-wtp-v2.dts
@@ -168,3 +168,54 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart_console_sleep>;
 };
+
+/* Pinctrl dt nodes for interrupt and reset gpio for Synaptics controller */
+&ts_int_active {
+	mux {
+		pins = "gpio98";
+	};
+
+	config {
+		pins = "gpio98";
+	};
+};
+
+&ts_int_suspend {
+	mux {
+		pins = "gpio98";
+	};
+
+	config {
+		pins = "gpio98";
+	};
+};
+
+&ts_reset_active {
+	mux {
+		pins = "gpio16";
+	};
+
+	config {
+		pins = "gpio16";
+	};
+};
+
+&ts_reset_suspend {
+	mux {
+		pins = "gpio16";
+	};
+
+	config {
+		pins = "gpio16";
+	};
+};
+
+&ts_release {
+	mux {
+		pins = "gpio98", "gpio16";
+	};
+
+	config {
+		pins = "gpio98", "gpio16";
+	};
+};
diff --git a/arch/arm/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dts b/arch/arm/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dts
index 59cc9c7..a41d549 100644
--- a/arch/arm/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dts
+++ b/arch/arm/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dts
@@ -158,3 +158,150 @@
 &secure_mem {
 	status = "disabled";
 };
+
+/* Warning, SPI6 & I2C6 cannot be enabled at the same time due to pin usage. */
+&spi_6 {
+	status = "disabled";
+};
+
+&i2c_6 {
+	status = "ok";
+	qcom,clk-freq-out = <100000>;
+
+	/* TI591XX LED Drivers */
+	tlc59116@60 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "ti,tlc59116";
+		reg = <0x60>;
+		out0@0 {
+			label = "ledsec1_g";
+			reg = <0x0>;
+		};
+		out1@1 {
+			label = "ledsec1_r";
+			reg = <0x1>;
+		};
+		out2@2 {
+			label = "ledsec1_b";
+			reg = <0x2>;
+		};
+		out3@3 {
+			label = "ledsec2_g";
+			reg = <0x3>;
+		};
+		out4@4 {
+			label = "ledsec2_r";
+			reg = <0x4>;
+		};
+		out5@5 {
+			label = "ledsec2_b";
+			reg = <0x5>;
+		};
+		out6@6 {
+			label = "ledsec3_g";
+			reg = <0x6>;
+		};
+		out7@7 {
+			label = "ledsec3_r";
+			reg = <0x7>;
+		};
+		out8@8 {
+			label = "ledsec3_b";
+			reg = <0x8>;
+		};
+		out9@9 {
+			label = "ledsec4_g";
+			reg = <0x9>;
+		};
+		out10@10 {
+			label = "ledsec4_r";
+			reg = <0xa>;
+		};
+		out11@11 {
+			label = "ledsec4_b";
+			reg = <0xb>;
+		};
+		out12@12 {
+			label = "ledsec5_g";
+			reg = <0xc>;
+		};
+		out13@13 {
+			label = "ledsec5_r";
+			reg = <0xd>;
+		};
+		out14@14 {
+			label = "ledsec5_b";
+			reg = <0xe>;
+		};
+	};
+
+	tlc59116@61 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "ti,tlc59116";
+		reg = <0x61>;
+		out0@0 {
+			label = "ledsec6_g";
+			reg = <0x0>;
+		};
+		out1@1 {
+			label = "ledsec6_r";
+			reg = <0x1>;
+		};
+		out2@2 {
+			label = "ledsec6_b";
+			reg = <0x2>;
+		};
+		out3@3 {
+			label = "ledsec7_g";
+			reg = <0x3>;
+		};
+		out4@4 {
+			label = "ledsec7_r";
+			reg = <0x4>;
+		};
+		out5@5 {
+			label = "ledsec7_b";
+			reg = <0x5>;
+		};
+		out6@6 {
+			label = "ledsec8_g";
+			reg = <0x6>;
+		};
+		out7@7 {
+			label = "ledsec8_r";
+			reg = <0x7>;
+		};
+		out8@8 {
+			label = "ledsec8_b";
+			reg = <0x8>;
+		};
+		out9@9 {
+			label = "ledsec9_g";
+			reg = <0x9>;
+		};
+		out10@10 {
+			label = "ledsec9_r";
+			reg = <0xa>;
+		};
+		out11@11 {
+			label = "ledsec9_b";
+			reg = <0xb>;
+		};
+	};
+};
+
+&soc {
+	pinctrl@1000000 {
+		i2c6{
+			tlc59116_reset: tlc59116_reset {
+				config {
+					pins = "gpio20";
+					drive-strength = <16>;
+					bias-pull-up;
+				};
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/qcom/apq8017-pmi8950-mtp.dts b/arch/arm/boot/dts/qcom/apq8017-pmi8950-mtp.dts
index d152ba3..91083b4 100644
--- a/arch/arm/boot/dts/qcom/apq8017-pmi8950-mtp.dts
+++ b/arch/arm/boot/dts/qcom/apq8017-pmi8950-mtp.dts
@@ -62,3 +62,149 @@
 &dsi_adv7533_1080p {
 	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
 };
+
+/* Warning, SPI6 & I2C6 cannot be enabled at the same time due to pin usage. */
+&spi_6 {
+	status = "disabled";
+};
+
+&i2c_6 {
+	status = "ok";
+	qcom,clk-freq-out = <100000>;
+
+	/* TI591XX LED Drivers */
+	tlc59116@60 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "ti,tlc59116";
+		reg = <0x60>;
+		out0@0 {
+			label = "ledsec1_g";
+			reg = <0x0>;
+		};
+		out1@1 {
+			label = "ledsec1_r";
+			reg = <0x1>;
+		};
+		out2@2 {
+			label = "ledsec1_b";
+			reg = <0x2>;
+		};
+		out3@3 {
+			label = "ledsec2_g";
+			reg = <0x3>;
+		};
+		out4@4 {
+			label = "ledsec2_r";
+			reg = <0x4>;
+		};
+		out5@5 {
+			label = "ledsec2_b";
+			reg = <0x5>;
+		};
+		out6@6 {
+			label = "ledsec3_g";
+			reg = <0x6>;
+		};
+		out7@7 {
+			label = "ledsec3_r";
+			reg = <0x7>;
+		};
+		out8@8 {
+			label = "ledsec3_b";
+			reg = <0x8>;
+		};
+		out9@9 {
+			label = "ledsec4_g";
+			reg = <0x9>;
+		};
+		out10@10 {
+			label = "ledsec4_r";
+			reg = <0xa>;
+		};
+		out11@11 {
+			label = "ledsec4_b";
+			reg = <0xb>;
+		};
+		out12@12 {
+			label = "ledsec5_g";
+			reg = <0xc>;
+		};
+		out13@13 {
+			label = "ledsec5_r";
+			reg = <0xd>;
+		};
+		out14@14 {
+			label = "ledsec5_b";
+			reg = <0xe>;
+		};
+	};
+	tlc59116@61 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "ti,tlc59116";
+		reg = <0x61>;
+		out0@0 {
+			label = "ledsec6_g";
+			reg = <0x0>;
+		};
+		out1@1 {
+			label = "ledsec6_r";
+			reg = <0x1>;
+		};
+		out2@2 {
+			label = "ledsec6_b";
+			reg = <0x2>;
+		};
+		out3@3 {
+			label = "ledsec7_g";
+			reg = <0x3>;
+		};
+		out4@4 {
+			label = "ledsec7_r";
+			reg = <0x4>;
+		};
+		out5@5 {
+			label = "ledsec7_b";
+			reg = <0x5>;
+		};
+		out6@6 {
+			label = "ledsec8_g";
+			reg = <0x6>;
+		};
+		out7@7 {
+			label = "ledsec8_r";
+			reg = <0x7>;
+		};
+		out8@8 {
+			label = "ledsec8_b";
+			reg = <0x8>;
+		};
+		out9@9 {
+			label = "ledsec9_g";
+			reg = <0x9>;
+		};
+		out10@10 {
+			label = "ledsec9_r";
+			reg = <0xa>;
+		};
+		out11@11 {
+			label = "ledsec9_b";
+			reg = <0xb>;
+		};
+	};
+};
+
+&soc {
+	pinctrl@1000000 {
+		i2c6{
+			tlc59116_reset: tlc59116_reset {
+				config {
+					pins = "gpio20";
+					drive-strength = <16>;
+					bias-pull-up;
+				};
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/qcom/apq8096-drone.dtsi b/arch/arm/boot/dts/qcom/apq8096-drone.dtsi
index 3d67b8e..7f23f47 100644
--- a/arch/arm/boot/dts/qcom/apq8096-drone.dtsi
+++ b/arch/arm/boot/dts/qcom/apq8096-drone.dtsi
@@ -548,7 +548,7 @@
 &pm8994_mpps {
 	mpp@a100 { /* MPP 2 - TP82 */
 		qcom,mode = <0>;		/* Digital input */
-		qcom,pull = <5>;		/* Pull down */
+		qcom,pull = <1>;		/* Pull up open */
 		qcom,vin-sel = <2>;		/* S4 1.8V */
 		qcom,src-sel = <0>;		/* Constant */
 		qcom,master-en = <1>;		/* Enable GPIO */
@@ -558,7 +558,7 @@
 
 	mpp@a300 { /* MPP 4 - FAN_DETECT */
 		qcom,mode = <0>;		/* Digital input */
-		qcom,pull = <5>;		/* Pull down */
+		qcom,pull = <1>;		/* Pull up open */
 		qcom,vin-sel = <2>;		/* S4 1.8V */
 		qcom,src-sel = <0>;		/* Constant */
 		qcom,master-en = <1>;		/* Enable GPIO */
@@ -568,7 +568,7 @@
 
 	mpp@a400 { /* MPP 5 - TP81 */
 		qcom,mode = <0>;		/* Digital input */
-		qcom,pull = <5>;		/* Pull down */
+		qcom,pull = <1>;		/* Pull up open */
 		qcom,vin-sel = <2>;		/* S4 1.8V */
 		qcom,src-sel = <0>;		/* Constant */
 		qcom,master-en = <1>;		/* Enable GPIO */
@@ -587,7 +587,7 @@
 
 	mpp@a600 { /* MPP 7 - TP83 */
 		qcom,mode = <0>;		/* Digital input */
-		qcom,pull = <5>;		/* Pull down */
+		qcom,pull = <1>;		/* Pull up open */
 		qcom,vin-sel = <2>;		/* S4 1.8V */
 		qcom,src-sel = <0>;		/* Constant */
 		qcom,master-en = <1>;		/* Enable GPIO */
diff --git a/arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi b/arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi
index e6f9b16..bf70999 100644
--- a/arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi
+++ b/arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi
@@ -30,16 +30,19 @@
 		compatible = "qcom,mdm-audio-auto";
 		qcom,model = "mdm-auto-i2s-snd-card";
 
-		qcom,mi2s-interface-mode = "pri_mi2s_master", "sec_mi2s_master";
-		qcom,auxpcm-interface-mode = "pri_pcm_master", "sec_pcm_master";
+		qcom,prim_mi2s_aux_master = <&prim_master>;
+		qcom,prim_mi2s_aux_slave = <&prim_slave>;
+		qcom,sec_mi2s_aux_master = <&sec_master>;
+		qcom,sec_mi2s_aux_slave = <&sec_slave>;
 		asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>,
 				<&loopback>, <&hostless>, <&afe>, <&routing>,
-				<&pcm_dtmf>, <&host_pcm>;
+				<&pcm_dtmf>, <&host_pcm>, <&compress>;
 		asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
 				"msm-voip-dsp", "msm-pcm-voice",
 				"msm-pcm-loopback", "msm-pcm-hostless",
 				"msm-pcm-afe", "msm-pcm-routing",
-				"msm-pcm-dtmf", "msm-voice-host-pcm";
+				"msm-pcm-dtmf", "msm-voice-host-pcm",
+				"msm-compress-dsp";
 		asoc-cpu = <&dai_pri_auxpcm>, <&mi2s_prim>, <&mi2s_sec>,
 				<&dtmf_tx>,
 				<&rx_capture_tx>, <&rx_playback_rx>,
@@ -149,7 +152,7 @@
 &tlmm_pinmux {
 	/* Set these up as hogs */
 	pinctrl-names = "default";
-	pinctrl-0 = <&can_reset_gpio>, <&ant_switch_gpio1>, <&ant_switch_gpio2>,
+	pinctrl-0 = <&ant_switch_gpio1>, <&ant_switch_gpio2>,
 		<&ant_switch_gpio3>, <&eth_can_supply_gpio>,
 		<&oabr_enable_gpio>;
 
@@ -180,20 +183,6 @@
 		};
 	};
 
-	can_reset_gpio: can_reset_gpio {
-		mux {
-			pins = "gpio89";
-			function = "gpio";
-		};
-
-		config {
-			pins = "gpio89";
-			drive-strength = <2>;
-			output-high;
-			bias-pull-up;
-		};
-	};
-
 	oabr_enable_gpio: oabr_enable_gpio {
 		mux {
 			pins = "gpio29";
@@ -208,8 +197,8 @@
 		};
 	};
 
-	pmx_sec_mi2s_dout {
-		sec_mi2s_ws_sleep {
+	pmx_sec_mi2s_aux {
+		sec_ws_sleep: sec_ws_sleep {
 			mux {
 				pins = "gpio20";
 				function = "gpio";
@@ -223,7 +212,7 @@
 			};
 		};
 
-		sec_mi2s_sck_sleep {
+		sec_sck_sleep: sec_sck_sleep {
 			mux {
 				pins = "gpio23";
 				function = "gpio";
@@ -237,7 +226,7 @@
 			};
 		};
 
-		sec_mi2s_dout_sleep {
+		sec_dout_sleep: sec_dout_sleep {
 			mux {
 				pins = "gpio22";
 				function = "gpio";
@@ -251,7 +240,7 @@
 			};
 		};
 
-		sec_mi2s_ws_active {
+		sec_ws_active_master: sec_ws_active_master {
 			mux {
 				pins = "gpio20";
 				function = "sec_mi2s_ws_b";
@@ -265,7 +254,7 @@
 			};
 		};
 
-		sec_mi2s_sck_active {
+		sec_sck_active_master: sec_sck_active_master {
 			mux {
 				pins = "gpio23";
 				function = "sec_mi2s_sck_b";
@@ -279,7 +268,33 @@
 			};
 		};
 
-		sec_mi2s_dout_active {
+		sec_ws_active_slave: sec_ws_active_slave {
+			mux {
+				pins = "gpio20";
+				function = "sec_mi2s_ws_b";
+			};
+
+			config {
+				pins = "gpio20";
+				drive-strength = <8>;	/* 8 mA */
+				bias-disable;		/* NO PULL*/
+			};
+		};
+
+		sec_sck_active_slave: sec_sck_active_slave {
+			mux {
+				pins = "gpio23";
+				function = "sec_mi2s_sck_b";
+			};
+
+			config {
+				pins = "gpio23";
+				drive-strength = <8>;	/* 8 mA */
+				bias-disable;		/* NO PULL*/
+			};
+		};
+
+		sec_dout_active: sec_dout_active {
 			mux {
 				pins = "gpio22";
 				function = "sec_mi2s_data1_b";
@@ -294,8 +309,8 @@
 		};
 	};
 
-	pmx_sec_mi2s_din {
-		sec_mi2s_din_sleep {
+	pmx_sec_mi2s_aux_din {
+		sec_din_sleep: sec_din_sleep {
 			mux {
 				pins = "gpio21";
 				function = "gpio";
@@ -309,7 +324,7 @@
 			};
 		};
 
-		sec_mi2s_din_active {
+		sec_din_active: sec_din_active {
 			mux {
 				pins = "gpio21";
 				function = "sec_mi2s_data0_b";
@@ -319,7 +334,6 @@
 				pins = "gpio21";
 				drive-strength = <8>;	/* 8 mA */
 				bias-disable;		/* NO PULL */
-				output-high;
 			};
 		};
 	};
@@ -420,6 +434,35 @@
 			};
 		};
 	};
+
+	can_reset {
+		can_rst_on: rst_on {
+			mux {
+				pins = "gpio89";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio89";
+				drive-strength = <2>; /* 2 mA */
+				bias-pull-up;
+			};
+		};
+
+		can_rst_off: rst_off {
+			mux {
+				pins = "gpio89";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio89";
+				drive-strength = <2>; /* 2 mA */
+				bias-pull-up;
+				output-high;
+			};
+		};
+	};
 };
 
 &cnss_pcie {
@@ -494,6 +537,20 @@
 &spi_4 {
 	status = "ok";
 	/delete-property/ qcom,use-bam;
+
+	can-controller@0 {
+		compatible = "nxp,mpc5746c";
+		reg = <0>;
+		spi-max-frequency = <9600000>;
+		interrupt-parent = <&tlmm_pinmux>;
+		interrupts = <87 0>;
+		reset-gpio = <&tlmm_pinmux 89 0x1>;
+		bits-per-word = <8>;
+		reset-delay-msec = <100>;
+		pinctrl-names = "active", "sleep";
+		pinctrl-0 = <&can_rst_on>;
+		pinctrl-1 = <&can_rst_off>;
+	};
 };
 
 &usb3 {
diff --git a/arch/arm/boot/dts/qcom/mdm9650-pm.dtsi b/arch/arm/boot/dts/qcom/mdm9650-pm.dtsi
index 14bc352..b03b5dc 100644
--- a/arch/arm/boot/dts/qcom/mdm9650-pm.dtsi
+++ b/arch/arm/boot/dts/qcom/mdm9650-pm.dtsi
@@ -147,6 +147,7 @@
 			<0xff 63>,  /* APCS_wcnIPCInterrupt(1) */
 			<0xff 66>,  /* bam_irq[2] */
 			<0xff 73>,  /* pcie20_int_msi */
+			<0xff 81>,  /* pcie20_int_global */
 			<0xff 88>,  /* qpic_lcdc_irq */
 			<0xff 89>,  /* qpic_bam_irq[1] */
 			<0xff 91>,  /* qpic_nandc_op_done_irq */
diff --git a/arch/arm/boot/dts/qcom/mdm9650-regulator.dtsi b/arch/arm/boot/dts/qcom/mdm9650-regulator.dtsi
index 33a420e..f9ef3ca 100644
--- a/arch/arm/boot/dts/qcom/mdm9650-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/mdm9650-regulator.dtsi
@@ -69,7 +69,7 @@
 			regulator-min-microvolt =
 					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
 			regulator-max-microvolt =
-					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+					<RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR>;
 			qcom,use-voltage-level;
 		};
 
@@ -80,7 +80,7 @@
 			regulator-min-microvolt =
 					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
 			regulator-max-microvolt =
-					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+					<RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR>;
 			qcom,use-voltage-level;
 		};
 
@@ -91,7 +91,7 @@
 			regulator-min-microvolt =
 					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
 			regulator-max-microvolt =
-					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+					<RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR>;
 			qcom,use-voltage-floor-level;
 		};
 	};
@@ -194,7 +194,7 @@
 			regulator-min-microvolt =
 					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
 			regulator-max-microvolt =
-					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+					<RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR>;
 			qcom,use-voltage-level;
 		};
 	};
diff --git a/arch/arm/boot/dts/qcom/mdm9650.dtsi b/arch/arm/boot/dts/qcom/mdm9650.dtsi
index 392c5e9..9da8220 100644
--- a/arch/arm/boot/dts/qcom/mdm9650.dtsi
+++ b/arch/arm/boot/dts/qcom/mdm9650.dtsi
@@ -216,7 +216,7 @@
 			< 200000000 RPM_SMD_REGULATOR_LEVEL_LOW_SVS>,
 			< 384000000 RPM_SMD_REGULATOR_LEVEL_SVS>,
 			< 787200000 RPM_SMD_REGULATOR_LEVEL_NOM>,
-			<1286400000 RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			<1286400000 RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR>;
 
 		cpu-vdd-supply = <&pmd9650_s5_level_ao>;
 		qcom,a7ssmux-opp-store-vcorner = <&CPU0>;
@@ -1057,8 +1057,8 @@
 		qcom,limit-temp = <60>;
 		qcom,temp-hysteresis = <10>;
 		qcom,freq-step = <2>;
-		qcom,vdd-restriction-temp = <5>;
-		qcom,vdd-restriction-temp-hysteresis = <10>;
+		qcom,vdd-restriction-temp = <10>;
+		qcom,vdd-restriction-temp-hysteresis = <15>;
 		vdd-dig-supply = <&pmd9650_s5_floor_level>;
 		qcom,disable-cx-phase-ctrl;
 		qcom,disable-gfx-phase-ctrl;
@@ -1068,9 +1068,9 @@
 
 		qcom,vdd-dig-rstr{
 			qcom,vdd-rstr-reg = "vdd-dig";
-			qcom,levels = <RPM_SMD_REGULATOR_LEVEL_NOM
-					RPM_SMD_REGULATOR_LEVEL_TURBO
-					RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			qcom,levels = <RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR
+					RPM_SMD_REGULATOR_LEVEL_BINNING
+					RPM_SMD_REGULATOR_LEVEL_BINNING>;
 			qcom,min-level = <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
 		};
 	};
diff --git a/arch/arm/boot/dts/qcom/msm-pm660.dtsi b/arch/arm/boot/dts/qcom/msm-pm660.dtsi
index 2a1a9c3..95c6069 100644
--- a/arch/arm/boot/dts/qcom/msm-pm660.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pm660.dtsi
@@ -573,6 +573,18 @@
 			reg = <0x7300 0x100>;
 			status = "disabled";
 		};
+
+		bcl@4200 {
+			compatible = "qcom,msm-bcl-lmh";
+			reg = <0x4200 0xff>;
+			reg-names = "fg_user_adc";
+			interrupts = <0x0 0x42 0x0>,
+					<0x0 0x42 0x2>;
+			interrupt-names = "bcl-high-ibat-int",
+					"bcl-low-vbat-int";
+			qcom,vbat-polling-delay-ms = <100>;
+			qcom,ibat-polling-delay-ms = <100>;
+		};
 	};
 
 	qcom,pm660@1 {
diff --git a/arch/arm/boot/dts/qcom/msm8909.dtsi b/arch/arm/boot/dts/qcom/msm8909.dtsi
index 0aace78..9b901df 100644
--- a/arch/arm/boot/dts/qcom/msm8909.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8909.dtsi
@@ -124,7 +124,7 @@
 					compatible = "android,system";
 					dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system";
 					type = "ext4";
-					mnt_flags = "ro,barrier=1";
+					mnt_flags = "ro,barrier=1,discard";
 					fsmgr_flags = "wait";
 					status = "ok";
 				};
diff --git a/arch/arm/boot/dts/qcom/msm8909w-bg-wtp-v2.dts b/arch/arm/boot/dts/qcom/msm8909w-bg-wtp-v2.dts
index 8dd3bb85..9bff173 100644
--- a/arch/arm/boot/dts/qcom/msm8909w-bg-wtp-v2.dts
+++ b/arch/arm/boot/dts/qcom/msm8909w-bg-wtp-v2.dts
@@ -139,6 +139,34 @@
 			qcom,irq-gpio = <&msm_gpio 110 1>;
 		};
 	};
+
+	qcom,msm-thermal {
+		vdd-dig-supply = <&pm660_s2_floor_corner>;
+
+		msm_thermal_freq: qcom,vdd-apps-rstr {
+			qcom,vdd-rstr-reg = "vdd-apps";
+			qcom,levels = <1094400>;
+			qcom,freq-req;
+		};
+	};
+
+	qcom,bcl {
+		compatible = "qcom,bcl";
+		qcom,bcl-enable;
+		qcom,bcl-framework-interface;
+		qcom,bcl-freq-control-list = <&CPU0 &CPU1 &CPU2 &CPU3>;
+		qcom,bcl-hotplug-list = <&CPU2 &CPU3>;
+		qcom,bcl-soc-hotplug-list = <&CPU2 &CPU3>;
+		qcom,ibat-monitor {
+			qcom,low-threshold-uamp = <1000000>;
+			qcom,high-threshold-uamp = <2000000>;
+			qcom,mitigation-freq-khz = <1094400>;
+			qcom,vph-high-threshold-uv = <3500000>;
+			qcom,vph-low-threshold-uv = <3200000>;
+			qcom,soc-low-threshold = <10>;
+			qcom,thermal-handle = <&msm_thermal_freq>;
+		};
+	};
 };
 
 &i2c_1 {
diff --git a/arch/arm/boot/dts/qcom/msm8909w-gpu.dtsi b/arch/arm/boot/dts/qcom/msm8909w-gpu.dtsi
index e811059..6fb5093 100644
--- a/arch/arm/boot/dts/qcom/msm8909w-gpu.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8909w-gpu.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -24,6 +24,9 @@
 
 	/delete-property/qcom,gpu-speed-config;
 
+	/* To disable GPU wake up on touch event */
+	qcom,disable-wake-on-touch;
+
 	/* Bus Scale Settings */
 	qcom,msm-bus,num-cases = <3>;
 	qcom,msm-bus,vectors-KBps =
diff --git a/arch/arm/boot/dts/qcom/msm8917-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8917-pinctrl.dtsi
index e4e6072..b9d9142 100644
--- a/arch/arm/boot/dts/qcom/msm8917-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8917-pinctrl.dtsi
@@ -1290,6 +1290,36 @@
 			};
 		};
 
+		i2c_6 {
+			i2c_6_active: i2c_6_active {
+				/* active state */
+				mux {
+					pins = "gpio22", "gpio23";
+					function = "blsp_i2c6";
+				};
+
+				config {
+					pins = "gpio22", "gpio23";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			i2c_6_sleep: i2c_6_sleep {
+				/* suspended state */
+				mux {
+					pins = "gpio22", "gpio23";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio22", "gpio23";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
 		pmx_rd_nfc_int {
 			/*qcom,pins = <&gp 17>;*/
 			pins = "gpio17";
diff --git a/arch/arm/boot/dts/qcom/msm8917.dtsi b/arch/arm/boot/dts/qcom/msm8917.dtsi
index c529836..ccad93e 100644
--- a/arch/arm/boot/dts/qcom/msm8917.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8917.dtsi
@@ -45,6 +45,7 @@
 		i2c5 = &i2c_5;
 		i2c3 = &i2c_3;
 		i2c4 = &i2c_4;
+		i2c6 = &i2c_6;
 		sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
 		sdhc2 = &sdhc_2; /* SDC2 for SD card */
 	};
@@ -649,6 +650,32 @@
 		dma-names = "tx", "rx";
 	};
 
+	i2c_6: i2c@7af6000 { /* BLSP2 QUP2 */
+		compatible = "qcom,i2c-msm-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		reg = <0x7af6000 0x600>;
+		interrupt-names = "qup_irq";
+		interrupts = <0 300 0>;
+		qcom,clk-freq-out = <400000>;
+		qcom,clk-freq-in  = <19200000>;
+		clock-names = "iface_clk", "core_clk";
+		clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>,
+			<&clock_gcc clk_gcc_blsp2_qup2_i2c_apps_clk>;
+
+		pinctrl-names = "i2c_active", "i2c_sleep";
+		pinctrl-0 = <&i2c_6_active>;
+		pinctrl-1 = <&i2c_6_sleep>;
+		qcom,noise-rjct-scl = <0>;
+		qcom,noise-rjct-sda = <0>;
+		qcom,master-id = <84>;
+		dmas = <&dma_blsp2 6 64 0x20000020 0x20>,
+			<&dma_blsp2 7 32 0x20000020 0x20>;
+		dma-names = "tx", "rx";
+		status = "disabled";
+	};
+
 	rpm_bus: qcom,rpm-smd {
 		compatible = "qcom,rpm-smd";
 		rpm-channel-name = "rpm_requests";
diff --git a/arch/arm/boot/dts/qcom/sdx20.dtsi b/arch/arm/boot/dts/qcom/sdx20.dtsi
index c045800..0d1b7df 100644
--- a/arch/arm/boot/dts/qcom/sdx20.dtsi
+++ b/arch/arm/boot/dts/qcom/sdx20.dtsi
@@ -353,6 +353,7 @@
 
 	qcom,pcie-phy-ver = <5>;
 	qcom,pcie-perst-enum;
+	qcom,pcie-mhi-a7-irq;
 	status = "disabled";
 };
 
@@ -392,6 +393,7 @@
 	interrupts = <0 119 0>;
 	interrupt-names = "mhi-device-inta";
 	qcom,mhi-ifc-id = <0x030317cb>;
+	qcom,mhi-interrupt;
 	status = "disabled";
 };
 
diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig
index 04a4c67..f1ae769 100644
--- a/arch/arm/configs/msm8909-perf_defconfig
+++ b/arch/arm/configs/msm8909-perf_defconfig
@@ -69,6 +69,7 @@
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 CONFIG_IP_ADVANCED_ROUTER=y
@@ -80,6 +81,7 @@
 CONFIG_INET_ESP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG_DESTROY=y
 CONFIG_IPV6=y
 CONFIG_IPV6_ROUTER_PREF=y
 CONFIG_IPV6_ROUTE_INFO=y
@@ -233,6 +235,7 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_APDS9930=y
 CONFIG_QSEECOM=y
+CONFIG_UID_SYS_STATS=y
 CONFIG_MSM_MCU_TIME_SYNC=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -426,6 +429,7 @@
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
+CONFIG_MSM_AVTIMER=y
 CONFIG_MSM_BUS_SCALING=y
 CONFIG_BUS_TOPOLOGY_ADHOC=y
 CONFIG_QPNP_POWER_ON=y
@@ -519,6 +523,7 @@
 CONFIG_SECURITY=y
 CONFIG_SECURITY_NETWORK=y
 CONFIG_LSM_MMAP_MIN_ADDR=4096
+CONFIG_HARDENED_USERCOPY=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_CRYPTO_NULL=y
 CONFIG_CRYPTO_CTR=y
diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig
index a0fcbbf..a273170 100644
--- a/arch/arm/configs/msm8909_defconfig
+++ b/arch/arm/configs/msm8909_defconfig
@@ -73,6 +73,7 @@
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 CONFIG_IP_ADVANCED_ROUTER=y
@@ -84,6 +85,7 @@
 CONFIG_INET_ESP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG_DESTROY=y
 CONFIG_IPV6=y
 CONFIG_IPV6_ROUTER_PREF=y
 CONFIG_IPV6_ROUTE_INFO=y
@@ -239,6 +241,7 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_APDS9930=y
 CONFIG_QSEECOM=y
+CONFIG_UID_SYS_STATS=y
 CONFIG_MSM_MCU_TIME_SYNC=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -438,6 +441,7 @@
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
+CONFIG_MSM_AVTIMER=y
 CONFIG_MSM_BUS_SCALING=y
 CONFIG_BUS_TOPOLOGY_ADHOC=y
 CONFIG_QPNP_POWER_ON=y
@@ -561,6 +565,7 @@
 CONFIG_SECURITY=y
 CONFIG_SECURITY_NETWORK=y
 CONFIG_LSM_MMAP_MIN_ADDR=4096
+CONFIG_HARDENED_USERCOPY=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_CRYPTO_NULL=y
 CONFIG_CRYPTO_CTR=y
diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig
index 2ba1e56..20f0972 100644
--- a/arch/arm/configs/msm8909w-perf_defconfig
+++ b/arch/arm/configs/msm8909w-perf_defconfig
@@ -290,6 +290,8 @@
 CONFIG_BATTERY_BCL=y
 CONFIG_QPNP_VM_BMS=y
 CONFIG_QPNP_LINEAR_CHARGER=y
+CONFIG_MSM_BCL_CTL=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
 CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_MSM=y
 CONFIG_MSM_DLOAD_MODE=y
@@ -390,6 +392,7 @@
 CONFIG_USB_BAM=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_QPNP_VIBRATOR=y
+CONFIG_QPNP_HAPTIC=y
 CONFIG_MSM_SPMI=y
 CONFIG_MSM_SPMI_PMIC_ARB=y
 CONFIG_MSM_QPNP_INT=y
diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig
index 3790578..8c61292 100644
--- a/arch/arm/configs/msm8909w_defconfig
+++ b/arch/arm/configs/msm8909w_defconfig
@@ -293,6 +293,8 @@
 CONFIG_BATTERY_BCL=y
 CONFIG_QPNP_VM_BMS=y
 CONFIG_QPNP_LINEAR_CHARGER=y
+CONFIG_MSM_BCL_CTL=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
 CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_MSM=y
 CONFIG_MSM_DLOAD_MODE=y
diff --git a/arch/arm64/configs/apq8053_IoE-perf_defconfig b/arch/arm64/configs/apq8053_IoE-perf_defconfig
index b163c06..684b75b 100644
--- a/arch/arm64/configs/apq8053_IoE-perf_defconfig
+++ b/arch/arm64/configs/apq8053_IoE-perf_defconfig
@@ -398,6 +398,7 @@
 CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
 CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LT8912=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_USB_AUDIO=y
diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig
index 0947a01..9cba4d5 100644
--- a/arch/arm64/configs/msm-perf_defconfig
+++ b/arch/arm64/configs/msm-perf_defconfig
@@ -1,5 +1,4 @@
 CONFIG_LOCALVERSION="-perf"
-CONFIG_SYSVIPC=y
 # CONFIG_USELIB is not set
 CONFIG_AUDIT=y
 # CONFIG_AUDITSYSCALL is not set
@@ -554,6 +553,7 @@
 CONFIG_MSM_EVENT_TIMER=y
 CONFIG_MSM_SYSMON_GLINK_COMM=y
 CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_IPC_ROUTER_MHI_XPRT=y
 CONFIG_MSM_GLINK_PKT=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_PIL=y
diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig
index 1945c37..56664ac 100644
--- a/arch/arm64/configs/msm8937_defconfig
+++ b/arch/arm64/configs/msm8937_defconfig
@@ -492,6 +492,7 @@
 CONFIG_MMC_SDHCI_MSM=y
 CONFIG_MMC_SDHCI_MSM_ICE=y
 CONFIG_MMC_CQ_HCI=y
+CONFIG_LEDS_TLC591XX=y
 CONFIG_LEDS_QPNP=y
 CONFIG_LEDS_QPNP_FLASH=y
 CONFIG_LEDS_QPNP_WLED=y
diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig
index 4021d5c..279316f 100644
--- a/arch/arm64/configs/msm_defconfig
+++ b/arch/arm64/configs/msm_defconfig
@@ -1,4 +1,3 @@
-CONFIG_SYSVIPC=y
 # CONFIG_USELIB is not set
 CONFIG_AUDIT=y
 # CONFIG_AUDITSYSCALL is not set
diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig
index 49d3fbb..6d2181a2 100644
--- a/arch/arm64/configs/msmcortex-perf_defconfig
+++ b/arch/arm64/configs/msmcortex-perf_defconfig
@@ -318,6 +318,7 @@
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM_LEGACY=y
+# CONFIG_DEVPORT is not set
 CONFIG_MSM_SMD_PKT=y
 CONFIG_MSM_ADSPRPC=y
 CONFIG_MSM_RDBG=m
diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig
index ff676ac..387d979 100644
--- a/arch/arm64/configs/msmcortex_defconfig
+++ b/arch/arm64/configs/msmcortex_defconfig
@@ -320,6 +320,7 @@
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM_LEGACY=y
+# CONFIG_DEVPORT is not set
 CONFIG_MSM_SMD_PKT=y
 CONFIG_MSM_ADSPRPC=y
 CONFIG_MSM_RDBG=m
diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h
index fb87ac5..2df83b2 100644
--- a/arch/arm64/include/asm/system_misc.h
+++ b/arch/arm64/include/asm/system_misc.h
@@ -43,6 +43,7 @@
 
 extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
 extern char* (*arch_read_hardware_id)(void);
+extern const char *machine_name;
 
 #define UDBG_UNDEFINED	(1 << 0)
 #define UDBG_SYSCALL	(1 << 1)
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index 103a7b6..f50585e 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -19,6 +19,7 @@
 #include <asm/cpu.h>
 #include <asm/cputype.h>
 #include <asm/cpufeature.h>
+#include <asm/system_misc.h>
 
 #include <linux/bitops.h>
 #include <linux/bug.h>
@@ -152,6 +153,11 @@
 		seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
 	}
 
+	if (!arch_read_hardware_id)
+		seq_printf(m, "Hardware\t: %s\n", machine_name);
+	else
+		seq_printf(m, "Hardware\t: %s\n", arch_read_hardware_id());
+
 	return 0;
 }
 
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 0538e6e..0bfd048 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -61,9 +61,7 @@
 #include <asm/memblock.h>
 #include <asm/psci.h>
 #include <asm/efi.h>
-
-char* (*arch_read_hardware_id)(void);
-EXPORT_SYMBOL(arch_read_hardware_id);
+#include <asm/system_misc.h>
 
 unsigned int boot_reason;
 EXPORT_SYMBOL(boot_reason);
@@ -71,7 +69,9 @@
 unsigned int cold_boot;
 EXPORT_SYMBOL(cold_boot);
 
-static const char *machine_name;
+char* (*arch_read_hardware_id)(void);
+const char *machine_name;
+
 phys_addr_t __fdt_pointer __initdata;
 
 /*
diff --git a/block/test-iosched.c b/block/test-iosched.c
index 2a0be42..eff1043 100644
--- a/block/test-iosched.c
+++ b/block/test-iosched.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, 2017 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
@@ -316,6 +316,13 @@
 		goto err;
 	}
 
+	/* Restrict num_bios value as it may lead to bios_buffer overflow */
+	if (num_bios >= BLK_MAX_SEGMENTS) {
+		pr_warn("%s: num_bios %d is changed to BLK_MAX_SEGMENTS\n",
+				__func__, num_bios);
+		num_bios = BLK_MAX_SEGMENTS;
+	}
+
 	test_rq->buf_size = TEST_BIO_SIZE * num_bios;
 	test_rq->wr_rd_data_pattern = pattern;
 
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 9f46c45..e5795fd 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1747,14 +1747,18 @@
 {
 	int i;
 
+	mutex_lock(&driver->diagchar_mutex);
 	for (i = 0; i < driver->num_clients; i++)
 		if (driver->client_map[i].pid == current->tgid)
 			break;
 
-	if (i == driver->num_clients)
+	if (i == driver->num_clients) {
+		mutex_unlock(&driver->diagchar_mutex);
 		return -EINVAL;
+	}
 
 	driver->data_ready[i] |= DEINIT_TYPE;
+	mutex_unlock(&driver->diagchar_mutex);
 	wake_up_interruptible(&driver->wait_q);
 
 	return 1;
@@ -2824,6 +2828,16 @@
 	return 0;
 }
 
+static int check_data_ready(int index)
+{
+	int data_type = 0;
+
+	mutex_lock(&driver->diagchar_mutex);
+	data_type = driver->data_ready[index];
+	mutex_unlock(&driver->diagchar_mutex);
+	return data_type;
+}
+
 static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count,
 			  loff_t *ppos)
 {
@@ -2836,9 +2850,11 @@
 	int write_len = 0;
 	struct diag_md_session_t *session_info = NULL;
 
+	mutex_lock(&driver->diagchar_mutex);
 	for (i = 0; i < driver->num_clients; i++)
 		if (driver->client_map[i].pid == current->tgid)
 			index = i;
+	mutex_unlock(&driver->diagchar_mutex);
 
 	if (index == -1) {
 		pr_err("diag: Client PID not found in table");
@@ -2848,7 +2864,7 @@
 		pr_err("diag: bad address from user side\n");
 		return -EFAULT;
 	}
-	wait_event_interruptible(driver->wait_q, driver->data_ready[index]);
+	wait_event_interruptible(driver->wait_q, (check_data_ready(index)) > 0);
 
 	mutex_lock(&driver->diagchar_mutex);
 
@@ -2985,11 +3001,11 @@
 	}
 
 exit:
-	mutex_unlock(&driver->diagchar_mutex);
 	if (driver->data_ready[index] & DCI_DATA_TYPE) {
-		mutex_lock(&driver->dci_mutex);
-		/* Copy the type of data being passed */
 		data_type = driver->data_ready[index] & DCI_DATA_TYPE;
+		mutex_unlock(&driver->diagchar_mutex);
+		/* Copy the type of data being passed */
+		mutex_lock(&driver->dci_mutex);
 		list_for_each_safe(start, temp, &driver->dci_client_list) {
 			entry = list_entry(start, struct diag_dci_client_tbl,
 									track);
@@ -3021,6 +3037,7 @@
 		mutex_unlock(&driver->dci_mutex);
 		goto end;
 	}
+	mutex_unlock(&driver->diagchar_mutex);
 end:
 	/*
 	 * Flush any read that is currently pending on DCI data and
diff --git a/drivers/clk/msm/clock-a7.c b/drivers/clk/msm/clock-a7.c
index 96f52df..1dd67b6 100644
--- a/drivers/clk/msm/clock-a7.c
+++ b/drivers/clk/msm/clock-a7.c
@@ -221,6 +221,7 @@
 	devm_kfree(&pdev->dev, array);
 	vdd->num_levels = prop_len;
 	vdd->cur_level = prop_len;
+	vdd->use_max_uV = true;
 	c->num_fmax = prop_len;
 	return 0;
 }
diff --git a/drivers/clk/msm/vdd-level-9650.h b/drivers/clk/msm/vdd-level-9650.h
index d8f95b0..6d496d4 100644
--- a/drivers/clk/msm/vdd-level-9650.h
+++ b/drivers/clk/msm/vdd-level-9650.h
@@ -90,7 +90,7 @@
 	RPM_REGULATOR_LEVEL_LOW_SVS,		/* VDD_DIG_LOWER */
 	RPM_REGULATOR_LEVEL_SVS,		/* VDD_DIG_LOW */
 	RPM_REGULATOR_LEVEL_NOM,		/* VDD_DIG_NOMINAL */
-	RPM_REGULATOR_LEVEL_TURBO,		/* VDD_DIG_HIGH */
+	RPM_REGULATOR_LEVEL_TURBO_NO_CPR,	/* VDD_DIG_HIGH */
 };
 
 #endif
diff --git a/drivers/devfreq/governor_bw_vbif.c b/drivers/devfreq/governor_bw_vbif.c
index 83196e1..ac670ad 100644
--- a/drivers/devfreq/governor_bw_vbif.c
+++ b/drivers/devfreq/governor_bw_vbif.c
@@ -80,15 +80,13 @@
 	case DEVFREQ_GOV_START:
 		mutex_lock(&df_lock);
 		df = devfreq;
-		if (df->profile->get_dev_status)
-			ret = df->profile->get_dev_status(df->dev.parent,
-					&stat);
-		else
-			ret = 0;
-		if (ret || !stat.private_data)
-			pr_warn("Device doesn't take AB votes!\n");
-		else
+		if (df->profile->get_dev_status &&
+			!df->profile->get_dev_status(df->dev.parent, &stat) &&
+			stat.private_data)
 			dev_ab = stat.private_data;
+		else
+			pr_warn("Device doesn't take AB votes!\n");
+
 		mutex_unlock(&df_lock);
 
 		ret = devfreq_vbif_update_bw(0, 0);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 90a393a..0ae1402 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2409,9 +2409,9 @@
 		unsigned int mem_len)
 {
 
-	unsigned int __iomem *reg;
+	void __iomem *reg;
 	BUG_ON(offsetwords*sizeof(uint32_t) >= mem_len);
-	reg = (unsigned int __iomem *)(base + (offsetwords << 2));
+	reg = (base + (offsetwords << 2));
 
 	if (!in_interrupt())
 		kgsl_pre_hwaccess(device);
@@ -2451,7 +2451,7 @@
 				unsigned int offsetwords,
 				unsigned int value)
 {
-	unsigned int __iomem *reg;
+	void __iomem *reg;
 
 	BUG_ON(offsetwords*sizeof(uint32_t) >= device->reg_len);
 
@@ -2461,7 +2461,7 @@
 	trace_kgsl_regwrite(device, offsetwords, value);
 
 	kgsl_cffdump_regwrite(device, offsetwords << 2, value);
-	reg = (unsigned int __iomem *)(device->reg_virt + (offsetwords << 2));
+	reg = (device->reg_virt + (offsetwords << 2));
 
 	/*ensure previous writes post before this one,
 	 * i.e. act like normal writel() */
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 3cb40c2..80640e1 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -182,6 +182,7 @@
 #define ADRENO_TIMEOUT_FAULT BIT(2)
 #define ADRENO_IOMMU_PAGE_FAULT BIT(3)
 #define ADRENO_PREEMPT_FAULT BIT(4)
+#define ADRENO_CTX_DETATCH_TIMEOUT_FAULT BIT(5)
 
 #define ADRENO_SPTP_PC_CTRL 0
 #define ADRENO_PPD_CTRL     1
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index 97b571b..da0ffa8 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -2026,6 +2026,9 @@
 
 	}
 
+	/* Disable All flat shading optimization */
+	kgsl_regrmw(device, A5XX_VPC_DBG_ECO_CNTL, 0, 0x1 << 10);
+
 	/*
 	 * VPC corner case with local memory load kill leads to corrupt
 	 * internal state. Normal Disable does not work for all a5x chips.
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index ab1aaee..98ff434 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -1519,7 +1519,8 @@
 	 * because we won't see this cmdbatch again
 	 */
 
-	if (fault & ADRENO_TIMEOUT_FAULT)
+	if ((fault & ADRENO_TIMEOUT_FAULT) ||
+				(fault & ADRENO_CTX_DETATCH_TIMEOUT_FAULT))
 		bitmap_zero(&cmdbatch->fault_policy, BITS_PER_LONG);
 
 	/*
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 8a66875..13ef0f5 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -297,6 +297,7 @@
 	/* Give the bad news to everybody waiting around */
 	wake_up_all(&drawctxt->waiting);
 	wake_up_all(&drawctxt->wq);
+	wake_up_all(&drawctxt->timeout);
 }
 
 /*
@@ -389,6 +390,7 @@
 	spin_lock_init(&drawctxt->lock);
 	init_waitqueue_head(&drawctxt->wq);
 	init_waitqueue_head(&drawctxt->waiting);
+	init_waitqueue_head(&drawctxt->timeout);
 
 	/* Set the context priority */
 	_set_context_priority(drawctxt);
@@ -501,20 +503,32 @@
 		drawctxt->internal_timestamp, 30 * 1000);
 
 	/*
-	 * If the wait for global fails due to timeout then nothing after this
-	 * point is likely to work very well - Get GPU snapshot and BUG_ON()
-	 * so we can take advantage of the debug tools to figure out what the
-	 * h - e - double hockey sticks happened. If EAGAIN error is returned
+	 * If the wait for global fails due to timeout then mark it as
+	 * context detach timeout fault and schedule dispatcher to kick
+	 * in GPU recovery. For a ADRENO_CTX_DETATCH_TIMEOUT_FAULT we clear
+	 * the policy and invalidate the context. If EAGAIN error is returned
 	 * then recovery will kick in and there will be no more commands in the
-	 * RB pipe from this context which is waht we are waiting for, so ignore
-	 * -EAGAIN error
+	 * RB pipe from this context which is what we are waiting for, so ignore
+	 * -EAGAIN error.
 	 */
 	if (ret && ret != -EAGAIN) {
-		KGSL_DRV_ERR(device, "Wait for global ts=%d type=%d error=%d\n",
-				drawctxt->internal_timestamp,
+		KGSL_DRV_ERR(device,
+				"Wait for global ctx=%d ts=%d type=%d error=%d\n",
+				drawctxt->base.id, drawctxt->internal_timestamp,
 				drawctxt->type, ret);
-		device->force_panic = 1;
-		kgsl_device_snapshot(device, context);
+
+		adreno_set_gpu_fault(adreno_dev,
+				ADRENO_CTX_DETATCH_TIMEOUT_FAULT);
+		mutex_unlock(&device->mutex);
+
+		/* Schedule dispatcher to kick in recovery */
+		adreno_dispatcher_schedule(device);
+
+		/* Wait for context to be invalidated and release context */
+		ret = wait_event_interruptible_timeout(drawctxt->timeout,
+					kgsl_context_invalid(&drawctxt->base),
+					msecs_to_jiffies(5000));
+		return;
 	}
 
 	kgsl_sharedmem_writel(device, &device->memstore,
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 5ea91195..0908862 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -39,6 +39,7 @@
  * @pending: Priority list node for the dispatcher list of pending contexts
  * @wq: Workqueue structure for contexts to sleep pending room in the queue
  * @waiting: Workqueue structure for contexts waiting for a timestamp or event
+ * @timeout: Workqueue structure for contexts waiting to invalidate
  * @queued: Number of commands queued in the cmdqueue
  * @fault_policy: GFT fault policy set in cmdbatch_skip_cmd();
  * @debug_root: debugfs entry for this context.
@@ -67,6 +68,7 @@
 	struct plist_node pending;
 	wait_queue_head_t wq;
 	wait_queue_head_t waiting;
+	wait_queue_head_t timeout;
 
 	int queued;
 	unsigned int fault_policy;
diff --git a/drivers/gpu/msm/adreno_perfcounter.c b/drivers/gpu/msm/adreno_perfcounter.c
index 9692297..f2ce02b 100644
--- a/drivers/gpu/msm/adreno_perfcounter.c
+++ b/drivers/gpu/msm/adreno_perfcounter.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2017, 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
@@ -654,6 +654,9 @@
 static void _power_counter_enable_alwayson(struct adreno_device *adreno_dev,
 				struct adreno_perfcounters *counters)
 {
+	if (!ADRENO_FEATURE(adreno_dev, ADRENO_GPMU))
+		return;
+
 	kgsl_regwrite(KGSL_DEVICE(adreno_dev),
 		A5XX_GPMU_ALWAYS_ON_COUNTER_RESET, 1);
 	counters->groups[KGSL_PERFCOUNTER_GROUP_ALWAYSON_PWR].regs[0].value = 0;
@@ -694,6 +697,9 @@
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 	struct adreno_perfcount_register *reg;
 
+	if (!ADRENO_FEATURE(adreno_dev, ADRENO_GPMU))
+		return;
+
 	reg = &counters->groups[group].regs[counter];
 	kgsl_regwrite(device, reg->select, countable);
 	kgsl_regwrite(device, A5XX_GPMU_POWER_COUNTER_ENABLE, 1);
@@ -927,6 +933,9 @@
 	struct adreno_perfcount_register *reg;
 	unsigned int lo = 0, hi = 0;
 
+	if (!ADRENO_FEATURE(adreno_dev, ADRENO_GPMU))
+		return 0;
+
 	reg = &group->regs[counter];
 
 	kgsl_regread(device, reg->offset, &lo);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 563cb5e..3f02344 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2163,7 +2163,7 @@
 		struct kgsl_mem_entry *entry,
 		struct kgsl_gpuobj_import *param)
 {
-	struct kgsl_gpuobj_import_useraddr useraddr;
+	struct kgsl_gpuobj_import_useraddr useraddr = {0};
 	int ret;
 
 	param->flags &= KGSL_MEMFLAGS_GPUREADONLY
@@ -3617,13 +3617,13 @@
 	if (!kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
 		val = get_unmapped_area(NULL, addr, len, 0, flags);
 		if (IS_ERR_VALUE(val))
-			KGSL_MEM_ERR(device,
+			KGSL_DRV_ERR_RATELIMIT(device,
 				"get_unmapped_area: pid %d addr %lx pgoff %lx len %ld failed error %d\n",
 				private->pid, addr, pgoff, len, (int) val);
 	} else {
 		 val = _get_svm_area(private, entry, addr, len, flags);
 		 if (IS_ERR_VALUE(val))
-			KGSL_MEM_ERR(device,
+			KGSL_DRV_ERR_RATELIMIT(device,
 				"_get_svm_area: pid %d addr %lx pgoff %lx len %ld failed error %d\n",
 				private->pid, addr, pgoff, len, (int) val);
 	}
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index f23d922f..0e9fa9f 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1497,6 +1497,8 @@
 			ret = PTR_ERR(mmu->defaultpagetable);
 			mmu->defaultpagetable = NULL;
 			return ret;
+		} else if (mmu->defaultpagetable == NULL) {
+			return -ENOMEM;
 		}
 	}
 
diff --git a/drivers/gpu/msm/kgsl_log.h b/drivers/gpu/msm/kgsl_log.h
index 51baabe..9b7833b 100644
--- a/drivers/gpu/msm/kgsl_log.h
+++ b/drivers/gpu/msm/kgsl_log.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2011,2013-2014,2016 The Linux Foundation.
+/* Copyright (c) 2002,2008-2011,2013-2014,2016-2017 The Linux Foundation.
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -67,6 +67,13 @@
 					__func__, ##args);\
 	} while (0)
 
+#define KGSL_LOG_ERR_RATELIMITED(dev, lvl, fmt, args...) \
+	do { \
+		if ((lvl) >= 3) \
+			dev_err_ratelimited(dev, "|%s| " fmt, \
+					__func__, ##args);\
+	} while (0)
+
 #define KGSL_DRV_INFO(_dev, fmt, args...) \
 KGSL_LOG_INFO(_dev->dev, _dev->drv_log, fmt, ##args)
 #define KGSL_DRV_WARN(_dev, fmt, args...) \
@@ -77,6 +84,8 @@
 KGSL_LOG_CRIT(_dev->dev, _dev->drv_log, fmt, ##args)
 #define KGSL_DRV_CRIT_RATELIMIT(_dev, fmt, args...) \
 KGSL_LOG_CRIT_RATELIMITED(_dev->dev, _dev->drv_log, fmt, ##args)
+#define KGSL_DRV_ERR_RATELIMIT(_dev, fmt, args...) \
+KGSL_LOG_ERR_RATELIMITED(_dev->dev, _dev->drv_log, fmt, ##args)
 #define KGSL_DRV_FATAL(_dev, fmt, args...) \
 KGSL_LOG_FATAL((_dev)->dev, (_dev)->drv_log, fmt, ##args)
 
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 7f4a5a3..27733b06 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -20,6 +20,7 @@
 #include <linux/scatterlist.h>
 #include <soc/qcom/scm.h>
 #include <soc/qcom/secure_buffer.h>
+#include <linux/ratelimit.h>
 
 #include "kgsl.h"
 #include "kgsl_sharedmem.h"
@@ -699,6 +700,10 @@
 	size_t len;
 	unsigned int align;
 
+	static DEFINE_RATELIMIT_STATE(_rs,
+					DEFAULT_RATELIMIT_INTERVAL,
+					DEFAULT_RATELIMIT_BURST);
+
 	size = PAGE_ALIGN(size);
 	if (size == 0 || size > UINT_MAX)
 		return -EINVAL;
@@ -761,7 +766,8 @@
 			 */
 			memdesc->size = (size - len);
 
-			if (sharedmem_noretry_flag != true)
+			if (sharedmem_noretry_flag != true &&
+					__ratelimit(&_rs))
 				KGSL_CORE_ERR(
 					"Out of memory: only allocated %lldKB of %lldKB requested\n",
 					(size - len) >> 10, size >> 10);
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index 5c3ae1b..dab7852 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -180,7 +180,7 @@
 		goto out;
 	}
 	snprintf(fence_name, sizeof(fence_name),
-		"%s-pid-%d-ctx-%d-ts-%d",
+		"%s-pid-%d-ctx-%d-ts-%u",
 		device->name, current->group_leader->pid,
 		context_id, timestamp);
 
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index eeb527d..690a9f0 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -188,27 +188,9 @@
 	uhid_queue(uhid, ev);
 	spin_unlock_irqrestore(&uhid->qlock, flags);
 
-	/*
-	 * Assumption: report_lock and devlock are both locked. So unlock
-	 * before sleeping.
-	 */
-	mutex_unlock(&uhid->report_lock);
-	mutex_unlock(&uhid->devlock);
 	ret = wait_event_interruptible_timeout(uhid->report_wait,
 				!uhid->report_running || !uhid->running,
 				5 * HZ);
-	ret = mutex_lock_interruptible(&uhid->devlock);
-	if (ret)
-		return ret;
-	ret = mutex_lock_interruptible(&uhid->report_lock);
-	if (ret) {
-		/*
-		 * Failed to lock, unlock previous mutex before exiting
-		 * this function.
-		 */
-		mutex_unlock(&uhid->devlock);
-		return ret;
-	}
 	if (!ret || !uhid->running || uhid->report_running)
 		ret = -EIO;
 	else if (ret < 0)
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c
index f50371c..0195dd8 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c
@@ -55,7 +55,7 @@
 #define TYPE_B_PROTOCOL
 #endif
 
-#define WAKEUP_GESTURE false
+#define WAKEUP_GESTURE true
 
 #define NO_0D_WHILE_2D
 #define REPORT_2D_Z
@@ -4422,7 +4422,8 @@
 				synaptics_secure_touch_stop(rmi4_data, false);
 			} else if (event == FB_EVENT_BLANK) {
 				transition = evdata->data;
-				if (*transition == FB_BLANK_POWERDOWN) {
+				if (*transition == FB_BLANK_POWERDOWN ||
+					*transition == FB_BLANK_VSYNC_SUSPEND) {
 					flush_work(
 						&(rmi4_data->fb_notify_work));
 					synaptics_rmi4_suspend(
@@ -4563,8 +4564,10 @@
 	synaptics_secure_touch_stop(rmi4_data, true);
 
 	if (rmi4_data->enable_wakeup_gesture) {
-		synaptics_rmi4_wakeup_gesture(rmi4_data, true);
-		enable_irq_wake(rmi4_data->irq);
+		if (!rmi4_data->suspend) {
+			synaptics_rmi4_wakeup_gesture(rmi4_data, true);
+			enable_irq_wake(rmi4_data->irq);
+		}
 		goto exit;
 	}
 
@@ -4577,9 +4580,10 @@
 	if (rmi4_data->ts_pinctrl) {
 		retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
 		rmi4_data->pinctrl_state_suspend);
-		if (retval < 0)
+		if (retval < 0) {
 			dev_err(dev, "Cannot get idle pinctrl state\n");
 			goto err_pinctrl;
+		}
 	}
 exit:
 	mutex_lock(&exp_data.mutex);
@@ -4590,7 +4594,7 @@
 	}
 	mutex_unlock(&exp_data.mutex);
 
-	if (!rmi4_data->suspend) {
+	if (!rmi4_data->suspend && !rmi4_data->enable_wakeup_gesture) {
 		synaptics_rmi4_enable_reg(rmi4_data, false);
 		synaptics_rmi4_get_reg(rmi4_data, false);
 	}
@@ -4619,8 +4623,10 @@
 	synaptics_secure_touch_stop(rmi4_data, true);
 
 	if (rmi4_data->enable_wakeup_gesture) {
-		synaptics_rmi4_wakeup_gesture(rmi4_data, false);
-		disable_irq_wake(rmi4_data->irq);
+		if (rmi4_data->suspend) {
+			synaptics_rmi4_wakeup_gesture(rmi4_data, false);
+			disable_irq_wake(rmi4_data->irq);
+		}
 		goto exit;
 	}
 
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 7e3e74c..d14d310 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -446,6 +446,14 @@
 	  LED driver chips accessed via the I2C bus.
 	  Driver support brightness control and hardware-assisted blinking.
 
+config LEDS_TLC591XX
+	tristate "LED driver for TLC59108 and TLC59116 controllers"
+	depends on LEDS_CLASS && I2C
+	select REGMAP_I2C
+	help
+	  This option enables support for Texas Instruments TLC59108
+	  and TLC59116 LED controllers.
+
 config LEDS_MAX8997
 	tristate "LED support for MAX8997 PMIC"
 	depends on LEDS_CLASS && MFD_MAX8997
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index c5178d9..f0d81db 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -29,6 +29,7 @@
 obj-$(CONFIG_LEDS_LP8501)		+= leds-lp8501.o
 obj-$(CONFIG_LEDS_LP8788)		+= leds-lp8788.o
 obj-$(CONFIG_LEDS_TCA6507)		+= leds-tca6507.o
+obj-$(CONFIG_LEDS_TLC591XX)		+= leds-tlc591xx.o
 obj-$(CONFIG_LEDS_CLEVO_MAIL)		+= leds-clevo-mail.o
 obj-$(CONFIG_LEDS_IPAQ_MICRO)		+= leds-ipaq-micro.o
 obj-$(CONFIG_LEDS_HP6XX)		+= leds-hp6xx.o
diff --git a/drivers/leds/leds-qpnp-flash.c b/drivers/leds/leds-qpnp-flash.c
index ec4b4e7..785fe51 100644
--- a/drivers/leds/leds-qpnp-flash.c
+++ b/drivers/leds/leds-qpnp-flash.c
@@ -1307,7 +1307,7 @@
 	int max_curr_avail_ma = 0;
 	int total_curr_ma = 0;
 	int i;
-	u8 val;
+	u8 val = 0;
 
 	/* Global lock is to synchronize between the flash leds and torch */
 	mutex_lock(&led->flash_led_lock);
@@ -1319,8 +1319,30 @@
 		goto turn_off;
 
 	if (led->open_fault) {
-		dev_err(&led->spmi_dev->dev, "Open fault detected\n");
-		goto unlock_mutex;
+		if (flash_node->type == FLASH) {
+			dev_dbg(&led->spmi_dev->dev, "Open fault detected\n");
+			goto unlock_mutex;
+		}
+		/*
+		 * Checking LED fault status again if open_fault has been
+		 * detected previously. Update open_fault status then the
+		 * flash leds could be controlled again if the hardware
+		 * status is recovered.
+		 */
+		rc = spmi_ext_register_readl(led->spmi_dev->ctrl,
+			led->spmi_dev->sid,
+			FLASH_LED_FAULT_STATUS(led->base), &val, 1);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Failed to read out fault status register\n");
+			goto unlock_mutex;
+		}
+
+		led->open_fault = (val & FLASH_LED_OPEN_FAULT_DETECTED);
+		if (led->open_fault) {
+			dev_err(&led->spmi_dev->dev, "Open fault detected\n");
+			goto unlock_mutex;
+		}
 	}
 
 	if (!flash_node->flash_on && flash_node->num_regulators > 0) {
@@ -1804,7 +1826,7 @@
 			goto exit_flash_led_work;
 		}
 
-		led->open_fault |= (val & FLASH_LED_OPEN_FAULT_DETECTED);
+		led->open_fault = (val & FLASH_LED_OPEN_FAULT_DETECTED);
 	}
 
 	rc = qpnp_led_masked_write(led->spmi_dev,
diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c
new file mode 100644
index 0000000..de16c29
--- /dev/null
+++ b/drivers/leds/leds-tlc591xx.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2014 Belkin Inc.
+ * Copyright 2015 Andrew Lunn <andrew@lunn.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#define TLC591XX_MAX_LEDS	16
+
+#define TLC591XX_REG_MODE1	0x00
+#define MODE1_RESPON_ADDR_MASK	0xF0
+#define MODE1_NORMAL_MODE	(0 << 4)
+#define MODE1_SPEED_MODE	(1 << 4)
+
+#define TLC591XX_REG_MODE2	0x01
+#define MODE2_DIM		(0 << 5)
+#define MODE2_BLINK		(1 << 5)
+#define MODE2_OCH_STOP		(0 << 3)
+#define MODE2_OCH_ACK		(1 << 3)
+
+#define TLC591XX_REG_PWM(x)	(0x02 + (x))
+
+#define TLC591XX_REG_GRPPWM	0x12
+#define TLC591XX_REG_GRPFREQ	0x13
+
+/* LED Driver Output State, determine the source that drives LED outputs */
+#define LEDOUT_OFF		0x0	/* Output LOW */
+#define LEDOUT_ON		0x1	/* Output HI-Z */
+#define LEDOUT_DIM		0x2	/* Dimming */
+#define LEDOUT_BLINK		0x3	/* Blinking */
+#define LEDOUT_MASK		0x3
+
+#define ldev_to_led(c)		container_of(c, struct tlc591xx_led, ldev)
+#define work_to_led(work)	container_of(work, struct tlc591xx_led, work)
+
+struct tlc591xx_led {
+	bool active;
+	unsigned int led_no;
+	struct led_classdev ldev;
+	struct work_struct work;
+	struct tlc591xx_priv *priv;
+};
+
+struct tlc591xx_priv {
+	struct tlc591xx_led leds[TLC591XX_MAX_LEDS];
+	struct regmap *regmap;
+	unsigned int reg_ledout_offset;
+};
+
+struct tlc591xx {
+	unsigned int max_leds;
+	unsigned int reg_ledout_offset;
+};
+
+static const struct tlc591xx tlc59116 = {
+	.max_leds = 16,
+	.reg_ledout_offset = 0x14,
+};
+
+static const struct tlc591xx tlc59108 = {
+	.max_leds = 8,
+	.reg_ledout_offset = 0x0c,
+};
+
+static int
+tlc591xx_set_mode(struct regmap *regmap, u8 mode)
+{
+	int err;
+	u8 val;
+
+	err = regmap_write(regmap, TLC591XX_REG_MODE1, MODE1_NORMAL_MODE);
+	if (err)
+		return err;
+
+	val = MODE2_OCH_STOP | mode;
+
+	return regmap_write(regmap, TLC591XX_REG_MODE2, val);
+}
+
+static int
+tlc591xx_set_ledout(struct tlc591xx_priv *priv, struct tlc591xx_led *led,
+		    u8 val)
+{
+	unsigned int i = (led->led_no % 4) * 2;
+	unsigned int mask = LEDOUT_MASK << i;
+	unsigned int addr = priv->reg_ledout_offset + (led->led_no >> 2);
+
+	val = val << i;
+
+	return regmap_update_bits(priv->regmap, addr, mask, val);
+}
+
+static int
+tlc591xx_set_pwm(struct tlc591xx_priv *priv, struct tlc591xx_led *led,
+		 u8 brightness)
+{
+	u8 pwm = TLC591XX_REG_PWM(led->led_no);
+
+	return regmap_write(priv->regmap, pwm, brightness);
+}
+
+static void
+tlc591xx_led_work(struct work_struct *work)
+{
+	struct tlc591xx_led *led = work_to_led(work);
+	struct tlc591xx_priv *priv = led->priv;
+	enum led_brightness brightness = led->ldev.brightness;
+	int err;
+
+	switch (brightness) {
+	case 0:
+		err = tlc591xx_set_ledout(priv, led, LEDOUT_OFF);
+		break;
+	case LED_FULL:
+		err = tlc591xx_set_ledout(priv, led, LEDOUT_ON);
+		break;
+	default:
+		err = tlc591xx_set_ledout(priv, led, LEDOUT_DIM);
+		if (!err)
+			err = tlc591xx_set_pwm(priv, led, brightness);
+	}
+
+	if (err)
+		dev_err(led->ldev.dev, "Failed setting brightness\n");
+}
+
+static void
+tlc591xx_brightness_set(struct led_classdev *led_cdev,
+			enum led_brightness brightness)
+{
+	struct tlc591xx_led *led = ldev_to_led(led_cdev);
+
+	led->ldev.brightness = brightness;
+	schedule_work(&led->work);
+}
+
+static void
+tlc591xx_destroy_devices(struct tlc591xx_priv *priv, unsigned int j)
+{
+	int i = j;
+
+	while (--i >= 0) {
+		if (priv->leds[i].active) {
+			led_classdev_unregister(&priv->leds[i].ldev);
+			cancel_work_sync(&priv->leds[i].work);
+		}
+	}
+}
+
+static int
+tlc591xx_configure(struct device *dev,
+		   struct tlc591xx_priv *priv,
+		   const struct tlc591xx *tlc591xx)
+{
+	unsigned int i;
+	int err = 0;
+
+	tlc591xx_set_mode(priv->regmap, MODE2_DIM);
+	for (i = 0; i < TLC591XX_MAX_LEDS; i++) {
+		struct tlc591xx_led *led = &priv->leds[i];
+
+		if (!led->active)
+			continue;
+
+		led->priv = priv;
+		led->led_no = i;
+		led->ldev.brightness_set = tlc591xx_brightness_set;
+		led->ldev.max_brightness = LED_FULL;
+		INIT_WORK(&led->work, tlc591xx_led_work);
+		err = led_classdev_register(dev, &led->ldev);
+		if (err < 0) {
+			dev_err(dev, "couldn't register LED %s\n",
+				led->ldev.name);
+			goto exit;
+		}
+	}
+
+	return 0;
+
+exit:
+	tlc591xx_destroy_devices(priv, i);
+	return err;
+}
+
+static const struct regmap_config tlc591xx_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = 0x1e,
+};
+
+static const struct of_device_id of_tlc591xx_leds_match[] = {
+	{ .compatible = "ti,tlc59116",
+	  .data = &tlc59116 },
+	{ .compatible = "ti,tlc59108",
+	  .data = &tlc59108 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_tlc591xx_leds_match);
+
+static int
+tlc591xx_probe(struct i2c_client *client,
+	       const struct i2c_device_id *id)
+{
+	struct device_node *np = client->dev.of_node, *child;
+	struct device *dev = &client->dev;
+	const struct of_device_id *match;
+	const struct tlc591xx *tlc591xx;
+	struct tlc591xx_priv *priv;
+	int err, count, reg;
+
+	match = of_match_device(of_tlc591xx_leds_match, dev);
+	if (!match)
+		return -ENODEV;
+
+	tlc591xx = match->data;
+	if (!np)
+		return -ENODEV;
+
+	count = of_get_child_count(np);
+	if (!count || count > tlc591xx->max_leds)
+		return -EINVAL;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->regmap = devm_regmap_init_i2c(client, &tlc591xx_regmap);
+	if (IS_ERR(priv->regmap)) {
+		err = PTR_ERR(priv->regmap);
+		dev_err(dev, "Failed to allocate register map: %d\n", err);
+		return err;
+	}
+	priv->reg_ledout_offset = tlc591xx->reg_ledout_offset;
+
+	i2c_set_clientdata(client, priv);
+
+	for_each_child_of_node(np, child) {
+		err = of_property_read_u32(child, "reg", &reg);
+		if (err)
+			return err;
+		if (reg < 0 || reg >= tlc591xx->max_leds)
+			return -EINVAL;
+		if (priv->leds[reg].active)
+			return -EINVAL;
+		priv->leds[reg].active = true;
+		priv->leds[reg].ldev.name =
+			of_get_property(child, "label", NULL) ? : child->name;
+		priv->leds[reg].ldev.default_trigger =
+			of_get_property(child, "linux,default-trigger", NULL);
+	}
+	return tlc591xx_configure(dev, priv, tlc591xx);
+}
+
+static int
+tlc591xx_remove(struct i2c_client *client)
+{
+	struct tlc591xx_priv *priv = i2c_get_clientdata(client);
+
+	tlc591xx_destroy_devices(priv, TLC591XX_MAX_LEDS);
+
+	return 0;
+}
+
+static const struct i2c_device_id tlc591xx_id[] = {
+	{ "tlc59116" },
+	{ "tlc59108" },
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, tlc591xx_id);
+
+static struct i2c_driver tlc591xx_driver = {
+	.driver = {
+		.name = "tlc591xx",
+		.of_match_table = of_match_ptr(of_tlc591xx_leds_match),
+	},
+	.probe = tlc591xx_probe,
+	.remove = tlc591xx_remove,
+	.id_table = tlc591xx_id,
+};
+
+module_i2c_driver(tlc591xx_driver);
+
+MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TLC591XX LED driver");
diff --git a/drivers/media/platform/msm/ais/camera/camera.c b/drivers/media/platform/msm/ais/camera/camera.c
index d5db823..bd82033 100644
--- a/drivers/media/platform/msm/ais/camera/camera.c
+++ b/drivers/media/platform/msm/ais/camera/camera.c
@@ -627,6 +627,7 @@
 	if (WARN_ON(!pvdev))
 		return -EIO;
 
+	mutex_lock(&pvdev->video_drvdata_mutex);
 	rc = camera_v4l2_fh_open(filep);
 	if (rc < 0) {
 		pr_err("%s : camera_v4l2_fh_open failed Line %d rc %d\n",
@@ -697,6 +698,7 @@
 	idx |= (1 << find_first_zero_bit((const unsigned long *)&opn_idx,
 				MSM_CAMERA_STREAM_CNT_BITS));
 	atomic_cmpxchg(&pvdev->opened, opn_idx, idx);
+	mutex_unlock(&pvdev->video_drvdata_mutex);
 
 	return rc;
 
@@ -711,6 +713,7 @@
 vb2_q_fail:
 	camera_v4l2_fh_release(filep);
 fh_open_fail:
+	mutex_unlock(&pvdev->video_drvdata_mutex);
 	return rc;
 }
 
@@ -745,6 +748,7 @@
 	if (WARN_ON(!session))
 		return -EIO;
 
+	mutex_lock(&pvdev->video_drvdata_mutex);
 	mutex_lock(&session->close_lock);
 	opn_idx = atomic_read(&pvdev->opened);
 	mask = (1 << sp->stream_id);
@@ -786,6 +790,7 @@
 	}
 
 	camera_v4l2_fh_release(filep);
+	mutex_unlock(&pvdev->video_drvdata_mutex);
 
 	return 0;
 }
@@ -932,6 +937,7 @@
 
 	*session = pvdev->vdev->num;
 	atomic_set(&pvdev->opened, 0);
+	mutex_init(&pvdev->video_drvdata_mutex);
 	video_set_drvdata(pvdev->vdev, pvdev);
 	device_init_wakeup(&pvdev->vdev->dev, 1);
 	goto init_end;
diff --git a/drivers/media/platform/msm/ais/msm.c b/drivers/media/platform/msm/ais/msm.c
index f6d6a45..b5d5c36 100644
--- a/drivers/media/platform/msm/ais/msm.c
+++ b/drivers/media/platform/msm/ais/msm.c
@@ -292,6 +292,7 @@
 		return;
 
 	while (1) {
+		unsigned long wl_flags;
 
 		if (try_count > 5) {
 			pr_err("%s : not able to delete stream %d\n",
@@ -299,18 +300,20 @@
 			break;
 		}
 
-		write_lock(&session->stream_rwlock);
+		write_lock_irqsave(&session->stream_rwlock, wl_flags);
 		try_count++;
 		stream = msm_queue_find(&session->stream_q, struct msm_stream,
 			list, __msm_queue_find_stream, &stream_id);
 
 		if (!stream) {
-			write_unlock(&session->stream_rwlock);
+			write_unlock_irqrestore(&session->stream_rwlock,
+				wl_flags);
 			return;
 		}
 
 		if (msm_vb2_get_stream_state(stream) != 1) {
-			write_unlock(&session->stream_rwlock);
+			write_unlock_irqrestore(&session->stream_rwlock,
+				wl_flags);
 			continue;
 		}
 
@@ -320,7 +323,7 @@
 		kfree(stream);
 		stream = NULL;
 		spin_unlock_irqrestore(&(session->stream_q.lock), flags);
-		write_unlock(&session->stream_rwlock);
+		write_unlock_irqrestore(&session->stream_rwlock, wl_flags);
 		break;
 	}
 
@@ -730,6 +733,16 @@
 	if (!event_data)
 		return -EINVAL;
 
+	switch (cmd) {
+	case MSM_CAM_V4L2_IOCTL_NOTIFY:
+	case MSM_CAM_V4L2_IOCTL_CMD_ACK:
+	case MSM_CAM_V4L2_IOCTL_NOTIFY_DEBUG:
+	case MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR:
+		break;
+	default:
+		return -ENOTTY;
+	}
+
 	memset(&event, 0, sizeof(struct v4l2_event));
 	session_id = event_data->session_id;
 	stream_id = event_data->stream_id;
diff --git a/drivers/media/platform/msm/ais/msm.h b/drivers/media/platform/msm/ais/msm.h
index 8a316c6..5c48368 100644
--- a/drivers/media/platform/msm/ais/msm.h
+++ b/drivers/media/platform/msm/ais/msm.h
@@ -45,6 +45,7 @@
 struct msm_video_device {
 	struct video_device *vdev;
 	atomic_t opened;
+	struct mutex video_drvdata_mutex;
 };
 
 struct msm_queue_head {
diff --git a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c
index aa2f696..f782b98 100644
--- a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c
+++ b/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c
@@ -46,22 +46,23 @@
 	struct msm_stream *stream;
 	struct msm_session *session;
 	struct msm_vb2_buffer *msm_vb2_buf;
+	unsigned long rl_flags;
 
 	session = msm_get_session_from_vb2q(vb->vb2_queue);
 	if (IS_ERR_OR_NULL(session))
 		return -EINVAL;
 
-	read_lock(&session->stream_rwlock);
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
 
 	stream = msm_get_stream_from_vb2q(vb->vb2_queue);
 	if (!stream) {
 		pr_err("%s: Couldn't find stream\n", __func__);
-		read_unlock(&session->stream_rwlock);
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 		return -EINVAL;
 	}
 	msm_vb2_buf = container_of(vb, struct msm_vb2_buffer, vb2_buf);
 	msm_vb2_buf->in_freeq = 0;
-	read_unlock(&session->stream_rwlock);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 	return 0;
 }
 
@@ -70,7 +71,7 @@
 	struct msm_vb2_buffer *msm_vb2;
 	struct msm_stream *stream;
 	struct msm_session *session;
-	unsigned long flags;
+	unsigned long flags, rl_flags;
 
 	msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf);
 
@@ -83,19 +84,19 @@
 	if (IS_ERR_OR_NULL(session))
 		return;
 
-	read_lock(&session->stream_rwlock);
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
 
 	stream = msm_get_stream_from_vb2q(vb->vb2_queue);
 	if (!stream) {
 		pr_err("%s:%d] NULL stream", __func__, __LINE__);
-		read_unlock(&session->stream_rwlock);
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 		return;
 	}
 
 	spin_lock_irqsave(&stream->stream_lock, flags);
 	list_add_tail(&msm_vb2->list, &stream->queued_list);
 	spin_unlock_irqrestore(&stream->stream_lock, flags);
-	read_unlock(&session->stream_rwlock);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 }
 
 static void msm_vb2_buf_finish(struct vb2_buffer *vb)
@@ -103,7 +104,7 @@
 	struct msm_vb2_buffer *msm_vb2;
 	struct msm_stream *stream;
 	struct msm_session *session;
-	unsigned long flags;
+	unsigned long flags, rl_flags;
 	struct msm_vb2_buffer *msm_vb2_entry, *temp;
 
 	msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf);
@@ -117,12 +118,12 @@
 	if (IS_ERR_OR_NULL(session))
 		return;
 
-	read_lock(&session->stream_rwlock);
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
 
 	stream = msm_get_stream_from_vb2q(vb->vb2_queue);
 	if (!stream) {
 		pr_err("%s:%d] NULL stream", __func__, __LINE__);
-		read_unlock(&session->stream_rwlock);
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 		return;
 	}
 
@@ -135,7 +136,7 @@
 		}
 	}
 	spin_unlock_irqrestore(&stream->stream_lock, flags);
-	read_unlock(&session->stream_rwlock);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 }
 
 static void msm_vb2_stop_stream(struct vb2_queue *q)
@@ -143,19 +144,19 @@
 	struct msm_vb2_buffer *msm_vb2, *temp;
 	struct msm_stream *stream;
 	struct msm_session *session;
-	unsigned long flags;
+	unsigned long flags, rl_flags;
 	struct vb2_buffer *vb2_buf;
 
 	session = msm_get_session_from_vb2q(q);
 	if (IS_ERR_OR_NULL(session))
 		return;
 
-	read_lock(&session->stream_rwlock);
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
 
 	stream = msm_get_stream_from_vb2q(q);
 	if (!stream) {
 		pr_err_ratelimited("%s:%d] NULL stream", __func__, __LINE__);
-		read_unlock(&session->stream_rwlock);
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 		return;
 	}
 
@@ -174,7 +175,7 @@
 			msm_vb2->in_freeq = 0;
 		}
 	spin_unlock_irqrestore(&stream->stream_lock, flags);
-	read_unlock(&session->stream_rwlock);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 }
 
 int msm_vb2_get_stream_state(struct msm_stream *stream)
@@ -252,17 +253,17 @@
 	struct vb2_buffer *vb2_buf = NULL;
 	struct msm_session *session;
 	struct msm_vb2_buffer *msm_vb2 = NULL;
-	unsigned long flags;
+	unsigned long flags, rl_flags;
 
 	session = msm_get_session(session_id);
 	if (IS_ERR_OR_NULL(session))
 		return NULL;
 
-	read_lock(&session->stream_rwlock);
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
 
 	stream = msm_get_stream(session, stream_id);
 	if (IS_ERR_OR_NULL(stream)) {
-		read_unlock(&session->stream_rwlock);
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 		return NULL;
 	}
 
@@ -288,7 +289,7 @@
 	vb2_buf = NULL;
 end:
 	spin_unlock_irqrestore(&stream->stream_lock, flags);
-	read_unlock(&session->stream_rwlock);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 	return vb2_buf;
 }
 
@@ -299,18 +300,18 @@
 	struct vb2_buffer *vb2_buf = NULL;
 	struct msm_session *session;
 	struct msm_vb2_buffer *msm_vb2 = NULL;
-	unsigned long flags;
+	unsigned long flags, rl_flags;
 
 	session = msm_get_session(session_id);
 	if (IS_ERR_OR_NULL(session))
 		return NULL;
 
-	read_lock(&session->stream_rwlock);
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
 
 	stream = msm_get_stream(session, stream_id);
 
 	if (IS_ERR_OR_NULL(stream)) {
-		read_unlock(&session->stream_rwlock);
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 		return NULL;
 	}
 
@@ -334,7 +335,7 @@
 	vb2_buf = NULL;
 end:
 	spin_unlock_irqrestore(&stream->stream_lock, flags);
-	read_unlock(&session->stream_rwlock);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 	return vb2_buf;
 }
 
@@ -346,17 +347,17 @@
 	struct msm_vb2_buffer *msm_vb2;
 	struct vb2_buffer *vb2_buf = NULL;
 	int rc = 0;
-	unsigned long flags;
+	unsigned long flags, rl_flags;
 
 	session = msm_get_session(session_id);
 	if (IS_ERR_OR_NULL(session))
 		return -EINVAL;
 
-	read_lock(&session->stream_rwlock);
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
 
 	stream = msm_get_stream(session, stream_id);
 	if (IS_ERR_OR_NULL(stream)) {
-		read_unlock(&session->stream_rwlock);
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 		return -EINVAL;
 	}
 
@@ -371,6 +372,8 @@
 			pr_err("VB buffer is INVALID vb=%pK, ses_id=%d, str_id=%d\n",
 					vb, session_id, stream_id);
 			spin_unlock_irqrestore(&stream->stream_lock, flags);
+			read_unlock_irqrestore(&session->stream_rwlock,
+				rl_flags);
 			return -EINVAL;
 		}
 		msm_vb2 =
@@ -386,7 +389,7 @@
 		rc = -EINVAL;
 	}
 	spin_unlock_irqrestore(&stream->stream_lock, flags);
-	read_unlock(&session->stream_rwlock);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 	return rc;
 }
 
@@ -394,7 +397,7 @@
 				unsigned int stream_id, uint32_t sequence,
 				struct timeval *ts, uint32_t reserved)
 {
-	unsigned long flags;
+	unsigned long flags, rl_flags;
 	struct msm_vb2_buffer *msm_vb2;
 	struct msm_stream *stream;
 	struct vb2_buffer *vb2_buf = NULL;
@@ -405,11 +408,11 @@
 	if (IS_ERR_OR_NULL(session))
 		return -EINVAL;
 
-	read_lock(&session->stream_rwlock);
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
 
 	stream = msm_get_stream(session, stream_id);
 	if (IS_ERR_OR_NULL(stream)) {
-		read_unlock(&session->stream_rwlock);
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 		return -EINVAL;
 	}
 
@@ -424,6 +427,8 @@
 			pr_err("VB buffer is INVALID ses_id=%d, str_id=%d, vb=%pK\n",
 				    session_id, stream_id, vb);
 			spin_unlock_irqrestore(&stream->stream_lock, flags);
+			read_unlock_irqrestore(&session->stream_rwlock,
+				rl_flags);
 			return -EINVAL;
 		}
 		msm_vb2 =
@@ -444,7 +449,7 @@
 		rc = -EINVAL;
 	}
 	spin_unlock_irqrestore(&stream->stream_lock, flags);
-	read_unlock(&session->stream_rwlock);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 	return rc;
 }
 
@@ -455,18 +460,18 @@
 	struct vb2_buffer *vb2_buf = NULL;
 	struct msm_session *session;
 	struct msm_vb2_buffer *msm_vb2 = NULL;
-	unsigned long flags;
+	unsigned long flags, rl_flags;
 	long rc = -EINVAL;
 
 	session = msm_get_session(session_id);
 	if (IS_ERR_OR_NULL(session))
 		return rc;
 
-	read_lock(&session->stream_rwlock);
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
 
 	stream = msm_get_stream(session, stream_id);
 	if (IS_ERR_OR_NULL(stream)) {
-		read_unlock(&session->stream_rwlock);
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 		return -EINVAL;
 	}
 
@@ -494,14 +499,14 @@
 
 end:
 	spin_unlock_irqrestore(&stream->stream_lock, flags);
-	read_unlock(&session->stream_rwlock);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 	return rc;
 }
 EXPORT_SYMBOL(msm_vb2_return_buf_by_idx);
 
 static int msm_vb2_flush_buf(int session_id, unsigned int stream_id)
 {
-	unsigned long flags;
+	unsigned long flags, rl_flags;
 	struct msm_vb2_buffer *msm_vb2;
 	struct msm_stream *stream;
 	struct vb2_buffer *vb2_buf = NULL;
@@ -511,11 +516,11 @@
 	if (IS_ERR_OR_NULL(session))
 		return -EINVAL;
 
-	read_lock(&session->stream_rwlock);
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
 
 	stream = msm_get_stream(session, stream_id);
 	if (IS_ERR_OR_NULL(stream)) {
-		read_unlock(&session->stream_rwlock);
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 		return -EINVAL;
 	}
 
@@ -527,7 +532,7 @@
 		msm_vb2->in_freeq = 0;
 	}
 	spin_unlock_irqrestore(&stream->stream_lock, flags);
-	read_unlock(&session->stream_rwlock);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
 	return 0;
 }
 
diff --git a/drivers/media/platform/msm/ais/sensor/flash/msm_flash.c b/drivers/media/platform/msm/ais/sensor/flash/msm_flash.c
index eac24da..225325f 100644
--- a/drivers/media/platform/msm/ais/sensor/flash/msm_flash.c
+++ b/drivers/media/platform/msm/ais/sensor/flash/msm_flash.c
@@ -1090,6 +1090,9 @@
 			break;
 		}
 		break;
+	case VIDIOC_MSM_FLASH_CFG:
+		pr_err("invalid cmd 0x%x received\n", cmd);
+		return -EINVAL;
 	default:
 		return msm_flash_subdev_ioctl(sd, cmd, arg);
 	}
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index 5bfcf28..12f07de 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -623,6 +623,7 @@
 	unsigned int opn_idx, idx;
 	BUG_ON(!pvdev);
 
+	mutex_lock(&pvdev->video_drvdata_mutex);
 	rc = camera_v4l2_fh_open(filep);
 	if (rc < 0) {
 		pr_err("%s : camera_v4l2_fh_open failed Line %d rc %d\n",
@@ -693,6 +694,7 @@
 	idx |= (1 << find_first_zero_bit((const unsigned long *)&opn_idx,
 				MSM_CAMERA_STREAM_CNT_BITS));
 	atomic_cmpxchg(&pvdev->opened, opn_idx, idx);
+	mutex_unlock(&pvdev->video_drvdata_mutex);
 
 	return rc;
 
@@ -707,6 +709,7 @@
 vb2_q_fail:
 	camera_v4l2_fh_release(filep);
 fh_open_fail:
+	mutex_unlock(&pvdev->video_drvdata_mutex);
 	return rc;
 }
 
@@ -737,6 +740,7 @@
 	if (WARN_ON(!session))
 		return -EIO;
 
+	mutex_lock(&pvdev->video_drvdata_mutex);
 	mutex_lock(&session->close_lock);
 	opn_idx = atomic_read(&pvdev->opened);
 	mask = (1 << sp->stream_id);
@@ -778,6 +782,7 @@
 	}
 
 	camera_v4l2_fh_release(filep);
+	mutex_unlock(&pvdev->video_drvdata_mutex);
 
 	return 0;
 }
@@ -924,6 +929,7 @@
 
 	*session = pvdev->vdev->num;
 	atomic_set(&pvdev->opened, 0);
+	mutex_init(&pvdev->video_drvdata_mutex);
 	video_set_drvdata(pvdev->vdev, pvdev);
 	device_init_wakeup(&pvdev->vdev->dev, 1);
 	goto init_end;
diff --git a/drivers/media/platform/msm/camera_v2/msm.h b/drivers/media/platform/msm/camera_v2/msm.h
index fec8ea4..79d70a0 100644
--- a/drivers/media/platform/msm/camera_v2/msm.h
+++ b/drivers/media/platform/msm/camera_v2/msm.h
@@ -45,6 +45,7 @@
 struct msm_video_device {
 	struct video_device *vdev;
 	atomic_t opened;
+	struct mutex video_drvdata_mutex;
 };
 
 struct msm_queue_head {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index 39cdae9d..001faf5 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -2039,8 +2039,6 @@
 	int32_t rc = 0;
 	CDBG("Enter\n");
 	rc = platform_driver_register(&msm_actuator_platform_driver);
-	if (!rc)
-		return rc;
 
 	CDBG("%s:%d rc %d\n", __func__, __LINE__, rc);
 	return i2c_add_driver(&msm_actuator_i2c_driver);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index a89f332..e851c56 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -230,16 +230,34 @@
 static int msm_csid_reset(struct csid_device *csid_dev)
 {
 	int32_t rc = 0;
+	uint32_t irq = 0, irq_bitshift;
+
+	irq_bitshift = csid_dev->ctrl_reg->csid_reg.csid_rst_done_irq_bitshift;
 	msm_camera_io_w(csid_dev->ctrl_reg->csid_reg.csid_rst_stb_all,
 		csid_dev->base +
 		csid_dev->ctrl_reg->csid_reg.csid_rst_cmd_addr);
 	rc = wait_for_completion_timeout(&csid_dev->reset_complete,
 		CSID_TIMEOUT);
-	if (rc <= 0) {
+	if (rc < 0) {
 		pr_err("wait_for_completion in msm_csid_reset fail rc = %d\n",
 			rc);
+	} else if (rc == 0) {
+		irq = msm_camera_io_r(csid_dev->base +
+			csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr);
+		pr_err_ratelimited("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n",
+			__func__, csid_dev->pdev->id, irq);
+		if (irq & (0x1 << irq_bitshift)) {
+			rc = 1;
+			CDBG("%s succeeded", __func__);
+		} else {
+			rc = 0;
+			pr_err("%s reset csid_irq_status failed = 0x%x\n",
+				__func__, irq);
+		}
 		if (rc == 0)
 			rc = -ETIMEDOUT;
+	} else {
+		CDBG("%s succeeded", __func__);
 	}
 	return rc;
 }
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
index 88d99fd..1670fa3 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
@@ -1089,6 +1089,9 @@
 			break;
 		}
 		break;
+	case VIDIOC_MSM_FLASH_CFG:
+		pr_err("invalid cmd 0x%x received\n", cmd);
+		return -EINVAL;
 	default:
 		return msm_flash_subdev_ioctl(sd, cmd, arg);
 	}
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 018e3ab..9c02da3 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -354,13 +354,17 @@
 	int level;
 	struct mpq_demux *mpq_demux = fp->private_data;
 
-	if (count >= 16)
+	if (count == 0 || count >= 16)
 		return -EINVAL;
 
-	ret_count = simple_write_to_buffer(user_str, 16, position, user_buffer,
+	memset(user_str, '\0', sizeof(user_str));
+
+	ret_count = simple_write_to_buffer(user_str, 15, position, user_buffer,
 		count);
 	if (ret_count < 0)
 		return ret_count;
+	else if (ret_count == 0)
+		return -EINVAL;
 
 	ret = kstrtoint(user_str, 0, &level);
 	if (ret)
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 9c897d3..dc5b44e 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -489,12 +489,16 @@
 	struct device *dev;
 	int nr = BASE_DEVICE_NUMBER;
 
+	if (!vidc_driver) {
+		dprintk(VIDC_ERR, "Invalid vidc driver\n");
+		return -EINVAL;
+	}
+
 	core = kzalloc(sizeof(*core), GFP_KERNEL);
-	if (!core || !vidc_driver) {
+	if (!core) {
 		dprintk(VIDC_ERR,
 			"Failed to allocate memory for device core\n");
-		rc = -ENOMEM;
-		goto err_no_mem;
+		return -ENOMEM;
 	}
 
 	dev_set_drvdata(&pdev->dev, core);
@@ -642,7 +646,6 @@
 err_core_init:
 	dev_set_drvdata(&pdev->dev, NULL);
 	kfree(core);
-err_no_mem:
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 39ab47a..0c60d1ac 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -936,7 +936,7 @@
 		b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
 		b->m.planes[i].reserved[0] = buffer_info->fd[i];
 		b->m.planes[i].reserved[1] = buffer_info->buff_off[i];
-		if (!b->m.planes[i].m.userptr) {
+		if (!(inst->flags & VIDC_SECURE) && !b->m.planes[i].m.userptr) {
 			dprintk(VIDC_ERR,
 			"%s: Failed to find user virtual address, %#lx, %d, %d\n",
 			__func__, b->m.planes[i].m.userptr, b->type, i);
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index b28c1eb..02fdbf8 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2017, 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
@@ -288,7 +288,7 @@
 	static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 1);
 	struct wcd9xxx_core_resource *wcd9xxx_res = data;
 	int num_irq_regs = wcd9xxx_res->num_irq_regs;
-	u8 status[num_irq_regs], status1[num_irq_regs];
+	u8 status[4], status1[4] = {0}, unmask_status[4] = {0};
 
 	if (unlikely(wcd9xxx_lock_sleep(wcd9xxx_res) == false)) {
 		dev_err(wcd9xxx_res->dev, "Failed to hold suspend\n");
@@ -311,6 +311,23 @@
 				"Failed to read interrupt status: %d\n", ret);
 		goto err_disable_irq;
 	}
+	/*
+	 * If status is 0 return without clearing.
+	 * status contains: HW status - masked interrupts
+	 * status1 contains: unhandled interrupts - masked interrupts
+	 * unmasked_status contains: unhandled interrupts
+	 */
+	if (unlikely(!memcmp(status, status1, sizeof(status)))) {
+		pr_debug("%s: status is 0\n", __func__);
+		wcd9xxx_unlock_sleep(wcd9xxx_res);
+		return IRQ_HANDLED;
+	}
+
+	/*
+	 * Copy status to unmask_status before masking, otherwise SW may miss
+	 * to clear masked interrupt in corner case.
+	 */
+	memcpy(unmask_status, status, sizeof(unmask_status));
 
 	/* Apply masking */
 	for (i = 0; i < num_irq_regs; i++)
@@ -334,6 +351,8 @@
 			wcd9xxx_irq_dispatch(wcd9xxx_res, &irqdata);
 			status1[BIT_BYTE(irqdata.intr_num)] &=
 					~BYTE_BIT_MASK(irqdata.intr_num);
+			unmask_status[BIT_BYTE(irqdata.intr_num)] &=
+					~BYTE_BIT_MASK(irqdata.intr_num);
 		}
 	}
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 36d7b30..bac22ef 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -3002,6 +3002,13 @@
 		pm_wakeup_event(mmc_dev(host), 5000);
 
 	host->detect_change = 1;
+	/*
+	 * Change in cd_gpio state, so make sure detection part is
+	 * not overided because of manual resume.
+	 */
+	if (cd_irq && mmc_bus_manual_resume(host))
+		host->ignore_bus_resume_flags = true;
+
 	mmc_schedule_delayed_work(&host->detect, delay);
 }
 
@@ -3923,6 +3930,8 @@
 		host->bus_ops->detect(host);
 
 	host->detect_change = 0;
+	if (host->ignore_bus_resume_flags)
+		host->ignore_bus_resume_flags = false;
 
 	/*
 	 * Let mmc_bus_put() free the bus/bus_ops if we've found that
@@ -4176,7 +4185,8 @@
 
 		spin_lock_irqsave(&host->lock, flags);
 		host->rescan_disable = 0;
-		if (mmc_bus_manual_resume(host)) {
+		if (mmc_bus_manual_resume(host) &&
+				!host->ignore_bus_resume_flags) {
 			spin_unlock_irqrestore(&host->lock, flags);
 			break;
 		}
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index a29c4b2..b58bf6d 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1234,7 +1234,10 @@
 	if (!err) {
 		pm_runtime_disable(&host->card->dev);
 		pm_runtime_set_suspended(&host->card->dev);
-	}
+	/* if suspend fails, force mmc_detect_change during resume */
+	} else if (mmc_bus_manual_resume(host))
+		host->ignore_bus_resume_flags = true;
+
 	MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err);
 
 	return err;
diff --git a/drivers/net/can/spi/k61.c b/drivers/net/can/spi/k61.c
index 975794c..f3c2c6e 100644
--- a/drivers/net/can/spi/k61.c
+++ b/drivers/net/can/spi/k61.c
@@ -57,6 +57,8 @@
 	int reset;
 	int wait_cmd;
 	int cmd_result;
+	int bits_per_word;
+	int reset_delay_msec;
 };
 
 struct k61_netdev_privdata {
@@ -309,7 +311,7 @@
 	xfer->tx_buf = priv_data->tx_buf;
 	xfer->rx_buf = priv_data->rx_buf;
 	xfer->len = XFER_BUFFER_SIZE;
-	xfer->bits_per_word = 16;
+	xfer->bits_per_word = priv_data->bits_per_word;
 
 	ret = spi_sync(spi, msg);
 	LOGDI("spi_sync ret %d\n", ret);
@@ -828,25 +830,31 @@
 	}
 	dev_dbg(dev, "k61_probe created priv_data");
 
-	priv_data->reset = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0);
-	if (!gpio_is_valid(priv_data->reset)) {
-		dev_err(&spi->dev, "Missing dt property: reset-gpio\n");
-		return -EINVAL;
-	}
-	err = gpio_request(priv_data->reset, "k61-reset");
-	if (err < 0) {
-		dev_err(&spi->dev,
-			"failed to request gpio %d: %d\n",
-			priv_data->reset, err);
-	}
+	err = of_property_read_u32(spi->dev.of_node, "bits-per-word",
+				   &priv_data->bits_per_word);
+	if (err)
+		priv_data->bits_per_word = 16;
 
-	gpio_direction_output(priv_data->reset, 0);
-	udelay(1);
-	gpio_direction_output(priv_data->reset, 1);
-	/* Provide a delay of 300us for the chip to reset. This is part of
-	 * the reset sequence.
-	 */
-	usleep_range(300, 301);
+	err = of_property_read_u32(spi->dev.of_node, "reset-delay-msec",
+				   &priv_data->reset_delay_msec);
+	if (err)
+		priv_data->reset_delay_msec = 1;
+
+	priv_data->reset = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0);
+	if (gpio_is_valid(priv_data->reset)) {
+		err = gpio_request(priv_data->reset, "k61-reset");
+		if (err < 0) {
+			dev_err(&spi->dev,
+				"failed to request gpio %d: %d\n",
+				priv_data->reset, err);
+			goto cleanup_candev;
+		}
+
+		gpio_direction_output(priv_data->reset, 0);
+		udelay(1);
+		gpio_direction_output(priv_data->reset, 1);
+		msleep(priv_data->reset_delay_msec);
+	}
 
 	err = k61_create_netdev(spi, priv_data);
 	if (err) {
@@ -908,6 +916,7 @@
 
 static const struct of_device_id k61_match_table[] = {
 	{ .compatible = "fsl,k61" },
+	{ .compatible = "nxp,mpc5746c" },
 	{ }
 };
 
diff --git a/drivers/net/wireless/cnss/logger/nl_service.c b/drivers/net/wireless/cnss/logger/nl_service.c
index 565cb3a..1bbdc47 100644
--- a/drivers/net/wireless/cnss/logger/nl_service.c
+++ b/drivers/net/wireless/cnss/logger/nl_service.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 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
@@ -104,9 +104,39 @@
  */
 static int logger_dispatch_skb(struct sk_buff *skb)
 {
+	struct nlmsghdr *nlh;
+	struct logger_context *ctx;
+	struct logger_device *cur;
+	struct logger_event_handler *evt;
+	int handled = 0;
+
+	ctx = logger_get_ctx();
+	if (!ctx)
+		return -ENOENT;
+
 	pr_info("skb_len: %d, skb_data_len: %d\n",
 		skb->len, skb->data_len);
 
+	if (skb->len < sizeof(struct nlmsghdr))
+		return 0;
+
+	nlh = (struct nlmsghdr *)skb->data;
+	list_for_each_entry(cur, &ctx->dev_list, list) {
+		list_for_each_entry(evt, &cur->event_list, list) {
+			if (nlh->nlmsg_type == evt->event) {
+				if (evt->cb) {
+					handled = 1;
+					evt->cb(skb);
+				}
+				/* Break inside loop, next dev */
+				break;
+			}
+		}
+	}
+
+	if (!handled)
+		pr_info("Not handled msg type: %d\n", nlh->nlmsg_type);
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/cnss2/debug.c b/drivers/net/wireless/cnss2/debug.c
index c69f0a4..047a988 100644
--- a/drivers/net/wireless/cnss2/debug.c
+++ b/drivers/net/wireless/cnss2/debug.c
@@ -158,6 +158,7 @@
 	} else if (sysfs_streq(cmd, "enumerate")) {
 		ret = cnss_pci_init(plat_priv);
 	} else if (sysfs_streq(cmd, "download")) {
+		set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
 		ret = cnss_pci_start_mhi(plat_priv->bus_priv);
 	} else if (sysfs_streq(cmd, "linkup")) {
 		ret = cnss_resume_pci_link(plat_priv->bus_priv);
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
index 8277de8..46eb300 100644
--- a/drivers/net/wireless/cnss2/main.c
+++ b/drivers/net/wireless/cnss2/main.c
@@ -1613,7 +1613,7 @@
 
 	if (plat_priv->device_id == QCA6174_DEVICE_ID) {
 		cnss_pr_info("Forced FW assert is not supported\n");
-		return -EINVAL;
+		return -EOPNOTSUPP;
 	}
 
 	if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
index 6335ade..af956f6 100644
--- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
+++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
@@ -20,6 +20,7 @@
 #include <linux/skbuff.h>
 #endif
 #include <linux/debugfs.h>
+#include <net/cnss_prealloc.h>
 
 static DEFINE_SPINLOCK(alloc_lock);
 
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h
index c9b5995..185c9cd 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h
@@ -289,6 +289,7 @@
 	u32                          link_speed;
 	bool                         active_config;
 	bool                         aggregated_irq;
+	bool                         mhi_a7_irq;
 	u32                          dbi_base_reg;
 	u32                          slv_space_reg;
 	u32                          phy_status_reg;
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c
index c535bee..fb187da 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c
@@ -600,9 +600,13 @@
 			BIT(EP_PCIE_INT_EVT_LINK_DOWN) |
 			BIT(EP_PCIE_INT_EVT_BME) |
 			BIT(EP_PCIE_INT_EVT_PM_TURNOFF) |
-			BIT(EP_PCIE_INT_EVT_MHI_A7) |
 			BIT(EP_PCIE_INT_EVT_DSTATE_CHANGE) |
 			BIT(EP_PCIE_INT_EVT_LINK_UP));
+		if (!dev->mhi_a7_irq)
+			ep_pcie_write_mask(dev->parf +
+				PCIE20_PARF_INT_ALL_MASK, 0,
+				BIT(EP_PCIE_INT_EVT_MHI_A7));
+
 		EP_PCIE_DBG(dev, "PCIe V%d: PCIE20_PARF_INT_ALL_MASK:0x%x\n",
 			dev->rev,
 			readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_MASK));
@@ -1050,7 +1054,6 @@
 		EP_PCIE_ERR(dev,
 			"PCIe V%d: request to turn on the power when link is already powered on.\n",
 			dev->rev);
-		ret = EP_PCIE_ERROR;
 		goto out;
 	}
 
@@ -1364,7 +1367,7 @@
 	spin_lock_irqsave(&dev->ext_lock, irqsave_flags);
 
 	if (dev->aggregated_irq) {
-		mask = readl_relaxed(dev->dm_core + PCIE20_PARF_INT_ALL_MASK);
+		mask = readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_MASK);
 		EP_PCIE_DUMP(dev,
 			"PCIe V%d: current PCIE20_PARF_INT_ALL_MASK:0x%x\n",
 			dev->rev, mask);
@@ -1377,7 +1380,7 @@
 		EP_PCIE_DUMP(dev,
 			"PCIe V%d: new PCIE20_PARF_INT_ALL_MASK:0x%x\n",
 			dev->rev,
-			readl_relaxed(dev->dm_core + PCIE20_PARF_INT_ALL_MASK));
+			readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_MASK));
 	} else {
 		EP_PCIE_ERR(dev,
 			"PCIe V%d: Client askes to %s IRQ event 0x%x when aggregated IRQ is not supported.\n",
@@ -2287,6 +2290,13 @@
 		"PCIe V%d: aggregated IRQ is %s enabled.\n",
 		ep_pcie_dev.rev, ep_pcie_dev.aggregated_irq ? "" : "not");
 
+	ep_pcie_dev.mhi_a7_irq =
+		of_property_read_bool((&pdev->dev)->of_node,
+				"qcom,pcie-mhi-a7-irq");
+	EP_PCIE_DBG(&ep_pcie_dev,
+		"PCIe V%d: Mhi a7 IRQ is %s enabled.\n",
+		ep_pcie_dev.rev, ep_pcie_dev.mhi_a7_irq ? "" : "not");
+
 	ep_pcie_dev.perst_enum = of_property_read_bool((&pdev->dev)->of_node,
 				"qcom,pcie-perst-enum");
 	EP_PCIE_DBG(&ep_pcie_dev,
diff --git a/drivers/platform/msm/ipa/ipa_v2/Makefile b/drivers/platform/msm/ipa/ipa_v2/Makefile
index 69b8a4c..fb03970 100644
--- a/drivers/platform/msm/ipa/ipa_v2/Makefile
+++ b/drivers/platform/msm/ipa/ipa_v2/Makefile
@@ -1,6 +1,7 @@
 obj-$(CONFIG_IPA) += ipat.o
 ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \
 	ipa_utils.o ipa_nat.o ipa_intf.o teth_bridge.o ipa_interrupts.o \
-	ipa_uc.o ipa_uc_wdi.o ipa_dma.o ipa_uc_mhi.o ipa_mhi.o ipa_uc_ntn.o
+	ipa_uc.o ipa_uc_wdi.o ipa_dma.o ipa_uc_mhi.o ipa_mhi.o ipa_uc_ntn.o \
+	ipa_wdi3_i.o
 
 obj-$(CONFIG_RMNET_IPA) += rmnet_ipa.o ipa_qmi_service_v01.o ipa_qmi_service.o rmnet_ipa_fd_ioctl.o
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
index 70f9cd8..f454205 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
@@ -431,7 +431,7 @@
 			link) {
 		nbytes = scnprintf(
 			dbg_buff,
-			IPA_MAX_MSG_LEN,
+			IPA_MAX_MSG_LEN - 1,
 			"name:%s len=%d ref=%d partial=%d type=%s ",
 			entry->name,
 			entry->hdr_len,
@@ -442,23 +442,23 @@
 		if (entry->is_hdr_proc_ctx) {
 			nbytes += scnprintf(
 				dbg_buff + nbytes,
-				IPA_MAX_MSG_LEN - nbytes,
+				IPA_MAX_MSG_LEN - 1 - nbytes,
 				"phys_base=0x%pa ",
 				&entry->phys_base);
 		} else {
 			nbytes += scnprintf(
 				dbg_buff + nbytes,
-				IPA_MAX_MSG_LEN - nbytes,
+				IPA_MAX_MSG_LEN - 1 - nbytes,
 				"ofst=%u ",
 				entry->offset_entry->offset >> 2);
 		}
 		for (i = 0; i < entry->hdr_len; i++) {
 			scnprintf(dbg_buff + nbytes + i * 2,
-				  IPA_MAX_MSG_LEN - nbytes - i * 2,
+				  IPA_MAX_MSG_LEN - 1 - nbytes - i * 2,
 				  "%02x", entry->hdr[i]);
 		}
 		scnprintf(dbg_buff + nbytes + entry->hdr_len * 2,
-			  IPA_MAX_MSG_LEN - nbytes - entry->hdr_len * 2,
+			  IPA_MAX_MSG_LEN - 1 - nbytes - entry->hdr_len * 2,
 			  "\n");
 		pr_err("%s", dbg_buff);
 	}
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index 2f60bb5..fe2695a 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -1558,6 +1558,12 @@
 int ipa2_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *), void *priv);
 void ipa2_ntn_uc_dereg_rdyCB(void);
 
+int ipa2_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
+	struct ipa_wdi3_conn_out_params *out);
+int ipa2_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
+int ipa2_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
+int ipa2_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
+
 /*
  * To retrieve doorbell physical address of
  * wlan pipes
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 0531919..293a60a 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -53,7 +53,7 @@
 	int pipe_idx;
 
 	if (buf == NULL) {
-		memset(tmp, 0, IPA_RT_FLT_HW_RULE_BUF_SIZE);
+		memset(tmp, 0, (IPA_RT_FLT_HW_RULE_BUF_SIZE/4));
 		buf = (u8 *)tmp;
 	}
 
@@ -75,8 +75,15 @@
 	rule_hdr->u.hdr.pipe_dest_idx = pipe_idx;
 	rule_hdr->u.hdr.system = !ipa_ctx->hdr_tbl_lcl;
 	if (entry->hdr) {
-		rule_hdr->u.hdr.hdr_offset =
-			entry->hdr->offset_entry->offset >> 2;
+		if (entry->hdr->cookie == IPA_HDR_COOKIE) {
+			rule_hdr->u.hdr.hdr_offset =
+				entry->hdr->offset_entry->offset >> 2;
+		} else {
+			IPAERR("Entry hdr deleted by user = %d cookie = %u\n",
+				entry->hdr->user_deleted, entry->hdr->cookie);
+			WARN_ON(1);
+			rule_hdr->u.hdr.hdr_offset = 0;
+		}
 	} else {
 		rule_hdr->u.hdr.hdr_offset = 0;
 	}
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h
index 75cc897..fb4986d 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h
@@ -26,6 +26,9 @@
 #define IPA_NTN_TX_DIR 1
 #define IPA_NTN_RX_DIR 2
 
+#define IPA_WDI3_TX_DIR 1
+#define IPA_WDI3_RX_DIR 2
+
 /**
  *  @brief   Enum value determined based on the feature it
  *           corresponds to
@@ -45,16 +48,20 @@
  * enum ipa_hw_features - Values that represent the features supported in IPA HW
  * @IPA_HW_FEATURE_COMMON : Feature related to common operation of IPA HW
  * @IPA_HW_FEATURE_MHI : Feature related to MHI operation in IPA HW
+ * @IPA_HW_FEATURE_POWER_COLLAPSE: Feature related to IPA Power collapse
  * @IPA_HW_FEATURE_WDI : Feature related to WDI operation in IPA HW
  * @IPA_HW_FEATURE_NTN : Feature related to NTN operation in IPA HW
  * @IPA_HW_FEATURE_OFFLOAD : Feature related to NTN operation in IPA HW
+ * @IPA_HW_FEATURE_WDI3 : Feature related to WDI operation in IPA HW
 */
 enum ipa_hw_features {
 	IPA_HW_FEATURE_COMMON = 0x0,
 	IPA_HW_FEATURE_MHI    = 0x1,
+	IPA_HW_FEATURE_POWER_COLLAPSE = 0x2,
 	IPA_HW_FEATURE_WDI    = 0x3,
 	IPA_HW_FEATURE_NTN    = 0x4,
 	IPA_HW_FEATURE_OFFLOAD = 0x5,
+	IPA_HW_FEATURE_WDI3    = 0x6,
 	IPA_HW_FEATURE_MAX    = IPA_HW_NUM_FEATURES
 };
 
@@ -274,6 +281,33 @@
 
 } __packed;
 
+struct IpaHwWdi3SetUpCmdData_t {
+	u32  transfer_ring_base_pa;
+	u32  transfer_ring_base_pa_hi;
+
+	u32  transfer_ring_size;
+
+	u32  transfer_ring_doorbell_pa;
+	u32  transfer_ring_doorbell_pa_hi;
+
+	u32  event_ring_base_pa;
+	u32  event_ring_base_pa_hi;
+
+	u32  event_ring_size;
+
+	u32  event_ring_doorbell_pa;
+	u32  event_ring_doorbell_pa_hi;
+
+	u16  num_pkt_buffers;
+	u8   ipa_pipe_number;
+	u8   dir;
+
+	u16  pkt_offset;
+	u16  reserved0;
+
+	u32  desc_format_template[IPA_HW_WDI3_MAX_ER_DESC_SIZE];
+} __packed;
+
 /**
  * struct IpaHwNtnCommonChCmdData_t - Structure holding the
  * parameters for Ntn Tear down command data params
@@ -288,6 +322,13 @@
 	uint32_t raw32b;
 } __packed;
 
+union IpaHwWdi3CommonChCmdData_t {
+	struct IpaHwWdi3CommonChCmdParams_t {
+		u32  ipa_pipe_number :8;
+		u32  reserved        :24;
+	} __packed params;
+	u32 raw32b;
+} __packed;
 
 /**
  * struct IpaHwNTNErrorEventData_t - Structure holding the
@@ -405,13 +446,30 @@
  * the offload commands from CPU
  * @IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP : Command to set up
  *				Offload protocol's Tx/Rx Path
- * @IPA_CPU_2_HW_CMD_OFFLOAD_RX_SET_UP : Command to tear down
+ * @IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN : Command to tear down
+ *				Offload protocol's Tx/ Rx Path
+ * @IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE : Command to enable
+ *				Offload protocol's Tx/Rx Path
+ * @IPA_CPU_2_HW_CMD_OFFLOAD_DISABLE : Command to disable
+ *				Offload protocol's Tx/ Rx Path
+ * @IPA_CPU_2_HW_CMD_OFFLOAD_SUSPEND : Command to suspend
+ *				Offload protocol's Tx/Rx Path
+ * @IPA_CPU_2_HW_CMD_OFFLOAD_RESUME : Command to resume
  *				Offload protocol's Tx/ Rx Path
  */
 enum ipa_cpu_2_hw_offload_commands {
 	IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP  =
 		FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 1),
-	IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN,
+	IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN =
+		FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 2),
+	IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE  =
+		FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 3),
+	IPA_CPU_2_HW_CMD_OFFLOAD_DISABLE =
+		FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 4),
+	IPA_CPU_2_HW_CMD_OFFLOAD_SUSPEND  =
+		FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 5),
+	IPA_CPU_2_HW_CMD_OFFLOAD_RESUME =
+		FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 6),
 };
 
 
@@ -519,6 +577,7 @@
  */
 union IpaHwSetUpCmd {
 	struct IpaHwNtnSetUpCmdData_t NtnSetupCh_params;
+	struct IpaHwWdi3SetUpCmdData_t Wdi3SetupCh_params;
 } __packed;
 
 /**
@@ -539,6 +598,7 @@
  */
 union IpaHwCommonChCmd {
 	union IpaHwNtnCommonChCmdData_t NtnCommonCh_params;
+	union IpaHwWdi3CommonChCmdData_t Wdi3CommonCh_params;
 } __packed;
 
 struct IpaHwOffloadCommonChCmdData_t {
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index 8712806..6783d20 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -5207,6 +5207,10 @@
 	api_ctrl->ipa_get_pdev = ipa2_get_pdev;
 	api_ctrl->ipa_ntn_uc_reg_rdyCB = ipa2_ntn_uc_reg_rdyCB;
 	api_ctrl->ipa_ntn_uc_dereg_rdyCB = ipa2_ntn_uc_dereg_rdyCB;
+	api_ctrl->ipa_conn_wdi3_pipes = ipa2_conn_wdi3_pipes;
+	api_ctrl->ipa_disconn_wdi3_pipes = ipa2_disconn_wdi3_pipes;
+	api_ctrl->ipa_enable_wdi3_pipes = ipa2_enable_wdi3_pipes;
+	api_ctrl->ipa_disable_wdi3_pipes = ipa2_disable_wdi3_pipes;
 
 	return 0;
 }
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c b/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c
new file mode 100644
index 0000000..fe527ffa
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c
@@ -0,0 +1,406 @@
+/* Copyright (c) 2017, 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 "ipa_i.h"
+#include "ipa_uc_offload_i.h"
+#include <linux/ipa_wdi3.h>
+
+#define IPA_HW_WDI3_RX_MBOX_START_INDEX 48
+#define IPA_HW_WDI3_TX_MBOX_START_INDEX 50
+
+static int ipa_send_wdi3_setup_pipe_cmd(
+	struct ipa_wdi3_setup_info *info, u8 dir)
+{
+	int ipa_ep_idx;
+	int result = 0;
+	struct ipa_mem_buffer cmd;
+	struct IpaHwWdi3SetUpCmdData_t *wdi3_params;
+	struct IpaHwOffloadSetUpCmdData_t *cmd_data;
+
+	if (info == NULL) {
+		IPAERR("invalid input\n");
+		return -EINVAL;
+	}
+
+	ipa_ep_idx = ipa_get_ep_mapping(info->client);
+	IPAERR("ep number: %d\n", ipa_ep_idx);
+	if (ipa_ep_idx == -1) {
+		IPAERR("fail to get ep idx.\n");
+		return -EFAULT;
+	}
+
+	IPAERR("client=%d ep=%d\n", info->client, ipa_ep_idx);
+	IPAERR("ring_base_pa = 0x%pad\n", &info->transfer_ring_base_pa);
+	IPAERR("ring_size = %hu\n", info->transfer_ring_size);
+	IPAERR("ring_db_pa = 0x%pad\n", &info->transfer_ring_doorbell_pa);
+	IPAERR("evt_ring_base_pa = 0x%pad\n", &info->event_ring_base_pa);
+	IPAERR("evt_ring_size = %hu\n", info->event_ring_size);
+	IPAERR("evt_ring_db_pa = 0x%pad\n", &info->event_ring_doorbell_pa);
+	IPAERR("num_pkt_buffers = %hu\n", info->num_pkt_buffers);
+	IPAERR("pkt_offset = %d.\n", info->pkt_offset);
+
+	cmd.size = sizeof(*cmd_data);
+	cmd.base = dma_alloc_coherent(ipa_ctx->uc_pdev, cmd.size,
+			&cmd.phys_base, GFP_KERNEL);
+	if (cmd.base == NULL) {
+		IPAERR("fail to get DMA memory.\n");
+		return -ENOMEM;
+	}
+	IPAERR("suceeded in allocating memory.\n");
+
+	cmd_data = (struct IpaHwOffloadSetUpCmdData_t *)cmd.base;
+	cmd_data->protocol = IPA_HW_FEATURE_WDI3;
+
+	wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
+	wdi3_params->transfer_ring_base_pa = (u32)info->transfer_ring_base_pa;
+	wdi3_params->transfer_ring_base_pa_hi =
+		(u32)((u64)info->transfer_ring_base_pa >> 32);
+	wdi3_params->transfer_ring_size = info->transfer_ring_size;
+	wdi3_params->transfer_ring_doorbell_pa =
+		(u32)info->transfer_ring_doorbell_pa;
+	wdi3_params->transfer_ring_doorbell_pa_hi =
+		(u32)((u64)info->transfer_ring_doorbell_pa >> 32);
+	wdi3_params->event_ring_base_pa = (u32)info->event_ring_base_pa;
+	wdi3_params->event_ring_base_pa_hi =
+		(u32)((u64)info->event_ring_base_pa >> 32);
+	wdi3_params->event_ring_size = info->event_ring_size;
+	wdi3_params->event_ring_doorbell_pa =
+		(u32)info->event_ring_doorbell_pa;
+	wdi3_params->event_ring_doorbell_pa_hi =
+		(u32)((u64)info->event_ring_doorbell_pa >> 32);
+	wdi3_params->num_pkt_buffers = info->num_pkt_buffers;
+	wdi3_params->ipa_pipe_number = ipa_ep_idx;
+	wdi3_params->dir = dir;
+	wdi3_params->pkt_offset = info->pkt_offset;
+	memcpy(wdi3_params->desc_format_template, info->desc_format_template,
+		sizeof(wdi3_params->desc_format_template));
+	IPAERR("suceeded in populating the command memory.\n");
+
+	result = ipa_uc_send_cmd((u32)(cmd.phys_base),
+				IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP,
+				IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS,
+				false, 10*HZ);
+	if (result) {
+		IPAERR("uc setup channel cmd failed: %d\n", result);
+		result = -EFAULT;
+	}
+
+	dma_free_coherent(ipa_ctx->uc_pdev, cmd.size, cmd.base, cmd.phys_base);
+	IPAERR("suceeded in freeing memory.\n");
+	return result;
+}
+
+int ipa2_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
+	struct ipa_wdi3_conn_out_params *out)
+{
+	struct ipa_ep_context *ep_rx;
+	struct ipa_ep_context *ep_tx;
+	int ipa_ep_idx_rx;
+	int ipa_ep_idx_tx;
+	int result = 0;
+
+	if (in == NULL || out == NULL) {
+		IPAERR("invalid input\n");
+		return -EINVAL;
+	}
+
+	ipa_ep_idx_rx = ipa_get_ep_mapping(in->rx.client);
+	ipa_ep_idx_tx = ipa_get_ep_mapping(in->tx.client);
+	if (ipa_ep_idx_rx == -1 || ipa_ep_idx_tx == -1) {
+		IPAERR("fail to alloc EP.\n");
+		return -EFAULT;
+	}
+
+	ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx];
+	ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx];
+
+	if (ep_rx->valid || ep_tx->valid) {
+		IPAERR("EP already allocated.\n");
+		return -EFAULT;
+	}
+
+	memset(ep_rx, 0, offsetof(struct ipa_ep_context, sys));
+	memset(ep_tx, 0, offsetof(struct ipa_ep_context, sys));
+
+	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+
+	/* setup rx ep cfg */
+	ep_rx->valid = 1;
+	ep_rx->client = in->rx.client;
+	result = ipa_disable_data_path(ipa_ep_idx_rx);
+	if (result) {
+		IPAERR("disable data path failed res=%d clnt=%d.\n", result,
+			ipa_ep_idx_rx);
+		IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+		return -EFAULT;
+	}
+	ep_rx->client_notify = in->notify;
+	ep_rx->priv = in->priv;
+
+	memcpy(&ep_rx->cfg, &in->rx.ipa_ep_cfg, sizeof(ep_rx->cfg));
+
+	if (ipa_cfg_ep(ipa_ep_idx_rx, &ep_rx->cfg)) {
+		IPAERR("fail to setup rx pipe cfg\n");
+		result = -EFAULT;
+		goto fail;
+	}
+	IPAERR("configured RX EP.\n");
+
+	if (ipa_send_wdi3_setup_pipe_cmd(&in->rx, IPA_WDI3_RX_DIR)) {
+		IPAERR("fail to send cmd to uc for rx pipe\n");
+		result = -EFAULT;
+		goto fail;
+	}
+	IPAERR("rx pipe was setup.\n");
+
+	ipa_install_dflt_flt_rules(ipa_ep_idx_rx);
+	out->rx_uc_db_pa = ipa_ctx->ipa_wrapper_base +
+		IPA_REG_BASE_OFST_v2_5 +
+		IPA_UC_MAILBOX_m_n_OFFS_v2_5(
+		IPA_HW_WDI3_RX_MBOX_START_INDEX/32,
+		IPA_HW_WDI3_RX_MBOX_START_INDEX % 32);
+	IPADBG("client %d (ep: %d) connected\n", in->rx.client,
+		ipa_ep_idx_rx);
+
+	/* setup dl ep cfg */
+	ep_tx->valid = 1;
+	ep_tx->client = in->tx.client;
+	result = ipa_disable_data_path(ipa_ep_idx_tx);
+	if (result) {
+		IPAERR("disable data path failed res=%d clnt=%d.\n", result,
+			ipa_ep_idx_tx);
+		result = -EFAULT;
+		goto fail;
+	}
+
+	memcpy(&ep_tx->cfg, &in->tx.ipa_ep_cfg, sizeof(ep_tx->cfg));
+
+	if (ipa_cfg_ep(ipa_ep_idx_tx, &ep_tx->cfg)) {
+		IPAERR("fail to setup tx pipe cfg\n");
+		result = -EFAULT;
+		goto fail;
+	}
+	IPAERR("configured TX EP in DMA mode.\n");
+
+	if (ipa_send_wdi3_setup_pipe_cmd(&in->tx, IPA_WDI3_TX_DIR)) {
+		IPAERR("fail to send cmd to uc for tx pipe\n");
+		result = -EFAULT;
+		goto fail;
+	}
+	IPAERR("tx pipe was setup.\n");
+
+	out->tx_uc_db_pa = ipa_ctx->ipa_wrapper_base +
+		IPA_REG_BASE_OFST_v2_5 +
+		IPA_UC_MAILBOX_m_n_OFFS_v2_5(
+		IPA_HW_WDI3_TX_MBOX_START_INDEX/32,
+		IPA_HW_WDI3_TX_MBOX_START_INDEX % 32);
+	out->tx_uc_db_va = ioremap(out->tx_uc_db_pa, 4);
+	IPADBG("client %d (ep: %d) connected\n", in->tx.client,
+		ipa_ep_idx_tx);
+
+fail:
+	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+	return result;
+}
+
+static int ipa_send_wdi3_common_ch_cmd(int ipa_ep_idx, int command)
+{
+	struct ipa_mem_buffer cmd;
+	struct IpaHwOffloadCommonChCmdData_t *cmd_data;
+	union IpaHwWdi3CommonChCmdData_t *wdi3;
+	int result = 0;
+
+	cmd.size = sizeof(*cmd_data);
+	cmd.base = dma_alloc_coherent(ipa_ctx->uc_pdev, cmd.size,
+		&cmd.phys_base, GFP_KERNEL);
+	if (cmd.base == NULL) {
+		IPAERR("fail to get DMA memory.\n");
+		return -ENOMEM;
+	}
+
+	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+	/* enable the TX pipe */
+	cmd_data = (struct IpaHwOffloadCommonChCmdData_t *)cmd.base;
+	cmd_data->protocol = IPA_HW_FEATURE_WDI3;
+
+	wdi3 = &cmd_data->CommonCh_params.Wdi3CommonCh_params;
+	wdi3->params.ipa_pipe_number = ipa_ep_idx;
+	IPAERR("cmd: %d ep_idx: %d\n", command, ipa_ep_idx);
+	result = ipa_uc_send_cmd((u32)(cmd.phys_base), command,
+				IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS,
+				false, 10*HZ);
+	if (result) {
+		result = -EFAULT;
+		goto fail;
+	}
+
+fail:
+	dma_free_coherent(ipa_ctx->uc_pdev, cmd.size, cmd.base, cmd.phys_base);
+	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+	return result;
+}
+
+int ipa2_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
+{
+	struct ipa_ep_context *ep_tx, *ep_rx;
+	int result = 0;
+
+	IPADBG("ep_tx = %d\n", ipa_ep_idx_tx);
+	IPADBG("ep_rx = %d\n", ipa_ep_idx_rx);
+
+	ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx];
+	ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx];
+
+	/* tear down tx pipe */
+	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
+		IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN)) {
+		IPAERR("fail to tear down tx pipe\n");
+		result = -EFAULT;
+		goto fail;
+	}
+	ipa_disable_data_path(ipa_ep_idx_tx);
+	memset(ep_tx, 0, sizeof(struct ipa_ep_context));
+	IPADBG("tx client (ep: %d) disconnected\n", ipa_ep_idx_tx);
+
+	/* tear down rx pipe */
+	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
+		IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN)) {
+		IPAERR("fail to tear down rx pipe\n");
+		result = -EFAULT;
+		goto fail;
+	}
+	ipa_disable_data_path(ipa_ep_idx_rx);
+	ipa_delete_dflt_flt_rules(ipa_ep_idx_rx);
+	memset(ep_rx, 0, sizeof(struct ipa_ep_context));
+	IPADBG("rx client (ep: %d) disconnected\n", ipa_ep_idx_rx);
+
+fail:
+	return result;
+}
+
+int ipa2_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
+{
+	struct ipa_ep_context *ep_tx, *ep_rx;
+	int result = 0;
+
+	IPAERR("ep_tx = %d\n", ipa_ep_idx_tx);
+	IPAERR("ep_rx = %d\n", ipa_ep_idx_rx);
+
+	ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx];
+	ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx];
+
+	/* enable tx pipe */
+	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
+		IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE)) {
+		IPAERR("fail to enable tx pipe\n");
+		BUG();
+		result = -EFAULT;
+		goto fail;
+	}
+
+	/* resume tx pipe */
+	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
+		IPA_CPU_2_HW_CMD_OFFLOAD_RESUME)) {
+		IPAERR("fail to resume tx pipe\n");
+		BUG();
+		result = -EFAULT;
+		goto fail;
+	}
+
+	/* enable rx pipe */
+	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
+		IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE)) {
+		IPAERR("fail to enable rx pipe\n");
+		BUG();
+		result = -EFAULT;
+		goto fail;
+	}
+
+	/* resume rx pipe */
+	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
+		IPA_CPU_2_HW_CMD_OFFLOAD_RESUME)) {
+		IPAERR("fail to resume rx pipe\n");
+		BUG();
+		result = -EFAULT;
+		goto fail;
+	}
+
+	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+
+	/* enable data path */
+	result = ipa_enable_data_path(ipa_ep_idx_rx);
+	if (result) {
+		IPAERR("enable data path failed res=%d clnt=%d.\n", result,
+			ipa_ep_idx_rx);
+		IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+		return -EFAULT;
+	}
+
+	result = ipa_enable_data_path(ipa_ep_idx_tx);
+	if (result) {
+		IPAERR("enable data path failed res=%d clnt=%d.\n", result,
+			ipa_ep_idx_tx);
+		IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+		return -EFAULT;
+	}
+
+	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+
+fail:
+	return result;
+}
+
+int ipa2_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
+{
+	struct ipa_ep_context *ep_tx, *ep_rx;
+	int result = 0;
+
+	IPADBG("ep_tx = %d\n", ipa_ep_idx_tx);
+	IPADBG("ep_rx = %d\n", ipa_ep_idx_rx);
+
+	ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx];
+	ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx];
+
+	/* suspend tx pipe */
+	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
+		IPA_CPU_2_HW_CMD_OFFLOAD_SUSPEND)) {
+		IPAERR("fail to suspend tx pipe\n");
+		result = -EFAULT;
+		goto fail;
+	}
+
+	/* disable tx pipe */
+	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
+		IPA_CPU_2_HW_CMD_OFFLOAD_DISABLE)) {
+		IPAERR("fail to disable tx pipe\n");
+		result = -EFAULT;
+		goto fail;
+	}
+
+	/* suspend rx pipe */
+	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
+		IPA_CPU_2_HW_CMD_OFFLOAD_SUSPEND)) {
+		IPAERR("fail to suspend rx pipe\n");
+		result = -EFAULT;
+		goto fail;
+	}
+
+	/* disable rx pipe */
+	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
+		IPA_CPU_2_HW_CMD_OFFLOAD_DISABLE)) {
+		IPAERR("fail to disable rx pipe\n");
+		result = -EFAULT;
+		goto fail;
+	}
+
+fail:
+	return result;
+}
diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
index 46841e1..77f1d87 100644
--- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
@@ -398,12 +398,15 @@
 {
 	int i, j;
 
+	/* prevent multi-threads accessing num_q6_rule */
+	mutex_lock(&add_mux_channel_lock);
 	if (rule_req->filter_spec_list_valid == true) {
 		num_q6_rule = rule_req->filter_spec_list_len;
 		IPAWANDBG("Received (%d) install_flt_req\n", num_q6_rule);
 	} else {
 		num_q6_rule = 0;
 		IPAWANERR("got no UL rules from modem\n");
+		mutex_unlock(&add_mux_channel_lock);
 		return -EINVAL;
 	}
 
@@ -597,9 +600,11 @@
 	num_q6_rule = 0;
 	memset(ipa_qmi_ctx->q6_ul_filter_rule, 0,
 		sizeof(ipa_qmi_ctx->q6_ul_filter_rule));
+	mutex_unlock(&add_mux_channel_lock);
 	return -EINVAL;
 
 success:
+	mutex_unlock(&add_mux_channel_lock);
 	return 0;
 }
 
@@ -1504,9 +1509,12 @@
 				/* already got Q6 UL filter rules*/
 				if (ipa_qmi_ctx &&
 					ipa_qmi_ctx->modem_cfg_emb_pipe_flt
-					== false)
+					== false) {
+					/* protect num_q6_rule */
+					mutex_lock(&add_mux_channel_lock);
 					rc = wwan_add_ul_flt_rule_to_ipa();
-				else
+					mutex_unlock(&add_mux_channel_lock);
+				} else
 					rc = 0;
 				egress_set = true;
 				if (rc)
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 6e07867..0f3f2e5 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -2446,7 +2446,6 @@
 	struct ipahal_imm_cmd_register_write reg_write;
 	struct ipahal_imm_cmd_pyld *cmd_pyld;
 	int retval;
-	struct ipahal_reg_valmask valmask;
 
 	desc = kcalloc(ipa3_ctx->ipa_num_pipes, sizeof(struct ipa3_desc),
 			GFP_KERNEL);
@@ -2461,40 +2460,10 @@
 		if (ep_idx == -1)
 			continue;
 
-		if (ipa3_ctx->ep[ep_idx].valid &&
-			ipa3_ctx->ep[ep_idx].skip_ep_cfg) {
-			BUG_ON(num_descs >= ipa3_ctx->ipa_num_pipes);
-
-			reg_write.skip_pipeline_clear = false;
-			reg_write.pipeline_clear_options =
-				IPAHAL_HPS_CLEAR;
-			reg_write.offset =
-				ipahal_get_reg_n_ofst(IPA_ENDP_STATUS_n,
-					ep_idx);
-			ipahal_get_status_ep_valmask(
-				ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS),
-				&valmask);
-			reg_write.value = valmask.val;
-			reg_write.value_mask = valmask.mask;
-			cmd_pyld = ipahal_construct_imm_cmd(
-				IPA_IMM_CMD_REGISTER_WRITE, &reg_write, false);
-			if (!cmd_pyld) {
-				IPAERR("fail construct register_write cmd\n");
-				BUG();
-			}
-
-			desc[num_descs].opcode = ipahal_imm_cmd_get_opcode(
-				IPA_IMM_CMD_REGISTER_WRITE);
-			desc[num_descs].type = IPA_IMM_CMD_DESC;
-			desc[num_descs].callback = ipa3_destroy_imm;
-			desc[num_descs].user1 = cmd_pyld;
-			desc[num_descs].pyld = cmd_pyld->data;
-			desc[num_descs].len = cmd_pyld->len;
-			num_descs++;
-		}
-
-		/* disable statuses for modem producers */
-		if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
+		/* disable statuses for all modem controlled prod pipes */
+		if (IPA_CLIENT_IS_Q6_PROD(client_idx) ||
+			(ipa3_ctx->ep[ep_idx].valid &&
+			ipa3_ctx->ep[ep_idx].skip_ep_cfg)) {
 			ipa_assert_on(num_descs >= ipa3_ctx->ipa_num_pipes);
 
 			reg_write.skip_pipeline_clear = false;
@@ -4537,12 +4506,12 @@
 	ipa3_post_init(&ipa3_res, ipa3_ctx->dev);
 }
 
-static int ipa3_trigger_fw_loading_mdms(void)
+static int ipa3_manual_load_ipa_fws(void)
 {
 	int result;
 	const struct firmware *fw;
 
-	IPADBG("FW loading process initiated\n");
+	IPADBG("Manual FW loading process initiated\n");
 
 	result = request_firmware(&fw, IPA_FWS_PATH, ipa3_ctx->dev);
 	if (result < 0) {
@@ -4558,7 +4527,7 @@
 
 	result = ipa3_load_fws(fw, ipa3_res.transport_mem_base);
 	if (result) {
-		IPAERR("IPA FWs loading has failed\n");
+		IPAERR("Manual IPA FWs loading has failed\n");
 		release_firmware(fw);
 		return result;
 	}
@@ -4574,15 +4543,15 @@
 
 	release_firmware(fw);
 
-	IPADBG("FW loading process is complete\n");
+	IPADBG("Manual FW loading process is complete\n");
 	return 0;
 }
 
-static int ipa3_trigger_fw_loading_msms(void)
+static int ipa3_pil_load_ipa_fws(void)
 {
 	void *subsystem_get_retval = NULL;
 
-	IPADBG("FW loading process initiated\n");
+	IPADBG("PIL FW loading process initiated\n");
 
 	subsystem_get_retval = subsystem_get(IPA_SUBSYSTEM_NAME);
 	if (IS_ERR_OR_NULL(subsystem_get_retval)) {
@@ -4590,7 +4559,7 @@
 		return -EINVAL;
 	}
 
-	IPADBG("FW loading process is complete\n");
+	IPADBG("PIL FW loading process is complete\n");
 	return 0;
 }
 
@@ -4620,34 +4589,39 @@
 	 * We will trigger the process only if we're in GSI mode, otherwise,
 	 * we just ignore the write.
 	 */
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+	if (ipa3_ctx->transport_prototype != IPA_TRANSPORT_TYPE_GSI)
+		return count;
 
-		if (ipa3_is_msm_device()) {
-			result = ipa3_trigger_fw_loading_msms();
+	/* Check MHI configuration on MDM devices */
+	if (!ipa3_is_msm_device()) {
+		if (!strcasecmp(dbg_buff, "MHI")) {
+			ipa3_ctx->ipa_config_is_mhi = true;
+			pr_info(
+			"IPA is loading with MHI configuration\n");
 		} else {
-			if (!strcasecmp(dbg_buff, "MHI")) {
-				ipa3_ctx->ipa_config_is_mhi = true;
-				pr_info(
-				"IPA is loading with MHI configuration\n");
-			} else {
-				pr_info(
-				"IPA is loading with non MHI configuration\n");
-			}
-			result = ipa3_trigger_fw_loading_mdms();
-		}
-		/* No IPAv3.x chipsets that don't support FW loading */
-
-		IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
-
-		if (result) {
-			IPAERR("FW loading process has failed\n");
-			return result;
-		} else {
-			queue_work(ipa3_ctx->transport_power_mgmt_wq,
-				&ipa3_post_init_work);
+			pr_info(
+			"IPA is loading with non MHI configuration\n");
 		}
 	}
+
+	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+
+	if (ipa3_is_msm_device() || (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5))
+		result = ipa3_pil_load_ipa_fws();
+	else
+		result = ipa3_manual_load_ipa_fws();
+
+	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+
+	if (result) {
+		IPAERR("IPA FW loading process has failed\n");
+		return result;
+	}
+
+	queue_work(ipa3_ctx->transport_power_mgmt_wq,
+		&ipa3_post_init_work);
+	pr_info("IPA FW loaded successfully\n");
+
 	return count;
 }
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index 0efcf2f..503e1c9 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -358,7 +358,7 @@
 			link) {
 		nbytes = scnprintf(
 			dbg_buff,
-			IPA_MAX_MSG_LEN,
+			IPA_MAX_MSG_LEN - 1,
 			"name:%s len=%d ref=%d partial=%d type=%s ",
 			entry->name,
 			entry->hdr_len,
@@ -369,23 +369,23 @@
 		if (entry->is_hdr_proc_ctx) {
 			nbytes += scnprintf(
 				dbg_buff + nbytes,
-				IPA_MAX_MSG_LEN - nbytes,
+				IPA_MAX_MSG_LEN - 1 - nbytes,
 				"phys_base=0x%pa ",
 				&entry->phys_base);
 		} else {
 			nbytes += scnprintf(
 				dbg_buff + nbytes,
-				IPA_MAX_MSG_LEN - nbytes,
+				IPA_MAX_MSG_LEN - 1 - nbytes,
 				"ofst=%u ",
 				entry->offset_entry->offset >> 2);
 		}
 		for (i = 0; i < entry->hdr_len; i++) {
 			scnprintf(dbg_buff + nbytes + i * 2,
-				  IPA_MAX_MSG_LEN - nbytes - i * 2,
+				  IPA_MAX_MSG_LEN - 1 - nbytes - i * 2,
 				  "%02x", entry->hdr[i]);
 		}
 		scnprintf(dbg_buff + nbytes + entry->hdr_len * 2,
-			  IPA_MAX_MSG_LEN - nbytes - entry->hdr_len * 2,
+			  IPA_MAX_MSG_LEN - 1 - nbytes - entry->hdr_len * 2,
 			  "\n");
 		pr_err("%s", dbg_buff);
 	}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
index 726d225..27a379b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
@@ -83,13 +83,21 @@
 	if (entry->proc_ctx || (entry->hdr && entry->hdr->is_hdr_proc_ctx)) {
 		struct ipa3_hdr_proc_ctx_entry *proc_ctx;
 		proc_ctx = (entry->proc_ctx) ? : entry->hdr->proc_ctx;
-		rule_hdr->u.hdr.system = !ipa3_ctx->hdr_proc_ctx_tbl_lcl;
-		BUG_ON(proc_ctx->offset_entry->offset & 31);
-		rule_hdr->u.hdr.proc_ctx = 1;
-		rule_hdr->u.hdr.hdr_offset =
-			(proc_ctx->offset_entry->offset +
-			ipa3_ctx->hdr_proc_ctx_tbl.start_offset) >> 5;
-	} else if (entry->hdr) {
+		if ((proc_ctx == NULL) ||
+			(proc_ctx->cookie != IPA_PROC_HDR_COOKIE)) {
+			rule_hdr->u.hdr.proc_ctx = 0;
+			rule_hdr->u.hdr.hdr_offset = 0;
+		} else {
+			rule_hdr->u.hdr.system =
+				!ipa3_ctx->hdr_proc_ctx_tbl_lcl;
+			BUG_ON(proc_ctx->offset_entry->offset & 31);
+			rule_hdr->u.hdr.proc_ctx = 1;
+			rule_hdr->u.hdr.hdr_offset =
+				(proc_ctx->offset_entry->offset +
+				ipa3_ctx->hdr_proc_ctx_tbl.start_offset) >> 5;
+		}
+	} else if ((entry->hdr != NULL) &&
+		(entry->hdr->cookie == IPA_HDR_COOKIE)) {
 		rule_hdr->u.hdr.system = !ipa3_ctx->hdr_tbl_lcl;
 		BUG_ON(entry->hdr->offset_entry->offset & 3);
 		rule_hdr->u.hdr.proc_ctx = 0;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
index 4075301..ca1c128 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
@@ -1605,20 +1605,3 @@
 
 	valmask->mask = valmask->val;
 }
-
-void ipahal_get_status_ep_valmask(int pipe_num,
-	struct ipahal_reg_valmask *valmask)
-{
-	if (!valmask) {
-		IPAHAL_ERR("Input error\n");
-		return;
-	}
-
-	valmask->val =
-		(pipe_num & IPA_ENDP_STATUS_n_STATUS_ENDP_BMSK) <<
-		IPA_ENDP_STATUS_n_STATUS_ENDP_SHFT;
-
-	valmask->mask =
-		IPA_ENDP_STATUS_n_STATUS_ENDP_BMSK <<
-		IPA_ENDP_STATUS_n_STATUS_ENDP_SHFT;
-}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
index ecb96e1..f37ddd9 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
@@ -464,8 +464,6 @@
 void ipahal_get_fltrt_hash_flush_valmask(
 	struct ipahal_reg_fltrt_hash_flush *flush,
 	struct ipahal_reg_valmask *valmask);
-void ipahal_get_status_ep_valmask(int pipe_num,
-	struct ipahal_reg_valmask *valmask);
 
 #endif /* _IPAHAL_REG_H_ */
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index fe73080..42e243f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -416,6 +416,8 @@
 {
 	int i, j;
 
+	/* prevent multi-threads accessing rmnet_ipa3_ctx->num_q6_rules */
+	mutex_lock(&rmnet_ipa3_ctx->add_mux_channel_lock);
 	if (rule_req->filter_spec_ex_list_valid == true) {
 		rmnet_ipa3_ctx->num_q6_rules =
 			rule_req->filter_spec_ex_list_len;
@@ -424,6 +426,8 @@
 	} else {
 		rmnet_ipa3_ctx->num_q6_rules = 0;
 		IPAWANERR("got no UL rules from modem\n");
+		mutex_unlock(&rmnet_ipa3_ctx->
+					add_mux_channel_lock);
 		return -EINVAL;
 	}
 
@@ -626,9 +630,13 @@
 	rmnet_ipa3_ctx->num_q6_rules = 0;
 	memset(ipa3_qmi_ctx->q6_ul_filter_rule, 0,
 		sizeof(ipa3_qmi_ctx->q6_ul_filter_rule));
+	mutex_unlock(&rmnet_ipa3_ctx->
+		add_mux_channel_lock);
 	return -EINVAL;
 
 success:
+	mutex_unlock(&rmnet_ipa3_ctx->
+		add_mux_channel_lock);
 	return 0;
 }
 
@@ -1324,8 +1332,13 @@
 
 	if (rmnet_ipa3_ctx->num_q6_rules != 0) {
 		/* already got Q6 UL filter rules*/
-		if (ipa3_qmi_ctx->modem_cfg_emb_pipe_flt == false)
+		if (ipa3_qmi_ctx->modem_cfg_emb_pipe_flt == false) {
+			/* prevent multi-threads accessing num_q6_rules */
+			mutex_lock(&rmnet_ipa3_ctx->add_mux_channel_lock);
 			rc = ipa3_wwan_add_ul_flt_rule_to_ipa();
+			mutex_unlock(&rmnet_ipa3_ctx->
+				add_mux_channel_lock);
+		}
 		if (rc)
 			IPAWANERR("install UL rules failed\n");
 		else
diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c
index b146409..2e95f6c 100644
--- a/drivers/platform/msm/mhi_dev/mhi.c
+++ b/drivers/platform/msm/mhi_dev/mhi.c
@@ -1139,7 +1139,7 @@
 
 	mutex_unlock(&mhi_ctx->mhi_lock);
 
-	if (mhi->config_iatu)
+	if (mhi->config_iatu || mhi->mhi_int)
 		enable_irq(mhi->mhi_irq);
 	else
 		ep_pcie_mask_irq_event(mhi->phandle,
@@ -1940,7 +1940,7 @@
 		return;
 	}
 
-	if (mhi_ctx->config_iatu)
+	if (mhi_ctx->config_iatu || mhi_ctx->mhi_int)
 		enable_irq(mhi_ctx->mhi_irq);
 
 	mhi_update_state_info(MHI_STATE_CONNECTED);
@@ -2072,7 +2072,10 @@
 		}
 	}
 
-	if (mhi->config_iatu) {
+	mhi_ctx->mhi_int = of_property_read_bool((&pdev->dev)->of_node,
+					"qcom,mhi-interrupt");
+
+	if (mhi->config_iatu || mhi_ctx->mhi_int) {
 		mhi->mhi_irq = platform_get_irq_byname(pdev, "mhi-device-inta");
 		if (mhi->mhi_irq < 0) {
 			pr_err("Invalid MHI device interrupt\n");
@@ -2249,7 +2252,7 @@
 	/* All set, notify the host */
 	mhi_dev_sm_set_ready();
 
-	if (mhi_ctx->config_iatu) {
+	if (mhi_ctx->config_iatu || mhi_ctx->mhi_int) {
 		rc = devm_request_irq(&pdev->dev, mhi_ctx->mhi_irq, mhi_dev_isr,
 			IRQF_TRIGGER_HIGH, "mhi_isr", mhi_ctx);
 		if (rc) {
diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h
index 535653d..4cc6747 100644
--- a/drivers/platform/msm/mhi_dev/mhi.h
+++ b/drivers/platform/msm/mhi_dev/mhi.h
@@ -557,6 +557,9 @@
 
 	/* MHI state info */
 	enum mhi_ctrl_info		ctrl_info;
+
+	/*Register for interrupt*/
+	bool				mhi_int;
 };
 
 enum mhi_msg_level {
diff --git a/drivers/platform/msm/mhi_dev/mhi_mmio.c b/drivers/platform/msm/mhi_dev/mhi_mmio.c
index 1031c84..42355c8 100644
--- a/drivers/platform/msm/mhi_dev/mhi_mmio.c
+++ b/drivers/platform/msm/mhi_dev/mhi_mmio.c
@@ -863,6 +863,9 @@
 	mhi_dev_mmio_clear_interrupts(dev);
 	mhi_dev_mmio_enable_ctrl_interrupt(dev);
 
+	/*Enable chdb interrupt*/
+	mhi_dev_mmio_enable_chdb_interrupts(dev);
+
 	/* Mask and enable control interrupt */
 	mb();
 
diff --git a/drivers/power/bcl_peripheral.c b/drivers/power/bcl_peripheral.c
index efde8a3..35dcdf4 100644
--- a/drivers/power/bcl_peripheral.c
+++ b/drivers/power/bcl_peripheral.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017, 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,7 +14,6 @@
 #define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__
 
 #include <linux/module.h>
-#include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/workqueue.h>
 #include <linux/kernel.h>
@@ -36,16 +35,11 @@
 #define BCL_IBAT_INT_NAME       "bcl-high-ibat-int"
 #define BCL_PARAM_MAX_ATTR      3
 
-#define BCL_INT_EN              0x15
 #define BCL_MONITOR_EN          0x46
 #define BCL_VBAT_VALUE          0x54
 #define BCL_IBAT_VALUE          0x55
-#define BCL_VBAT_CP_VALUE       0x56
-#define BCL_IBAT_CP_VALUE       0x57
 #define BCL_VBAT_MIN            0x58
 #define BCL_IBAT_MAX            0x59
-#define BCL_VBAT_MIN_CP         0x5A
-#define BCL_IBAT_MAX_CP         0x5B
 #define BCL_V_GAIN_BAT          0x60
 #define BCL_I_GAIN_RSENSE       0x61
 #define BCL_I_OFFSET_RSENSE     0x62
@@ -57,6 +51,21 @@
 #define BCL_VBAT_TRIP           0x68
 #define BCL_IBAT_TRIP           0x69
 
+#define BCL_8998_VBAT_VALUE     0x58
+#define BCL_8998_IBAT_VALUE     0x59
+#define BCL_8998_VBAT_MIN       0x5C
+#define BCL_8998_IBAT_MAX       0x5D
+#define BCL_8998_MAX_MIN_CLR    0x48
+#define BCL_8998_IBAT_MAX_CLR   3
+#define BCL_8998_VBAT_MIN_CLR   2
+#define BCL_8998_VBAT_ADC_LOW   0x72
+#define BCL_8998_IBAT_HIGH      0x78
+#define BCL_8998_BCL_CFG        0x6A
+
+#define BCL_8998_VBAT_SCALING   39000
+#define BCL_8998_IBAT_SCALING   80000
+#define BCL_CFG_VAL             0x81
+
 #define BCL_CONSTANT_NUM        32
 #define BCL_READ_RETRY_LIMIT    3
 #define VAL_CP_REG_BUF_LEN      3
@@ -92,6 +101,12 @@
 	BCL_PARAM_POLLING,
 };
 
+enum bcl_hw_type {
+	BCL_PMI8994,
+	BCL_PMI8998,
+	BCL_VERSION_MAX,
+};
+
 struct bcl_peripheral_data {
 	struct bcl_param_data   *param_data;
 	struct bcl_driver_ops   ops;
@@ -132,6 +147,7 @@
 static bool calibration_done;
 static DEFINE_MUTEX(bcl_access_mutex);
 static DEFINE_MUTEX(bcl_enable_mutex);
+static enum bcl_hw_type bcl_perph_version;
 
 static int bcl_read_multi_register(int16_t reg_offset, uint8_t *data, int len)
 {
@@ -196,14 +212,24 @@
 {
 	struct bcl_peripheral_data *perph_data = NULL;
 
-	if (!bcl_perph)
-		return;
-	perph_data = &bcl_perph->param[BCL_PARAM_VOLTAGE];
-	*val = (*val * 100
-		/ (100 + (perph_data->gain_factor_num * perph_data->gain)
-		* BCL_CONSTANT_NUM
-		/ perph_data->gain_factor_den))
-		/ perph_data->scaling_factor;
+	switch (bcl_perph_version) {
+	case BCL_PMI8994:
+		if (!bcl_perph)
+			return;
+		perph_data = &bcl_perph->param[BCL_PARAM_VOLTAGE];
+		*val = (*val * 100
+			/ (100 + (perph_data->gain_factor_num
+			* perph_data->gain) * BCL_CONSTANT_NUM
+			/ perph_data->gain_factor_den))
+			/ perph_data->scaling_factor;
+		break;
+	case BCL_PMI8998:
+		*val = *val / BCL_8998_VBAT_SCALING;
+		break;
+	default:
+		break;
+	}
+
 	return;
 }
 
@@ -211,13 +237,24 @@
 {
 	struct bcl_peripheral_data *perph_data = NULL;
 
-	if (!bcl_perph)
-		return;
-	perph_data = &bcl_perph->param[BCL_PARAM_VOLTAGE];
-	*val = ((*val + 2) * perph_data->scaling_factor)
-		* (100 + (perph_data->gain_factor_num * perph_data->gain)
-		* BCL_CONSTANT_NUM  / perph_data->gain_factor_den)
-		/ 100;
+	switch (bcl_perph_version) {
+	case BCL_PMI8994:
+		if (!bcl_perph)
+			return;
+		perph_data = &bcl_perph->param[BCL_PARAM_VOLTAGE];
+		*val = ((*val + 2) * perph_data->scaling_factor)
+			* (100 + (perph_data->gain_factor_num
+			* perph_data->gain)
+			* BCL_CONSTANT_NUM  / perph_data->gain_factor_den)
+			/ 100;
+		break;
+	case BCL_PMI8998:
+		*val = *val * BCL_8998_VBAT_SCALING;
+		break;
+	default:
+		break;
+	}
+
 	return;
 }
 
@@ -225,15 +262,26 @@
 {
 	struct bcl_peripheral_data *perph_data = NULL;
 
-	if (!bcl_perph)
-		return;
-	perph_data = &bcl_perph->param[BCL_PARAM_CURRENT];
-	*val = (*val * 100
-		/ (100 + (perph_data->gain_factor_num * perph_data->gain)
-		* BCL_CONSTANT_NUM / perph_data->gain_factor_den)
-		- (perph_data->offset_factor_num * perph_data->offset)
-		/ perph_data->offset_factor_den)
-		/  perph_data->scaling_factor;
+	switch (bcl_perph_version) {
+	case BCL_PMI8994:
+		if (!bcl_perph)
+			return;
+		perph_data = &bcl_perph->param[BCL_PARAM_CURRENT];
+		*val = (*val * 100
+			/ (100 + (perph_data->gain_factor_num
+			* perph_data->gain)
+			* BCL_CONSTANT_NUM / perph_data->gain_factor_den)
+			- (perph_data->offset_factor_num * perph_data->offset)
+			/ perph_data->offset_factor_den)
+			/  perph_data->scaling_factor;
+		break;
+	case BCL_PMI8998:
+		*val = *val / BCL_8998_IBAT_SCALING;
+		break;
+	default:
+		break;
+	}
+
 	return;
 }
 
@@ -241,14 +289,25 @@
 {
 	struct bcl_peripheral_data *perph_data = NULL;
 
-	if (!bcl_perph)
-		return;
-	perph_data = &bcl_perph->param[BCL_PARAM_CURRENT];
-	*val = (*val * perph_data->scaling_factor
-		+ (perph_data->offset_factor_num * perph_data->offset)
-		/ perph_data->offset_factor_den)
-		* (100 + (perph_data->gain_factor_num * perph_data->gain)
-		* BCL_CONSTANT_NUM / perph_data->gain_factor_den) / 100;
+	switch (bcl_perph_version) {
+	case BCL_PMI8994:
+		if (!bcl_perph)
+			return;
+		perph_data = &bcl_perph->param[BCL_PARAM_CURRENT];
+		*val = (*val * perph_data->scaling_factor
+			+ (perph_data->offset_factor_num * perph_data->offset)
+			/ perph_data->offset_factor_den)
+			* (100 + (perph_data->gain_factor_num
+			* perph_data->gain) * BCL_CONSTANT_NUM /
+			perph_data->gain_factor_den) / 100;
+		break;
+	case BCL_PMI8998:
+		*val = *val * BCL_8998_IBAT_SCALING;
+		break;
+	default:
+		break;
+	}
+
 	return;
 }
 
@@ -274,7 +333,8 @@
 	pr_debug("Setting Ibat high trip:%d. ADC_val:%d\n", ibat_ua,
 			thresh_value);
 	val = (int8_t)thresh_value;
-	ret = bcl_write_register(BCL_IBAT_TRIP, val);
+	ret = bcl_write_register((bcl_perph_version == BCL_PMI8994) ?
+		BCL_IBAT_TRIP : BCL_8998_IBAT_HIGH, val);
 	if (ret) {
 		pr_err("Error accessing BCL peripheral. err:%d\n", ret);
 		return ret;
@@ -315,7 +375,8 @@
 	pr_debug("Setting Vbat low trip:%d. ADC_val:%d\n", vbat_uv,
 			thresh_value);
 	val = (int8_t)thresh_value;
-	ret = bcl_write_register(BCL_VBAT_TRIP, val);
+	ret = bcl_write_register((bcl_perph_version == BCL_PMI8994)
+		? BCL_VBAT_TRIP : BCL_8998_VBAT_ADC_LOW, val);
 	if (ret) {
 		pr_err("Error accessing BCL peripheral. err:%d\n", ret);
 		return ret;
@@ -399,7 +460,8 @@
 	int8_t val = 0;
 
 	*thresh_value = (int)val;
-	ret = bcl_read_register(BCL_IBAT_TRIP, &val);
+	ret = bcl_read_register((bcl_perph_version == BCL_PMI8994) ?
+		BCL_IBAT_TRIP : BCL_8998_IBAT_HIGH, &val);
 	if (ret) {
 		pr_err("BCL register read error. err:%d\n", ret);
 		ret = 0;
@@ -427,7 +489,9 @@
 	int8_t val = 0;
 
 	*thresh_value = (int)val;
-	ret = bcl_read_register(BCL_VBAT_TRIP, &val);
+	ret = bcl_read_register((bcl_perph_version == BCL_PMI8994)
+			? BCL_VBAT_TRIP : BCL_8998_VBAT_ADC_LOW,
+			&val);
 	if (ret) {
 		pr_err("BCL register read error. err:%d\n", ret);
 		ret = 0;
@@ -452,7 +516,11 @@
 {
 	int ret  = 0;
 
-	ret = bcl_write_register(BCL_VBAT_MIN_CLR, BIT(7));
+	if (bcl_perph_version == BCL_PMI8994)
+		ret = bcl_write_register(BCL_VBAT_MIN_CLR, BIT(7));
+	else
+		ret = bcl_write_register(BCL_8998_MAX_MIN_CLR,
+			BIT(BCL_8998_VBAT_MIN_CLR));
 	if (ret)
 		pr_err("Error in clearing vbat min reg. err:%d", ret);
 
@@ -463,7 +531,11 @@
 {
 	int ret  = 0;
 
-	ret = bcl_write_register(BCL_IBAT_MAX_CLR, BIT(7));
+	if (bcl_perph_version == BCL_PMI8994)
+		ret = bcl_write_register(BCL_IBAT_MAX_CLR, BIT(7));
+	else
+		ret = bcl_write_register(BCL_8998_MAX_MIN_CLR,
+			BIT(BCL_8998_IBAT_MAX_CLR));
 	if (ret)
 		pr_err("Error in clearing ibat max reg. err:%d", ret);
 
@@ -477,7 +549,9 @@
 
 	*adc_value = (int)val[VAL_REG_BUF_OFFSET];
 	do {
-		ret = bcl_read_multi_register(BCL_IBAT_MAX, val,
+		ret = bcl_read_multi_register(
+			(bcl_perph_version == BCL_PMI8994) ? BCL_IBAT_MAX
+			: BCL_8998_IBAT_MAX, val,
 			VAL_CP_REG_BUF_LEN);
 		if (ret) {
 			pr_err("BCL register read error. err:%d\n", ret);
@@ -506,7 +580,9 @@
 
 	*adc_value = (int)val[VAL_REG_BUF_OFFSET];
 	do {
-		ret = bcl_read_multi_register(BCL_VBAT_MIN, val,
+		ret = bcl_read_multi_register(
+			(bcl_perph_version == BCL_PMI8994) ? BCL_VBAT_MIN
+			: BCL_8998_VBAT_MIN, val,
 			VAL_CP_REG_BUF_LEN);
 		if (ret) {
 			pr_err("BCL register read error. err:%d\n", ret);
@@ -535,7 +611,9 @@
 
 	*adc_value = (int)val[VAL_REG_BUF_OFFSET];
 	do {
-		ret = bcl_read_multi_register(BCL_IBAT_VALUE, val,
+		ret = bcl_read_multi_register(
+			(bcl_perph_version == BCL_PMI8994) ? BCL_IBAT_VALUE
+			: BCL_8998_IBAT_VALUE, val,
 			VAL_CP_REG_BUF_LEN);
 		if (ret) {
 			pr_err("BCL register read error. err:%d\n", ret);
@@ -564,7 +642,9 @@
 
 	*adc_value = (int)val[VAL_REG_BUF_OFFSET];
 	do {
-		ret = bcl_read_multi_register(BCL_VBAT_VALUE, val,
+		ret = bcl_read_multi_register(
+			(bcl_perph_version == BCL_PMI8994) ? BCL_VBAT_VALUE :
+			BCL_8998_VBAT_VALUE, val,
 			VAL_CP_REG_BUF_LEN);
 		if (ret) {
 			pr_err("BCL register read error. err:%d\n", ret);
@@ -824,40 +904,43 @@
 	}
 	bcl_perph->param[BCL_PARAM_CURRENT].irq_num = irq_num;
 
-	/* Get VADC and IADC scaling factor */
-	key = "qcom,vbat-scaling-factor";
-	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
-		bcl_perph->param[BCL_PARAM_VOLTAGE].scaling_factor);
-	key = "qcom,vbat-gain-numerator";
-	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
-		bcl_perph->param[BCL_PARAM_VOLTAGE].gain_factor_num);
-	key = "qcom,vbat-gain-denominator";
-	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
-		bcl_perph->param[BCL_PARAM_VOLTAGE].gain_factor_den);
-	key = "qcom,ibat-scaling-factor";
-	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
-		bcl_perph->param[BCL_PARAM_CURRENT].scaling_factor);
-	key = "qcom,ibat-offset-numerator";
-	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
-		bcl_perph->param[BCL_PARAM_CURRENT].offset_factor_num);
-	key = "qcom,ibat-offset-denominator";
-	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
-		bcl_perph->param[BCL_PARAM_CURRENT].offset_factor_den);
-	key = "qcom,ibat-gain-numerator";
-	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
-		bcl_perph->param[BCL_PARAM_CURRENT].gain_factor_num);
-	key = "qcom,ibat-gain-denominator";
-	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
-		bcl_perph->param[BCL_PARAM_CURRENT].gain_factor_den);
+	if (bcl_perph_version == BCL_PMI8994) {
+		/* Get VADC and IADC scaling factor */
+		key = "qcom,vbat-scaling-factor";
+		READ_CONV_FACTOR(dev_node, key, temp_val, ret,
+			bcl_perph->param[BCL_PARAM_VOLTAGE].scaling_factor);
+		key = "qcom,vbat-gain-numerator";
+		READ_CONV_FACTOR(dev_node, key, temp_val, ret,
+			bcl_perph->param[BCL_PARAM_VOLTAGE].gain_factor_num);
+		key = "qcom,vbat-gain-denominator";
+		READ_CONV_FACTOR(dev_node, key, temp_val, ret,
+			bcl_perph->param[BCL_PARAM_VOLTAGE].gain_factor_den);
+		key = "qcom,ibat-scaling-factor";
+		READ_CONV_FACTOR(dev_node, key, temp_val, ret,
+			bcl_perph->param[BCL_PARAM_CURRENT].scaling_factor);
+		key = "qcom,ibat-offset-numerator";
+		READ_CONV_FACTOR(dev_node, key, temp_val, ret,
+			bcl_perph->param[BCL_PARAM_CURRENT].offset_factor_num);
+		key = "qcom,ibat-offset-denominator";
+		READ_CONV_FACTOR(dev_node, key, temp_val, ret,
+			bcl_perph->param[BCL_PARAM_CURRENT].offset_factor_den);
+		key = "qcom,ibat-gain-numerator";
+		READ_CONV_FACTOR(dev_node, key, temp_val, ret,
+			bcl_perph->param[BCL_PARAM_CURRENT].gain_factor_num);
+		key = "qcom,ibat-gain-denominator";
+		READ_CONV_FACTOR(dev_node, key, temp_val, ret,
+			bcl_perph->param[BCL_PARAM_CURRENT].gain_factor_den);
+		key = "qcom,inhibit-derating-ua";
+		READ_OPTIONAL_PROP(dev_node, key, temp_val, ret,
+			bcl_perph->param[BCL_PARAM_CURRENT].
+			inhibit_derating_ua);
+	}
 	key = "qcom,vbat-polling-delay-ms";
 	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
 		bcl_perph->param[BCL_PARAM_VOLTAGE].polling_delay_ms);
 	key = "qcom,ibat-polling-delay-ms";
 	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
 		bcl_perph->param[BCL_PARAM_CURRENT].polling_delay_ms);
-	key = "qcom,inhibit-derating-ua";
-	READ_OPTIONAL_PROP(dev_node, key, temp_val, ret,
-		bcl_perph->param[BCL_PARAM_CURRENT].inhibit_derating_ua);
 
 bcl_dev_exit:
 	return ret;
@@ -1020,7 +1103,6 @@
 		pr_err("Memory alloc failed\n");
 		return -ENOMEM;
 	}
-	memset(bcl_perph, 0, sizeof(struct bcl_device));
 	bcl_perph->spmi = spmi;
 	bcl_perph->dev = &(spmi->dev);
 
@@ -1029,21 +1111,26 @@
 		pr_err("Device tree data fetch error. err:%d", ret);
 		goto bcl_probe_exit;
 	}
-	ret = bcl_calibrate();
-	if (ret) {
-		pr_debug("Could not read calibration values. err:%d", ret);
-		goto bcl_probe_exit;
-	}
-	bcl_psy.name = bcl_psy_name;
-	bcl_psy.type = POWER_SUPPLY_TYPE_BMS;
-	bcl_psy.get_property     = bcl_psy_get_property;
-	bcl_psy.set_property     = bcl_psy_set_property;
-	bcl_psy.num_properties   = 0;
-	bcl_psy.external_power_changed = power_supply_callback;
-	ret = power_supply_register(&spmi->dev, &bcl_psy);
-	if (ret < 0) {
-		pr_err("Unable to register bcl_psy rc = %d\n", ret);
-		return ret;
+	if (bcl_perph_version == BCL_PMI8994) {
+		ret = bcl_calibrate();
+		if (ret) {
+			pr_debug("Could not read calibration values. err:%d",
+					ret);
+			goto bcl_probe_exit;
+		}
+		bcl_psy.name = bcl_psy_name;
+		bcl_psy.type = POWER_SUPPLY_TYPE_BMS;
+		bcl_psy.get_property     = bcl_psy_get_property;
+		bcl_psy.set_property     = bcl_psy_set_property;
+		bcl_psy.num_properties   = 0;
+		bcl_psy.external_power_changed = power_supply_callback;
+		ret = power_supply_register(&spmi->dev, &bcl_psy);
+		if (ret < 0) {
+			pr_err("Unable to register bcl_psy rc = %d\n", ret);
+			return ret;
+		}
+	} else {
+		bcl_write_register(BCL_8998_BCL_CFG, BCL_CFG_VAL);
 	}
 
 	ret = bcl_update_data();
@@ -1123,7 +1210,11 @@
 }
 
 static struct of_device_id bcl_match[] = {
-	{	.compatible = "qcom,msm-bcl",
+	{	.compatible	= "qcom,msm-bcl",
+		.data		= (void *) BCL_PMI8994,
+	},
+	{	.compatible	= "qcom,msm-bcl-lmh",
+		.data		= (void *) BCL_PMI8998,
 	},
 	{},
 };
@@ -1140,7 +1231,22 @@
 
 static int __init bcl_perph_init(void)
 {
-	pr_info("BCL Initialized\n");
+	struct device_node *comp_node;
+
+	comp_node = of_find_matching_node(NULL, bcl_match);
+	bcl_perph_version = BCL_PMI8994;
+	if (comp_node) {
+		const struct of_device_id *match = of_match_node(bcl_match,
+							comp_node);
+		if (!match) {
+			pr_err("Couldnt find a match\n");
+			goto plt_register;
+		}
+		bcl_perph_version = (enum bcl_hw_type)match->data;
+		of_node_put(comp_node);
+	}
+
+plt_register:
 	return spmi_driver_register(&bcl_driver);
 }
 
diff --git a/drivers/soc/qcom/bgcom_interface.c b/drivers/soc/qcom/bgcom_interface.c
index 29dee03..bf18045 100644
--- a/drivers/soc/qcom/bgcom_interface.c
+++ b/drivers/soc/qcom/bgcom_interface.c
@@ -285,6 +285,7 @@
 	switch (opcode) {
 	case SUBSYS_BEFORE_SHUTDOWN:
 		bge.e_type = BG_BEFORE_POWER_DOWN;
+		bgcom_set_spi_state(BGCOM_SPI_BUSY);
 		send_uevent(&bge);
 		break;
 	case SUBSYS_AFTER_POWERUP:
diff --git a/drivers/soc/qcom/bgcom_spi.c b/drivers/soc/qcom/bgcom_spi.c
index 13658bf..7454384 100644
--- a/drivers/soc/qcom/bgcom_spi.c
+++ b/drivers/soc/qcom/bgcom_spi.c
@@ -40,6 +40,7 @@
 
 #define BG_SPI_MAX_WORDS (0x3FFFFFFD)
 #define BG_SPI_MAX_REGS (0x0A)
+#define SLEEP_IN_STATE_CHNG 2000
 
 enum bgcom_state {
 	/*BGCOM Staus ready*/
@@ -90,9 +91,19 @@
 
 int bgcom_set_spi_state(enum bgcom_spi_state state)
 {
+	struct bg_spi_priv *bg_spi = container_of(bg_com_drv,
+						struct bg_spi_priv, lhandle);
 	if (state < 0 || state > 1)
 		return -EINVAL;
+
+	if (state == spi_state)
+		return 0;
+
+	mutex_lock(&bg_spi->xfer_mutex);
 	spi_state = state;
+	if (spi_state == BGCOM_SPI_BUSY)
+		msleep(SLEEP_IN_STATE_CHNG);
+	mutex_unlock(&bg_spi->xfer_mutex);
 	return 0;
 }
 EXPORT_SYMBOL(bgcom_set_spi_state);
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index d17d2e8..f239a43 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -172,7 +172,11 @@
 	ret = do_elf_ramdump(ramdump_dev, ramdump_segs, count);
 	kfree(ramdump_segs);
 
-	if (!ret && desc->subsys_vmid > 0)
+	if (ret)
+		pil_err(desc, "%s: Ramdump collection failed for subsys %s rc:%d\n",
+				__func__, desc->name, ret);
+
+	if (desc->subsys_vmid > 0)
 		ret = pil_assign_mem_to_subsys(desc, priv->region_start,
 				(priv->region_end - priv->region_start));
 
diff --git a/drivers/soc/qcom/pil_bg_intf.h b/drivers/soc/qcom/pil_bg_intf.h
index cc9219b..ba25af8 100644
--- a/drivers/soc/qcom/pil_bg_intf.h
+++ b/drivers/soc/qcom/pil_bg_intf.h
@@ -22,6 +22,7 @@
 	BGPIL_RAMDUMP,
 	BGPIL_IMAGE_LOAD,
 	BGPIL_AUTH_MDT,
+	BGPIL_DLOAD_CONT,
 };
 
 /* tzapp bg request.*/
diff --git a/drivers/soc/qcom/subsys-pil-bg.c b/drivers/soc/qcom/subsys-pil-bg.c
index 8816c47..e09801b 100644
--- a/drivers/soc/qcom/subsys-pil-bg.c
+++ b/drivers/soc/qcom/subsys-pil-bg.c
@@ -36,6 +36,7 @@
 #define desc_to_data(d)	container_of(d, struct pil_bg_data, desc)
 #define subsys_to_data(d) container_of(d, struct pil_bg_data, subsys_desc)
 #define BG_RAMDUMP_SZ	0x00102000
+#define BG_CRASH_IN_TWM	2
 /**
  * struct pil_bg_data
  * @qseecom_handle: handle of TZ app
@@ -264,6 +265,7 @@
 		return ret;
 	}
 	enable_irq(bg_data->status_irq);
+	enable_irq(bg_data->errfatal_irq);
 	ret = wait_for_err_ready(bg_data);
 	if (ret) {
 		dev_err(bg_data->desc.dev,
@@ -375,6 +377,12 @@
 	bg_tz_req.size_fw = bg_data->size_fw;
 
 	ret = bgpil_tzapp_comm(bg_data, &bg_tz_req);
+	if (bg_data->cmd_status == BG_CRASH_IN_TWM) {
+		/* Do ramdump and resend boot cmd */
+		bg_data->subsys_desc.ramdump(true, &bg_data->subsys_desc);
+		bg_tz_req.tzapp_bg_cmd = BGPIL_DLOAD_CONT;
+		ret = bgpil_tzapp_comm(bg_data, &bg_tz_req);
+	}
 	if (ret || bg_data->cmd_status) {
 		dev_err(pil->dev,
 			"%s: BGPIL_IMAGE_LOAD qseecom call failed\n",
diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c
index 3c9d8ef..e9da395 100644
--- a/drivers/soc/qcom/wcd-dsp-glink.c
+++ b/drivers/soc/qcom/wcd-dsp-glink.c
@@ -540,7 +540,7 @@
 
 	mutex_lock(&wpriv->glink_mutex);
 	if (wpriv->ch) {
-		dev_err(wpriv->dev, "%s: glink ch memory is already allocated\n",
+		dev_err_ratelimited(wpriv->dev, "%s: glink ch memory is already allocated\n",
 			 __func__);
 		ret = -EINVAL;
 		goto done;
@@ -549,7 +549,7 @@
 	no_of_channels = pkt->no_of_channels;
 
 	if (no_of_channels > WDSP_MAX_NO_OF_CHANNELS) {
-		dev_err(wpriv->dev, "%s: no_of_channels: %d but max allowed are %d\n",
+		dev_err_ratelimited(wpriv->dev, "%s: no_of_channels: %d but max allowed are %d\n",
 			__func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS);
 		ret = -EINVAL;
 		goto done;
@@ -568,20 +568,20 @@
 
 		size += WDSP_CH_CFG_SIZE;
 		if (size > pkt_size) {
-			dev_err(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
+			dev_err_ratelimited(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
 				__func__, size, pkt_size);
 			ret = -EINVAL;
 			goto err_ch_mem;
 		}
 		if (ch_cfg->no_of_intents > WDSP_MAX_NO_OF_INTENTS) {
-			dev_err(wpriv->dev, "%s: Invalid no_of_intents = %d\n",
+			dev_err_ratelimited(wpriv->dev, "%s: Invalid no_of_intents = %d\n",
 				__func__, ch_cfg->no_of_intents);
 			ret = -EINVAL;
 			goto err_ch_mem;
 		}
 		size += (sizeof(u32) * ch_cfg->no_of_intents);
 		if (size > pkt_size) {
-			dev_err(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
+			dev_err_ratelimited(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
 				__func__, size, pkt_size);
 			ret = -EINVAL;
 			goto err_ch_mem;
@@ -716,7 +716,7 @@
 	}
 
 	if (count > WDSP_MAX_READ_SIZE) {
-		dev_info(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_READ_SIZE\n",
+		dev_info_ratelimited(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_READ_SIZE\n",
 			__func__, count);
 		count = WDSP_MAX_READ_SIZE;
 	}
@@ -748,7 +748,7 @@
 
 		if (ret1) {
 			mutex_unlock(&wpriv->rsp_mutex);
-			dev_err(wpriv->dev, "%s: copy_to_user failed %d\n",
+			dev_err_ratelimited(wpriv->dev, "%s: copy_to_user failed %d\n",
 				__func__, ret);
 			ret = -EFAULT;
 			goto done;
@@ -794,7 +794,7 @@
 
 	if ((count < WDSP_WRITE_PKT_SIZE) ||
 	    (count > WDSP_MAX_WRITE_SIZE)) {
-		dev_err(wpriv->dev, "%s: Invalid count = %zd\n",
+		dev_err_ratelimited(wpriv->dev, "%s: Invalid count = %zd\n",
 			__func__, count);
 		ret = -EINVAL;
 		goto done;
@@ -811,7 +811,7 @@
 
 	ret = copy_from_user(tx_buf->buf, buf, count);
 	if (ret) {
-		dev_err(wpriv->dev, "%s: copy_from_user failed %d\n",
+		dev_err_ratelimited(wpriv->dev, "%s: copy_from_user failed %d\n",
 			__func__, ret);
 		ret = -EFAULT;
 		goto free_buf;
@@ -822,7 +822,7 @@
 	case WDSP_REG_PKT:
 		if (count < (WDSP_WRITE_PKT_SIZE + WDSP_REG_PKT_SIZE +
 			     WDSP_CH_CFG_SIZE)) {
-			dev_err(wpriv->dev, "%s: Invalid reg pkt size = %zd\n",
+			dev_err_ratelimited(wpriv->dev, "%s: Invalid reg pkt size = %zd\n",
 				__func__, count);
 			ret = -EINVAL;
 			goto free_buf;
@@ -831,7 +831,7 @@
 					(struct wdsp_reg_pkt *)wpkt->payload,
 					count);
 		if (IS_ERR_VALUE(ret))
-			dev_err(wpriv->dev, "%s: glink register failed, ret = %d\n",
+			dev_err_ratelimited(wpriv->dev, "%s: glink register failed, ret = %d\n",
 				__func__, ret);
 		vfree(tx_buf);
 		break;
@@ -841,7 +841,7 @@
 							GLINK_LINK_STATE_UP),
 					 msecs_to_jiffies(TIMEOUT_MS));
 		if (!ret) {
-			dev_err(wpriv->dev, "%s: Link state wait timeout\n",
+			dev_err_ratelimited(wpriv->dev, "%s: Link state wait timeout\n",
 				__func__);
 			ret = -ETIMEDOUT;
 			goto free_buf;
@@ -851,7 +851,7 @@
 		break;
 	case WDSP_CMD_PKT:
 		if (count <= (WDSP_WRITE_PKT_SIZE + WDSP_CMD_PKT_SIZE)) {
-			dev_err(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n",
+			dev_err_ratelimited(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n",
 				__func__, count);
 			ret = -EINVAL;
 			goto free_buf;
@@ -859,7 +859,7 @@
 		mutex_lock(&wpriv->glink_mutex);
 		if (wpriv->glink_state.link_state == GLINK_LINK_STATE_DOWN) {
 			mutex_unlock(&wpriv->glink_mutex);
-			dev_err(wpriv->dev, "%s: Link state is Down\n",
+			dev_err_ratelimited(wpriv->dev, "%s: Link state is Down\n",
 				__func__);
 
 			ret = -ENETRESET;
@@ -871,7 +871,7 @@
 					sizeof(struct wdsp_cmd_pkt) +
 					cpkt->payload_size;
 		if (count < pkt_max_size) {
-			dev_err(wpriv->dev, "%s: Invalid cmd pkt count = %zd, pkt_size = %zd\n",
+			dev_err_ratelimited(wpriv->dev, "%s: Invalid cmd pkt count = %zd, pkt_size = %zd\n",
 				__func__, count, pkt_max_size);
 			ret = -EINVAL;
 			goto free_buf;
@@ -887,7 +887,7 @@
 			}
 		}
 		if (!tx_buf->ch) {
-			dev_err(wpriv->dev, "%s: Failed to get glink channel\n",
+			dev_err_ratelimited(wpriv->dev, "%s: Failed to get glink channel\n",
 				__func__);
 			ret = -EINVAL;
 			goto free_buf;
@@ -898,7 +898,7 @@
 							GLINK_CONNECTED),
 					 msecs_to_jiffies(TIMEOUT_MS));
 		if (!ret) {
-			dev_err(wpriv->dev, "%s: glink channel %s is not in connected state %d\n",
+			dev_err_ratelimited(wpriv->dev, "%s: glink channel %s is not in connected state %d\n",
 				__func__, tx_buf->ch->ch_cfg.name,
 				tx_buf->ch->channel_state);
 			ret = -ETIMEDOUT;
@@ -910,7 +910,8 @@
 		queue_work(wpriv->work_queue, &tx_buf->tx_work);
 		break;
 	default:
-		dev_err(wpriv->dev, "%s: Invalid packet type\n", __func__);
+		dev_err_ratelimited(wpriv->dev, "%s: Invalid packet type\n",
+				    __func__);
 		ret = -EINVAL;
 		vfree(tx_buf);
 		break;
@@ -956,6 +957,7 @@
 		goto err_wq;
 	}
 
+	wpriv->glink_state.link_state = GLINK_LINK_STATE_DOWN;
 	init_completion(&wpriv->rsp_complete);
 	init_waitqueue_head(&wpriv->link_state_wait);
 	mutex_init(&wpriv->rsp_mutex);
diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c
index 3a4e3a2..7f1e0a9 100644
--- a/drivers/soundwire/swr-wcd-ctrl.c
+++ b/drivers/soundwire/swr-wcd-ctrl.c
@@ -373,11 +373,17 @@
 		return -EINVAL;
 
 	if (enable) {
-		swrm->clk(swrm->handle, true);
-		swrm->state = SWR_MSTR_UP;
-	} else {
+		swrm->clk_ref_count++;
+		if (swrm->clk_ref_count == 1) {
+			swrm->clk(swrm->handle, true);
+			swrm->state = SWR_MSTR_UP;
+		}
+	} else if (--swrm->clk_ref_count == 0) {
 		swrm->clk(swrm->handle, false);
 		swrm->state = SWR_MSTR_DOWN;
+	} else if (swrm->clk_ref_count < 0) {
+		pr_err("%s: swrm clk count mismatch\n", __func__);
+		swrm->clk_ref_count = 0;
 	}
 	return 0;
 }
@@ -1136,7 +1142,10 @@
 	u8 devnum = 0;
 	int ret = IRQ_HANDLED;
 
-	pm_runtime_get_sync(&swrm->pdev->dev);
+	mutex_lock(&swrm->reslock);
+	swrm_clk_request(swrm, true);
+	mutex_unlock(&swrm->reslock);
+
 	intr_sts = swrm->read(swrm->handle, SWRM_INTERRUPT_STATUS);
 	intr_sts &= SWRM_INTERRUPT_STATUS_RMSK;
 	for (i = 0; i < SWRM_INTERRUPT_MAX; i++) {
@@ -1224,8 +1233,10 @@
 			break;
 		}
 	}
-	pm_runtime_mark_last_busy(&swrm->pdev->dev);
-	pm_runtime_put_autosuspend(&swrm->pdev->dev);
+
+	mutex_lock(&swrm->reslock);
+	swrm_clk_request(swrm, false);
+	mutex_unlock(&swrm->reslock);
 	return ret;
 }
 
@@ -1416,6 +1427,7 @@
 	swrm->wcmd_id = 0;
 	swrm->slave_status = 0;
 	swrm->num_rx_chs = 0;
+	swrm->clk_ref_count = 0;
 	swrm->state = SWR_MSTR_RESUME;
 	init_completion(&swrm->reset);
 	init_completion(&swrm->broadcast);
diff --git a/drivers/soundwire/swr-wcd-ctrl.h b/drivers/soundwire/swr-wcd-ctrl.h
index 8992318..57327cb 100644
--- a/drivers/soundwire/swr-wcd-ctrl.h
+++ b/drivers/soundwire/swr-wcd-ctrl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, 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
@@ -74,6 +74,7 @@
 	struct device *dev;
 	struct resource *supplies;
 	struct clk *mclk;
+	int clk_ref_count;
 	struct completion reset;
 	struct completion broadcast;
 	struct mutex mlock;
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index d7119db..01436b0 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015, 2017 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
@@ -47,7 +47,7 @@
 #define SPMI_MAPPING_BIT_IS_1_FLAG(X)	(((X) >> 8) & 0x1)
 #define SPMI_MAPPING_BIT_IS_1_RESULT(X)	(((X) >> 0) & 0xFF)
 
-#define SPMI_MAPPING_TABLE_LEN		255
+#define SPMI_MAPPING_TABLE_LEN		256
 #define SPMI_MAPPING_TABLE_TREE_DEPTH	16	/* Maximum of 16-bits */
 #define PPID_TO_CHAN_TABLE_SZ		BIT(12)	/* PPID is 12bit chan is 1byte*/
 
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index b356ad7..705906a 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -3250,6 +3250,7 @@
 err_dead_proc_or_thread:
 	return_error = BR_DEAD_REPLY;
 	return_error_line = __LINE__;
+	binder_dequeue_work(proc, tcomplete);
 err_translate_failed:
 err_bad_object_type:
 err_bad_offset:
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 7205245..7860ded 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -264,7 +264,7 @@
 	mutex_lock(&dev->buffer_lock);
 	ion_buffer_add(dev, buffer);
 	mutex_unlock(&dev->buffer_lock);
-	atomic_add(len, &heap->total_allocated);
+	atomic_long_add(len, &heap->total_allocated);
 	return buffer;
 
 err:
@@ -282,7 +282,7 @@
 		buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
 	buffer->heap->ops->unmap_dma(buffer->heap, buffer);
 
-	atomic_sub(buffer->size, &buffer->heap->total_allocated);
+	atomic_long_sub(buffer->size, &buffer->heap->total_allocated);
 	buffer->heap->ops->free(buffer);
 	if (buffer->pages)
 		vfree(buffer->pages);
@@ -321,7 +321,7 @@
 {
 	mutex_lock(&buffer->lock);
 	if (buffer->handle_count == 0)
-		atomic_add(buffer->size, &buffer->heap->total_handles);
+		atomic_long_add(buffer->size, &buffer->heap->total_handles);
 
 	buffer->handle_count++;
 	mutex_unlock(&buffer->lock);
@@ -347,7 +347,7 @@
 		task = current->group_leader;
 		get_task_comm(buffer->task_comm, task);
 		buffer->pid = task_pid_nr(task);
-		atomic_sub(buffer->size, &buffer->heap->total_handles);
+		atomic_long_sub(buffer->size, &buffer->heap->total_handles);
 	}
 	mutex_unlock(&buffer->lock);
 }
@@ -1906,10 +1906,10 @@
 					"Total orphaned size");
 	pr_info("---------------------------------\n");
 	plist_for_each_entry(heap, &dev->heaps, node) {
-		pr_info("%16.s 0x%16.x 0x%16.x\n",
-			heap->name, atomic_read(&heap->total_allocated),
-			atomic_read(&heap->total_allocated) -
-			atomic_read(&heap->total_handles));
+		pr_info("%16.s 0x%16.lx 0x%16.lx\n",
+			heap->name, atomic_long_read(&heap->total_allocated),
+			atomic_long_read(&heap->total_allocated) -
+			atomic_long_read(&heap->total_handles));
 		if (heap->debug_show)
 			heap->debug_show(heap, NULL, 0);
 
diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h
index c681c1a..1313f83 100644
--- a/drivers/staging/android/ion/ion_priv.h
+++ b/drivers/staging/android/ion/ion_priv.h
@@ -2,7 +2,7 @@
  * drivers/staging/android/ion/ion_priv.h
  *
  * Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017, 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
@@ -200,8 +200,8 @@
 	struct task_struct *task;
 
 	int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *);
-	atomic_t total_allocated;
-	atomic_t total_handles;
+	atomic_long_t total_allocated;
+	atomic_long_t total_handles;
 };
 
 /**
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 86c1e699..745ff53 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -1111,10 +1111,23 @@
 
 	switch (event->status) {
 	case DEPEVT_STATUS_CONTROL_DATA:
-		dwc3_trace(trace_dwc3_ep0, "Control Data");
 		dep->dbg_ep_events.control_data++;
 
 		/*
+		 * When we issue a STALL and RESTART of EP0 OUT, then
+		 * ep0_next_event is set as DWC3_EP0_COMPLETE and we wait for
+		 * the next setup packet. We will ignore a XferNotReady (DATA)
+		 * event until setup packet arrives, so as to avoid HW latency
+		 * issues.
+		 */
+		if (dwc->ep0_next_event == DWC3_EP0_COMPLETE) {
+			dwc3_trace(trace_dwc3_ep0, "Ignore Control Data");
+			return;
+		}
+
+		dwc3_trace(trace_dwc3_ep0, "Control Data");
+
+		/*
 		 * We already have a DATA transfer in the controller's cache,
 		 * if we receive a XferNotReady(DATA) we will ignore it, unless
 		 * it's for the wrong direction.
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 02d5cc9..2607129 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2253,6 +2253,12 @@
 		mReq->map     = 0;
 	}
 
+	if (mReq->zptr) {
+		dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
+		mReq->zptr = NULL;
+		mReq->zdma = 0;
+	}
+
 	if (mEp->multi_req) {
 		restore_original_req(mReq);
 		mEp->multi_req = false;
@@ -2314,6 +2320,12 @@
 		release_ep_request(mEp, mReq);
 	}
 
+	if (mEp->last_zptr) {
+		dma_pool_free(mEp->td_pool, mEp->last_zptr, mEp->last_zdma);
+		mEp->last_zptr = NULL;
+		mEp->last_zdma = 0;
+	}
+
 	return 0;
 }
 
@@ -2348,12 +2360,6 @@
 	_ep_nuke(&udc->ep0in);
 	spin_unlock_irqrestore(udc->lock, flags);
 
-	if (udc->ep0in.last_zptr) {
-		dma_pool_free(udc->ep0in.td_pool, udc->ep0in.last_zptr,
-				udc->ep0in.last_zdma);
-		udc->ep0in.last_zptr = NULL;
-	}
-
 	return 0;
 }
 
@@ -2982,12 +2988,6 @@
 
 	} while (mEp->dir != direction);
 
-	if (mEp->last_zptr) {
-		dma_pool_free(mEp->td_pool, mEp->last_zptr,
-				mEp->last_zdma);
-		mEp->last_zptr = NULL;
-	}
-
 	mEp->desc = NULL;
 	mEp->ep.desc = NULL;
 	mEp->ep.maxpacket = USHRT_MAX;
diff --git a/drivers/usb/gadget/function/f_gps.c b/drivers/usb/gadget/function/f_gps.c
index f25c79a..073915c 100644
--- a/drivers/usb/gadget/function/f_gps.c
+++ b/drivers/usb/gadget/function/f_gps.c
@@ -22,7 +22,7 @@
 
 #define GPS_NOTIFY_INTERVAL	5
 #define GPS_MAX_NOTIFY_SIZE	64
-
+#define GPS_RESP_Q_LENGTH	100
 
 #define ACM_CTRL_DTR	(1 << 0)
 
@@ -46,11 +46,14 @@
 	/* control info */
 	struct list_head		cpkt_resp_q;
 	atomic_t			notify_count;
+	atomic_t			resp_q_count;
 	unsigned long			cpkts_len;
 
 	/* remote wakeup info */
 	bool				is_suspended;
 	bool				is_rw_allowed;
+
+	struct delayed_work		wakeup_work;
 };
 
 static struct gps_ports {
@@ -146,6 +149,10 @@
 
 static void gps_ctrl_response_available(struct f_gps *dev);
 
+static void gps_queue_notify_request(struct f_gps *dev);
+
+static int gps_wakeup_host(struct f_gps *dev);
+
 /* ------- misc functions --------------------*/
 
 static inline struct f_gps *func_to_gps(struct usb_function *f)
@@ -245,9 +252,18 @@
 
 	gps_free_req(dev->notify, dev->notify_req);
 
+	cancel_delayed_work_sync(&dev->wakeup_work);
 	kfree(f->name);
 }
 
+static void gps_remote_wakeup_work(struct work_struct *data)
+{
+	struct f_gps *dev = container_of(data, struct f_gps, wakeup_work.work);
+
+	pr_debug("%s: wakeup host\n", __func__);
+	gps_wakeup_host(dev);
+}
+
 static void gps_purge_responses(struct f_gps *dev)
 {
 	unsigned long flags;
@@ -265,12 +281,16 @@
 		rmnet_free_ctrl_pkt(cpkt);
 	}
 	atomic_set(&dev->notify_count, 0);
+	atomic_set(&dev->resp_q_count, 0);
 	spin_unlock_irqrestore(&dev->lock, flags);
 }
 
+#define GPS_WAKEUP_HOST_DELAY msecs_to_jiffies(100)
+
 static void gps_suspend(struct usb_function *f)
 {
 	struct f_gps *dev = func_to_gps(f);
+	unsigned long flags;
 
 	pr_debug("%s: suspending gps function\n", __func__);
 	if (f->config->cdev->gadget->speed == USB_SPEED_SUPER)
@@ -278,13 +298,26 @@
 	else
 		dev->is_rw_allowed = f->config->cdev->gadget->remote_wakeup;
 
-	gps_purge_responses(dev);
 	dev->is_suspended = true;
+	spin_lock_irqsave(&dev->lock, flags);
+	/*
+	 * The notify count is set to zero and the correct count of
+	 * notifications for responses received (before suspend + during
+	 * suspend) will be handled during resume
+	 */
+	atomic_set(&dev->notify_count, 0);
+	if (dev->is_rw_allowed && (atomic_read(&dev->notify_count) > 0)) {
+		pr_debug("%s: queue not empty; wakeup host\n", __func__);
+		schedule_delayed_work(&dev->wakeup_work,
+					GPS_WAKEUP_HOST_DELAY);
+	}
+	spin_unlock_irqrestore(&dev->lock, flags);
 }
 
 static void gps_resume(struct usb_function *f)
 {
 	struct f_gps *dev = func_to_gps(f);
+	struct list_head *cpkt;
 
 	pr_debug("%s: resume gps function, func_is_supended:%d\n",
 			__func__, f->func_is_suspended);
@@ -304,7 +337,9 @@
 		return;
 	}
 	spin_unlock(&dev->lock);
-	gps_ctrl_response_available(dev);
+
+	list_for_each(cpkt, &dev->cpkt_resp_q)
+		gps_ctrl_response_available(dev);
 }
 
 static int gps_get_status(struct usb_function *f)
@@ -381,6 +416,8 @@
 
 	atomic_set(&dev->online, 0);
 
+	cancel_delayed_work(&dev->wakeup_work);
+
 	gps_purge_responses(dev);
 
 	gport_gps_disconnect(dev);
@@ -419,6 +456,7 @@
 
 	atomic_set(&dev->online, 1);
 
+	cancel_delayed_work(&dev->wakeup_work);
 	/* In case notifications were aborted, but there are pending control
 	   packets in the response queue, re-add the notifications */
 	list_for_each(cpkt, &dev->cpkt_resp_q)
@@ -427,13 +465,32 @@
 	return ret;
 }
 
+static void gps_queue_notify_request(struct f_gps *dev)
+{
+	int ret;
+
+	pr_debug("%s: queue new notification[%d]\n",
+			__func__, atomic_read(&dev->notify_count));
+	ret = usb_ep_queue(dev->notify, dev->notify_req, GFP_ATOMIC);
+	if (ret) {
+		/*
+		 * The modem response thread and the response completion
+		 * thread can try to queue the same notification and may
+		 * result in EBUSY error
+		 */
+		if (ret == -EBUSY) {
+			pr_debug("%s: notify_count:%u\n",
+				__func__, atomic_read(&dev->notify_count));
+		}
+		pr_debug("ep enqueue error %d\n", ret);
+	}
+}
+
 static void gps_ctrl_response_available(struct f_gps *dev)
 {
 	struct usb_request		*req = dev->notify_req;
 	struct usb_cdc_notification	*event;
 	unsigned long			flags;
-	int				ret;
-	struct rmnet_ctrl_pkt	*cpkt;
 
 	pr_debug("%s:dev:%pK\n", __func__, dev);
 
@@ -457,24 +514,8 @@
 	event->wLength = cpu_to_le16(0);
 	spin_unlock_irqrestore(&dev->lock, flags);
 
-	ret = usb_ep_queue(dev->notify, dev->notify_req, GFP_ATOMIC);
-	if (ret) {
-		if (ret == -EBUSY) {
-			pr_err("%s: notify_count:%u\n",
-				__func__, atomic_read(&dev->notify_count));
-			WARN_ON(1);
-		}
-		spin_lock_irqsave(&dev->lock, flags);
-		if (!list_empty(&dev->cpkt_resp_q)) {
-			atomic_dec(&dev->notify_count);
-			cpkt = list_first_entry(&dev->cpkt_resp_q,
-					struct rmnet_ctrl_pkt, list);
-			list_del(&cpkt->list);
-			gps_free_ctrl_pkt(cpkt);
-		}
-		spin_unlock_irqrestore(&dev->lock, flags);
-		pr_debug("ep enqueue error %d\n", ret);
-	}
+	gps_queue_notify_request(dev);
+
 }
 
 static void gps_connect(struct grmnet *gr)
@@ -543,19 +584,27 @@
 		return 0;
 	}
 
+	if (atomic_read(&dev->resp_q_count) >= GPS_RESP_Q_LENGTH) {
+		pr_err_ratelimited("%s: dropping packets as queue is full\n",
+					__func__);
+		gps_free_ctrl_pkt(cpkt);
+		return 0;
+	}
+
 	spin_lock_irqsave(&dev->lock, flags);
 	list_add_tail(&cpkt->list, &dev->cpkt_resp_q);
+	atomic_inc(&dev->resp_q_count);
 	spin_unlock_irqrestore(&dev->lock, flags);
 
-	if (dev->is_suspended && dev->is_rw_allowed) {
-		pr_debug("%s: calling gps_wakeup_host\n", __func__);
-		gps_wakeup_host(dev);
-		goto end;
+	if (dev->is_suspended) {
+		if (dev->is_rw_allowed) {
+			pr_debug("%s: calling gps_wakeup_host\n", __func__);
+			gps_wakeup_host(dev);
+		}
+		return 0;
 	}
 
 	gps_ctrl_response_available(dev);
-
-end:
 	return 0;
 }
 
@@ -582,8 +631,6 @@
 {
 	struct f_gps *dev = req->context;
 	int status = req->status;
-	unsigned long		flags;
-	struct rmnet_ctrl_pkt	*cpkt;
 
 	pr_debug("%s: dev:%pK port#%d\n", __func__, dev, dev->port_num);
 
@@ -602,33 +649,24 @@
 
 		pr_debug("%s: decrement notify_count:%u\n", __func__,
 				atomic_read(&dev->notify_count));
-		if (atomic_dec_and_test(&dev->notify_count))
-			break;
+		atomic_dec(&dev->notify_count);
 
-		status = usb_ep_queue(dev->notify, req, GFP_ATOMIC);
-		if (status) {
-			if (status == -EBUSY) {
-				pr_err("%s: notify_count:%u\n",
-					__func__,
-					atomic_read(&dev->notify_count));
-				WARN_ON(1);
-			}
-
-			spin_lock_irqsave(&dev->lock, flags);
-			if (!list_empty(&dev->cpkt_resp_q)) {
-				atomic_dec(&dev->notify_count);
-				cpkt = list_first_entry(&dev->cpkt_resp_q,
-						struct rmnet_ctrl_pkt, list);
-				list_del(&cpkt->list);
-				gps_free_ctrl_pkt(cpkt);
-			}
-			spin_unlock_irqrestore(&dev->lock, flags);
-			pr_debug("ep enqueue error %d\n", status);
-		}
 		break;
 	}
 }
 
+static void gps_ctrl_send_response_complete(struct usb_ep *ep,
+		struct usb_request *req)
+{
+	struct f_gps *dev = (struct f_gps *)req->context;
+
+	pr_debug("%s: response queue count:%u notify count: %u\n", __func__,
+			atomic_read(&dev->resp_q_count),
+			atomic_read(&dev->notify_count));
+	if (atomic_read(&dev->notify_count) > 0)
+		gps_queue_notify_request(dev);
+}
+
 static int
 gps_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
 {
@@ -674,12 +712,15 @@
 			cpkt = list_first_entry(&dev->cpkt_resp_q,
 					struct rmnet_ctrl_pkt, list);
 			list_del(&cpkt->list);
+			atomic_dec(&dev->resp_q_count);
 			spin_unlock(&dev->lock);
 
 			len = min_t(unsigned, w_length, cpkt->len);
 			memcpy(req->buf, cpkt->buf, len);
 			ret = len;
 
+			req->complete = gps_ctrl_send_response_complete;
+			req->context = dev;
 			gps_free_ctrl_pkt(cpkt);
 		}
 		break;
@@ -786,6 +827,8 @@
 			__func__, dev->port_num,
 			gadget_is_dualspeed(cdev->gadget) ? "dual" : "full");
 
+	INIT_DELAYED_WORK(&dev->wakeup_work, gps_remote_wakeup_work);
+
 	return 0;
 
 fail:
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 38741d4..7a64d9a 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -1834,9 +1834,13 @@
 			return -ENOMEM;
 		}
 		if (data->mapped) {
-			mdss_smmu_unmap_dma_buf(data->srcp_table,
-						dom, dir,
-					data->srcp_dma_buf);
+			if (client == MDP3_CLIENT_PPP ||
+						client == MDP3_CLIENT_DMA_P)
+				mdss_smmu_unmap_dma_buf(data->tab_clone,
+					dom, dir, data->srcp_dma_buf);
+			else
+				mdss_smmu_unmap_dma_buf(data->srcp_table,
+					dom, dir, data->srcp_dma_buf);
 			data->mapped = false;
 		}
 		if (!data->skip_detach) {
@@ -1851,6 +1855,10 @@
 	} else {
 		return -EINVAL;
 	}
+	if (client == MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) {
+		kfree(data->tab_clone->sgl);
+		kfree(data->tab_clone);
+	}
 	return 0;
 }
 
@@ -1913,9 +1921,27 @@
 				goto err_detach;
 			}
 
-			ret = mdss_smmu_map_dma_buf(data->srcp_dma_buf,
-					data->srcp_table, dom,
-				&data->addr, &data->len, DMA_BIDIRECTIONAL);
+			if (client == MDP3_CLIENT_PPP ||
+						client == MDP3_CLIENT_DMA_P) {
+				data->tab_clone =
+				mdss_smmu_sg_table_clone(data->srcp_table,
+							GFP_KERNEL, true);
+				if (IS_ERR_OR_NULL(data->tab_clone)) {
+					if (!(data->tab_clone))
+						ret = -EINVAL;
+					else
+						ret = PTR_ERR(data->tab_clone);
+					goto clone_err;
+				}
+				ret = mdss_smmu_map_dma_buf(data->srcp_dma_buf,
+					data->tab_clone, dom,
+					&data->addr, &data->len,
+					DMA_BIDIRECTIONAL);
+			} else {
+				ret = mdss_smmu_map_dma_buf(data->srcp_dma_buf,
+					data->srcp_table, dom, &data->addr,
+					&data->len, DMA_BIDIRECTIONAL);
+			}
 
 			if (IS_ERR_VALUE(ret)) {
 				pr_err("smmu map dma buf failed: (%d)\n", ret);
@@ -1926,6 +1952,10 @@
 		data->skip_detach = false;
 	}
 done:
+	if (client ==  MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) {
+		data->addr  += data->tab_clone->sgl->length;
+		data->len   -= data->tab_clone->sgl->length;
+	}
 	if (!ret && (img->offset < data->len)) {
 		data->addr += img->offset;
 		data->len -= img->offset;
@@ -1940,6 +1970,9 @@
 	}
 	return ret;
 
+clone_err:
+	dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table,
+		mdss_smmu_dma_data_direction(DMA_BIDIRECTIONAL));
 err_detach:
 	dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment);
 err_put:
@@ -1950,6 +1983,11 @@
 			mdss_smmu_dma_data_direction(DMA_BIDIRECTIONAL));
 	dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment);
 	dma_buf_put(data->srcp_dma_buf);
+
+	if (client ==  MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) {
+		kfree(data->tab_clone->sgl);
+		kfree(data->tab_clone);
+	}
 	return ret;
 
 }
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 814398c..c224416 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016-2017, The Linux Foundation. All rights reserved.
  * Copyright (C) 2007 Google Incorporated
  *
  * This program is free software; you can redistribute it and/or modify
@@ -233,6 +233,7 @@
 	struct dma_buf *srcp_dma_buf;
 	struct dma_buf_attachment *srcp_attachment;
 	struct sg_table *srcp_table;
+	struct sg_table *tab_clone;
 };
 
 extern struct mdp3_hw_resource *mdp3_res;
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index a79ca46..6846e68 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -265,6 +265,8 @@
 	void (*smmu_dsi_unmap_buffer)(dma_addr_t dma_addr, int domain,
 			unsigned long size, int dir);
 	void (*smmu_deinit)(struct mdss_data_type *mdata);
+	struct sg_table * (*smmu_sg_table_clone)(struct sg_table *orig_table,
+			gfp_t gfp_mask, bool padding);
 };
 
 struct mdss_data_type {
diff --git a/drivers/video/msm/mdss/mdss_rotator.c b/drivers/video/msm/mdss/mdss_rotator.c
index 523b1ff..25d56e3 100644
--- a/drivers/video/msm/mdss/mdss_rotator.c
+++ b/drivers/video/msm/mdss/mdss_rotator.c
@@ -1126,6 +1126,7 @@
 		bool free_perf = false;
 		u32 wb_idx = entry->queue->hw->wb_id;
 
+		mutex_lock(&mgr->lock);
 		mutex_lock(&entry->perf->work_dis_lock);
 		if (entry->perf->work_distribution[wb_idx])
 			entry->perf->work_distribution[wb_idx]--;
@@ -1149,6 +1150,7 @@
 			mdss_rotator_clk_ctrl(mgr, false);
 			entry->perf = NULL;
 		}
+		mutex_unlock(&mgr->lock);
 	}
 }
 
@@ -2045,7 +2047,6 @@
 	list_del_init(&perf->list);
 	mutex_unlock(&perf->work_dis_lock);
 	mutex_unlock(&private->perf_lock);
-	mutex_unlock(&mgr->lock);
 
 	if (offload_release_work)
 		goto done;
@@ -2058,6 +2059,7 @@
 done:
 	pr_debug("Closed session id:%u", id);
 	ATRACE_END(__func__);
+	mutex_unlock(&mgr->lock);
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_smmu.c b/drivers/video/msm/mdss/mdss_smmu.c
index 67e87c8..e0d0579 100644
--- a/drivers/video/msm/mdss/mdss_smmu.c
+++ b/drivers/video/msm/mdss/mdss_smmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2007-2017, 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
@@ -480,6 +480,134 @@
 	}
 }
 
+/*
+ * sg_clone -	Duplicate an existing chained sgl
+ * @orig_sgl:	Original sg list to be duplicated
+ * @len:	Total length of sg while taking chaining into account
+ * @gfp_mask:	GFP allocation mask
+ * @padding:	specifies if padding is required
+ *
+ * Description:
+ *   Clone a chained sgl. This cloned copy may be modified in some ways while
+ *   keeping the original sgl in tact. Also allow the cloned copy to have
+ *   a smaller length than the original which may reduce the sgl total
+ *   sg entries and also allows cloned copy to have one extra sg  entry on
+ *   either sides of sgl.
+ *
+ * Returns:
+ *   Pointer to new kmalloced sg list, ERR_PTR() on error
+ *
+ */
+static struct scatterlist *sg_clone(struct scatterlist *orig_sgl, u64 len,
+				gfp_t gfp_mask, bool padding)
+{
+	int nents;
+	bool last_entry;
+	struct scatterlist *sgl, *head;
+
+	nents = sg_nents(orig_sgl);
+	if (nents < 0)
+		return ERR_PTR(-EINVAL);
+	if (padding)
+		nents += 2;
+
+	head = kmalloc_array(nents, sizeof(struct scatterlist), gfp_mask);
+	if (!head)
+		return ERR_PTR(-ENOMEM);
+
+	sgl = head;
+
+	sg_init_table(sgl, nents);
+
+	if (padding) {
+		*sgl = *orig_sgl;
+		if (sg_is_chain(orig_sgl)) {
+			orig_sgl = sg_next(orig_sgl);
+			*sgl = *orig_sgl;
+		}
+		sgl->page_link &= (unsigned long)(~0x03);
+		sgl = sg_next(sgl);
+	}
+
+	for (; sgl; orig_sgl = sg_next(orig_sgl), sgl = sg_next(sgl)) {
+
+		last_entry = sg_is_last(sgl);
+
+		/*
+		 * * If page_link is pointing to a chained sgl then set
+		 * the sg entry in the cloned list to the next sg entry
+		 * in the original sg list as chaining is already taken
+		 * care.
+		 */
+
+		if (sg_is_chain(orig_sgl))
+			orig_sgl = sg_next(orig_sgl);
+
+		if (padding)
+			last_entry = sg_is_last(orig_sgl);
+
+		*sgl = *orig_sgl;
+		sgl->page_link &= (unsigned long)(~0x03);
+
+		if (last_entry) {
+			if (padding) {
+				len -= sg_dma_len(sgl);
+				sgl = sg_next(sgl);
+				*sgl = *orig_sgl;
+			}
+			sg_dma_len(sgl) = len ? len : SZ_4K;
+			/* Set bit 1 to indicate end of sgl */
+			sgl->page_link |= 0x02;
+		} else {
+			len -= sg_dma_len(sgl);
+		}
+	}
+
+	return head;
+}
+
+/*
+ * sg_table_clone - Duplicate an existing sg_table including chained sgl
+ * @orig_table:     Original sg_table to be duplicated
+ * @len:            Total length of sg while taking chaining into account
+ * @gfp_mask:       GFP allocation mask
+ * @padding:	    specifies if padding is required
+ *
+ * Description:
+ *   Clone a sg_table along with chained sgl. This cloned copy may be
+ *   modified in some ways while keeping the original table and sgl in tact.
+ *   Also allow the cloned sgl copy to have a smaller length than the original
+ *   which may reduce the sgl total sg entries.
+ *
+ * Returns:
+ *   Pointer to new kmalloced sg_table, ERR_PTR() on error
+ *
+ */
+static struct sg_table *sg_table_clone(struct sg_table *orig_table,
+				gfp_t gfp_mask, bool padding)
+{
+	struct sg_table *table;
+	struct scatterlist *sg = orig_table->sgl;
+	u64 len = 0;
+
+	for (len = 0; sg; sg = sg_next(sg))
+		len += sg->length;
+
+	table = kmalloc(sizeof(struct sg_table), gfp_mask);
+	if (!table)
+		return ERR_PTR(-ENOMEM);
+
+	table->sgl = sg_clone(orig_table->sgl, len, gfp_mask, padding);
+	if (IS_ERR(table->sgl)) {
+		kfree(table);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	table->nents = table->orig_nents = sg_nents(table->sgl);
+
+	return table;
+}
+
 static void mdss_smmu_ops_init(struct mdss_data_type *mdata)
 {
 	mdata->smmu_ops.smmu_attach = mdss_smmu_attach_v2;
@@ -501,6 +629,7 @@
 	mdata->smmu_ops.smmu_dsi_unmap_buffer =
 				mdss_smmu_dsi_unmap_buffer_v2;
 	mdata->smmu_ops.smmu_deinit = mdss_smmu_deinit_v2;
+	mdata->smmu_ops.smmu_sg_table_clone = sg_table_clone;
 }
 
 /*
diff --git a/drivers/video/msm/mdss/mdss_smmu.h b/drivers/video/msm/mdss/mdss_smmu.h
index 8044880..658f1ee 100644
--- a/drivers/video/msm/mdss/mdss_smmu.h
+++ b/drivers/video/msm/mdss/mdss_smmu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2007-2017, 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
@@ -292,4 +292,16 @@
 		mdata->smmu_ops.smmu_deinit(mdata);
 }
 
+static inline struct sg_table *mdss_smmu_sg_table_clone(struct sg_table
+			*orig_table, gfp_t gfp_mask, bool padding)
+{
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+	if (!mdata || !mdata->smmu_ops.smmu_sg_table_clone)
+		return NULL;
+
+	return mdata->smmu_ops.smmu_sg_table_clone(orig_table,
+				gfp_mask, padding);
+}
+
 #endif /* MDSS_SMMU_H */
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 8a1b72d..fcc8545 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -443,7 +443,7 @@
 	return rc;
 }
 
-void mdss_dsi_phy_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl)
+static void mdss_dsi_phy_sw_reset_sub(struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	struct mdss_dsi_ctrl_pdata *sctrl = NULL;
 	struct dsi_shared_data *sdata;
@@ -500,7 +500,39 @@
 
 	}
 	mutex_unlock(&sdata->phy_reg_lock);
+}
 
+void mdss_dsi_phy_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	struct mdss_dsi_ctrl_pdata *sctrl = NULL;
+	struct dsi_shared_data *sdata;
+
+	if (ctrl == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return;
+	}
+
+	sdata = ctrl->shared_data;
+
+	/*
+	 * When operating in split display mode, make sure that the PHY reset
+	 * is only done from the clock master. This will ensure that the PLL is
+	 * off when PHY reset is called.
+	 */
+	if (mdss_dsi_is_ctrl_clk_slave(ctrl))
+		return;
+
+	mdss_dsi_phy_sw_reset_sub(ctrl);
+
+	if (mdss_dsi_is_ctrl_clk_master(ctrl)) {
+		sctrl = mdss_dsi_get_ctrl_clk_slave();
+		if (sctrl)
+			mdss_dsi_phy_sw_reset_sub(sctrl);
+		else
+			pr_warn("%s: unable to get slave ctrl\n", __func__);
+	}
+
+	/* All other quirks go here */
 	if ((sdata->hw_rev == MDSS_DSI_HW_REV_103) &&
 		!mdss_dsi_is_hw_config_dual(sdata) &&
 		mdss_dsi_is_right_ctrl(ctrl)) {
@@ -899,8 +931,11 @@
 {
 	int ln;
 	void __iomem *base;
+	u32 data;
 
-	MIPI_OUTP(ctrl->phy_io.base + DSIPHY_CMN_CTRL_0, 0x7f);
+	/* Turn off PLL power */
+	data = MIPI_INP(ctrl->phy_io.base + DSIPHY_CMN_CTRL_0);
+	MIPI_OUTP(ctrl->phy_io.base + DSIPHY_CMN_CTRL_0, data & ~BIT(7));
 
 	/* 4 lanes + clk lane configuration */
 	for (ln = 0; ln < 5; ln++) {
@@ -956,6 +991,7 @@
 	void __iomem *base;
 	struct mdss_dsi_phy_ctrl *pd;
 	char *ip;
+	u32 data;
 
 	pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
 
@@ -975,6 +1011,10 @@
 	}
 
 	mdss_dsi_8996_phy_regulator_enable(ctrl);
+
+	/* Turn on PLL power */
+	data = MIPI_INP(ctrl->phy_io.base + DSIPHY_CMN_CTRL_0);
+	MIPI_OUTP(ctrl->phy_io.base + DSIPHY_CMN_CTRL_0, data | BIT(7));
 }
 
 static void mdss_dsi_phy_power_on(
@@ -1078,6 +1118,7 @@
 			mdss_dsi_8996_pll_source_standalone(ctrl);
 	}
 
+	MIPI_OUTP(ctrl->phy_io.base + DSIPHY_CMN_CTRL_0, 0x7f);
 	wmb(); /* make sure registers committed */
 }
 
@@ -1193,12 +1234,36 @@
 	wmb();
 }
 
-void mdss_dsi_phy_init(struct mdss_dsi_ctrl_pdata *ctrl)
+static void mdss_dsi_phy_init_sub(struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	mdss_dsi_phy_regulator_ctrl(ctrl, true);
 	mdss_dsi_phy_ctrl(ctrl, true);
 }
 
+void mdss_dsi_phy_init(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	struct mdss_dsi_ctrl_pdata *sctrl = NULL;
+
+	/*
+	 * When operating in split display mode, make sure that both the PHY
+	 * blocks are initialized together prior to the PLL being enabled. This
+	 * is achieved by calling the phy_init function for the clk_slave from
+	 * the clock_master.
+	 */
+	if (mdss_dsi_is_ctrl_clk_slave(ctrl))
+		return;
+
+	mdss_dsi_phy_init_sub(ctrl);
+
+	if (mdss_dsi_is_ctrl_clk_master(ctrl)) {
+		sctrl = mdss_dsi_get_ctrl_clk_slave();
+		if (sctrl)
+			mdss_dsi_phy_init_sub(sctrl);
+		else
+			pr_warn("%s: unable to get slave ctrl\n", __func__);
+	}
+}
+
 void mdss_dsi_core_clk_deinit(struct device *dev, struct dsi_shared_data *sdata)
 {
 	if (sdata->mmss_misc_ahb_clk)
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
index 581bf4d..6282f3d 100644
--- a/fs/gfs2/acl.c
+++ b/fs/gfs2/acl.c
@@ -81,7 +81,8 @@
 		struct posix_acl *old_acl = acl;
 		error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
 
-		error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+		if (!acl)
+			posix_acl_release(old_acl);
 		if (error)
 			return error;
 		if (mode != inode->i_mode)
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index e040671..c5bda4b 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -287,8 +287,10 @@
 
 	if (type == ACL_TYPE_ACCESS) {
 		umode_t mode;
-
+		struct posix_acl *old_acl = acl;
 		error = posix_acl_update_mode(inode, &mode, &acl);
+		if (!acl)
+			posix_acl_release(old_acl);
 		if (error)
 			return error;
 		error = xfs_set_mode(inode, mode);
diff --git a/include/dt-bindings/regulator/qcom,rpm-smd-regulator.h b/include/dt-bindings/regulator/qcom,rpm-smd-regulator.h
index cd38c02..8718c47 100644
--- a/include/dt-bindings/regulator/qcom,rpm-smd-regulator.h
+++ b/include/dt-bindings/regulator/qcom,rpm-smd-regulator.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2017 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
@@ -23,6 +23,7 @@
 #define RPM_SMD_REGULATOR_LEVEL_NOM		256
 #define RPM_SMD_REGULATOR_LEVEL_NOM_PLUS	320
 #define RPM_SMD_REGULATOR_LEVEL_TURBO		384
+#define RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR	416
 #define RPM_SMD_REGULATOR_LEVEL_BINNING		512
 
 #endif
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index e6e54e3..92d7b74 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -551,6 +551,7 @@
 	unsigned int		bus_resume_flags;
 #define MMC_BUSRESUME_MANUAL_RESUME	(1 << 0)
 #define MMC_BUSRESUME_NEEDS_RESUME	(1 << 1)
+	bool ignore_bus_resume_flags;
 
 	unsigned int		sdio_irqs;
 	struct task_struct	*sdio_irq_thread;
diff --git a/include/linux/regulator/rpm-smd-regulator.h b/include/linux/regulator/rpm-smd-regulator.h
index c57995d..1c735cd 100644
--- a/include/linux/regulator/rpm-smd-regulator.h
+++ b/include/linux/regulator/rpm-smd-regulator.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2012-2013, 2015 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 2015, 2017 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
@@ -58,6 +59,7 @@
 	RPM_REGULATOR_LEVEL_NOM			= 256,
 	RPM_REGULATOR_LEVEL_NOM_PLUS		= 320,
 	RPM_REGULATOR_LEVEL_TURBO		= 384,
+	RPM_REGULATOR_LEVEL_TURBO_NO_CPR	= 416,
 	RPM_REGULATOR_LEVEL_BINNING		= 512,
 	RPM_REGULATOR_LEVEL_MAX			= 65535,
 };
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index a37530e..e3a7ef5 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -78,6 +78,7 @@
 #define CFG80211_BEACON_TX_RATE_CUSTOM_BACKPORT 1
 #define CFG80211_RAND_TA_FOR_PUBLIC_ACTION_FRAME 1
 #define CFG80211_REPORT_BETTER_BSS_IN_SCHED_SCAN 1
+#define CFG80211_BEACON_INTERVAL_BACKPORT 1
 
 /*
  * wireless hardware capability structures
diff --git a/include/net/cnss.h b/include/net/cnss.h
index 2bf1385..03b76ee 100644
--- a/include/net/cnss.h
+++ b/include/net/cnss.h
@@ -169,10 +169,6 @@
 static inline int wcnss_pre_alloc_reset(void) { return 0; }
 #endif
 
-#if !defined(CONFIG_WCNSS_MEM_PRE_ALLOC) || !defined(CONFIG_SLUB_DEBUG)
-static inline void wcnss_prealloc_check_memory_leak(void) {}
-#endif
-
 extern int msm_pcie_enumerate(u32 rc_idx);
 extern int cnss_auto_suspend(void);
 extern int cnss_auto_resume(void);
diff --git a/include/net/cnss_prealloc.h b/include/net/cnss_prealloc.h
index 21c564d..bf50c16 100644
--- a/include/net/cnss_prealloc.h
+++ b/include/net/cnss_prealloc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -21,7 +21,12 @@
 extern void *wcnss_prealloc_get(unsigned int size);
 extern int wcnss_prealloc_put(void *ptr);
 extern int wcnss_pre_alloc_reset(void);
+
+#if !defined(CONFIG_WCNSS_MEM_PRE_ALLOC) || !defined(CONFIG_SLUB_DEBUG)
+static inline void wcnss_prealloc_check_memory_leak(void) {}
+#else
 void wcnss_prealloc_check_memory_leak(void);
+#endif
 
 extern void wcnss_skb_prealloc_check_memory_leak(void);
 extern int wcnss_skb_pre_alloc_reset(void);
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 1db48a5..3878c34 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1380,6 +1380,8 @@
 	f->arr[f->num_members] = sk;
 	smp_wmb();
 	f->num_members++;
+	if (f->num_members == 1)
+		dev_add_pack(&f->prot_hook);
 	spin_unlock(&f->lock);
 }
 
@@ -1396,6 +1398,8 @@
 	BUG_ON(i >= f->num_members);
 	f->arr[i] = f->arr[f->num_members - 1];
 	f->num_members--;
+	if (f->num_members == 0)
+		__dev_remove_pack(&f->prot_hook);
 	spin_unlock(&f->lock);
 }
 
@@ -1468,7 +1472,6 @@
 		match->prot_hook.func = packet_rcv_fanout;
 		match->prot_hook.af_packet_priv = match;
 		match->prot_hook.id_match = match_fanout_group;
-		dev_add_pack(&match->prot_hook);
 		list_add(&match->list, &fanout_list);
 	}
 	err = -EINVAL;
@@ -1489,7 +1492,14 @@
 	return err;
 }
 
-static void fanout_release(struct sock *sk)
+/* If pkt_sk(sk)->fanout->sk_ref is zero, this function removes
+ * pkt_sk(sk)->fanout from fanout_list and returns pkt_sk(sk)->fanout.
+ * It is the responsibility of the caller to free the returned packet_fanout 
+ * (after synchronize_net())
+ * This Branch still does not have support classic BPF fanout mode.
+ *  upstream commit 47dceb8ecdc: packet: add classic BPF fanout mode
+ */
+static struct packet_fanout *fanout_release(struct sock *sk)
 {
 	struct packet_sock *po = pkt_sk(sk);
 	struct packet_fanout *f;
@@ -1499,13 +1509,15 @@
 	if (f) {
 		po->fanout = NULL;
 
-		if (atomic_dec_and_test(&f->sk_ref)) {
+		if (atomic_dec_and_test(&f->sk_ref))
 			list_del(&f->list);
-			dev_remove_pack(&f->prot_hook);
-			kfree(f);
-		}
+		else
+			f = NULL;
+
 	}
 	mutex_unlock(&fanout_mutex);
+
+	return f;
 }
 
 static bool packet_extra_vlan_len_allowed(const struct net_device *dev,
@@ -2587,6 +2599,7 @@
 {
 	struct sock *sk = sock->sk;
 	struct packet_sock *po;
+	struct packet_fanout *f;
 	struct net *net;
 	union tpacket_req_u req_u;
 
@@ -2626,9 +2639,13 @@
 		packet_set_ring(sk, &req_u, 1, 1);
 	}
 
-	fanout_release(sk);
+	f = fanout_release(sk);
 
 	synchronize_net();
+
+	if (f)
+		kfree(f);
+
 	/*
 	 *	Now the socket is dead. No more input will appear.
 	 */
@@ -3567,7 +3584,6 @@
 				}
 				if (msg == NETDEV_UNREGISTER) {
 					packet_cached_dev_reset(po);
-					fanout_release(sk);
 					po->ifindex = -1;
 					if (po->prot_hook.dev)
 						dev_put(po->prot_hook.dev);
diff --git a/sound/soc/codecs/wsa881x-analog.c b/sound/soc/codecs/wsa881x-analog.c
index ba26579..8f9256a 100644
--- a/sound/soc/codecs/wsa881x-analog.c
+++ b/sound/soc/codecs/wsa881x-analog.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017, 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
@@ -1258,8 +1258,10 @@
 
 	if ((client->addr == WSA881X_I2C_SPK0_SLAVE1_ADDR ||
 		client->addr == WSA881X_I2C_SPK1_SLAVE1_ADDR) &&
-		(pdata->status == WSA881X_STATUS_PROBING))
+		(pdata->status == WSA881X_STATUS_PROBING)) {
+		wsa881x_probing_count++;
 		return ret;
+	}
 
 	if (pdata->status == WSA881X_STATUS_I2C) {
 		dev_dbg(&client->dev, "%s:probe for other slaves\n"
@@ -1342,6 +1344,7 @@
 			dev_err(&client->dev,
 				"failed to ping wsa with addr:%x, ret = %d\n",
 						client->addr, ret);
+			wsa881x_probing_count++;
 			goto err1;
 		}
 		pdata->version = wsa881x_i2c_read_device(pdata,
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 7eb038d..d221bb8 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -30,7 +30,7 @@
 obj-$(CONFIG_SND_SOC_MSM8X16) += snd-soc-msm8x16.o
 
 # for MDM 9650 sound card driver
-snd-soc-mdm9650-objs := mdm9650.o mdm9650-auto.o
+snd-soc-mdm9650-objs := mdm9650.o
 obj-$(CONFIG_SND_SOC_MDM9650) += snd-soc-mdm9650.o
 
 # for MDM 9607 sound card driver
diff --git a/sound/soc/msm/mdm9650-auto.c b/sound/soc/msm/mdm9650-auto.c
deleted file mode 100644
index f2fd9c3..0000000
--- a/sound/soc/msm/mdm9650-auto.c
+++ /dev/null
@@ -1,1811 +0,0 @@
-/* Copyright (c) 2014-2017, 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/clk.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/pcm.h>
-#include <sound/jack.h>
-#include <sound/q6afe-v2.h>
-#include <sound/info.h>
-#include <sound/pcm_params.h>
-#include <device_event.h>
-#include <soc/qcom/socinfo.h>
-#include <qdsp6v2/msm-pcm-routing-v2.h>
-#include <sound/q6core.h>
-#include <../codecs/tlv320aic3x.h>
-
-/*
- * MDM9650 runs TLV320AIC3X at 12.288 Mhz.
- */
-#define MDM_MCLK_CLK_12P288MHZ 12288000
-#define MDM_MCLK_CLK_9P6HZ 9600000
-#define MDM_MI2S_RATE 48000
-#define DEV_NAME_STR_LEN  32
-
-#define SAMPLE_RATE_8KHZ 8000
-#define SAMPLE_RATE_16KHZ 16000
-#define SAMPLE_RATE_48KHZ 48000
-#define NO_OF_BITS_PER_SAMPLE  16
-
-#define LPAIF_OFFSET 0x07700000
-#define LPAIF_PRI_MODE_MUXSEL (LPAIF_OFFSET + 0x2008)
-#define LPAIF_SEC_MODE_MUXSEL (LPAIF_OFFSET + 0x200c)
-
-#define LPASS_CSR_GP_IO_MUX_SPKR_CTL (LPAIF_OFFSET + 0x2004)
-#define LPASS_CSR_GP_IO_MUX_MIC_CTL  (LPAIF_OFFSET + 0x2000)
-
-#define I2S_SEL 0
-#define PCM_SEL 1
-#define I2S_PCM_SEL_OFFSET 0
-#define I2S_PCM_MASTER_MODE 1
-#define I2S_PCM_SLAVE_MODE 0
-
-#define PRI_TLMM_CLKS_EN_MASTER 0x4
-#define SEC_TLMM_CLKS_EN_MASTER 0x2
-#define PRI_TLMM_CLKS_EN_SLAVE 0x100000
-#define SEC_TLMM_CLKS_EN_SLAVE 0x800000
-#define CLOCK_ON  1
-#define CLOCK_OFF 0
-
-/* Machine driver Name*/
-#define DRV_NAME "mdm9650-asoc-auto"
-
-enum mi2s_pcm_mux {
-	PRI_MI2S_PCM,
-	SEC_MI2S_PCM,
-	MI2S_PCM_MAX_INTF
-};
-
-struct mdm_machine_data {
-	u32 mclk_freq;
-	u16 prim_mi2s_mode;
-	u16 sec_mi2s_mode;
-	u16 prim_auxpcm_mode;
-	u16 sec_auxpcm_mode;
-	u32 prim_clk_usrs;
-};
-
-static const struct afe_clk_cfg lpass_default = {
-	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 int mdm_auxpcm_rate = 8000;
-static void *lpaif_pri_muxsel_virt_addr;
-static void *lpaif_sec_muxsel_virt_addr;
-static void *lpass_gpio_mux_spkr_ctl_virt_addr;
-static void *lpass_gpio_mux_mic_ctl_virt_addr;
-
-static int mdm_mi2s_rx_ch = 1;
-static int mdm_mi2s_tx_ch = 1;
-static int mdm_sec_mi2s_rx_ch = 1;
-static int mdm_sec_mi2s_tx_ch = 1;
-static int mdm_mi2s_rx_rate = SAMPLE_RATE_48KHZ;
-static int mdm_mi2s_tx_rate = SAMPLE_RATE_48KHZ;
-static int mdm_sec_mi2s_rx_rate = SAMPLE_RATE_48KHZ;
-static int mdm_sec_mi2s_tx_rate = SAMPLE_RATE_48KHZ;
-
-static atomic_t mi2s_ref_count;
-static atomic_t sec_mi2s_ref_count;
-
-static void *adsp_state_notifier;
-static bool dummy_device_registered;
-
-static int mdm_mi2s_clk_ctl(struct snd_soc_pcm_runtime *rtd, bool enable)
-{
-	struct snd_soc_card *card = rtd->card;
-	struct mdm_machine_data *pdata = snd_soc_card_get_drvdata(card);
-	struct afe_clk_cfg *lpass_clk = NULL;
-	int ret = 0;
-
-	if (pdata == NULL) {
-		pr_err("%s:platform data is null\n", __func__);
-
-		ret = -ENOMEM;
-		goto done;
-	}
-	lpass_clk = kzalloc(sizeof(struct afe_clk_cfg), GFP_KERNEL);
-	if (!lpass_clk) {
-		ret = -ENOMEM;
-		goto done;
-	}
-	memcpy(lpass_clk, &lpass_default, sizeof(struct afe_clk_cfg));
-	pr_debug("%s enable = %x\n", __func__, enable);
-
-	if (enable) {
-		ret = afe_set_lpass_clock(MI2S_RX, lpass_clk);
-		if (ret < 0)
-			pr_err("%s:afe_set_lpass_clock failed\n", __func__);
-	} else {
-		lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_BOTH_VALID;
-		lpass_clk->clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
-		lpass_clk->clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
-		ret = afe_set_lpass_clock(MI2S_RX, lpass_clk);
-		if (ret < 0)
-			pr_err("%s:afe_set_lpass_clock failed\n", __func__);
-	}
-	pr_debug("%s clk 1 = %x clk2 = %x mode = %x\n",
-		 __func__, lpass_clk->clk_val1, lpass_clk->clk_val2,
-		 lpass_clk->clk_set_mode);
-
-	kfree(lpass_clk);
-done:
-	return ret;
-}
-
-static void mdm_mi2s_shutdown(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	int ret;
-
-	if (atomic_dec_return(&mi2s_ref_count) == 0) {
-		ret = mdm_mi2s_clk_ctl(rtd, false);
-		if (ret < 0)
-			pr_err("%s Clock disable failed\n", __func__);
-	}
-}
-
-static int mdm_mi2s_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_card *card = rtd->card;
-	struct mdm_machine_data *pdata = snd_soc_card_get_drvdata(card);
-	int ret = 0;
-
-	if (atomic_inc_return(&mi2s_ref_count) == 1) {
-		if (lpaif_pri_muxsel_virt_addr != NULL) {
-			ret = afe_enable_lpass_core_shared_clock(MI2S_RX,
-								 CLOCK_ON);
-			if (ret < 0) {
-				ret = -EINVAL;
-				goto done;
-			}
-			iowrite32(I2S_SEL << I2S_PCM_SEL_OFFSET,
-				  lpaif_pri_muxsel_virt_addr);
-			if (lpass_gpio_mux_spkr_ctl_virt_addr != NULL) {
-				if (pdata->prim_mi2s_mode == 1) {
-					iowrite32(PRI_TLMM_CLKS_EN_MASTER,
-					  lpass_gpio_mux_spkr_ctl_virt_addr);
-				} else if (pdata->prim_mi2s_mode == 0) {
-					iowrite32(PRI_TLMM_CLKS_EN_SLAVE,
-					  lpass_gpio_mux_spkr_ctl_virt_addr);
-				} else {
-					dev_err(card->dev, "%s Invalid primary mi2s mode\n",
-						__func__);
-					ret = -EINVAL;
-					goto err;
-				}
-			} else {
-				dev_err(card->dev, "%s: mux spkr ctl virt addr is NULL\n",
-					   __func__);
-
-				ret = -EINVAL;
-				goto err;
-			}
-		} else {
-			dev_err(card->dev, "%s lpaif_pri_muxsel_virt_addr is NULL\n",
-				__func__);
-
-			ret = -EINVAL;
-			goto done;
-		}
-		/*
-		 * This sets the CONFIG PARAMETER WS_SRC.
-		 * 1 means internal clock master mode.
-		 * 0 means external clock slave mode.
-		 */
-		if (pdata->prim_mi2s_mode == 1) {
-			ret = mdm_mi2s_clk_ctl(rtd, true);
-			if (ret < 0) {
-				dev_err(card->dev, "%s clock enable failed\n",
-						__func__);
-				goto err;
-			}
-			ret = snd_soc_dai_set_fmt(cpu_dai,
-					SND_SOC_DAIFMT_CBS_CFS);
-			if (ret < 0) {
-				mdm_mi2s_clk_ctl(rtd, false);
-				dev_err(card->dev, "%s Set fmt for cpu dai failed\n",
-					__func__);
-				goto err;
-			}
-			ret = snd_soc_dai_set_fmt(codec_dai,
-					SND_SOC_DAIFMT_CBS_CFS |
-					SND_SOC_DAIFMT_I2S);
-			if (ret < 0) {
-				mdm_mi2s_clk_ctl(rtd, false);
-				dev_err(card->dev, "%s Set fmt for codec dai failed\n",
-					__func__);
-			}
-		} else {
-			dev_err(card->dev, "%s Invalid primary mi2s mode\n",
-					__func__);
-			ret = -EINVAL;
-		}
-		/* Set the mclk as the sysclk for the codec dai */
-		ret = snd_soc_dai_set_sysclk(codec_dai,
-				CLKIN_MCLK,
-				pdata->mclk_freq, SND_SOC_CLOCK_OUT);
-		if (ret < 0)
-			pr_err("%s Set sysclk for codec dai failed\n",
-				__func__);
-err:
-		if (ret)
-			atomic_dec_return(&mi2s_ref_count);
-		afe_enable_lpass_core_shared_clock(MI2S_RX, CLOCK_OFF);
-	}
-done:
-	return ret;
-}
-
-static int mdm_sec_mi2s_clk_ctl(struct snd_soc_pcm_runtime *rtd, bool enable)
-{
-	struct snd_soc_card *card = rtd->card;
-	struct mdm_machine_data *pdata = snd_soc_card_get_drvdata(card);
-	struct afe_clk_cfg *lpass_clk = NULL;
-	int ret = 0;
-
-	if (pdata == NULL) {
-		dev_err(card->dev, "%s:platform data is null\n", __func__);
-
-		ret = -EINVAL;
-		goto done;
-	}
-	lpass_clk = kzalloc(sizeof(struct afe_clk_cfg), GFP_KERNEL);
-	if (!lpass_clk) {
-		ret = -ENOMEM;
-		goto done;
-	}
-	memcpy(lpass_clk, &lpass_default, sizeof(struct afe_clk_cfg));
-	dev_dbg(card->dev, "%s enable = %x\n", __func__, enable);
-
-	lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID;
-	if (enable) {
-		ret = afe_set_lpass_clock(SECONDARY_I2S_RX, lpass_clk);
-		if (ret < 0)
-			dev_err(card->dev,
-				"%s:afe_set_lpass_clock failed to enable\n",
-				__func__);
-	} else {
-		lpass_clk->clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
-		ret = afe_set_lpass_clock(SECONDARY_I2S_RX, lpass_clk);
-		if (ret < 0)
-			dev_err(card->dev,
-				"%s:afe_set_lpass_clock failed disable\n",
-				__func__);
-	}
-	dev_dbg(card->dev, "%s clk 1 = %x clk2 = %x mode = %x\n",
-		 __func__, lpass_clk->clk_val1, lpass_clk->clk_val2,
-		 lpass_clk->clk_set_mode);
-
-	kfree(lpass_clk);
-done:
-	return ret;
-}
-
-static void mdm_sec_mi2s_shutdown(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	int ret;
-
-	if (atomic_dec_return(&sec_mi2s_ref_count) == 0) {
-		ret = mdm_sec_mi2s_clk_ctl(rtd, false);
-		if (ret < 0)
-			pr_err("%s Clock disable failed\n", __func__);
-	}
-}
-
-static int mdm_sec_mi2s_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_card *card = rtd->card;
-	struct mdm_machine_data *pdata = snd_soc_card_get_drvdata(card);
-	int ret = 0;
-
-	if (atomic_inc_return(&sec_mi2s_ref_count) == 1) {
-		if (lpaif_sec_muxsel_virt_addr != NULL) {
-			ret = afe_enable_lpass_core_shared_clock(
-					SECONDARY_I2S_RX, CLOCK_ON);
-			if (ret < 0) {
-				ret = -EINVAL;
-				goto done;
-			}
-			iowrite32(I2S_SEL << I2S_PCM_SEL_OFFSET,
-				  lpaif_sec_muxsel_virt_addr);
-
-			if (lpass_gpio_mux_mic_ctl_virt_addr != NULL) {
-				if (pdata->sec_mi2s_mode == 1) {
-					iowrite32(SEC_TLMM_CLKS_EN_MASTER,
-					lpass_gpio_mux_mic_ctl_virt_addr);
-				} else if (pdata->sec_mi2s_mode == 0) {
-					iowrite32(SEC_TLMM_CLKS_EN_SLAVE,
-					lpass_gpio_mux_mic_ctl_virt_addr);
-				} else {
-					dev_err(card->dev, "%s Invalid secondary mi2s mode\n",
-						__func__);
-					ret = -EINVAL;
-					goto err;
-				}
-			} else {
-				dev_err(card->dev, "%s: mux spkr ctl virt addr is NULL\n",
-					   __func__);
-				ret = -EINVAL;
-				goto err;
-			}
-
-		} else {
-			dev_err(card->dev, "%s lpaif_sec_muxsel_virt_addr is NULL\n",
-				__func__);
-			ret = -EINVAL;
-			goto done;
-		}
-		/*
-		 * This sets the CONFIG PARAMETER WS_SRC.
-		 * 1 means internal clock master mode.
-		 * 0 means external clock slave mode.
-		 */
-		if (pdata->sec_mi2s_mode == 1) {
-			ret = mdm_sec_mi2s_clk_ctl(rtd, true);
-			if (ret < 0) {
-				dev_err(card->dev, "%s clock enable failed\n",
-					__func__);
-				goto err;
-			}
-			ret = snd_soc_dai_set_fmt(cpu_dai,
-				SND_SOC_DAIFMT_CBS_CFS);
-			if (ret < 0) {
-				ret = mdm_sec_mi2s_clk_ctl(rtd, false);
-				dev_err(card->dev, "%s Set fmt for cpu dai failed\n",
-					__func__);
-			}
-		} else if (pdata->sec_mi2s_mode == 0) {
-			/*
-			 * Enable mclk here, if needed for external codecs.
-			 * Optional. Refer primary mi2s slave interface.
-			 */
-			ret = snd_soc_dai_set_fmt(cpu_dai,
-			SND_SOC_DAIFMT_CBM_CFM);
-			if (ret < 0)
-				dev_err(card->dev,
-					"%s Set fmt for cpu dai failed\n",
-					__func__);
-		} else {
-			dev_err(card->dev,
-				"%s Invalid secondary mi2s mode\n",
-				__func__);
-			ret = -EINVAL;
-		}
-err:
-			if (ret)
-				atomic_dec_return(&sec_mi2s_ref_count);
-			afe_enable_lpass_core_shared_clock(
-							SECONDARY_I2S_RX,
-							CLOCK_OFF);
-	}
-done:
-	return ret;
-}
-
-static struct snd_soc_ops mdm_mi2s_be_ops = {
-	.startup = mdm_mi2s_startup,
-	.shutdown = mdm_mi2s_shutdown,
-};
-
-static struct snd_soc_ops mdm_sec_mi2s_be_ops = {
-	.startup = mdm_sec_mi2s_startup,
-	.shutdown = mdm_sec_mi2s_shutdown,
-};
-
-static int mdm_mi2s_rx_rate_get(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: mdm_i2s_rate  = %d", __func__,
-		 mdm_mi2s_rx_rate);
-	ucontrol->value.integer.value[0] = mdm_mi2s_rx_rate;
-	return 0;
-}
-
-static int mdm_sec_mi2s_rx_rate_get(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: mdm_sec_i2s_rate  = %d", __func__,
-		 mdm_sec_mi2s_rx_rate);
-	ucontrol->value.integer.value[0] = mdm_sec_mi2s_rx_rate;
-	return 0;
-}
-
-static int mdm_mi2s_rx_rate_put(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	switch (ucontrol->value.integer.value[0]) {
-	case 0:
-		mdm_mi2s_rx_rate = SAMPLE_RATE_8KHZ;
-		break;
-	case 1:
-		mdm_mi2s_rx_rate = SAMPLE_RATE_16KHZ;
-		break;
-	case 2:
-		mdm_mi2s_rx_rate = SAMPLE_RATE_48KHZ;
-		break;
-	default:
-		mdm_mi2s_rx_rate = SAMPLE_RATE_8KHZ;
-		break;
-	}
-	pr_debug("%s: mdm_i2s_rx_rate = %d ucontrol->value = %d\n",
-		 __func__, mdm_mi2s_rx_rate,
-		 (int)ucontrol->value.integer.value[0]);
-	return 0;
-}
-
-static int mdm_sec_mi2s_rx_rate_put(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	switch (ucontrol->value.integer.value[0]) {
-	case 0:
-		mdm_sec_mi2s_rx_rate = SAMPLE_RATE_8KHZ;
-		break;
-	case 1:
-		mdm_sec_mi2s_rx_rate = SAMPLE_RATE_16KHZ;
-		break;
-	case 2:
-		mdm_sec_mi2s_rx_rate = SAMPLE_RATE_48KHZ;
-		break;
-	default:
-		mdm_sec_mi2s_rx_rate = SAMPLE_RATE_8KHZ;
-		break;
-	}
-	pr_debug("%s: mdm_sec_mi2s_rx_rate = %d ucontrol->value = %d\n",
-		 __func__, mdm_sec_mi2s_rx_rate,
-		 (int)ucontrol->value.integer.value[0]);
-	return 0;
-}
-
-static int mdm_mi2s_tx_rate_get(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: mdm_i2s_rate  = %d", __func__,
-		 mdm_mi2s_tx_rate);
-	ucontrol->value.integer.value[0] = mdm_mi2s_tx_rate;
-	return 0;
-}
-
-static int mdm_sec_mi2s_tx_rate_get(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: mdm_sec_mi2s_rate  = %d", __func__,
-		 mdm_sec_mi2s_tx_rate);
-	ucontrol->value.integer.value[0] = mdm_sec_mi2s_tx_rate;
-	return 0;
-}
-
-static int mdm_mi2s_tx_rate_put(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	switch (ucontrol->value.integer.value[0]) {
-	case 0:
-		mdm_mi2s_tx_rate = SAMPLE_RATE_8KHZ;
-		break;
-	case 1:
-		mdm_mi2s_tx_rate = SAMPLE_RATE_16KHZ;
-		break;
-	case 2:
-		mdm_mi2s_tx_rate = SAMPLE_RATE_48KHZ;
-		break;
-	default:
-		mdm_mi2s_tx_rate = SAMPLE_RATE_8KHZ;
-		break;
-	}
-	pr_debug("%s: mdm_i2s_tx_rate = %d ucontrol->value = %d\n",
-		 __func__, mdm_mi2s_tx_rate,
-		 (int)ucontrol->value.integer.value[0]);
-	return 0;
-}
-
-static int mdm_sec_mi2s_tx_rate_put(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	switch (ucontrol->value.integer.value[0]) {
-	case 0:
-		mdm_sec_mi2s_tx_rate = SAMPLE_RATE_8KHZ;
-		break;
-	case 1:
-		mdm_sec_mi2s_tx_rate = SAMPLE_RATE_16KHZ;
-		break;
-	case 2:
-		mdm_sec_mi2s_tx_rate = SAMPLE_RATE_48KHZ;
-		break;
-	default:
-		mdm_sec_mi2s_tx_rate = SAMPLE_RATE_8KHZ;
-		break;
-	}
-	pr_debug("%s: mdm_sec_mi2s_tx_rate = %d ucontrol->value = %d\n",
-		 __func__, mdm_sec_mi2s_tx_rate,
-		 (int)ucontrol->value.integer.value[0]);
-	return 0;
-}
-
-static int mdm_mi2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rt,
-					      struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-						      SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_CHANNELS);
-	rate->min = rate->max = mdm_mi2s_rx_rate;
-	channels->min = channels->max = mdm_mi2s_rx_ch;
-	return 0;
-}
-
-static int mdm_sec_mi2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rt,
-					      struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-						      SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_CHANNELS);
-	rate->min = rate->max = mdm_sec_mi2s_rx_rate;
-	channels->min = channels->max = mdm_sec_mi2s_rx_ch;
-	return 0;
-}
-
-static int mdm_mi2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rt,
-					     struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-						      SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-						SNDRV_PCM_HW_PARAM_CHANNELS);
-	rate->min = rate->max = mdm_mi2s_tx_rate;
-	channels->min = channels->max = mdm_mi2s_tx_ch;
-	return 0;
-}
-
-static int mdm_sec_mi2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rt,
-					     struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-						      SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-						SNDRV_PCM_HW_PARAM_CHANNELS);
-	rate->min = rate->max = mdm_sec_mi2s_tx_rate;
-	channels->min = channels->max = mdm_sec_mi2s_tx_ch;
-	return 0;
-}
-
-static int mdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rt,
-				      struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-						      SNDRV_PCM_HW_PARAM_RATE);
-	rate->min = rate->max = MDM_MI2S_RATE;
-	return 0;
-}
-
-static int mdm_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s mdm_mi2s_rx_ch %d\n", __func__,
-		 mdm_mi2s_rx_ch);
-
-	ucontrol->value.integer.value[0] = mdm_mi2s_rx_ch - 1;
-	return 0;
-}
-
-static int mdm_sec_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s mdm_sec_mi2s_rx_ch %d\n", __func__,
-		 mdm_mi2s_rx_ch);
-
-	ucontrol->value.integer.value[0] = mdm_sec_mi2s_rx_ch - 1;
-	return 0;
-}
-
-static int mdm_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	mdm_mi2s_rx_ch = ucontrol->value.integer.value[0] + 1;
-	pr_debug("%s mdm_mi2s_rx_ch %d\n", __func__,
-		 mdm_mi2s_rx_ch);
-
-	return 1;
-}
-
-static int mdm_sec_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	mdm_mi2s_rx_ch = ucontrol->value.integer.value[0] + 1;
-	pr_debug("%s mdm_sec_mi2s_rx_ch %d\n", __func__,
-		 mdm_sec_mi2s_rx_ch);
-
-	return 1;
-}
-
-static int mdm_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
-				  struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s mdm_mi2s_tx_ch %d\n", __func__,
-		 mdm_mi2s_tx_ch);
-
-	ucontrol->value.integer.value[0] = mdm_mi2s_tx_ch - 1;
-	return 0;
-}
-
-static int mdm_sec_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
-				  struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s mdm_sec_mi2s_tx_ch %d\n", __func__,
-		 mdm_mi2s_tx_ch);
-
-	ucontrol->value.integer.value[0] = mdm_sec_mi2s_tx_ch - 1;
-	return 0;
-}
-
-static int mdm_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
-				  struct snd_ctl_elem_value *ucontrol)
-{
-	mdm_mi2s_tx_ch = ucontrol->value.integer.value[0] + 1;
-	pr_debug("%s mdm_mi2s_tx_ch %d\n", __func__,
-		 mdm_mi2s_tx_ch);
-
-	return 1;
-}
-
-static int mdm_sec_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
-				  struct snd_ctl_elem_value *ucontrol)
-{
-	mdm_mi2s_tx_ch = ucontrol->value.integer.value[0] + 1;
-	pr_debug("%s mdm_sec_mi2s_tx_ch %d\n", __func__,
-		 mdm_sec_mi2s_tx_ch);
-
-	return 1;
-}
-
-static int mdm_auxpcm_startup(struct snd_pcm_substream *substream)
-{
-	int ret = 0;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_card *card = rtd->card;
-	struct mdm_machine_data *pdata = snd_soc_card_get_drvdata(card);
-
-	if (lpaif_pri_muxsel_virt_addr != NULL) {
-		ret = afe_enable_lpass_core_shared_clock(MI2S_RX, CLOCK_ON);
-		if (ret < 0) {
-			ret = -EINVAL;
-			goto done;
-		}
-		iowrite32(PCM_SEL << I2S_PCM_SEL_OFFSET,
-			  lpaif_pri_muxsel_virt_addr);
-		if (lpass_gpio_mux_spkr_ctl_virt_addr != NULL) {
-			if (pdata->prim_auxpcm_mode == 1) {
-				iowrite32(PRI_TLMM_CLKS_EN_MASTER,
-				  lpass_gpio_mux_spkr_ctl_virt_addr);
-			} else if (pdata->prim_auxpcm_mode == 0) {
-					iowrite32(PRI_TLMM_CLKS_EN_SLAVE,
-				  lpass_gpio_mux_spkr_ctl_virt_addr);
-			} else {
-				dev_err(card->dev, "%s Invalid primary auxpcm mode\n",
-				__func__);
-				ret = -EINVAL;
-			}
-		} else {
-			dev_err(card->dev, "%s lpass_mux_spkr_ctl_virt_addr is NULL\n",
-			__func__);
-			ret = -EINVAL;
-		}
-	} else {
-		dev_err(card->dev, "%s lpaif_pri_muxsel_virt_addr is NULL\n",
-		       __func__);
-		ret = -EINVAL;
-		goto done;
-	}
-	afe_enable_lpass_core_shared_clock(MI2S_RX, CLOCK_OFF);
-done:
-	return ret;
-}
-
-static struct snd_soc_ops mdm_auxpcm_be_ops = {
-	.startup = mdm_auxpcm_startup,
-};
-
-static int mdm_sec_auxpcm_startup(struct snd_pcm_substream *substream)
-{
-	int ret = 0;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_card *card = rtd->card;
-	struct mdm_machine_data *pdata = snd_soc_card_get_drvdata(card);
-
-	if (lpaif_sec_muxsel_virt_addr != NULL) {
-		ret = afe_enable_lpass_core_shared_clock(MI2S_RX, CLOCK_ON);
-		if (ret < 0) {
-			ret = -EINVAL;
-			goto done;
-		}
-		iowrite32(PCM_SEL << I2S_PCM_SEL_OFFSET,
-			  lpaif_sec_muxsel_virt_addr);
-		if (lpass_gpio_mux_mic_ctl_virt_addr != NULL) {
-			if (pdata->sec_auxpcm_mode == 1) {
-				iowrite32(SEC_TLMM_CLKS_EN_MASTER,
-				  lpass_gpio_mux_mic_ctl_virt_addr);
-			} else if (pdata->sec_auxpcm_mode == 0) {
-					iowrite32(SEC_TLMM_CLKS_EN_SLAVE,
-					      lpass_gpio_mux_mic_ctl_virt_addr);
-			} else {
-				dev_err(card->dev, "%s Invalid primary auxpcm mode\n",
-						__func__);
-						ret = -EINVAL;
-			}
-		} else {
-			dev_err(card->dev,
-				"%s lpass_gpio_mux_mic_ctl_virt_addr is NULL\n",
-			__func__);
-			ret = -EINVAL;
-		}
-	} else {
-		dev_err(card->dev,
-			"%s lpaif_sec_muxsel_virt_addr is NULL\n", __func__);
-		ret = -EINVAL;
-		goto done;
-	}
-	afe_enable_lpass_core_shared_clock(MI2S_RX, CLOCK_OFF);
-done:
-	return ret;
-}
-
-static struct snd_soc_ops mdm_sec_auxpcm_be_ops = {
-	.startup = mdm_sec_auxpcm_startup,
-};
-
-static int mdm_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
-				   struct snd_ctl_elem_value *ucontrol)
-{
-	ucontrol->value.integer.value[0] = mdm_auxpcm_rate;
-	return 0;
-}
-
-static int mdm_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
-				   struct snd_ctl_elem_value *ucontrol)
-{
-	switch (ucontrol->value.integer.value[0]) {
-	case 0:
-		mdm_auxpcm_rate = 8000;
-		break;
-	case 1:
-		mdm_auxpcm_rate = 16000;
-		break;
-	default:
-		mdm_auxpcm_rate = 8000;
-		break;
-	}
-	return 0;
-}
-
-static int mdm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
-					  struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate =
-		hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
-
-	struct snd_interval *channels =
-		hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
-
-	rate->min = rate->max = mdm_auxpcm_rate;
-	channels->min = channels->max = 1;
-
-	return 0;
-}
-
-static const char *const mi2s_rx_ch_text[] = {"One", "Two"};
-static const char *const mi2s_tx_ch_text[] = {"One", "Two"};
-static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
-
-static const char *const mi2s_rx_rate_text[] = {"rate_8000",
-						"rate_16000", "rate_48000"};
-static const char *const mi2s_tx_rate_text[] = {"rate_8000",
-						"rate_16000", "rate_48000"};
-
-static const struct soc_enum mdm_enum[] = {
-	SOC_ENUM_SINGLE_EXT(2, mi2s_rx_ch_text),
-	SOC_ENUM_SINGLE_EXT(2, mi2s_tx_ch_text),
-	SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
-	SOC_ENUM_SINGLE_EXT(3, mi2s_rx_rate_text),
-	SOC_ENUM_SINGLE_EXT(3, mi2s_tx_rate_text),
-};
-
-static const struct snd_kcontrol_new mdm_snd_controls[] = {
-	SOC_ENUM_EXT("MI2S_RX Channels",   mdm_enum[0],
-				 mdm_mi2s_rx_ch_get,
-				 mdm_mi2s_rx_ch_put),
-	SOC_ENUM_EXT("MI2S_TX Channels",   mdm_enum[1],
-				 mdm_mi2s_tx_ch_get,
-				 mdm_mi2s_tx_ch_put),
-	SOC_ENUM_EXT("AUX PCM SampleRate", mdm_enum[2],
-				 mdm_auxpcm_rate_get,
-				 mdm_auxpcm_rate_put),
-	SOC_ENUM_EXT("MI2S Rx SampleRate", mdm_enum[3],
-				 mdm_mi2s_rx_rate_get,
-				 mdm_mi2s_rx_rate_put),
-	SOC_ENUM_EXT("MI2S Tx SampleRate", mdm_enum[4],
-				 mdm_mi2s_tx_rate_get,
-				 mdm_mi2s_tx_rate_put),
-	SOC_ENUM_EXT("SEC_MI2S_RX Channels",   mdm_enum[0],
-				 mdm_sec_mi2s_rx_ch_get,
-				 mdm_sec_mi2s_rx_ch_put),
-	SOC_ENUM_EXT("SEC_MI2S_TX Channels",   mdm_enum[1],
-				 mdm_sec_mi2s_tx_ch_get,
-				 mdm_sec_mi2s_tx_ch_put),
-	SOC_ENUM_EXT("SEC MI2S Rx SampleRate", mdm_enum[3],
-				 mdm_sec_mi2s_rx_rate_get,
-				 mdm_sec_mi2s_rx_rate_put),
-	SOC_ENUM_EXT("SEC MI2S Tx SampleRate", mdm_enum[4],
-				 mdm_sec_mi2s_tx_rate_get,
-				 mdm_sec_mi2s_tx_rate_put),
-};
-
-static int mdm_mi2s_audrx_init(struct snd_soc_pcm_runtime *rtd)
-{
-	int ret = 0;
-	struct snd_soc_codec *codec = rtd->codec;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	pr_debug("%s dev_name %s\n", __func__, dev_name(cpu_dai->dev));
-
-	rtd->pmdown_time = 0;
-	ret = snd_soc_add_codec_controls(codec, mdm_snd_controls,
-					 ARRAY_SIZE(mdm_snd_controls));
-	if (ret < 0) {
-		pr_err("%s: add_codec_controls failed, %d\n",
-			__func__, ret);
-		goto done;
-	}
-
-done:
-	return ret;
-}
-
-/* Digital audio interface connects codec <---> CPU */
-static struct snd_soc_dai_link mdm_dai[] = {
-	/* FrontEnd DAI Links */
-	{
-		.name = "MDM Media1",
-		.stream_name = "MultiMedia1",
-		.cpu_dai_name = "MultiMedia1",
-		.platform_name  = "msm-pcm-dsp.0",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 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_MULTIMEDIA1
-	},
-	{
-		.name = "MSM VoIP",
-		.stream_name = "VoIP",
-		.cpu_dai_name = "VoIP",
-		.platform_name  = "msm-voip-dsp",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 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 VOIP support */
-		.ignore_pmdown_time = 1,
-		.be_id = MSM_FRONTEND_DAI_VOIP,
-	},
-	{
-		.name = "Circuit-Switch Voice",
-		.stream_name = "CS-Voice",
-		.cpu_dai_name   = "CS-VOICE",
-		.platform_name  = "msm-pcm-voice",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 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 Voice support */
-		.ignore_pmdown_time = 1,
-		.be_id = MSM_FRONTEND_DAI_CS_VOICE,
-	},
-	{
-		.name = "Primary MI2S RX Hostless",
-		.stream_name = "Primary MI2S_RX Hostless Playback",
-		.cpu_dai_name = "PRI_MI2S_RX_HOSTLESS",
-		.platform_name  = "msm-pcm-hostless",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 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,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-	},
-	{
-		.name = "VoLTE",
-		.stream_name = "VoLTE",
-		.cpu_dai_name   = "VoLTE",
-		.platform_name  = "msm-pcm-voice",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 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",
-		.be_id = MSM_FRONTEND_DAI_VOLTE,
-	},
-	{	.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,
-	},
-	{
-		.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,
-	},
-	{
-		.name = "DTMF RX Hostless",
-		.stream_name = "DTMF RX Hostless",
-		.cpu_dai_name	= "DTMF_RX_HOSTLESS",
-		.platform_name	= "msm-pcm-dtmf",
-		.dynamic = 1,
-		.dpcm_playback = 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,
-		.ignore_pmdown_time = 1,
-		.be_id = MSM_FRONTEND_DAI_DTMF_RX,
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-	},
-	{
-		.name = "DTMF TX",
-		.stream_name = "DTMF TX",
-		.cpu_dai_name = "msm-dai-stub-dev.4",
-		.platform_name = "msm-pcm-dtmf",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.ignore_suspend = 1,
-	},
-	{
-		.name = "CS-VOICE HOST RX CAPTURE",
-		.stream_name = "CS-VOICE HOST RX CAPTURE",
-		.cpu_dai_name = "msm-dai-stub-dev.5",
-		.platform_name  = "msm-voice-host-pcm",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.ignore_suspend = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-	},
-	{
-		.name = "CS-VOICE HOST RX PLAYBACK",
-		.stream_name = "CS-VOICE HOST RX PLAYBACK",
-		.cpu_dai_name = "msm-dai-stub-dev.6",
-		.platform_name  = "msm-voice-host-pcm",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-	},
-	{
-		.name = "CS-VOICE HOST TX CAPTURE",
-		.stream_name = "CS-VOICE HOST TX CAPTURE",
-		.cpu_dai_name = "msm-dai-stub-dev.7",
-		.platform_name  = "msm-voice-host-pcm",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.ignore_suspend = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-	},
-	{
-		.name = "CS-VOICE HOST TX PLAYBACK",
-		.stream_name = "CS-VOICE HOST TX PLAYBACK",
-		.cpu_dai_name = "msm-dai-stub-dev.8",
-		.platform_name  = "msm-voice-host-pcm",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.ignore_suspend = 1,
-		 .ignore_pmdown_time = 1,
-	},
-	{
-		.name = "MDM Media2",
-		.stream_name = "MultiMedia2",
-		.cpu_dai_name   = "MultiMedia2",
-		.platform_name  = "msm-pcm-dsp.0",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 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,
-		.ignore_pmdown_time = 1,
-		/* this dainlink has playback support */
-		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
-	},
-	{
-		.name = "MDM Media6",
-		.stream_name = "MultiMedia6",
-		.cpu_dai_name   = "MultiMedia6",
-		.platform_name  = "msm-pcm-loopback",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 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,
-		.ignore_pmdown_time = 1,
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		/* this dainlink has playback support */
-		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
-	},
-	{
-		.name = "Primary MI2S TX Hostless",
-		.stream_name = "Primary MI2S_TX Hostless Playback",
-		.cpu_dai_name = "PRI_MI2S_TX_HOSTLESS",
-		.platform_name  = "msm-pcm-hostless",
-		.dynamic = 1,
-		.dpcm_capture = 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,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-	},
-	{
-		.name = "MDM LowLatency",
-		.stream_name = "MultiMedia5",
-		.cpu_dai_name   = "MultiMedia5",
-		.platform_name  = "msm-pcm-dsp.1",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 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,
-	},
-	{
-		.name = "MDM VoiceMMode1",
-		.stream_name = "VoiceMMode1",
-		.cpu_dai_name   = "VoiceMMode1",
-		.platform_name  = "msm-pcm-voice",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 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 Voice support */
-		.ignore_pmdown_time = 1,
-		.be_id = MSM_FRONTEND_DAI_VOICEMMODE1,
-	},
-	{
-		.name = "MDM VoiceMMode2",
-		.stream_name = "VoiceMMode2",
-		.cpu_dai_name   = "VoiceMMode2",
-		.platform_name  = "msm-pcm-voice",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 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 Voice support */
-		.ignore_pmdown_time = 1,
-		.be_id = MSM_FRONTEND_DAI_VOICEMMODE2,
-	},
-	{
-		.name = "VoiceMMode1 HOST RX CAPTURE",
-		.stream_name = "VoiceMMode1 HOST RX CAPTURE",
-		.cpu_dai_name = "msm-dai-stub-dev.5",
-		.platform_name  = "msm-voice-host-pcm",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.ignore_suspend = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-	},
-	{
-		.name = "VoiceMMode1 HOST RX PLAYBACK",
-		.stream_name = "VoiceMMode1 HOST RX PLAYBACK",
-		.cpu_dai_name = "msm-dai-stub-dev.6",
-		.platform_name  = "msm-voice-host-pcm",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-	},
-	{
-		.name = "VoiceMMode1 HOST TX CAPTURE",
-		.stream_name = "VoiceMMode1 HOST TX CAPTURE",
-		.cpu_dai_name = "msm-dai-stub-dev.7",
-		.platform_name  = "msm-voice-host-pcm",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.ignore_suspend = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-	},
-	{
-		.name = "VoiceMMode1 HOST TX PLAYBACK",
-		.stream_name = "VoiceMMode1 HOST TX PLAYBACK",
-		.cpu_dai_name = "msm-dai-stub-dev.8",
-		.platform_name  = "msm-voice-host-pcm",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.ignore_suspend = 1,
-		 .ignore_pmdown_time = 1,
-	},
-	{
-		.name = "VoiceMMode2 HOST RX CAPTURE",
-		.stream_name = "VoiceMMode2 HOST RX CAPTURE",
-		.cpu_dai_name = "msm-dai-stub-dev.5",
-		.platform_name  = "msm-voice-host-pcm",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.ignore_suspend = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-	},
-	{
-		.name = "VoiceMMode2 HOST RX PLAYBACK",
-		.stream_name = "VOiceMMode2 HOST RX PLAYBACK",
-		.cpu_dai_name = "msm-dai-stub-dev.6",
-		.platform_name  = "msm-voice-host-pcm",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-	},
-	{
-		.name = "VoiceMMode2 HOST TX CAPTURE",
-		.stream_name = "VoiceMMode2 HOST TX CAPTURE",
-		.cpu_dai_name = "msm-dai-stub-dev.7",
-		.platform_name  = "msm-voice-host-pcm",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.ignore_suspend = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-	},
-	{
-		.name = "VoiceMMode2 HOST TX PLAYBACK",
-		.stream_name = "VOiceMMode2 HOST TX PLAYBACK",
-		.cpu_dai_name = "msm-dai-stub-dev.8",
-		.platform_name  = "msm-voice-host-pcm",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.ignore_suspend = 1,
-		 .ignore_pmdown_time = 1,
-	},
-	/* Backend DAI Links */
-	{
-		.name = LPASS_BE_PRI_MI2S_RX,
-		.stream_name = "Primary MI2S Playback",
-		.cpu_dai_name = "msm-dai-q6-mi2s.0",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "tlv320aic3x-codec",
-		.codec_dai_name = "tlv320aic3x-hifi",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.be_id = MSM_BACKEND_DAI_PRI_MI2S_RX,
-		.init  = &mdm_mi2s_audrx_init,
-		.be_hw_params_fixup = &mdm_mi2s_rx_be_hw_params_fixup,
-		.ops = &mdm_mi2s_be_ops,
-		.ignore_pmdown_time = 1,
-		.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 = "tlv320aic3x-codec",
-		.codec_dai_name = "tlv320aic3x-hifi",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
-		.be_hw_params_fixup = &mdm_mi2s_tx_be_hw_params_fixup,
-		.ops = &mdm_mi2s_be_ops,
-		.ignore_pmdown_time = 1,
-		.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,
-		.dpcm_playback = 1,
-		.be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
-		.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,
-		.dpcm_capture = 1,
-		.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
-		.ignore_suspend = 1,
-	},
-	{
-		.name = LPASS_BE_AUXPCM_RX,
-		.stream_name = "AUX PCM Playback",
-		.cpu_dai_name = "msm-dai-q6-auxpcm.1",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.be_id = MSM_BACKEND_DAI_AUXPCM_RX,
-		.be_hw_params_fixup = mdm_auxpcm_be_params_fixup,
-		.ops = &mdm_auxpcm_be_ops,
-		.ignore_pmdown_time = 1,
-		/* this dainlink has playback support */
-		.ignore_suspend = 1,
-	},
-	{
-		.name = LPASS_BE_AUXPCM_TX,
-		.stream_name = "AUX PCM Capture",
-		.cpu_dai_name = "msm-dai-q6-auxpcm.1",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
-		.be_hw_params_fixup = mdm_auxpcm_be_params_fixup,
-		.ops = &mdm_auxpcm_be_ops,
-		.ignore_suspend = 1,
-	},
-	{
-		.name = LPASS_BE_SEC_AUXPCM_RX,
-		.stream_name = "Sec AUX PCM Playback",
-		.cpu_dai_name = "msm-dai-q6-auxpcm.2",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.be_id = MSM_BACKEND_DAI_SEC_AUXPCM_RX,
-		.be_hw_params_fixup = mdm_auxpcm_be_params_fixup,
-		.ops = &mdm_sec_auxpcm_be_ops,
-		.ignore_pmdown_time = 1,
-		.ignore_suspend = 1,
-	},
-	{
-		.name = LPASS_BE_SEC_AUXPCM_TX,
-		.stream_name = "Sec AUX PCM Capture",
-		.cpu_dai_name = "msm-dai-q6-auxpcm.2",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.be_id = MSM_BACKEND_DAI_SEC_AUXPCM_TX,
-		.be_hw_params_fixup = mdm_auxpcm_be_params_fixup,
-		.ops = &mdm_sec_auxpcm_be_ops,
-		.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,
-		.dpcm_capture = 1,
-		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
-		.be_hw_params_fixup = mdm_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,
-		.dpcm_capture = 1,
-		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
-		.be_hw_params_fixup = mdm_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,
-		.dpcm_playback = 1,
-		.be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
-		.be_hw_params_fixup = mdm_be_hw_params_fixup,
-		.ignore_suspend = 1,
-	},
-	{
-		.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 = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
-		.be_hw_params_fixup = &mdm_sec_mi2s_rx_be_hw_params_fixup,
-		.ops = &mdm_sec_mi2s_be_ops,
-		.ignore_pmdown_time = 1,
-		.ignore_suspend = 1,
-	},
-	{
-		.name = LPASS_BE_SEC_MI2S_TX,
-		.stream_name = "Secondary MI2S Capture",
-		.cpu_dai_name = "msm-dai-q6-mi2s.1",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
-		.be_hw_params_fixup = &mdm_sec_mi2s_tx_be_hw_params_fixup,
-		.ops = &mdm_sec_mi2s_be_ops,
-		.ignore_pmdown_time = 1,
-		.ignore_suspend = 1,
-	},
-};
-
-static struct snd_soc_card snd_soc_card_mdm = {
-	.name = "mdm-auto-i2s-snd-card",
-	.dai_link = mdm_dai,
-	.num_links = ARRAY_SIZE(mdm_dai),
-};
-
-static int mdm_populate_dai_link_component_of_node(
-					struct snd_soc_card *card)
-{
-	int i, index, ret = 0;
-	struct device *cdev = card->dev;
-	struct snd_soc_dai_link *dai_link = card->dai_link;
-	struct device_node *np;
-
-	if (!cdev) {
-		pr_err("%s: Sound card device memory NULL\n", __func__);
-		return -ENODEV;
-	}
-
-	for (i = 0; i < card->num_links; i++) {
-		if (dai_link[i].platform_of_node && dai_link[i].cpu_of_node)
-			continue;
-
-		/* populate platform_of_node for snd card dai links */
-		if (dai_link[i].platform_name &&
-		    !dai_link[i].platform_of_node) {
-			index = of_property_match_string(cdev->of_node,
-						"asoc-platform-names",
-						dai_link[i].platform_name);
-			if (index < 0) {
-				pr_debug("%s: No match found for platform name: %s\n",
-					__func__, dai_link[i].platform_name);
-				ret = index;
-				goto err;
-			}
-
-			np = of_parse_phandle(cdev->of_node, "asoc-platform",
-					      index);
-			if (!np) {
-				pr_err("%s: retrieving phandle for platform %s, index %d failed\n",
-					__func__, dai_link[i].platform_name,
-					index);
-				ret = -ENODEV;
-				goto err;
-			}
-			dai_link[i].platform_of_node = np;
-			dai_link[i].platform_name = NULL;
-		}
-
-		/* populate cpu_of_node for snd card dai links */
-		if (dai_link[i].cpu_dai_name && !dai_link[i].cpu_of_node) {
-			index = of_property_match_string(cdev->of_node,
-						 "asoc-cpu-names",
-						 dai_link[i].cpu_dai_name);
-			if (index >= 0) {
-				np = of_parse_phandle(cdev->of_node, "asoc-cpu",
-						index);
-				if (!np) {
-					pr_err("%s: retrieving phandle for cpu dai %s failed\n",
-						__func__,
-						dai_link[i].cpu_dai_name);
-					ret = -ENODEV;
-					goto err;
-				}
-				dai_link[i].cpu_of_node = np;
-				dai_link[i].cpu_dai_name = NULL;
-			}
-		}
-
-		/* populate codec_of_node for snd card dai links */
-		if (dai_link[i].codec_name && !dai_link[i].codec_of_node) {
-			index = of_property_match_string(cdev->of_node,
-						 "asoc-codec-names",
-						 dai_link[i].codec_name);
-			if (index < 0)
-				continue;
-			np = of_parse_phandle(cdev->of_node, "asoc-codec",
-					      index);
-			if (!np) {
-				pr_err("%s: retrieving phandle for codec %s failed\n",
-					__func__, dai_link[i].codec_name);
-				ret = -ENODEV;
-				goto err;
-			}
-			dai_link[i].codec_of_node = np;
-			dai_link[i].codec_name = NULL;
-		}
-	}
-
-err:
-	return ret;
-}
-
-static int mdm_populate_mi2s_interface_mode(
-					struct snd_soc_card *card)
-{
-	int size, ret = 0;
-	struct device *cdev = card->dev;
-	struct mdm_machine_data *pdata = snd_soc_card_get_drvdata(card);
-	const char *val_array[MI2S_PCM_MAX_INTF];
-
-	size = of_property_read_string_array(cdev->of_node,
-					"qcom,mi2s-interface-mode",
-					val_array, MI2S_PCM_MAX_INTF);
-	if (size <= 0) {
-		dev_info(cdev, "%s: Looking up %s property in node %s failed",
-			__func__, "qcom,mi2s-interface-mode",
-			cdev->of_node->full_name);
-		pdata->prim_mi2s_mode = I2S_PCM_MASTER_MODE;
-		pdata->sec_mi2s_mode = I2S_PCM_MASTER_MODE;
-	} else {
-		if (!strcmp(val_array[PRI_MI2S_PCM], "pri_mi2s_master")) {
-			pdata->prim_mi2s_mode = I2S_PCM_MASTER_MODE;
-		} else if (!strcmp(val_array[PRI_MI2S_PCM], "pri_mi2s_slave")) {
-			pdata->prim_mi2s_mode = I2S_PCM_SLAVE_MODE;
-		} else {
-			dev_err(cdev, "%s: invalid DT intf mode\n",
-					__func__);
-			ret = -EINVAL;
-			goto err_intf;
-		}
-
-		if (!strcmp(val_array[SEC_MI2S_PCM], "sec_mi2s_master")) {
-			pdata->sec_mi2s_mode = I2S_PCM_MASTER_MODE;
-		} else if (!strcmp(val_array[SEC_MI2S_PCM], "sec_mi2s_slave")) {
-			pdata->sec_mi2s_mode = I2S_PCM_SLAVE_MODE;
-		} else {
-			dev_err(cdev, "%s: invalid DT intf mode\n",
-				__func__);
-			ret = -EINVAL;
-		}
-	}
-err_intf:
-	return ret;
-}
-
-static int mdm_populate_auxpcm_interface_mode(
-					struct snd_soc_card *card)
-{
-	int size, ret = 0;
-	struct device *cdev = card->dev;
-	struct mdm_machine_data *pdata = snd_soc_card_get_drvdata(card);
-	const char *val_array[MI2S_PCM_MAX_INTF];
-
-	size = of_property_read_string_array(cdev->of_node,
-				"qcom,auxpcm-interface-mode",
-				val_array, MI2S_PCM_MAX_INTF);
-	if (size <= 0) {
-		dev_info(cdev, "%s: Looking up %s property in node %s failed",
-			__func__, "qcom,auxpcm-interface-mode",
-			cdev->of_node->full_name);
-		pdata->prim_auxpcm_mode = I2S_PCM_MASTER_MODE;
-		pdata->sec_auxpcm_mode = I2S_PCM_MASTER_MODE;
-	} else {
-		if (!strcmp(val_array[PRI_MI2S_PCM], "pri_pcm_master")) {
-			pdata->prim_auxpcm_mode = I2S_PCM_MASTER_MODE;
-		} else if (!strcmp(val_array[PRI_MI2S_PCM], "pri_pcm_slave")) {
-			pdata->prim_auxpcm_mode = I2S_PCM_SLAVE_MODE;
-		} else {
-			dev_err(cdev, "%s: invalid DT intf mode\n",
-				__func__);
-			ret = -EINVAL;
-			goto err_intf;
-		}
-		if (!strcmp(val_array[SEC_MI2S_PCM], "sec_pcm_master")) {
-			pdata->sec_auxpcm_mode = I2S_PCM_MASTER_MODE;
-		} else if (!strcmp(val_array[SEC_MI2S_PCM], "sec_pcm_slave")) {
-			pdata->sec_auxpcm_mode = I2S_PCM_SLAVE_MODE;
-		} else {
-			dev_err(cdev, "%s: invalid DT intf mode\n",
-				__func__);
-			ret = -EINVAL;
-		}
-	}
-err_intf:
-	return ret;
-}
-
-static int mdm_asoc_machine_probe(struct platform_device *pdev)
-{
-	int ret;
-	struct mdm_machine_data *pdata;
-	struct snd_soc_card *card = &snd_soc_card_mdm;
-
-	if (!pdev->dev.of_node) {
-		dev_err(&pdev->dev,
-			"%s No platform supplied from device tree\n", __func__);
-
-		return -EINVAL;
-	}
-	pdata = devm_kzalloc(&pdev->dev, sizeof(struct mdm_machine_data),
-			     GFP_KERNEL);
-	if (!pdata)
-		return -ENOMEM;
-
-	/* At present only 12.288MHz is supported on MDM. */
-	pdata->mclk_freq = MDM_MCLK_CLK_12P288MHZ;
-	if (q6afe_check_osr_clk_freq(pdata->mclk_freq)) {
-		dev_err(&pdev->dev, "%s Unsupported mclk freq %u\n",
-			__func__, pdata->mclk_freq);
-
-		ret = -EINVAL;
-		goto err;
-	}
-
-	atomic_set(&mi2s_ref_count, 0);
-	atomic_set(&sec_mi2s_ref_count, 0);
-	pdata->prim_clk_usrs = 0;
-
-	card->dev = &pdev->dev;
-	platform_set_drvdata(pdev, card);
-	snd_soc_card_set_drvdata(card, pdata);
-
-	ret = snd_soc_of_parse_card_name(card, "qcom,model");
-	if (ret)
-		goto err;
-
-	ret = mdm_populate_mi2s_interface_mode(card);
-	if (ret)
-		goto err;
-
-	ret = mdm_populate_auxpcm_interface_mode(card);
-	if (ret)
-		goto err;
-
-	ret = mdm_populate_dai_link_component_of_node(card);
-	if (ret) {
-		ret = -EPROBE_DEFER;
-		goto err;
-	}
-
-	ret = snd_soc_register_card(card);
-	if (ret == -EPROBE_DEFER) {
-		goto err;
-	} else if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
-		goto err;
-	}
-
-	lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
-	if (lpaif_pri_muxsel_virt_addr == NULL) {
-		pr_err("%s Pri muxsel virt addr is null\n", __func__);
-
-		ret = -EINVAL;
-		goto err;
-	}
-	lpass_gpio_mux_spkr_ctl_virt_addr =
-				ioremap(LPASS_CSR_GP_IO_MUX_SPKR_CTL, 4);
-	if (lpass_gpio_mux_spkr_ctl_virt_addr == NULL) {
-		pr_err("%s lpass spkr ctl virt addr is null\n", __func__);
-
-		ret = -EINVAL;
-		goto err1;
-	}
-
-	lpaif_sec_muxsel_virt_addr = ioremap(LPAIF_SEC_MODE_MUXSEL, 4);
-	if (lpaif_sec_muxsel_virt_addr == NULL) {
-		pr_err("%s Sec muxsel virt addr is null\n", __func__);
-		ret = -EINVAL;
-		goto err2;
-	}
-
-	lpass_gpio_mux_mic_ctl_virt_addr =
-				ioremap(LPASS_CSR_GP_IO_MUX_MIC_CTL, 4);
-	if (lpass_gpio_mux_mic_ctl_virt_addr == NULL) {
-		pr_err("%s lpass_gpio_mux_mic_ctl_virt_addr is null\n",
-		       __func__);
-		ret = -EINVAL;
-		goto err3;
-	}
-
-	return 0;
-err3:
-	iounmap(lpaif_sec_muxsel_virt_addr);
-err2:
-	iounmap(lpass_gpio_mux_spkr_ctl_virt_addr);
-err1:
-	iounmap(lpaif_pri_muxsel_virt_addr);
-err:
-	devm_kfree(&pdev->dev, pdata);
-	return ret;
-}
-
-static int mdm_asoc_machine_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-	struct mdm_machine_data *pdata = snd_soc_card_get_drvdata(card);
-
-	pdata->mclk_freq = 0;
-	iounmap(lpaif_pri_muxsel_virt_addr);
-	iounmap(lpass_gpio_mux_spkr_ctl_virt_addr);
-	iounmap(lpaif_sec_muxsel_virt_addr);
-	iounmap(lpass_gpio_mux_mic_ctl_virt_addr);
-	snd_soc_unregister_card(card);
-
-	return 0;
-}
-
-static const struct of_device_id mdm_asoc_machine_of_match[]  = {
-	{ .compatible = "qcom,mdm-audio-auto", },
-	{},
-};
-
-static struct platform_driver mdm_asoc_machine_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-		.pm = &snd_soc_pm_ops,
-		.of_match_table = mdm_asoc_machine_of_match,
-	},
-	.probe = mdm_asoc_machine_probe,
-	.remove = mdm_asoc_machine_remove,
-};
-
-static int dummy_machine_probe(struct platform_device *pdev)
-{
-	return 0;
-}
-
-static int dummy_machine_remove(struct platform_device *pdev)
-{
-	return 0;
-}
-
-static struct platform_device dummy_machine_device = {
-	.name = "dummymachinedriverauto",
-};
-
-static struct platform_driver mdm_asoc_machine_dummy_driver = {
-	.driver = {
-		.name = "dummymachinedriverauto",
-		.owner = THIS_MODULE,
-	},
-	.probe = dummy_machine_probe,
-	.remove = dummy_machine_remove,
-};
-
-static int  mdm_adsp_state_callback(struct notifier_block *nb,
-					unsigned long value, void *priv)
-{
-	if (!dummy_device_registered && SUBSYS_AFTER_POWERUP == value) {
-		platform_driver_register(&mdm_asoc_machine_dummy_driver);
-		platform_device_register(&dummy_machine_device);
-		dummy_device_registered = true;
-	}
-
-		return NOTIFY_OK;
-}
-
-static struct notifier_block adsp_state_notifier_block = {
-	.notifier_call = mdm_adsp_state_callback,
-	.priority = -INT_MAX,
-};
-
-static int __init mdm_soc_platform_init(void)
-{
-	adsp_state_notifier = subsys_notif_register_notifier("modem",
-						&adsp_state_notifier_block);
-	return 0;
-}
-
-module_init(mdm_soc_platform_init);
-
-module_platform_driver(mdm_asoc_machine_driver);
-
-MODULE_DESCRIPTION("ALSA SoC msm");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" MDM9650_MACHINE_DRV_NAME);
-MODULE_DEVICE_TABLE(of, mdm9650_asoc_machine_of_match);
diff --git a/sound/soc/msm/mdm9650.c b/sound/soc/msm/mdm9650.c
index cdf2c7e..34a8c7a 100644
--- a/sound/soc/msm/mdm9650.c
+++ b/sound/soc/msm/mdm9650.c
@@ -34,6 +34,7 @@
 #include "../codecs/wcd9xxx-common.h"
 #include "../codecs/wcd9335.h"
 #include "../codecs/wsa881x.h"
+#include "../codecs/tlv320aic3x.h"
 
 /* Spk control */
 #define MDM_SPK_ON 1
@@ -77,7 +78,7 @@
 #define CLOCK_OFF 0
 
 /* Machine driver Name*/
-#define DRV_NAME "mdm9650-asoc-tasha"
+#define DRV_NAME "mdm9650-asoc-snd"
 
 enum mi2s_pcm_mux {
 	PRI_MI2S_PCM,
@@ -229,6 +230,7 @@
 				u16 mode)
 {
 	struct snd_soc_card *card = rtd->card;
+	struct mdm_machine_data *pdata = snd_soc_card_get_drvdata(card);
 	struct afe_clk_cfg lpass_clks = lpass_default;
 	int bit_clk_freq = (rate * 2 * NO_OF_BITS_PER_SAMPLE);
 	int ret;
@@ -236,10 +238,19 @@
 	dev_dbg(card->dev, "%s: Setting clock using v1\n", __func__);
 
 	if (mode) {
-		lpass_clks.clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID;
-		lpass_clks.clk_val1 = bit_clk_freq;
-		if (!enable)
+		/* enable mclk for the automotive card */
+		if (!strcmp(card->name, "mdm-auto-i2s-snd-card"))
+			lpass_clks.clk_set_mode = Q6AFE_LPASS_MODE_BOTH_VALID;
+		else
+			lpass_clks.clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID;
+
+		if (enable) {
+			lpass_clks.clk_val1 = bit_clk_freq;
+			lpass_clks.clk_val2 = pdata->mclk_freq;
+		} else {
 			lpass_clks.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+			lpass_clks.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+		}
 
 		ret = afe_set_lpass_clock(mi2s_port, &lpass_clks);
 		if (ret < 0) {
@@ -440,7 +451,8 @@
 				goto err;
 			}
 			ret = snd_soc_dai_set_fmt(codec_dai,
-					SND_SOC_DAIFMT_CBS_CFS);
+					SND_SOC_DAIFMT_CBS_CFS |
+					SND_SOC_DAIFMT_I2S);
 			if (ret < 0) {
 				mdm_mi2s_clk_ctl(rtd, false,
 						0, pdata->prim_mi2s_mode);
@@ -448,6 +460,12 @@
 					"%s Set fmt for codec dai failed\n",
 					__func__);
 			}
+			ret = snd_soc_dai_set_sysclk(codec_dai,
+					CLKIN_MCLK,
+					pdata->mclk_freq, SND_SOC_CLOCK_OUT);
+			if (ret < 0)
+				pr_err("%s Set sysclk for codec dai failed\n",
+					__func__);
 		} else {
 			/*
 			 * Disable bit clk in slave mode for QC codec.
@@ -1499,6 +1517,27 @@
 	return ret;
 }
 
+static int mdm_mi2s_audrx_init_auto(struct snd_soc_pcm_runtime *rtd)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+	pr_debug("%s dev_name %s\n", __func__, dev_name(cpu_dai->dev));
+
+	rtd->pmdown_time = 0;
+	ret = snd_soc_add_codec_controls(codec, mdm_snd_controls,
+					 ARRAY_SIZE(mdm_snd_controls));
+	if (ret < 0) {
+		pr_err("%s: add_codec_controls failed, %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+done:
+	return ret;
+}
+
 static void *def_tasha_mbhc_cal(void)
 {
 	void *tasha_wcd_cal;
@@ -1914,37 +1953,6 @@
 	},
 	/* Backend DAI Links */
 	{
-		.name = LPASS_BE_PRI_MI2S_RX,
-		.stream_name = "Primary MI2S Playback",
-		.cpu_dai_name = "msm-dai-q6-mi2s.0",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "tasha_codec",
-		.codec_dai_name = "tasha_i2s_rx1",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.be_id = MSM_BACKEND_DAI_PRI_MI2S_RX,
-		.init  = &mdm_mi2s_audrx_init,
-		.be_hw_params_fixup = &mdm_mi2s_rx_be_hw_params_fixup,
-		.ops = &mdm_mi2s_be_ops,
-		.ignore_pmdown_time = 1,
-		.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 = "tasha_codec",
-		.codec_dai_name = "tasha_i2s_tx1",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
-		.be_hw_params_fixup = &mdm_mi2s_tx_be_hw_params_fixup,
-		.ops = &mdm_mi2s_be_ops,
-		.ignore_pmdown_time = 1,
-		.ignore_suspend = 1,
-	},
-	{
 		.name = LPASS_BE_AFE_PCM_RX,
 		.stream_name = "AFE Playback",
 		.cpu_dai_name = "msm-dai-q6-dev.224",
@@ -2101,10 +2109,86 @@
 	},
 };
 
-static struct snd_soc_card snd_soc_card_mdm = {
+static struct snd_soc_dai_link mdm_tasha_dai[] = {
+	/* Backend DAI Links */
+	{
+		.name = LPASS_BE_PRI_MI2S_RX,
+		.stream_name = "Primary MI2S Playback",
+		.cpu_dai_name = "msm-dai-q6-mi2s.0",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tasha_codec",
+		.codec_dai_name = "tasha_i2s_rx1",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.be_id = MSM_BACKEND_DAI_PRI_MI2S_RX,
+		.init  = &mdm_mi2s_audrx_init,
+		.be_hw_params_fixup = &mdm_mi2s_rx_be_hw_params_fixup,
+		.ops = &mdm_mi2s_be_ops,
+		.ignore_pmdown_time = 1,
+		.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 = "tasha_codec",
+		.codec_dai_name = "tasha_i2s_tx1",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
+		.be_hw_params_fixup = &mdm_mi2s_tx_be_hw_params_fixup,
+		.ops = &mdm_mi2s_be_ops,
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+};
+
+static struct snd_soc_dai_link mdm_auto_dai[] = {
+	/* Backend DAI Links */
+	{
+		.name = LPASS_BE_PRI_MI2S_RX,
+		.stream_name = "Primary MI2S Playback",
+		.cpu_dai_name = "msm-dai-q6-mi2s.0",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tlv320aic3x-codec",
+		.codec_dai_name = "tlv320aic3x-hifi",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.be_id = MSM_BACKEND_DAI_PRI_MI2S_RX,
+		.init  = &mdm_mi2s_audrx_init_auto,
+		.be_hw_params_fixup = &mdm_mi2s_rx_be_hw_params_fixup,
+		.ops = &mdm_mi2s_be_ops,
+		.ignore_pmdown_time = 1,
+		.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 = "tlv320aic3x-codec",
+		.codec_dai_name = "tlv320aic3x-hifi",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
+		.be_hw_params_fixup = &mdm_mi2s_tx_be_hw_params_fixup,
+		.ops = &mdm_mi2s_be_ops,
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+};
+
+static struct snd_soc_dai_link *mdm_tasha_dai_links;
+
+static struct snd_soc_dai_link *mdm_auto_dai_links;
+
+static struct snd_soc_card snd_soc_card_mdm_tasha = {
 	.name = "mdm-tasha-i2s-snd-card",
-	.dai_link = mdm_dai,
-	.num_links = ARRAY_SIZE(mdm_dai),
+};
+
+static struct snd_soc_card snd_soc_card_mdm_auto = {
+	.name = "mdm-auto-i2s-snd-card",
 };
 
 static int mdm_populate_dai_link_component_of_node(
@@ -2357,12 +2441,68 @@
 	return 0;
 }
 
+static const struct of_device_id mdm_asoc_machine_of_match[]  = {
+	{ .compatible = "qcom,mdm-audio-tasha",
+	  .data = "tasha_codec"},
+	{ .compatible = "qcom,mdm-audio-auto",
+	  .data = "auto_codec"},
+	{},
+};
+
+static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
+{
+	struct snd_soc_card *card = NULL;
+	struct snd_soc_dai_link *dailink;
+	const struct of_device_id *match;
+	int len_1, len_2;
+
+	match = of_match_node(mdm_asoc_machine_of_match, dev->of_node);
+	if (!match) {
+		dev_err(dev, "%s: No DT match found for sound card\n",
+				__func__);
+		return NULL;
+	}
+
+	if (!strcmp(match->data, "tasha_codec")) {
+		len_1 = ARRAY_SIZE(mdm_dai);
+		len_2 = len_1 + ARRAY_SIZE(mdm_tasha_dai);
+		mdm_tasha_dai_links = devm_kcalloc(dev, len_2,
+			sizeof(*mdm_tasha_dai_links), GFP_KERNEL);
+		if (!mdm_tasha_dai_links)
+			return NULL;
+		card = &snd_soc_card_mdm_tasha;
+		memcpy(mdm_tasha_dai_links, mdm_dai, sizeof(mdm_dai));
+		memcpy(mdm_tasha_dai_links + len_1, mdm_tasha_dai,
+		       sizeof(mdm_tasha_dai));
+		dailink = mdm_tasha_dai_links;
+	} else if (!strcmp(match->data, "auto_codec")) {
+		len_1 = ARRAY_SIZE(mdm_dai);
+		len_2 = len_1 + ARRAY_SIZE(mdm_auto_dai);
+		mdm_auto_dai_links = devm_kcalloc(dev, len_2,
+			sizeof(*mdm_auto_dai_links), GFP_KERNEL);
+		if (!mdm_auto_dai_links)
+			return NULL;
+		card = &snd_soc_card_mdm_auto;
+		memcpy(mdm_auto_dai_links, mdm_dai, sizeof(mdm_dai));
+		memcpy(mdm_auto_dai_links + len_1, mdm_auto_dai,
+		       sizeof(mdm_auto_dai));
+		dailink = mdm_auto_dai_links;
+	}
+
+	if (card) {
+		card->dai_link = dailink;
+		card->num_links = len_2;
+	}
+
+	return card;
+}
 
 static int mdm_asoc_machine_probe(struct platform_device *pdev)
 {
 	int ret;
 	struct mdm_machine_data *pdata;
-	struct snd_soc_card *card = &snd_soc_card_mdm;
+	struct snd_soc_card *card;
+	const struct of_device_id *match;
 
 	if (!pdev->dev.of_node) {
 		dev_err(&pdev->dev,
@@ -2370,22 +2510,35 @@
 
 		return -EINVAL;
 	}
+
+	match = of_match_node(mdm_asoc_machine_of_match, pdev->dev.of_node);
+	if (!match) {
+		dev_err(&pdev->dev, "%s: No DT match found for sound card\n",
+				__func__);
+		return -EINVAL;
+	}
+
 	pdata = devm_kzalloc(&pdev->dev, sizeof(struct mdm_machine_data),
 			     GFP_KERNEL);
 	if (!pdata)
 		return -ENOMEM;
 
-	ret = of_property_read_u32(pdev->dev.of_node,
-				   "qcom,tasha-mclk-clk-freq",
-				   &pdata->mclk_freq);
-	if (ret) {
-		dev_err(&pdev->dev,
-			"%s Looking up %s property in node %s failed",
-			__func__, "qcom,tasha-mclk-clk-freq",
-			pdev->dev.of_node->full_name);
+	if (!strcmp(match->data, "tasha_codec")) {
+		ret = of_property_read_u32(pdev->dev.of_node,
+					   "qcom,tasha-mclk-clk-freq",
+					   &pdata->mclk_freq);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"%s Looking up %s property in node %s failed",
+				__func__, "qcom,tasha-mclk-clk-freq",
+				pdev->dev.of_node->full_name);
 
-		goto err;
+			goto err;
+		}
+	} else {
+		pdata->mclk_freq = MDM_MCLK_CLK_12P288MHZ;
 	}
+
 	/* At present only 12.288MHz is supported on MDM. */
 	if (q6afe_check_osr_clk_freq(pdata->mclk_freq)) {
 		dev_err(&pdev->dev, "%s Unsupported tasha mclk freq %u\n",
@@ -2408,6 +2561,13 @@
 	atomic_set(&sec_mi2s_ref_count, 0);
 	pdata->prim_clk_usrs = 0;
 
+	card = populate_snd_card_dailinks(&pdev->dev);
+	if (!card) {
+		dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
 	snd_soc_card_set_drvdata(card, pdata);
@@ -2415,18 +2575,23 @@
 	ret = snd_soc_of_parse_card_name(card, "qcom,model");
 	if (ret)
 		goto err;
-	ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing");
-	if (ret)
-		goto err;
+	if (of_property_read_bool(pdev->dev.of_node, "qcom,audio-routing")) {
+		ret = snd_soc_of_parse_audio_routing(card,
+						     "qcom,audio-routing");
+		if (ret)
+			goto err;
+	}
 	ret = mdm_populate_dai_link_component_of_node(card);
 	if (ret) {
 		ret = -EPROBE_DEFER;
 		goto err;
 	}
 
-	ret = mdm_init_wsa_dev(pdev, card);
-	if (ret)
-		goto err;
+	if (!strcmp(match->data, "tasha_codec")) {
+		ret = mdm_init_wsa_dev(pdev, card);
+		if (ret)
+			goto err;
+	}
 
 	ret = snd_soc_register_card(card);
 	if (ret == -EPROBE_DEFER) {
@@ -2497,11 +2662,6 @@
 	return 0;
 }
 
-static const struct of_device_id mdm_asoc_machine_of_match[]  = {
-	{ .compatible = "qcom,mdm-audio-tasha", },
-	{},
-};
-
 static struct platform_driver mdm_asoc_machine_driver = {
 	.driver = {
 		.name = DRV_NAME,
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 8aa3d72..838cc2a 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -1062,6 +1062,9 @@
 	int dir = IN, ret = 0;
 	struct audio_client *ac = prtd->audio_client;
 	uint32_t stream_index;
+	union snd_codec_options *codec_options =
+		&(prtd->codec_param.codec.options);
+
 	struct asm_softpause_params softpause = {
 		.enable = SOFT_PAUSE_ENABLE,
 		.period = SOFT_PAUSE_PERIOD,
@@ -1086,6 +1089,9 @@
 		bits_per_sample = 24;
 	else if (prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S32_LE)
 		bits_per_sample = 32;
+	else if (prtd->codec == FORMAT_FLAC && codec_options &&
+		(codec_options->flac_dec.sample_size != 0))
+		bits_per_sample = codec_options->flac_dec.sample_size;
 
 	if (prtd->compr_passthr != LEGACY_PCM) {
 		ret = q6asm_open_write_compressed(ac, prtd->codec,
@@ -1899,6 +1905,8 @@
 	int stream_id;
 	uint32_t stream_index;
 	uint16_t bits_per_sample = 16;
+	union snd_codec_options *codec_options =
+		&(prtd->codec_param.codec.options);
 
 	spin_lock_irqsave(&prtd->lock, flags);
 	if (atomic_read(&prtd->error)) {
@@ -2318,6 +2326,9 @@
 		else if (prtd->codec_param.codec.format ==
 			 SNDRV_PCM_FORMAT_S32_LE)
 			bits_per_sample = 32;
+		else if (prtd->codec == FORMAT_FLAC && codec_options &&
+			(codec_options->flac_dec.sample_size != 0))
+			bits_per_sample = codec_options->flac_dec.sample_size;
 
 		pr_debug("%s: open_write stream_id %d bits_per_sample %d",
 				__func__, stream_id, bits_per_sample);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 9710ed4..eefae71 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -122,7 +122,7 @@
 
 /* default value is DTS (i.e read from device tree) */
 static char const *msm_pcm_fe_topology_text[] = {
-	"DTS", "ULL", "ULL_PP", "LL" };
+	"DTS", "ULL", "ULL_PP", "LL", "LEGACY" };
 
 static const struct soc_enum msm_pcm_fe_topology_enum[] = {
 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(msm_pcm_fe_topology_text),
@@ -985,6 +985,8 @@
 		pdata->perf_mode_set = ULTRA_LOW_LATENCY_PCM_MODE;
 	else if (!strcmp(msm_pcm_fe_topology_text[topology], "LL"))
 		pdata->perf_mode_set = LOW_LATENCY_PCM_MODE;
+	else if (!strcmp(msm_pcm_fe_topology_text[topology], "LEGACY"))
+		pdata->perf_mode_set = LEGACY_PCM_MODE;
 	else
 		/* use the default from the device tree */
 		pdata->perf_mode_set = pdata->perf_mode;