Merge "msm: kgsl: Dump the A6XX SQE firmware version in the snapshot" into msm-4.9
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_qmp.txt b/Documentation/devicetree/bindings/arm/msm/msm_qmp.txt
new file mode 100644
index 0000000..0a5c0b3
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm_qmp.txt
@@ -0,0 +1,55 @@
+Qualcomm Technologies, Inc. QTI Mailbox Protocol
+
+QMP Driver
+===================
+
+Required properties:
+- compatible : should be "qcom,qmp-mbox".
+- label : the name of the remote proc this link connects to.
+- reg : The location and size of shared memory.
+	The irq register base address for triggering interrupts.
+- reg-names : "msgram" - string to identify the shared memory region.
+	"irq-reg-base" - string to identify the irq register region.
+- qcom,irq-mask : the bitmask to trigger an interrupt.
+- interrupt : the receiving interrupt line.
+- mbox-desc-offset : offset of mailbox descriptor from start of the msgram.
+- #mbox-cells: Common mailbox binding property to identify the number of cells
+		required for the mailbox specifier, should be 1.
+
+Optional properties:
+- mbox-offset : offset of the mcore mailbox from the offset of msgram. If this
+			property is not used, qmp will use the configuration
+			provided by the ucore.
+- mbox-size : size of the mcore mailbox. If this property is not used, qmp will
+			use the configuration provided by the ucore.
+
+Example:
+	qmp_aop: qcom,qmp-aop {
+		compatible = "qcom,qmp-mbox";
+		label = "aop";
+		reg = <0xc300000 0x100000>,
+			<0x1799000C 0x4>;
+		reg-names = "msgram", "irq-reg-base";
+		qcom,irq-mask = <0x1>;
+		interrupt = <0 389 1>;
+		mbox-desc-offset = <0x100>;
+		mbox-offset = <0x500>;
+		mbox-size = <0x400>;
+		#mbox-cells = <1>;
+	};
+
+Mailbox Client
+==============
+"mboxes" and the optional "mbox-names" (please see
+Documentation/devicetree/bindings/mailbox/mailbox.txt for details). Each value
+of the mboxes property should contain a phandle to the mailbox controller
+device node and second argument is the channel index. It must be 0 (qmp
+supports only one channel).The equivalent "mbox-names" property value can be
+used to give a name to the communication channel to be used by the client user.
+
+Example:
+	qmp-client {
+		compatible = "qcom,qmp-client";
+		mbox-names = "aop";
+		mboxes = <&qmp_aop 0>,
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt
index 90ddc27..50488b4 100644
--- a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt
@@ -49,6 +49,16 @@
 	Value Type: <stringlist>
 	Definition: Address names. Must be "llcc"
 
+- llcc-bank-off:
+	Usage: required
+	Value Type: <u32 array>
+	Definition: Offsets of llcc banks from llcc base address starting from
+		    LLCC bank0.
+- llcc-broadcast-off:
+	Usage: required
+	Value Type: <u32>
+	Definition: Offset of broadcast register from LLCC bank0 address.
+
 - #cache-cells:
 	Usage: required
 	Value Type: <u32>
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index 7405115..d95aa59 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -17,6 +17,7 @@
 			"qcom,gcc-msm8996"
 			"qcom,gcc-mdm9615"
 			"qcom,gcc-sdm845"
+			"qcom,debugcc-sdm845"
 
 - reg : shall contain base register location and length
 - #clock-cells : shall contain 1
diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
new file mode 100644
index 0000000..f214c58
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
@@ -0,0 +1,33 @@
+Qualcomm Technologies, Inc. Graphics Clock & Reset Controller Binding
+--------------------------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+		"qcom,gpucc-sdm845",
+		"qcom,gfxcc-sdm845"
+
+- reg : shall contain base register offset and size.
+- #clock-cells : shall contain 1.
+- #reset-cells : shall contain 1.
+- #vdd_<rail>-supply : The logic rail supply.
+
+Optional properties :
+- #power-domain-cells : shall contain 1.
+
+Example:
+	clock_gfx: qcom,gfxcc@5090000 {
+		compatible = "qcom,gfxcc-sdm845";
+		reg = <0x5090000 0x9000>;
+		vdd_gfx-supply = <&pm8005_s1_level>;
+		vdd_mx-supply = <&pm8998_s6_level>;
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+	clock_gpucc: qcom,gpucc@5090000 {
+		compatible = "qcom,gpucc-sdm845";
+		reg = <0x5090000 0x9000>;
+		vdd_cx-supply = <&pm8998_s9_level>;
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
diff --git a/Documentation/devicetree/bindings/cnss/icnss.txt b/Documentation/devicetree/bindings/cnss/icnss.txt
index 15feda3..c801e848 100644
--- a/Documentation/devicetree/bindings/cnss/icnss.txt
+++ b/Documentation/devicetree/bindings/cnss/icnss.txt
@@ -12,13 +12,22 @@
   - reg-names: Names of the memory regions defined in reg entry
   - interrupts: Copy engine interrupt table
   - qcom,wlan-msa-memory: MSA memory size
+  - clocks: List of clock phandles
+  - clock-names: List of clock names corresponding to the "clocks" property
   - iommus: SMMUs and corresponding Stream IDs needed by WLAN
   - qcom,wlan-smmu-iova-address: I/O virtual address range as <start length>
     format to be used for allocations associated between WLAN and SMMU
 
 Optional properties:
+  - <supply-name>-supply: phandle to the regulator device tree node
+			   optional "supply-name" is "vdd-0.8-cx-mx".
+  - qcom,<supply>-config: Specifies voltage levels for supply. Should be
+			   specified in pairs (min, max), units uV.  There can
+			   be optional load in uA and Regulator settle delay in
+			   uS.
   - qcom,icnss-vadc: VADC handle for vph_pwr read APIs.
   - qcom,icnss-adc_tm: VADC handle for vph_pwr notification APIs.
+  - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass
 
 Example:
 
@@ -26,6 +35,8 @@
         compatible = "qcom,icnss";
         reg = <0x0a000000 0x1000000>;
         reg-names = "membase";
+        clocks = <&clock_gcc clk_aggre2_noc_clk>;
+        clock-names = "smmu_aggre2_noc_clk";
         iommus = <&anoc2_smmu 0x1900>,
                  <&anoc2_smmu 0x1901>;
         qcom,wlan-smmu-iova-address = <0 0x10000000>;
@@ -43,4 +54,7 @@
 		   <0 140 0 /* CE10 */ >,
 		   <0 141 0 /* CE11 */ >;
         qcom,wlan-msa-memory = <0x200000>;
+	qcom,smmu-s1-bypass;
+	vdd-0.8-cx-mx-supply = <&pm8998_l5>;
+	qcom,vdd-0.8-cx-mx-config = <800000 800000 2400 1000>;
     };
diff --git a/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt b/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt
index 01b2424..67dc991 100644
--- a/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt
+++ b/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt
@@ -10,11 +10,20 @@
 - qcom,core-dev-table:		A mapping table of core frequency to a required bandwidth vote at the
 				given core frequency.
 
+Optional properties:
+- qcom,cachemiss-ev:		The cache miss event that this monitor is supposed to measure.
+				Defaults to 0x17 if not specified.
+- qcom,inst-ev:			The instruction count event that this monitor is supposed to measure.
+				Defaults to 0x08 if not specified.
+
+
 Example:
 	qcom,arm-memlat-mon {
 		compatible = "qcom,arm-memlat-mon";
 		qcom,cpulist = <&CPU0 &CPU1>;
 		qcom,target-dev = <&memlat0>;
+		qcom,cachemiss-ev = <0x2A>;
+		qcom,inst-ev = <0x08>;
 		qcom,core-dev-table =
 			<  300000 1525>,
 			<  499200 3143>,
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index b6544961..f4b6013 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -152,6 +152,11 @@
 				baseAddr - base address of the gpu channels in the qdss stm memory region
 				size     - size of the gpu stm region
 
+- qcom,gpu-qtimer:
+				<baseAddr size>
+				baseAddr - base address of the qtimer memory region
+				size     - size of the qtimer region
+
 - qcom,tsens-name:
 				Specify the name of GPU temperature sensor. This name will be used
 				to get the temperature from the thermal driver API.
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index ef6c04a..2d971b7a 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -25,6 +25,8 @@
 
 - reg           : Base address and size of the SMMU.
 
+- reg-names	: For the "qcom,qsmmu-v500" device "tcu-base" is expected.
+
 - #global-interrupts : The number of global interrupts exposed by the
                        device.
 
@@ -176,6 +178,9 @@
 		"base" is the main TBU register region.
 		"status-reg" indicates whether hw can process a new request.
 
+-qcom,stream-id-range:
+		Pair of values describing the smallest supported stream-id
+		and the size of the entire set.
 
 Example:
 smmu {
@@ -186,5 +191,6 @@
 			<0x2000 0x8>;
 		reg-names = "base",
 			"status-reg";
+		qcom,stream-id-range = <0x800 0x400>;
 	};
 };
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
index a77a291..1e6aac5 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
@@ -75,6 +75,9 @@
 - qcom,lcd-auto-pfm-thresh	: Specify the auto-pfm threshold, if the headroom voltage level
 				  falls below this threshold and auto PFM is enabled, boost
 				  controller will enter into PFM mode automatically.
+- qcom,lcd-psm-ctrl	: A boolean property to specify if PSM needs to be
+			  controlled dynamically when WLED module is enabled
+			  or disabled.
 
 Optional properties if 'qcom,disp-type-amoled' is mentioned in DT:
 - qcom,loop-comp-res-kohm	: control to select the compensation resistor in kohm. default is 320.
diff --git a/Documentation/devicetree/bindings/mailbox/qcom-tcs.txt b/Documentation/devicetree/bindings/mailbox/qcom-tcs.txt
index 4ef34bf..318ef30 100644
--- a/Documentation/devicetree/bindings/mailbox/qcom-tcs.txt
+++ b/Documentation/devicetree/bindings/mailbox/qcom-tcs.txt
@@ -81,6 +81,10 @@
 		ACTIVE_TCS
 		CONTROL_TCS
 	- Cell #2 (Number of TCS): <u32>
+- label:
+	Usage: optional
+	Value type: <string>
+	Definition: Name for the mailbox. The name would be used in trace logs.
 
 EXAMPLE 1:
 
@@ -92,6 +96,7 @@
 
 	apps_rsc: mailbox@179e000 {
 		compatible = "qcom,tcs_drv";
+		label = "apps_rsc";
 		reg = <0x179E0000 0x10000>, <0x179E0D00 0x3000>;
 		interrupts = <0 5 0>;
 		#mbox-cells = <1>;
@@ -110,17 +115,18 @@
 Second tuple: 0xAF20000 + 0x1C00
 
 	disp_rsc: mailbox@af20000 {
-			status = "disabled";
-			compatible = "qcom,tcs-drv";
-			reg = <0xAF20000 0x10000>, <0xAF21C00 0x3000>;
-			interrupts = <0 129 0>;
-			#mbox-cells = <1>;
-			qcom,drv-id = <0>;
-			qcom,tcs-config = <SLEEP_TCS 1>,
-					<WAKE_TCS    1>,
-					<ACTIVE_TCS  0>,
-					<CONTROL_TCS 1>;
-		};
+		status = "disabled";
+		label = "disp_rsc";
+		compatible = "qcom,tcs-drv";
+		reg = <0xAF20000 0x10000>, <0xAF21C00 0x3000>;
+		interrupts = <0 129 0>;
+		#mbox-cells = <1>;
+		qcom,drv-id = <0>;
+		qcom,tcs-config = <SLEEP_TCS 1>,
+				<WAKE_TCS    1>,
+				<ACTIVE_TCS  0>,
+				<CONTROL_TCS 1>;
+	};
 
 
 CLIENT:
diff --git a/Documentation/devicetree/bindings/misc/qpnp-misc.txt b/Documentation/devicetree/bindings/misc/qpnp-misc.txt
new file mode 100644
index 0000000..a34cbde
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/qpnp-misc.txt
@@ -0,0 +1,25 @@
+QPNP-MISC
+
+QPNP-MISC provides a way to read the PMIC part number and revision.
+
+Required properties:
+- compatible : should be "qcom,qpnp-misc"
+- reg : offset and length of the PMIC peripheral register map.
+
+Optional properties:
+- qcom,pwm-sel:			Select PWM source. Possible values:
+				0: LOW
+				1: PWM1_in
+				2: PWM2_in
+				3: PWM1_in & PWM2_in
+- qcom,enable-gp-driver:	Enable the GP driver. Should only be specified
+				if a non-zero PWM source is specified under
+				"qcom,pwm-sel" property.
+
+Example:
+	qcom,misc@900 {
+		compatible = "qcom,qpnp-misc";
+		reg = <0x900 0x100>;
+		qcom,pwm-sel = <2>;
+		qcom,enable-gp-driver;
+	};
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 485483a..6111c88 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -1,55 +1,81 @@
-* Qualcomm SDHCI controller (sdhci-msm)
+Qualcomm Technologies, Inc. Standard Secure Digital Host Controller (SDHC)
 
-This file documents differences between the core properties in mmc.txt
-and the properties used by the sdhci-msm driver.
+Secure Digital Host Controller provides standard host interface to SD/MMC/SDIO cards.
 
 Required properties:
-- compatible: Should contain "qcom,sdhci-msm-v4".
-- reg: Base address and length of the register in the following order:
-	- Host controller register map (required)
-	- SD Core register map (required)
-- interrupts: Should contain an interrupt-specifiers for the interrupts:
-	- Host controller interrupt (required)
-- pinctrl-names: Should contain only one value - "default".
-- pinctrl-0: Should specify pin control groups used for this controller.
-- clocks: A list of phandle + clock-specifier pairs for the clocks listed in clock-names.
-- clock-names: Should contain the following:
-	"iface" - Main peripheral bus clock (PCLK/HCLK - AHB Bus clock) (required)
-	"core"	- SDC MMC clock (MCLK) (required)
-	"bus"	- SDCC bus voter clock (optional)
+  - compatible : should be "qcom,sdhci-msm"
+  - reg : should contain SDHC, SD Core register map.
+  - reg-names : indicates various resources passed to driver (via reg proptery) by name.
+		Required "reg-names" are "hc_mem" and "core_mem"
+  - interrupts : should contain SDHC interrupts.
+  - interrupt-names : indicates interrupts passed to driver (via interrupts property) by name.
+		      Required "interrupt-names" are "hc_irq" and "pwr_irq".
+  - <supply-name>-supply: phandle to the regulator device tree node
+			  Required "supply-name" are "vdd" and "vdd-io".
+
+Required alias:
+- The slot number is specified via an alias with the following format
+	'sdhc{n}' where n is the slot number.
+
+Optional Properties:
+	- interrupt-names - "status_irq". This status_irq will be used for card
+			     detection.
+	- qcom,bus-width - defines the bus I/O width that controller supports.
+			   Units - number of bits. The valid bus-width values are
+			   1, 4 and 8.
+	- qcom,nonremovable - specifies whether the card in slot is
+			      hot pluggable or hard wired.
+	- qcom,bus-speed-mode - specifies supported bus speed modes by host.
+				The supported bus speed modes are :
+				"HS200_1p8v" - indicates that host can support HS200 at 1.8v.
+				"HS200_1p2v" - indicates that host can support HS200 at 1.2v.
+				"DDR_1p8v" - indicates that host can support DDR mode at 1.8v.
+				"DDR_1p2v" - indicates that host can support DDR mode at 1.2v.
+
+In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
+	- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
+	- qcom,<supply>-lpm_sup - specifies whether supply can be kept in low power mode (lpm).
+	- qcom,<supply>-voltage_level - specifies voltage levels for supply. Should be
+					specified in pairs (min, max), units uV.
+	- qcom,<supply>-current_level - specifies load levels for supply in lpm or
+					high power mode (hpm). Should be specified in
+					pairs (lpm, hpm), units uA.
+
+	- gpios - specifies gpios assigned for sdhc slot.
+	- qcom,gpio-names -  a list of strings that map in order to the list of gpios
 
 Example:
 
-	sdhc_1: sdhci@f9824900 {
-		compatible = "qcom,sdhci-msm-v4";
-		reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
-		interrupts = <0 123 0>;
-		bus-width = <8>;
-		non-removable;
-
-		vmmc-supply = <&pm8941_l20>;
-		vqmmc-supply = <&pm8941_s3>;
-
-		pinctrl-names = "default";
-		pinctrl-0 = <&sdc1_clk &sdc1_cmd &sdc1_data>;
-
-		clocks = <&gcc GCC_SDCC1_APPS_CLK>, <&gcc GCC_SDCC1_AHB_CLK>;
-		clock-names = "core", "iface";
+	aliases {
+		sdhc1 = &sdhc_1;
 	};
 
-	sdhc_2: sdhci@f98a4900 {
-		compatible = "qcom,sdhci-msm-v4";
-		reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
-		interrupts = <0 125 0>;
-		bus-width = <4>;
-		cd-gpios = <&msmgpio 62 0x1>;
+	sdhc_1: qcom,sdhc@f9824900 {
+		compatible = "qcom,sdhci-msm";
+                reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
+                reg-names = "hc_mem", "core_mem";
+                interrupts = <0 123 0>, <0 138 0>;
+                interrupt-names = "hc_irq", "pwr_irq";
 
-		vmmc-supply = <&pm8941_l21>;
-		vqmmc-supply = <&pm8941_l13>;
+		vdd-supply = <&pm8941_l21>;
+		vdd-io-supply = <&pm8941_l13>;
+		qcom,vdd-voltage-level = <2950000 2950000>;
+		qcom,vdd-current-level = <9000 800000>;
 
-		pinctrl-names = "default";
-		pinctrl-0 = <&sdc2_clk &sdc2_cmd &sdc2_data>;
+		qcom,vdd-io-always-on;
+		qcom,vdd-io-lpm-sup;
+		qcom,vdd-io-voltage-level = <1800000 2950000>;
+		qcom,vdd-io-current-level = <6 22000>;
 
-		clocks = <&gcc GCC_SDCC2_APPS_CLK>, <&gcc GCC_SDCC2_AHB_CLK>;
-		clock-names = "core", "iface";
+                qcom,bus-width = <4>;
+		qcom,nonremovable;
+		qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+
+		gpios = <&msmgpio 40 0>, /* CLK */
+			<&msmgpio 39 0>, /* CMD */
+			<&msmgpio 38 0>, /* DATA0 */
+			<&msmgpio 37 0>, /* DATA1 */
+			<&msmgpio 36 0>, /* DATA2 */
+			<&msmgpio 35 0>; /* DATA3 */
+		qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
 	};
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,lpi-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,lpi-pinctrl.txt
new file mode 100644
index 0000000..57510ec
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,lpi-pinctrl.txt
@@ -0,0 +1,154 @@
+Qualcomm Technologies, Inc. LPI GPIO controller driver
+
+This DT bindings describes the GPIO controller driver
+being added for supporting LPI (Low Power Island) TLMM
+from QTI chipsets.
+
+Following properties are for LPI GPIO controller device main node.
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: must be "qcom,lpi-pinctrl"
+
+- reg:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: Register base of the GPIO controller and length.
+
+- qcom,num-gpios:
+	Usage: required
+	Value type: <u32>
+	Definition: Number of GPIOs supported by the controller.
+
+- gpio-controller:
+	Usage: required
+	Value type: <none>
+	Definition: Used to mark the device node as a GPIO controller.
+
+- #gpio-cells:
+	Usage: required
+	Value type: <u32>
+	Definition: Must be 2;
+		    The first cell will be used to define gpio number and the
+		    second denotes the flags for this gpio.
+
+Please refer to ../gpio/gpio.txt for general description of GPIO bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin or a list of pins. This configuration can include the
+mux function to select on those pin(s), and various pin configuration
+parameters, as listed below.
+
+SUBNODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+	Usage: required
+	Value type: <string-array>
+	Definition: List of gpio pins affected by the properties specified in
+		    this subnode.  Valid pins are: gpio0-gpio31 for LPI.
+
+- function:
+	Usage: required
+	Value type: <string>
+	Definition: Specify the alternative function to be configured for the
+		    specified pins. Valid values are:
+			"gpio",
+			"func1",
+			"func2",
+			"func3",
+			"func4",
+			"func5"
+
+- bias-disable:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins should be configured as no pull.
+
+- bias-pull-down:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins should be configured as pull down.
+
+- bias-bus-hold:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins should be configured as bus-keeper mode.
+
+- bias-pull-up:
+	Usage: optional
+	Value type: <empty>
+	Definition: The specified pins should be configured as pull up.
+
+- input-enable:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins are put in input mode.
+
+- output-high:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins are configured in output mode, driven
+		    high.
+
+- output-low:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins are configured in output mode, driven
+		    low.
+
+- qcom,drive-strength:
+	Usage: optional
+	Value type: <u32>
+	Definition: Selects the drive strength for the specified pins.
+
+Example:
+
+	lpi_tlmm: lpi_pinctrl@152c000 {
+		compatible = "qcom,lpi-pinctrl";
+		qcom,num-gpios = <32>;
+		reg = <0x152c000 0>;
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		hph_comp_active: hph_comp_active {
+			mux {
+				pins = "gpio22";
+				function = "func1";
+			};
+
+			config {
+				pins = "gpio22";
+				output-high;
+				qcom,drive-strength = <8>;
+			};
+		};
+
+		hph_comp_sleep: hph_comp_sleep {
+			mux {
+				pins = "gpio22";
+				function = "func1";
+			};
+
+			config {
+				pins = "gpio22";
+				qcom,drive-strength = <2>;
+			};
+		};
+	};
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt
index 521c783..c01036d 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt
@@ -43,6 +43,17 @@
 		    the first cell will be used to define gpio number and the
 		    second denotes the flags for this gpio
 
+- qcom,gpios-disallowed:
+	Usage: optional
+	Value type: <prop-encoded-array>
+	Definition: Array of the GPIO hardware numbers corresponding to GPIOs
+		    which the APSS processor is not allowed to configure.
+		    The hardware numbers are indexed from 1.
+		    The interrupt resources for these GPIOs must not be defined
+		    in "interrupts" and "interrupt-names" properties.
+		    GPIOs defined in this array won't be registered as pins
+		    in the pinctrl device or gpios in the gpio chip.
+
 Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
 a general description of GPIO and interrupt bindings.
 
@@ -233,6 +244,7 @@
 
 		gpio-controller;
 		#gpio-cells = <2>;
+		qcom,gpios-disallowed = <1 20>;
 
 		pm8921_gpio_keys: gpio-keys {
 			volume-keys {
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt
index d08ca95..c9cfc88 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt
@@ -149,6 +149,8 @@
 					already. If it it not specified, then
 					output voltage can be configured to
 					any value in the allowed limit.
+- qcom,notify-lab-vreg-ok-sts:		A boolean property which upon set will
+					poll and notify the lab_vreg_ok status.
 
 Following properties are available only for PM660A:
 
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
index 8b3a38da0..63da8ec 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
@@ -26,6 +26,13 @@
 	Value type: <prop-encoded-array>
 	Definition:  Base address of the LCDB SPMI peripheral.
 
+- qcom,force-module-reenable
+	Usage:      required if using SW mode for module enable
+	Value type:  <bool>
+	Definition: This enables the workaround to force enable
+		    the vph_pwr_2p5_ok signal required for
+		    turning on the LCDB module.
+
 Touch-to-wake (TTW) properties:
 
 TTW supports 2 modes of operation - HW and SW. In the HW mode the enable/disable
@@ -59,7 +66,6 @@
 	Definition: ON time (in mS) for the VDISP/VDISN signals.
 		    Possible values are 4, 8, 16, 32.
 
-
 ========================================
 Second Level Nodes - LDO/NCP/BOOST block
 ========================================
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt
index 5d80a04..38f599b 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt
@@ -44,12 +44,12 @@
 	Value type: <bool>
 	Definition: Enables the voltage programming through SWIRE signal.
 
- qcom,ext-pin-control
+- qcom,ext-pin-control
 	Usage:      optional
 	Value type: <bool>
 	Definition: Configures the OLED module to be enabled by a external pin.
 
- qcom,dynamic-ext-pinctl-config
+- qcom,dynamic-ext-pinctl-config
 	Usage:      optional
 	Value type: <bool>
 	Definition:  Used to dynamically enable/disable the OLEDB module
@@ -57,13 +57,27 @@
 		     rail.  This property is applicable only if qcom,ext-pin-ctl
 		     property is specified and it is specific to PM660A.
 
- qcom,pbs-control
+- qcom,force-pd-control
+	Usage:      optional
+	Value type: <bool>
+	Definition:  Used to enable the pull down control forcibly via SPMI by
+		     disabling the pull down configuration done by hardware
+		     automatically through SWIRE pulses.
+
+- qcom,pbs-client
+	Usage:      optional
+	Value type: <phandle>
+	Definition:  Used to send the PBS trigger to the specified PBS client.
+		     This property is applicable only if qcom,force-pd-control
+		     property is specified.
+
+- qcom,pbs-control
 	Usage:      optional
 	Value type: <bool>
 	Definition: PMIC PBS logic directly configures the output voltage update
 		    and pull down control.
 
- qcom,oledb-init-voltage-mv
+- qcom,oledb-init-voltage-mv
 	Usage:      optional
 	Value type: <u32>
 	Definition: Sets the AVDD bias voltage (in mV) when the module is
@@ -71,53 +85,53 @@
 		    property is not specified. Supported values are from 5.0V
 		    to 8.1V with a step of 100mV.
 
-qcom,oledb-default-voltage-mv
+- qcom,oledb-default-voltage-mv
 	Usage:      optional
 	Value type: <u32>
 	Definition: Sets the default AVDD bias voltage (in mV) before module
 		    enable. Supported values are from 5.0V to 8.1V with the
 		    step of 100mV.
 
-qcom,bias-gen-warmup-delay-ns
+- qcom,bias-gen-warmup-delay-ns
 	Usage:      optional
 	Value type: <u32>
 	Definition: Bias generator warm-up time (ns). Supported values are
 		    6700, 13300, 267000, 534000.
 
-qcom,peak-curr-limit-ma
+- qcom,peak-curr-limit-ma
 	Usage:      optional
 	Value type: <u32>
 	Definition: Peak current limit (in mA). Supported values are 115, 265,
 		    415, 570, 720, 870, 1020, 1170.
 
-qcom,pull-down-enable
+- qcom,pull-down-enable
 	Usage:      optional
 	Value type: <u32>
 	Definition: Pull down configuration of OLEDB.
 		    1 - Enable pull-down
 		    0 - Disable pull-down
 
-qcom,negative-curr-limit-enable
+- qcom,negative-curr-limit-enable
 	Usage:      optional
 	Value type: <u32>
 	Definition: negative current limit enable/disable.
 			1 = enable negative current limit
 			0 = disable negative current limit
 
-qcom,negative-curr-limit-ma
+- qcom,negative-curr-limit-ma
 	Usage:      optional
 	Value type: <u32>
 	Definition: Negative current limit (in mA). Supported values are
 		    170, 300, 420, 550.
 
-qcom,enable-short-circuit
+- qcom,enable-short-circuit
 	Usage:      optional
 	Value type: <u32>
 	Definition: Short circuit protection enable/disable.
 			1 = enable short circuit protection
 			0 = disable short circuit protection
 
-qcom,short-circuit-dbnc-time
+- qcom,short-circuit-dbnc-time
 	usage:      optional
 	Value type: <u32>
 	Definitioan: Short circuit debounce time (in Fsw). Supported
@@ -126,26 +140,26 @@
 Fast precharge properties:
 -------------------------
 
-qcom,fast-precharge-ppulse-enable
+- qcom,fast-precharge-ppulse-enable
 	usage:      optional
 	Value type: <u32>
 	Definitioan: Fast precharge pfet pulsing enable/disable.
 			1 = enable fast precharge pfet pulsing
 			0 = disable fast precharge pfet pulsing
 
-qcom,precharge-debounce-time-ms
+- qcom,precharge-debounce-time-ms
 	usage:      optional
 	Value type: <u32>
 	Definitioan: Fast precharge debounce time (in ms). Supported
 		     values are 1, 2, 4, 8.
 
-qcom,precharge-pulse-period-us
+- qcom,precharge-pulse-period-us
 	usage:      optional
 	Value type: <u32>
 	Definitioan: Fast precharge pulse period (in us). Supported
 		     values are 3, 6, 9, 12.
 
-qcom,precharge-pulse-on-time-us
+- qcom,precharge-pulse-on-time-us
 	usage:      optional
 	Value type: <u32>
 	Definitioan: Fast precharge pulse on time (in ns). Supported
@@ -154,20 +168,20 @@
 Pulse Skip Modulation (PSM) properties:
 --------------------------------------
 
-qcom,psm-enable
+- qcom,psm-enable
 	Usage:      optional
 	Value type: <u32>
 	Definition: Pulse Skip Modulation mode.
 		    1 - Enable PSM mode
 		    0 - Disable PSM mode
 
-qcom,psm-hys-mv
+- qcom,psm-hys-mv
 	Usage:      optional
 	Value type: <u32>
 	Definition: PSM hysterysis voltage (in mV).
 		    Supported values are 13mV and 26mV.
 
-qcom,psm-vref-mv
+- qcom,psm-vref-mv
 	Usage:      optional
 	Value type: <u32>
 	Definition: Reference voltage(in mV) control for PSM comparator.
@@ -177,26 +191,26 @@
 Pulse Frequency Modulation (PFM) properties:
 -------------------------------------------
 
-qcom,pfm-enable
+- qcom,pfm-enable
 	Usage:      optional
 	Value type: <u32>
 	Definition: Pulse Frequency Modulation mode.
 		    1 - Enable PFM mode
 		    0 - Disable PFM mode
 
-qcom,pfm-hys-mv
+- qcom,pfm-hys-mv
 	Usage:      optional
 	Value type: <u32>
 	Definition: PFM hysterysis voltage (in mV).
 		    Supported values are 13mV and 26mV.
 
-qcom,pfm-curr-limit-ma
+- qcom,pfm-curr-limit-ma
 	Usage:      optional
 	Value type: <u32>
 	Definition: PFM current limit (in mA).
 		    Supported values are 130, 200, 270, 340.
 
-qcom,pfm-off-time-ns
+- qcom,pfm-off-time-ns
 	Usage:      optional
 	Value type: <u32>
 	Definition: NFET off time at PFM (in ns).
diff --git a/Documentation/devicetree/bindings/soc/qcom/avtimer.txt b/Documentation/devicetree/bindings/soc/qcom/avtimer.txt
index 157f79b..7c70b1e 100644
--- a/Documentation/devicetree/bindings/soc/qcom/avtimer.txt
+++ b/Documentation/devicetree/bindings/soc/qcom/avtimer.txt
@@ -13,8 +13,16 @@
 - compatible : Must be "qcom,avtimer"
 
 Optional properties:
-- clk-div : The clk is at 27MHz and hence ticks are to be
- divided by 27 to achive the msec value.
+- clk-div : Divisor to divide the ticks value to get msec value.
+ If the clock is at 27MHz, the ticks value read from AVTimer
+ registers will have to be divided by 27, to achieve the msec value.
+- clk-mult : Multiplier to multiply the ticks value in order to avoid
+ a floating point operation if the clock is of decimal value.
+ E.g. To get msec out of ticks from a 19.2MHz clock source, the ticks
+ value will have to be divided by 19.2, which will then become a
+ floating point operation. However, to avoid using a floating point
+ operation, the msec can be calculated by multiplying ticks with 10
+ and dividing the result by 192. i.e. msec = (ticks * 10) / 192;
 
 Example:
 	qcom,avtimer@90f7000 {
@@ -23,4 +31,5 @@
 		      <0x90f7010 0x4>;
 		reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
 		qcom,clk-div = <27>;
+		qcom,clk-mult = <10>;
 	};
diff --git a/Documentation/devicetree/bindings/soc/qcom/qpnp-pbs.txt b/Documentation/devicetree/bindings/soc/qcom/qpnp-pbs.txt
new file mode 100644
index 0000000..d7aefbf
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/qpnp-pbs.txt
@@ -0,0 +1,30 @@
+QPNP PBS
+
+QPNP (Qualcomm Technologies, Inc. Plug N Play) PBS is programmable boot sequence
+and this driver is for helping the client drivers triggering such sequence
+to be configured in PMIC.
+
+This document describes the bindings for QPNP PBS driver.
+
+=======================
+Required Node Structure
+=======================
+
+- compatible
+	Usage:      required
+	Value type: <string>
+	Definition: should be "qcom,qpnp-pbs".
+
+- reg
+	Usage:      required
+	Value type: <prop-encoded-array>
+	Definition:  Base address of the PBS registers.
+
+
+=======
+Example
+=======
+	pm660l_pbs: qcom,pbs@7300 {
+		compatible = "qcom,qpnp-pbs";
+		reg = <0x7300 0x100>;
+	};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 3ff3b2f..e0ab31f 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -181,6 +181,11 @@
 
  - compatible : "qcom,msm-pcm-loopback"
 
+Optional properties:
+
+ - qcom,msm-pcm-loopback-low-latency : Flag indicating whether
+   the device node is of type low latency.
+
 * msm-dai-q6
 
 [First Level Nodes]
@@ -365,6 +370,10 @@
 
  - compatible : "qcom,msm-cdc-pinctrl"
 
+Optional properties:
+ - qcom,lpi-gpios : This boolean property is added if GPIOs are under
+		    LPI TLMM.
+
 * msm-dai-slim
 
 Required properties:
@@ -421,6 +430,11 @@
 		qcom,msm-pcm-low-latency;
 	};
 
+	qcom,msm-pcm-loopback-low-latency {
+		compatible = "qcom,msm-pcm-loopback";
+		qcom,msm-pcm-loopback-low-latency;
+	};
+
         qcom,msm-pcm-routing {
                 compatible = "qcom,msm-pcm-routing";
         };
@@ -829,17 +843,6 @@
 Required properties:
 - compatible : "qcom,msm8974-audio-taiko"
 - qcom,model : The user-visible name of this sound card.
-- reg : Offset and length of the register region(s) for MI2S/PCM MUX
-- reg-names : Register region name(s) referenced in reg above
-	 Required register resource entries are:
-	 "lpaif_pri_mode_muxsel": Physical address of MUX to select between
-				  Primary PCM and Primary MI2S
-	 "lpaif_sec_mode_muxsel": Physical address of MUX to select between
-				  Secondary PCM and Secondary MI2S
-	 "lpaif_tert_mode_muxsel": Physical address of MUX to select between
-				   Primary PCM and Tertiary MI2S
-	 "lpaif_quat_mode_muxsel": Physical address of MUX to select between
-				   Secondary PCM and Quarternary MI2S
 - qcom,audio-routing : A list of the connections between audio components.
   Each entry is a pair of strings, the first being the connection's sink,
   the second being the connection's source.
@@ -877,6 +880,19 @@
 		    codec dai names should match to that of the phandle order given
 		    in "asoc-codec".
 Optional properties:
+- reg : Offset and length of the register region(s) for MI2S/PCM MUX.
+	Not applicable for all targets.
+- reg-names : Register region name(s) referenced in reg above.
+	      Not applicable for all targets.
+	 Required register resource entries are:
+	 "lpaif_pri_mode_muxsel": Physical address of MUX to select between
+				  Primary PCM and Primary MI2S
+	 "lpaif_sec_mode_muxsel": Physical address of MUX to select between
+				  Secondary PCM and Secondary MI2S
+	 "lpaif_tert_mode_muxsel": Physical address of MUX to select between
+				   Primary PCM and Tertiary MI2S
+	 "lpaif_quat_mode_muxsel": Physical address of MUX to select between
+				   Secondary PCM and Quarternary MI2S
 - qcom,hdmi-audio-rx: specifies if HDMI audio support is enabled or not.
 - qcom,ext-ult-spk-amp-gpio : GPIO for enabling of speaker path amplifier.
 
@@ -1510,10 +1526,10 @@
 		asoc-wsa-codec-prefixes = "SpkrMono";
 	};
 
-* MSMFALCON ASoC Machine driver
+* SDM660 ASoC Machine driver
 
 Required properties:
-- compatible : "qcom,msmfalcon-asoc-snd"
+- compatible : "qcom,sdm660-asoc-snd"
 - qcom,model : The user-visible name of this sound card.
 - qcom,msm-hs-micbias-type : This property is used to recognize the headset
   micbias type, internal or external.
@@ -1539,6 +1555,7 @@
 capacitor mode.
 - qcom,msm-micbias2-ext-cap : Boolean. Enable micbias2 external
 capacitor mode.
+- qcom,wsa-disable : Boolean. Disables WSA speaker dailinks from sound node.
 - qcom,msm-spk-ext-pa : GPIO which enables external speaker pa.
 - qcom,msm-mclk-freq : This property is used to inform machine driver about
 mclk frequency needs to be configured for internal and external PA.
@@ -1559,11 +1576,19 @@
 - qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
 - qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target
 - qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device
+- qcom,cdc-pdm-gpios : phandle for pdm gpios.
+- qcom,cdc-comp-gpios : phandle for compander gpios.
+- qcom,cdc-dmic-gpios : phandle for Digital mic clk and data gpios.
+- qcom,cdc-sdw-gpios : phandle for soundwire clk and data gpios.
+- qcom,msm-mbhc-moist-cfg: This property is used to set moisture detection
+		threshold values for different codecs. First parameter is V(voltage)
+		second one is i(current), third one is r (resistance). Depending on the
+		codec set corresponding element in array and set others to 0.
 
 Example:
 	 sound {
-		compatible = "qcom,msmfalcon-asoc-snd";
-		qcom,model = "msmfalcon-snd-card";
+		compatible = "qcom,sdm660-asoc-snd";
+		qcom,model = "sdm660-snd-card";
 		qcom,msm-mclk-freq = <9600000>;
 		qcom,msm-mbhc-hphl-swh = <0>;
 		qcom,msm-mbhc-gnd-swh = <0>;
@@ -1579,24 +1604,11 @@
 			"AMIC1", "MIC BIAS External",
 			"AMIC2", "MIC BIAS Internal2",
 			"AMIC3", "MIC BIAS External";
-		qcom,msm-gpios =
-			"int_pdm",
-			"us_eu_gpio";
-		qcom,pinctrl-names =
-			"all_off",
-			"int_pdm_act",
-			"us_eu_gpio_act",
-			"int_pdm_us_eu_gpio_act";
-		pinctrl-names =
-			"all_off",
-			"int_pdm_act",
-			"us_eu_gpio_act",
-			"int_pdm_us_eu_gpio_act";
-		pinctrl-0 = <&cdc_pdm_lines_sus &cdc_pdm_lines_2_sus &cross_conn_det_sus>;
-		pinctrl-1 = <&cdc_pdm_lines_act &cdc_pdm_lines_2_act &cross_conn_det_sus>;
-		pinctrl-2 = <&cdc_pdm_lines_sus &cdc_pdm_lines_2_sus &cross_conn_det_act>;
-		pinctrl-3 = <&cdc_pdm_lines_act &cdc_pdm_lines_2_act &cross_conn_det_act>;
 		qcom,cdc-us-euro-gpios = <&msm_gpio 63 0>;
+		qcom,cdc-pdm-gpios = <&cdc_pdm_gpios>;
+		qcom,cdc-comp-gpios = <&cdc_comp_gpios>;
+		qcom,cdc-dmic-gpios = <&cdc_dmic_gpios>;
+		qcom,cdc-sdw-gpios = <&cdc_sdw_gpios>;
 		asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>,
 				<&loopback>, <&compress>, <&hostless>,
 				<&afe>, <&lsm>, <&routing>, <&lpa>;
@@ -1681,6 +1693,10 @@
 - qcom,msm-mi2s-master: This property is used to inform machine driver
   if MSM is the clock master of mi2s. 1 means master and 0 means slave. The
   first entry is primary mi2s; the second entry is secondary mi2s, and so on.
+- qcom,msm-mi2s-ext-mclk: This property is used to inform machine driver
+  if MCLK from MSM is used for any external audio connections. 1 means used
+  as external mclk source and 0 indicate not used. The first entry is
+  primary mclk; the second entry is secondary mclk, and so on.
 - reg: This property provides the AUX PCM/MI2S mux select register addresses
   and size.
 - reg_names: This property provides the name of the AUX PCM/MI2S mux select
@@ -1721,6 +1737,7 @@
 		qcom,mi2s-audio-intf;
 		qcom,auxpcm-audio-intf;
 		qcom,msm-mi2s-master = <1>, <0>, <1>, <1>;
+		qcom,msm-mi2s-ext-mclk = <1>, <1>, <0>, <1>;
 		reg = <0x1711a000 0x4>,
 		      <0x1711b000 0x4>,
 		      <0x1711c000 0x4>,
@@ -1732,6 +1749,8 @@
 		qcom,msm-mclk-freq = <9600000>;
 		qcom,msm-mbhc-hphl-swh = <0>;
 		qcom,msm-mbhc-gnd-swh = <0>;
+		qcom,wsa-disable;
+		qcom,msm-mbhc-moist-cfg = <1>, <3>, <0>;
 		qcom,msm-hs-micbias-type = "internal";
 		qcom,msm-micbias1-ext-cap;
 		qcom,audio-routing =
@@ -2020,13 +2039,15 @@
 
 		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
 				<&loopback>, <&compress>, <&hostless>,
-				<&afe>, <&lsm>, <&routing>, <&compr>;
+				<&afe>, <&lsm>, <&routing>, <&compr>,
+				<&loopback1>;
 		asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
 				"msm-pcm-dsp.2", "msm-voip-dsp",
 				"msm-pcm-voice", "msm-pcm-loopback",
 				"msm-compress-dsp", "msm-pcm-hostless",
 				"msm-pcm-afe", "msm-lsm-client",
-				"msm-pcm-routing", "msm-compr-dsp";
+				"msm-pcm-routing", "msm-compr-dsp",
+				"msm-pcm-loopback.1";
 		asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>,
 				<&dai_mi2s>, <&dai_mi2s_quat>,
 				<&afe_pcm_rx>, <&afe_pcm_tx>,
@@ -2060,11 +2081,11 @@
 		asoc-codec-names = "msm-stub-codec.1";
 	};
 
-* MSMFALCON ASoC Slimbus Machine driver
+* SDM660 ASoC Slimbus Machine driver
 
 Required properties:
-- compatible : "qcom,msmfalcon-asoc-snd-tasha" for tasha codec,
-		"qcom,msmfalcon-asoc-snd-tavil" for tavil codec.
+- compatible : "qcom,sdm660-asoc-snd-tasha" for tasha codec,
+		"qcom,sdm660-asoc-snd-tavil" for tavil codec.
 - qcom,model : The user-visible name of this sound card.
 - qcom,msm-mclk-freq : MCLK frequency value for external codec
 - qcom,msm-gpios : Lists down all the gpio sets that are supported.
@@ -2104,8 +2125,8 @@
 Example:
 
 	sound-9335 {
-	compatible = "qcom,msmfalcon-asoc-snd-tasha";
-	qcom,model = "msmfalcon-tasha-snd-card";
+	compatible = "qcom,sdm660-asoc-snd-tasha";
+	qcom,model = "sdm660-tasha-snd-card";
 
 	qcom,audio-routing =
 		"RX_BIAS", "MCLK",
@@ -2233,6 +2254,11 @@
 - qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target
 - qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device
 - qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target
+- qcom,msm-mbhc-usbc-audio-supported : Property to specify if analog audio feature is
+				       enabled or not.
+- qcom,usbc-analog-en1_gpio : EN1 GPIO to enable USB type-C analog audio
+- qcom,usbc-analog-en2_n_gpio : EN2 GPIO to enable USB type-C analog audio
+- qcom,usbc-analog-force_detect_gpio : Force detect GPIO to enable USB type-C analog audio
 
 Example:
 
@@ -2306,6 +2332,10 @@
 				<&wsa881x_213>, <&wsa881x_214>;
 		qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft",
 					  "SpkrRight", "SpkrLeft";
+		qcom,msm-mbhc-usbc-audio-supported = <1>;
+		qcom,usbc-analog-en1_gpio = <&wcd_usbc_analog_en1_gpio>;
+		qcom,usbc-analog-en2_n_gpio = <&wcd_usbc_analog_en2n_gpio>;
+		qcom,usbc-analog-force_detect_gpio = <&wcd_usbc_analog_f_gpio>;
 	};
 
 * MSMSTUB ASoC Machine driver
diff --git a/Documentation/devicetree/bindings/sound/wcd_codec.txt b/Documentation/devicetree/bindings/sound/wcd_codec.txt
index c0a7a24..0df9417 100644
--- a/Documentation/devicetree/bindings/sound/wcd_codec.txt
+++ b/Documentation/devicetree/bindings/sound/wcd_codec.txt
@@ -384,8 +384,8 @@
 Tombak audio CODEC in SPMI mode
 
  - compatible = "qcom,msm-codec-core",
- - compatible = "qcom,pmic-codec-digital"
- - compatible = "qcom,pmic-codec-analog"
+ - compatible = "qcom,msm-digital-codec"
+ - compatible = "qcom,pmic-analog-codec"
  - reg: represents the slave base address provided to the peripheral.
  - interrupt-parent : The parent interrupt controller.
  - interrupts: List of interrupts in given SPMI peripheral.
@@ -438,19 +438,14 @@
 
 Example:
 
-msm_dig_codec: qcom,msm-int-codec {
-	compatible = "qcom,msm_int_core_codec";
-	qcom,dig-cdc-base-addr = <0xc0f0000>;
+msm_digital_codec: msm-dig-codec@c0f0000 {
+	compatible = "qcom,msm-digital-codec";
+	reg = <0xc0f0000 0x0>;
 };
 
-msm8x16_wcd_codec@f100 {
-	compatible = "qcom,msm_int_pmic_analog_codec";
-	reg = <0xf100 0x100>;
-};
-
-msm8x16_wcd_codec@f000{
-	compatible = "qcom,msm_int_pmic_digital_codec";
-	reg = <0xf000 0x100>;
+pmic_analog_codec: analog-codec@f000 {
+	compatible = "qcom,pmic-analog-codec";
+	reg = <0xf000 0x200>;
 	interrupt-parent = <&spmi_bus>;
 	interrupts = <0x1 0xf0 0x0>,
 		     <0x1 0xf0 0x1>,
@@ -501,7 +496,41 @@
 				   "cdc-vdda-cp";
 
 	qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
-	qcom,dig-cdc-base-addr = <0xc0f0000>;
+};
+
+MSM based Soundwire audio codec
+
+Required properties:
+ - compatible = "qcom,msm-sdw-codec";
+ - reg: Specifies the soundwire codec base address for MSM digital
+	soundwire core registers.
+ - interrupts: Specifies the soundwire master interrupt number to Apps processor.
+ - interrupt-names: Specify the interrupt name from soundwire master.
+ - swr_master: This node is added as a child of MSM soundwire codec
+	       and uses already existing driver soundwire master.
+	       And there is/are subchild node(s) under soundwire master
+	       which is also existing driver WSA881x that represents
+	       soundwire slave devices.
+
+Example:
+
+msm_sdw_codec: qcom,msm-sdw-codec@152c1000 {
+	compatible = "qcom,msm-sdw-codec";
+	reg = <0x152c1000 0x0>;
+	interrupts = <0 161 0>;
+	interrupt-names = "swr_master_irq";
+
+	swr_master {
+		compatible = "qcom,swr-wcd";
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		wsa881x_1: wsa881x@20170212 {
+			compatible = "qcom,wsa881x";
+			reg = <0x00 0x20170212>;
+			qcom,spkr-sd-n-gpio = <&tlmm 80 0>;
+		};
+	};
 };
 
 Tasha audio CODEC in I2C mode
diff --git a/Documentation/devicetree/bindings/thermal/thermal.txt b/Documentation/devicetree/bindings/thermal/thermal.txt
index 88b6ea1..123a65b 100644
--- a/Documentation/devicetree/bindings/thermal/thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/thermal.txt
@@ -168,6 +168,18 @@
 			by means of sensor ID. Additional coefficients are
 			interpreted as constant offset.
 
+- thermal-governor:     Thermal governor to be used for this thermal zone.
+			Expected values are:
+			"step_wise": Use step wise governor.
+			"fair_share": Use fair share governor.
+			"user_space": Use user space governor.
+			"power_allocator": Use power allocator governor.
+			"low_limits_floor": Use low limits floor
+						mitigation governor.
+			"low_limits_cap": Use a low limits cap mitigation
+						governor.
+  Type: string
+
 - sustainable-power:	An estimate of the sustainable power (in mW) that the
   Type: unsigned	thermal zone can dissipate at the desired
   Size: one cell	control temperature.  For reference, the
@@ -175,6 +187,11 @@
 			2000mW, while on a 10'' tablet is around
 			4500mW.
 
+- tracks-low:		Indicates that the temperature sensor tracks the low
+  Type: bool		thresholds, so the governors may mitigate by ensuring
+			timing closures and other low temperature operating
+			issues.
+
 Note: The delay properties are bound to the maximum dT/dt (temperature
 derivative over time) in two situations for a thermal zone:
 (i)  - when passive cooling is activated (polling-delay-passive); and
diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
new file mode 100644
index 0000000..1065456
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -0,0 +1,54 @@
+Qualcomm Technologies, Inc. TSENS driver
+
+Temperature sensor (TSENS) driver supports reading temperature from sensors
+across the MSM. The driver defaults to support a 12 bit ADC.
+
+The driver uses the Thermal sysfs framework to provide thermal
+clients the ability to read from supported on-die temperature sensors,
+set temperature thresholds for cool/warm thresholds and receive notification
+on temperature threshold events.
+
+TSENS node
+
+Required properties:
+- compatible : should be "qcom,msm8996-tsens" for 8996 TSENS driver.
+	       should be "qcom,msm8953-tsens" for 8953 TSENS driver.
+	       should be "qcom,msm8998-tsens" for 8998 TSENS driver.
+	       should be "qcom,msmhamster-tsens" for hamster TSENS driver.
+	       should be "qcom,sdm660-tsens" for 660 TSENS driver.
+	       should be "qcom,sdm630-tsens" for 630 TSENS driver.
+	       should be "qcom,sdm845-tsens" for SDM845 TSENS driver.
+	       The compatible property is used to identify the respective controller to use
+	       for the corresponding SoC.
+- reg : offset and length of the TSENS registers with associated property in reg-names
+	as "tsens_physical" for TSENS TM physical address region.
+- reg-names : resource names used for the physical address of the TSENS
+	      registers. Should be "tsens_physical" for physical address of the TSENS.
+- interrupts : TSENS interrupt to notify Upper/Lower and Critical temperature threshold.
+- interrupt-names: Should be "tsens-upper-lower" for temperature threshold.
+		   Add "tsens-critical" for Critical temperature threshold notification
+		   in addition to "tsens-upper-lower" for 8996 TSENS since
+		   8996 supports Upper/Lower and Critical temperature threshold.
+- qcom,sensors : Total number of available Temperature sensors for TSENS.
+
+Optional properties:
+- qcom,sensor-id : If the flag is present map the TSENS sensors based on the
+		remote sensors that are enabled in HW. Ensure the mapping is not
+		more than the number of supported sensors.
+- qcom,client-id : If the flag is present use it to identify the SW ID mapping
+		used to associate it with the controller and the physical sensor
+		mapping within the controller. The physical sensor mapping within
+		each controller is done using the qcom,sensor-id property. If the
+		property is not present the SW ID mapping with default from 0 to
+		total number of supported sensors with each controller instance.
+
+Example:
+
+tsens@fc4a8000 {
+	compatible = "qcom,msm-tsens";
+	reg = <0xfc4a8000 0x2000>;,
+	reg-names = "tsens_physical";
+	interrupts = <0 184 0>;
+	interrupt-names = "tsens-upper-lower";
+	qcom,sensors = <11>;
+};
diff --git a/Documentation/devicetree/bindings/ufs/ufs-qcom.txt b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt
index af1ba92..af754fe 100644
--- a/Documentation/devicetree/bindings/ufs/ufs-qcom.txt
+++ b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt
@@ -7,11 +7,12 @@
 contain a phandle reference to UFS PHY node.
 
 Required properties:
-- compatible        : compatible list, contains one of the following:
+- compatible        : compatible list, contains one of the following
+		      according to the relevant phy in use:
 		      "qcom,ufs-phy-qmp-14nm"
 		      "qcom,ufs-phy-qmp-v3"
 		      "qcom,ufs-phy-qrbtc-sdm845"
-according to the relevant phy in use.
+		      "qcom,ufs-phy-qmp-v3-660"
 - reg               : should contain PHY register address space (mandatory),
 - reg-names         : indicates various resources passed to driver (via reg proptery) by name.
                       Required "reg-names" is "phy_mem".
@@ -27,11 +28,12 @@
 Optional properties:
 - vdda-phy-max-microamp : specifies max. load that can be drawn from phy supply
 - vdda-pll-max-microamp : specifies max. load that can be drawn from pll supply
-- vddp-ref-clk-supply   : phandle to UFS device ref_clk pad power supply
-- vddp-ref-clk-max-microamp : specifies max. load that can be drawn from this supply
-- vddp-ref-clk-always-on : specifies if this supply needs to be kept always on
 - qcom,disable-lpm : disable various LPM mechanisms in UFS for platform compatibility
   (limit link to PWM Gear-1, 1-lane slow mode; disable hibernate, and avoid suspend/resume)
+- lanes-per-direction:	number of lanes available per direction - either 1 or 2.
+			Note that it is assumed that same number of lanes is
+			used both directions at once.
+			If not specified, default is 2 lanes per direction.
 
 Example:
 
@@ -40,6 +42,7 @@
 		reg = <0xfc597000 0x800>;
 		reg-names = "phy_mem";
 		#phy-cells = <0>;
+		lanes-per-direction = <1>;
 		vdda-phy-supply = <&pma8084_l4>;
 		vdda-pll-supply = <&pma8084_l12>;
 		vdda-phy-max-microamp = <50000>;
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 81c74c5..958194b 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -13,6 +13,9 @@
 - reg               : <registers mapping>
 		      first entry should contain UFS host controller register address space (mandatory),
                       second entry is the device ref. clock control register map (optional).
+- reset             : reset specifier pair consists of phandle for the reset provider
+                      and reset lines used by this controller.
+- reset-names       : reset signal name strings sorted in the same order as the resets property.
 
 Optional properties:
 - phys                  : phandle to UFS PHY node
@@ -52,6 +55,8 @@
 - lanes-per-direction:	number of lanes available per direction - either 1 or 2.
 			Note that it is assume same number of lanes is used both directions at once.
 			If not specified, default is 2 lanes per direction.
+- pinctrl-names, pinctrl-0, pinctrl-1,.. pinctrl-n: Refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt"
+			for these optional properties
 - limit-tx-hs-gear	: Specify the max. limit on the TX HS gear.
 			  Valid range: 1-3. 1 => HS-G1, 2 => HS-G2, 3 => HS-G3
 - limit-rx-hs-gear	: Specify the max. limit on the RX HS gear. Refer "limit-tx-hs-gear" for expected values.
@@ -89,6 +94,8 @@
 		clocks = <&core 0>, <&ref 0>, <&iface 0>;
 		clock-names = "core_clk", "ref_clk", "iface_clk";
 		freq-table-hz = <100000000 200000000>, <0 0>, <0 0>;
+		resets = <clock_gcc GCC_UFS_BCR>;
+		reset-names = "core_reset";
 		phys = <&ufsphy1>;
 		phy-names = "ufsphy";
 		rpm-level = <3>;
@@ -146,6 +153,9 @@
 - qcom,pm-qos-default-cpu:		PM QoS voting is based on the cpu associated with each IO request by the block layer.
 					This defined the default cpu used for PM QoS voting in case a specific cpu value is not available.
 
+- qcom,vddp-ref-clk-supply	 : reference clock to ufs device. Controlled by the host driver.
+- qcom,vddp-ref-clk-max-microamp : specifies max. load that can be drawn for
+				   ref-clk supply.
 Example:
 	ufshc@0xfc598000 {
 		...
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index 18056ee..bc66690 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -66,6 +66,7 @@
   event buffers. 1 event buffer is needed per h/w accelerated endpoint.
 - qcom,pm-qos-latency: This represents max tolerable CPU latency in microsecs,
 	which is used as a vote by driver to get max performance in perf mode.
+- qcom,smmu-s1-bypass: If present, configure SMMU to bypass stage 1 translation.
 
 Sub nodes:
 - Sub node for "DWC3- USB3 controller".
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index 404a0e9..379dc99 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -74,3 +74,13 @@
 	"raw_rpmb_size_mult" is a mutliple of 128kB block.
 	RPMB size in byte is calculated by using the following equation:
 	RPMB partition size = 128kB x raw_rpmb_size_mult
+
+SD/MMC/SDIO Clock Gating Attribute
+==================================
+
+Read and write access is provided to following attribute.
+This attribute appears only if CONFIG_MMC_CLKGATE is enabled.
+
+	clkgate_delay	Tune the clock gating delay with desired value in milliseconds.
+
+echo <desired delay> > /sys/class/mmc_host/mmcX/clkgate_delay
diff --git a/Makefile b/Makefile
index d8f21b3..e70a1eb 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 9
-SUBLEVEL = 18
+SUBLEVEL = 20
 EXTRAVERSION =
 NAME = Roaring Lionus
 
diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi
index 7173ec9..8158c873 100644
--- a/arch/arm/boot/dts/sama5d2.dtsi
+++ b/arch/arm/boot/dts/sama5d2.dtsi
@@ -266,7 +266,7 @@
 		};
 
 		usb1: ohci@00400000 {
-			compatible = "atmel,sama5d2-ohci", "usb-ohci";
+			compatible = "atmel,at91rm9200-ohci", "usb-ohci";
 			reg = <0x00400000 0x100000>;
 			interrupts = <41 IRQ_TYPE_LEVEL_HIGH 2>;
 			clocks = <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h
index 2ef282f..b4e74af 100644
--- a/arch/arm/include/asm/dma-iommu.h
+++ b/arch/arm/include/asm/dma-iommu.h
@@ -24,6 +24,8 @@
 	struct kref		kref;
 };
 
+#ifdef CONFIG_ARM_DMA_USE_IOMMU
+
 struct dma_iommu_mapping *
 arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size);
 
@@ -33,5 +35,29 @@
 					struct dma_iommu_mapping *mapping);
 void arm_iommu_detach_device(struct device *dev);
 
+#else  /* !CONFIG_ARM_DMA_USE_IOMMU */
+
+static inline struct dma_iommu_mapping *
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size)
+{
+	return NULL;
+}
+
+static inline void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
+{
+}
+
+static inline int arm_iommu_attach_device(struct device *dev,
+			struct dma_iommu_mapping *mapping)
+{
+	return -ENODEV;
+}
+
+static inline void arm_iommu_detach_device(struct device *dev)
+{
+}
+
+#endif	/* CONFIG_ARM_DMA_USE_IOMMU */
+
 #endif /* __KERNEL__ */
 #endif
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index b4332b7..31dde8b 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -289,6 +289,22 @@
 		at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1);
 }
 
+static void sama5d3_ddr_standby(void)
+{
+	u32 lpr0;
+	u32 saved_lpr0;
+
+	saved_lpr0 = at91_ramc_read(0, AT91_DDRSDRC_LPR);
+	lpr0 = saved_lpr0 & ~AT91_DDRSDRC_LPCB;
+	lpr0 |= AT91_DDRSDRC_LPCB_POWER_DOWN;
+
+	at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0);
+
+	cpu_do_idle();
+
+	at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0);
+}
+
 /* We manage both DDRAM/SDRAM controllers, we need more than one value to
  * remember.
  */
@@ -323,7 +339,7 @@
 	{ .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby },
 	{ .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby },
 	{ .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby },
-	{ .compatible = "atmel,sama5d3-ddramc", .data = at91_ddr_standby },
+	{ .compatible = "atmel,sama5d3-ddramc", .data = sama5d3_ddr_standby },
 	{ /*sentinel*/ }
 };
 
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index d0d096e..ba0695b 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1079,6 +1079,26 @@
 	  DTBs to be built by default (instead of a standalone Image.gz.)
 	  The image will built in arch/arm64/boot/Image.gz-dtb
 
+choice
+	prompt "Appended DTB Kernel Image name"
+	depends on BUILD_ARM64_APPENDED_DTB_IMAGE
+	help
+	  Enabling this option will cause a specific kernel image Image or
+	  Image.gz to be used for final image creation.
+	  The image will built in arch/arm64/boot/IMAGE-NAME-dtb
+
+	config IMG_GZ_DTB
+		bool "Image.gz-dtb"
+	config IMG_DTB
+		bool "Image-dtb"
+endchoice
+
+config BUILD_ARM64_APPENDED_KERNEL_IMAGE_NAME
+	string
+	depends on BUILD_ARM64_APPENDED_DTB_IMAGE
+	default "Image.gz-dtb" if IMG_GZ_DTB
+	default "Image-dtb" if IMG_DTB
+
 config BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES
 	string "Default dtb names"
 	depends on BUILD_ARM64_APPENDED_DTB_IMAGE
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index f7a21a6..445aeb6 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -120,7 +120,7 @@
 	  This enables support for the ARMv8 based Qualcomm chipsets.
 
 config ARCH_SDM845
-	bool "Enable Support for Qualcomm SDM845"
+	bool "Enable Support for Qualcomm Technologies Inc. SDM845"
 	depends on ARCH_QCOM
 	select COMMON_CLK_QCOM
 	select QCOM_GDSC
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index bba8d2c..13a64c9 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -96,7 +96,7 @@
 
 # Default target when executing plain make
 ifeq ($(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE),y)
-KBUILD_IMAGE	:= Image.gz-dtb
+KBUILD_IMAGE	:= $(subst $\",,$(CONFIG_BUILD_ARM64_APPENDED_KERNEL_IMAGE_NAME))
 else
 KBUILD_IMAGE	:= Image.gz
 endif
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 3eea0af..c32324f 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -9,7 +9,9 @@
 	sdm845-v2-rumi.dtb \
 	sdm845-v2-mtp.dtb \
 	sdm845-v2-cdp.dtb \
-	sdm845-qrd.dtb
+	sdm845-qrd.dtb \
+	sdm845-4k-panel-mtp.dtb \
+	sdm845-4k-panel-cdp.dtb
 
 dtb-$(CONFIG_ARCH_SDM830) += sdm830-sim.dtb \
 	sdm830-rumi.dtb \
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
index 3497e50..a94a716 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
@@ -49,7 +49,9 @@
 
 	apps_smmu: apps-smmu@0x15000000 {
 		compatible = "qcom,qsmmu-v500";
-		reg = <0x15000000 0x80000>;
+		reg = <0x15000000 0x80000>,
+			<0x150c2000 0x20>;
+		reg-names = "base", "tcu-base";
 		#iommu-cells = <1>;
 		qcom,skip-init;
 		#global-interrupts = <1>;
@@ -128,6 +130,7 @@
 			reg = <0x150c5000 0x1000>,
 				<0x150c2200 0x8>;
 			reg-names = "base", "status-reg";
+			qcom,stream-id-range = <0x0 0x400>;
 			qcom,regulator-names = "vdd";
 			vdd-supply = <&hlos1_vote_aggre_noc_mmu_tbu1_gdsc>;
 		};
@@ -138,6 +141,7 @@
 			reg = <0x150c9000 0x1000>,
 				<0x150c2208 0x8>;
 			reg-names = "base", "status-reg";
+			qcom,stream-id-range = <0x400 0x400>;
 			qcom,regulator-names = "vdd";
 			vdd-supply = <&hlos1_vote_aggre_noc_mmu_tbu2_gdsc>;
 		};
@@ -148,6 +152,7 @@
 			reg = <0x150cd000 0x1000>,
 				<0x150c2210 0x8>;
 			reg-names = "base", "status-reg";
+			qcom,stream-id-range = <0x800 0x400>;
 			qcom,regulator-names = "vdd";
 			vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc>;
 		};
@@ -158,6 +163,7 @@
 			reg = <0x150d1000 0x1000>,
 				<0x150c2218 0x8>;
 			reg-names = "base", "status-reg";
+			qcom,stream-id-range = <0xc00 0x400>;
 			qcom,regulator-names = "vdd";
 			vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc>;
 		};
@@ -168,6 +174,7 @@
 			reg = <0x150d5000 0x1000>,
 				<0x150c2220 0x8>;
 			reg-names = "base", "status-reg";
+			qcom,stream-id-range = <0x1000 0x400>;
 			qcom,regulator-names = "vdd";
 			vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc>;
 		};
@@ -178,6 +185,7 @@
 			reg = <0x150d9000 0x1000>,
 				<0x150c2228 0x8>;
 			reg-names = "base", "status-reg";
+			qcom,stream-id-range = <0x1400 0x400>;
 			/* No GDSC */
 		};
 
@@ -187,6 +195,7 @@
 			reg = <0x150dd000 0x1000>,
 				<0x150c2230 0x8>;
 			reg-names = "base", "status-reg";
+			qcom,stream-id-range = <0x1800 0x400>;
 			qcom,regulator-names = "vdd";
 			vdd-supply = <&hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc>;
 		};
@@ -197,6 +206,7 @@
 			reg = <0x150e1000 0x1000>,
 				<0x150c2238 0x8>;
 			reg-names = "base", "status-reg";
+			qcom,stream-id-range = <0x1c00 0x400>;
 			qcom,regulator-names = "vdd";
 			vdd-supply = <&hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc>;
 		};
diff --git a/arch/arm64/boot/dts/qcom/pm8005.dtsi b/arch/arm64/boot/dts/qcom/pm8005.dtsi
index 241864f..1f8d20e 100644
--- a/arch/arm64/boot/dts/qcom/pm8005.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8005.dtsi
@@ -32,37 +32,15 @@
 			label = "pm8005_tz";
 		};
 
-		pm8005_gpios: gpios {
-			compatible = "qcom,qpnp-pin";
+		pm8005_gpios: pinctrl@c000 {
+			compatible = "qcom,spmi-gpio";
+			reg = <0xc000 0x400>;
+			interrupts = <0x4 0xc0 0 IRQ_TYPE_NONE>,
+					<0x4 0xc1 0 IRQ_TYPE_NONE>;
+			interrupt-names = "pm8005_gpio1", "pm8005_gpio2";
 			gpio-controller;
 			#gpio-cells = <2>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			label = "pm8005-gpio";
-
-			gpio@c000 {
-				reg = <0xc000 0x100>;
-				qcom,pin-num = <1>;
-				status = "disabled";
-			};
-
-			gpio@c100 {
-				reg = <0xc100 0x100>;
-				qcom,pin-num = <2>;
-				status = "disabled";
-			};
-
-			gpio@c200 {
-				reg = <0xc200 0x100>;
-				qcom,pin-num = <3>;
-				status = "disabled";
-			};
-
-			gpio@c300 {
-				reg = <0xc300 0x100>;
-				qcom,pin-num = <4>;
-				status = "disabled";
-			};
+			qcom,gpios-disallowed = <3 4>;
 		};
 	};
 
diff --git a/arch/arm64/boot/dts/qcom/pm8998.dtsi b/arch/arm64/boot/dts/qcom/pm8998.dtsi
index ed4fdde..5290f46 100644
--- a/arch/arm64/boot/dts/qcom/pm8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8998.dtsi
@@ -72,169 +72,41 @@
 			label = "pm8998_tz";
 		};
 
-		pm8998_gpios: gpios {
-			compatible = "qcom,qpnp-pin";
+		pm8998_gpios: pinctrl@c000 {
+			compatible = "qcom,spmi-gpio";
+			reg = <0xc000 0x1a00>;
+			interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>,
+					<0x0 0xc1 0 IRQ_TYPE_NONE>,
+					<0x0 0xc3 0 IRQ_TYPE_NONE>,
+					<0x0 0xc4 0 IRQ_TYPE_NONE>,
+					<0x0 0xc5 0 IRQ_TYPE_NONE>,
+					<0x0 0xc6 0 IRQ_TYPE_NONE>,
+					<0x0 0xc7 0 IRQ_TYPE_NONE>,
+					<0x0 0xc8 0 IRQ_TYPE_NONE>,
+					<0x0 0xc9 0 IRQ_TYPE_NONE>,
+					<0x0 0xca 0 IRQ_TYPE_NONE>,
+					<0x0 0xcb 0 IRQ_TYPE_NONE>,
+					<0x0 0xcc 0 IRQ_TYPE_NONE>,
+					<0x0 0xcd 0 IRQ_TYPE_NONE>,
+					<0x0 0xcf 0 IRQ_TYPE_NONE>,
+					<0x0 0xd0 0 IRQ_TYPE_NONE>,
+					<0x0 0xd1 0 IRQ_TYPE_NONE>,
+					<0x0 0xd2 0 IRQ_TYPE_NONE>,
+					<0x0 0xd4 0 IRQ_TYPE_NONE>,
+					<0x0 0xd6 0 IRQ_TYPE_NONE>;
+			interrupt-names = "pm8998_gpio1", "pm8998_gpio2",
+					"pm8998_gpio4", "pm8998_gpio5",
+					"pm8998_gpio6", "pm8998_gpio7",
+					"pm8998_gpio8", "pm8998_gpio9",
+					"pm8998_gpio10", "pm8998_gpio11",
+					"pm8998_gpio12", "pm8998_gpio13",
+					"pm8998_gpio14", "pm8998_gpio16",
+					"pm8998_gpio17", "pm8998_gpio18",
+					"pm8998_gpio19", "pm8998_gpio21",
+					"pm8998_gpio23";
 			gpio-controller;
 			#gpio-cells = <2>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			label = "pm8998-gpio";
-
-			gpio@c000 {
-				reg = <0xc000 0x100>;
-				qcom,pin-num = <1>;
-				status = "disabled";
-			};
-
-			gpio@c100 {
-				reg = <0xc100 0x100>;
-				qcom,pin-num = <2>;
-				status = "disabled";
-			};
-
-			gpio@c200 {
-				reg = <0xc200 0x100>;
-				qcom,pin-num = <3>;
-				status = "disabled";
-			};
-
-			gpio@c300 {
-				reg = <0xc300 0x100>;
-				qcom,pin-num = <4>;
-				status = "disabled";
-			};
-
-			gpio@c400 {
-				reg = <0xc400 0x100>;
-				qcom,pin-num = <5>;
-				status = "disabled";
-			};
-
-			gpio@c500 {
-				reg = <0xc500 0x100>;
-				qcom,pin-num = <6>;
-				status = "disabled";
-			};
-
-			gpio@c600 {
-				reg = <0xc600 0x100>;
-				qcom,pin-num = <7>;
-				status = "disabled";
-			};
-
-			gpio@c700 {
-				reg = <0xc700 0x100>;
-				qcom,pin-num = <8>;
-				status = "disabled";
-			};
-
-			gpio@c800 {
-				reg = <0xc800 0x100>;
-				qcom,pin-num = <9>;
-				status = "disabled";
-			};
-
-			gpio@c900 {
-				reg = <0xc900 0x100>;
-				qcom,pin-num = <10>;
-				status = "disabled";
-			};
-
-			gpio@ca00 {
-				reg = <0xca00 0x100>;
-				qcom,pin-num = <11>;
-				status = "disabled";
-			};
-
-			gpio@cb00 {
-				reg = <0xcb00 0x100>;
-				qcom,pin-num = <12>;
-				status = "disabled";
-			};
-
-			gpio@cc00 {
-				reg = <0xcc00 0x100>;
-				qcom,pin-num = <13>;
-				status = "disabled";
-			};
-
-			gpio@cd00 {
-				reg = <0xcd00 0x100>;
-				qcom,pin-num = <14>;
-				status = "disabled";
-			};
-
-			gpio@ce00 {
-				reg = <0xce00 0x100>;
-				qcom,pin-num = <15>;
-				status = "disabled";
-			};
-
-			gpio@cf00 {
-				reg = <0xcf00 0x100>;
-				qcom,pin-num = <16>;
-				status = "disabled";
-			};
-
-			gpio@d000 {
-				reg = <0xd000 0x100>;
-				qcom,pin-num = <17>;
-				status = "disabled";
-			};
-
-			gpio@d100 {
-				reg = <0xd100 0x100>;
-				qcom,pin-num = <18>;
-				status = "disabled";
-			};
-
-			gpio@d200 {
-				reg = <0xd200 0x100>;
-				qcom,pin-num = <19>;
-				status = "disabled";
-			};
-
-			gpio@d300 {
-				reg = <0xd300 0x100>;
-				qcom,pin-num = <20>;
-				status = "disabled";
-			};
-
-			gpio@d400 {
-				reg = <0xd400 0x100>;
-				qcom,pin-num = <21>;
-				status = "disabled";
-			};
-
-			gpio@d500 {
-				reg = <0xd500 0x100>;
-				qcom,pin-num = <22>;
-				status = "disabled";
-			};
-
-			gpio@d600 {
-				reg = <0xd600 0x100>;
-				qcom,pin-num = <23>;
-				status = "disabled";
-			};
-
-			gpio@d700 {
-				reg = <0xd700 0x100>;
-				qcom,pin-num = <24>;
-				status = "disabled";
-			};
-
-			gpio@d800 {
-				reg = <0xd800 0x100>;
-				qcom,pin-num = <25>;
-				status = "disabled";
-			};
-
-			gpio@d900 {
-				reg = <0xd900 0x100>;
-				qcom,pin-num = <26>;
-				status = "disabled";
-			};
+			qcom,gpios-disallowed = <3 15 20 22 24 25 26>;
 		};
 
 		pm8998_coincell: qcom,coincell@2800 {
diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
index 1659706..1f27b21 100644
--- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
@@ -38,97 +38,29 @@
 			label = "pmi8998_tz";
 		};
 
-		pmi8998_gpios: gpios {
-			compatible = "qcom,qpnp-pin";
+		pmi8998_gpios: pinctrl@c000 {
+			compatible = "qcom,spmi-gpio";
+			reg = <0xc000 0xe00>;
+			interrupts = <0x2 0xc0 0 IRQ_TYPE_NONE>,
+					<0x2 0xc1 0 IRQ_TYPE_NONE>,
+					<0x2 0xc2 0 IRQ_TYPE_NONE>,
+					<0x2 0xc4 0 IRQ_TYPE_NONE>,
+					<0x2 0xc5 0 IRQ_TYPE_NONE>,
+					<0x2 0xc7 0 IRQ_TYPE_NONE>,
+					<0x2 0xc8 0 IRQ_TYPE_NONE>,
+					<0x2 0xc9 0 IRQ_TYPE_NONE>,
+					<0x2 0xca 0 IRQ_TYPE_NONE>,
+					<0x2 0xcb 0 IRQ_TYPE_NONE>,
+					<0x2 0xcd 0 IRQ_TYPE_NONE>;
+			interrupt-names = "pmi8998_gpio1", "pmi8998_gpio2",
+					"pmi8998_gpio3", "pmi8998_gpio5",
+					"pmi8998_gpio6", "pmi8998_gpio8",
+					"pmi8998_gpio9", "pmi8998_gpio10",
+					"pmi8998_gpio11", "pmi8998_gpio12",
+					"pmi8998_gpio14";
 			gpio-controller;
 			#gpio-cells = <2>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			label = "pmi8998-gpio";
-
-			gpio@c000 {
-				reg = <0xc000 0x100>;
-				qcom,pin-num = <1>;
-				status = "disabled";
-			};
-
-			gpio@c100 {
-				reg = <0xc100 0x100>;
-				qcom,pin-num = <2>;
-				status = "disabled";
-			};
-
-			gpio@c200 {
-				reg = <0xc200 0x100>;
-				qcom,pin-num = <3>;
-				status = "disabled";
-			};
-
-			gpio@c300 {
-				reg = <0xc300 0x100>;
-				qcom,pin-num = <4>;
-				status = "disabled";
-			};
-
-			gpio@c400 {
-				reg = <0xc400 0x100>;
-				qcom,pin-num = <5>;
-				status = "disabled";
-			};
-
-			gpio@c500 {
-				reg = <0xc500 0x100>;
-				qcom,pin-num = <6>;
-				status = "disabled";
-			};
-
-			gpio@c600 {
-				reg = <0xc600 0x100>;
-				qcom,pin-num = <7>;
-				status = "disabled";
-			};
-
-			gpio@c700 {
-				reg = <0xc700 0x100>;
-				qcom,pin-num = <8>;
-				status = "disabled";
-			};
-
-			gpio@c800 {
-				reg = <0xc800 0x100>;
-				qcom,pin-num = <9>;
-				status = "disabled";
-			};
-
-			gpio@c900 {
-				reg = <0xc900 0x100>;
-				qcom,pin-num = <10>;
-				status = "disabled";
-			};
-
-			gpio@ca00 {
-				reg = <0xca00 0x100>;
-				qcom,pin-num = <11>;
-				status = "disabled";
-			};
-
-			gpio@cb00 {
-				reg = <0xcb00 0x100>;
-				qcom,pin-num = <12>;
-				status = "disabled";
-			};
-
-			gpio@cc00 {
-				reg = <0xcc00 0x100>;
-				qcom,pin-num = <13>;
-				status = "disabled";
-			};
-
-			gpio@cd00 {
-				reg = <0xcd00 0x100>;
-				qcom,pin-num = <14>;
-				status = "disabled";
-			};
+			qcom,gpios-disallowed = <4 7 13>;
 		};
 
 		pmi8998_rradc: rradc@4500 {
@@ -372,7 +304,7 @@
 			qcom,en-ext-pfet-sc-pro;
 			qcom,pmic-revid = <&pmi8998_revid>;
 			qcom,loop-auto-gm-en;
-			status = "okay";
+			status = "disabled";
 		};
 
 		flash_led: qcom,leds@d300 {
diff --git a/arch/arm64/boot/dts/qcom/sdm830-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm830-pinctrl.dtsi
index a8d559c..4b3fa93 100644
--- a/arch/arm64/boot/dts/qcom/sdm830-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm830-pinctrl.dtsi
@@ -11,9 +11,9 @@
  */
 
 &soc {
-	tlmm: pinctrl@03800000 {
+	tlmm: pinctrl@03400000 {
 		compatible = "qcom,sdm830-pinctrl";
-		reg = <0x03800000 0xc00000>;
+		reg = <0x03400000 0xc00000>;
 		interrupts = <0 208 0>;
 		gpio-controller;
 		#gpio-cells = <2>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
new file mode 100644
index 0000000..d5646bf
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
@@ -0,0 +1,23 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm845.dtsi"
+#include "sdm845-cdp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel CDP";
+	compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
+	qcom,board-id = <1 1>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
new file mode 100644
index 0000000..d641276
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
@@ -0,0 +1,23 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm845.dtsi"
+#include "sdm845-mtp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel MTP";
+	compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
+	qcom,board-id = <8 1>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
index 115c7b8..b66ca94 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
@@ -27,7 +27,8 @@
 		reg = <0x170f700c 0x4>,
 		      <0x170f7010 0x4>;
 		reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
-		qcom,clk-div = <27>;
+		qcom,clk-div = <192>;
+		qcom,clk-mult = <10>;
 	};
 
 	sound-tavil {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
index 2d2b264..a51f411 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
@@ -24,22 +24,38 @@
 			<0x1380000 0x40000>,
 			<0x1380000 0x40000>,
 			<0x1740000 0x40000>,
+			<0x1620000 0x40000>,
 			<0x1620000 0x40000>;
 
 		reg-names = "aggre1_noc-base", "aggre2_noc-base",
 			"config_noc-base", "dc_noc-base",
 			"gladiator_noc-base", "mc_virt-base", "mem_noc-base",
-			"mmss_noc-base", "system_noc-base";
+			"mmss_noc-base", "system_noc-base", "ipa_virt-base";
 
 		mbox-names = "apps_rsc", "disp_rsc";
 		mboxes = <&apps_rsc 0 &disp_rsc 0>;
 
+	/*RSCs*/
+		rsc_apps: rsc-apps {
+			cell-id = <MSM_BUS_RSC_APPS>;
+			label = "apps_rsc";
+			qcom,rsc-dev;
+			qcom,req_state = <2>;
+		};
+
+		rsc_disp: rsc-disp {
+			cell-id = <MSM_BUS_RSC_DISP>;
+			label = "disp_rsc";
+			qcom,rsc-dev;
+			qcom,req_state = <3>;
+		};
+
 	/*BCMs*/
 		bcm_acv: bcm-acv {
 			cell-id = <MSM_BUS_BCM_ACV>;
 			label = "ACV";
 			qcom,bcm-name = "ACV";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -47,7 +63,7 @@
 			cell-id = <MSM_BUS_BCM_ALC>;
 			label = "ALC";
 			qcom,bcm-name = "ALC";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -55,7 +71,7 @@
 			cell-id = <MSM_BUS_BCM_MC0>;
 			label = "MC0";
 			qcom,bcm-name = "MC0";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -63,7 +79,7 @@
 			cell-id = <MSM_BUS_BCM_SH0>;
 			label = "SH0";
 			qcom,bcm-name = "SH0";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -71,7 +87,7 @@
 			cell-id = <MSM_BUS_BCM_MM0>;
 			label = "MM0";
 			qcom,bcm-name = "MM0";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -79,7 +95,7 @@
 			cell-id = <MSM_BUS_BCM_SH1>;
 			label = "SH1";
 			qcom,bcm-name = "SH1";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -87,7 +103,7 @@
 			cell-id = <MSM_BUS_BCM_MM1>;
 			label = "MM1";
 			qcom,bcm-name = "MM1";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -95,7 +111,7 @@
 			cell-id = <MSM_BUS_BCM_SH2>;
 			label = "SH2";
 			qcom,bcm-name = "SH2";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -103,7 +119,7 @@
 			cell-id = <MSM_BUS_BCM_MM2>;
 			label = "MM2";
 			qcom,bcm-name = "MM2";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -111,7 +127,7 @@
 			cell-id = <MSM_BUS_BCM_SH3>;
 			label = "SH3";
 			qcom,bcm-name = "SH3";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -119,7 +135,7 @@
 			cell-id = <MSM_BUS_BCM_MM3>;
 			label = "MM3";
 			qcom,bcm-name = "MM3";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -127,7 +143,7 @@
 			cell-id = <MSM_BUS_BCM_SH4>;
 			label = "SH4";
 			qcom,bcm-name = "SH4";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -135,15 +151,7 @@
 			cell-id = <MSM_BUS_BCM_SH5>;
 			label = "SH5";
 			qcom,bcm-name = "SH5";
-			qcom,drv-id = <2>;
-			qcom,bcm-dev;
-		};
-
-		bcm_mm5: bcm-mm5 {
-			cell-id = <MSM_BUS_BCM_MM5>;
-			label = "MM5";
-			qcom,bcm-name = "MM5";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -151,7 +159,7 @@
 			cell-id = <MSM_BUS_BCM_SN0>;
 			label = "SN0";
 			qcom,bcm-name = "SN0";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -159,7 +167,7 @@
 			cell-id = <MSM_BUS_BCM_CE0>;
 			label = "CE0";
 			qcom,bcm-name = "CE0";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -167,7 +175,7 @@
 			cell-id = <MSM_BUS_BCM_IP0>;
 			label = "IP0";
 			qcom,bcm-name = "IP0";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -175,7 +183,14 @@
 			cell-id = <MSM_BUS_BCM_CN0>;
 			label = "CN0";
 			qcom,bcm-name = "CN0";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
+			qcom,bcm-dev;
+		};
+
+		bcm_qup0: bcm-qup0 {
+			cell-id = <MSM_BUS_BCM_QUP0>;
+			label = "QUP0";
+			qcom,bcm-name = "QUP0";
 			qcom,bcm-dev;
 		};
 
@@ -183,7 +198,7 @@
 			cell-id = <MSM_BUS_BCM_SN1>;
 			label = "SN1";
 			qcom,bcm-name = "SN1";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -191,7 +206,7 @@
 			cell-id = <MSM_BUS_BCM_SN2>;
 			label = "SN2";
 			qcom,bcm-name = "SN2";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -199,7 +214,7 @@
 			cell-id = <MSM_BUS_BCM_SN3>;
 			label = "SN3";
 			qcom,bcm-name = "SN3";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -207,7 +222,7 @@
 			cell-id = <MSM_BUS_BCM_SN4>;
 			label = "SN4";
 			qcom,bcm-name = "SN4";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -215,7 +230,7 @@
 			cell-id = <MSM_BUS_BCM_SN5>;
 			label = "SN5";
 			qcom,bcm-name = "SN5";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -223,7 +238,7 @@
 			cell-id = <MSM_BUS_BCM_SN6>;
 			label = "SN6";
 			qcom,bcm-name = "SN6";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -231,7 +246,7 @@
 			cell-id = <MSM_BUS_BCM_SN7>;
 			label = "SN7";
 			qcom,bcm-name = "SN7";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -239,7 +254,7 @@
 			cell-id = <MSM_BUS_BCM_SN8>;
 			label = "SN8";
 			qcom,bcm-name = "SN8";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -247,7 +262,7 @@
 			cell-id = <MSM_BUS_BCM_SN9>;
 			label = "SN9";
 			qcom,bcm-name = "SN9";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -255,7 +270,7 @@
 			cell-id = <MSM_BUS_BCM_SN11>;
 			label = "SN11";
 			qcom,bcm-name = "SN11";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -263,7 +278,7 @@
 			cell-id = <MSM_BUS_BCM_SN12>;
 			label = "SN12";
 			qcom,bcm-name = "SN12";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -271,7 +286,7 @@
 			cell-id = <MSM_BUS_BCM_SN14>;
 			label = "SN14";
 			qcom,bcm-name = "SN14";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -279,7 +294,7 @@
 			cell-id = <MSM_BUS_BCM_SN15>;
 			label = "SN15";
 			qcom,bcm-name = "SN15";
-			qcom,drv-id = <2>;
+			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
 
@@ -287,7 +302,7 @@
 			cell-id = <MSM_BUS_BCM_MC0_DISPLAY>;
 			label = "MC0_DISPLAY";
 			qcom,bcm-name = "MC0";
-			qcom,drv-id = <0>;
+			qcom,rscs = <&rsc_disp>;
 			qcom,bcm-dev;
 		};
 
@@ -295,7 +310,7 @@
 			cell-id = <MSM_BUS_BCM_SH0_DISPLAY>;
 			label = "SH0_DISPLAY";
 			qcom,bcm-name = "SH0";
-			qcom,drv-id = <0>;
+			qcom,rscs = <&rsc_disp>;
 			qcom,bcm-dev;
 		};
 
@@ -303,7 +318,7 @@
 			cell-id = <MSM_BUS_BCM_MM0_DISPLAY>;
 			label = "MM0_DISPLAY";
 			qcom,bcm-name = "MM0";
-			qcom,drv-id = <0>;
+			qcom,rscs = <&rsc_disp>;
 			qcom,bcm-dev;
 		};
 
@@ -311,7 +326,7 @@
 			cell-id = <MSM_BUS_BCM_MM1_DISPLAY>;
 			label = "MM1_DISPLAY";
 			qcom,bcm-name = "MM1";
-			qcom,drv-id = <0>;
+			qcom,rscs = <&rsc_disp>;
 			qcom,bcm-dev;
 		};
 
@@ -319,7 +334,7 @@
 			cell-id = <MSM_BUS_BCM_MM2_DISPLAY>;
 			label = "MM2_DISPLAY";
 			qcom,bcm-name = "MM2";
-			qcom,drv-id = <0>;
+			qcom,rscs = <&rsc_disp>;
 			qcom,bcm-dev;
 		};
 
@@ -327,7 +342,7 @@
 			cell-id = <MSM_BUS_BCM_MM3_DISPLAY>;
 			label = "MM3_DISPLAY";
 			qcom,bcm-name = "MM3";
-			qcom,drv-id = <0>;
+			qcom,rscs = <&rsc_disp>;
 			qcom,bcm-dev;
 		};
 
@@ -382,6 +397,15 @@
 			clocks = <>;
 		};
 
+		fab_ipa_virt: fab-ipa_virt {
+			cell-id = <MSM_BUS_FAB_IPA_VIRT>;
+			label = "fab-ipa_virt";
+			qcom,fab-dev;
+			qcom,base-name = "ipa_virt-base";
+			qcom,bypass-qos-prg;
+			clocks = <>;
+		};
+
 		fab_mc_virt: fab-mc_virt {
 			cell-id = <MSM_BUS_FAB_MC_VIRT>;
 			label = "fab-mc_virt";
@@ -468,6 +492,7 @@
 			qcom,agg-ports = <1>;
 			qcom,connections = <&slv_qns_a1noc_snoc>;
 			qcom,bus-dev = <&fab_aggre1_noc>;
+			qcom,bcms = <&bcm_qup0>;
 		};
 
 		mas_qhm_tsif: mas-qhm-tsif {
@@ -544,6 +569,7 @@
 			qcom,agg-ports = <1>;
 			qcom,connections = <&slv_qns_a2noc_snoc>;
 			qcom,bus-dev = <&fab_aggre2_noc>;
+			qcom,bcms = <&bcm_qup0>;
 		};
 
 		mas_qnm_cnoc: mas-qnm-cnoc {
@@ -575,7 +601,6 @@
 			qcom,qport = <2>;
 			qcom,connections = <&slv_qns_a2noc_snoc>;
 			qcom,bus-dev = <&fab_aggre2_noc>;
-			qcom,bcms = <&bcm_ip0>;
 		};
 
 		mas_xm_pcie3_1: mas-xm-pcie3-1 {
@@ -761,6 +786,15 @@
 			qcom,bus-dev = <&fab_gladiator_noc>;
 		};
 
+		mas_ipa_core: mas-ipa-core {
+			cell-id = <MSM_BUS_MASTER_IPA_CORE>;
+			label = "mas-ipa-core";
+			qcom,buswidth = <1>;
+			qcom,agg-ports = <1>;
+			qcom,connections = <&slv_ipa_core>;
+			qcom,bus-dev = <&fab_ipa_virt>;
+		};
+
 		mas_llcc_mc: mas-llcc-mc {
 			cell-id = <MSM_BUS_MASTER_LLCC>;
 			label = "mas-llcc-mc";
@@ -863,7 +897,6 @@
 			qcom,agg-ports = <1>;
 			qcom,connections = <&slv_srvc_mnoc>;
 			qcom,bus-dev = <&fab_mmss_noc>;
-			qcom,bcms = <&bcm_mm5>;
 		};
 
 		mas_qxm_camnoc_hf: mas-qxm-camnoc-hf {
@@ -1586,6 +1619,15 @@
 			qcom,bus-dev = <&fab_gladiator_noc>;
 		};
 
+		slv_ipa_core:slv-ipa-core {
+			cell-id = <MSM_BUS_SLAVE_IPA>;
+			label = "slv-ipa-core";
+			qcom,buswidth = <1>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_ipa_virt>;
+			qcom,bcms = <&bcm_ip0>;
+		};
+
 		slv_ebi:slv-ebi {
 			cell-id = <MSM_BUS_SLAVE_EBI_CH0>;
 			label = "slv-ebi";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index d47dd36..cd324e6 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -10,8 +10,123 @@
  * GNU General Public License for more details.
  */
 
+#include <dt-bindings/gpio/gpio.h>
+
 &soc {
 	sound-tavil {
 		qcom,us-euro-gpios = <&tavil_us_euro_sw>;
 	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		label = "gpio-keys";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&key_home_default
+			     &key_vol_up_default
+			     &key_cam_snapshot_default
+			     &key_cam_focus_default>;
+
+		home {
+			label = "home";
+			gpios = <&pm8998_gpios 5 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <102>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&pm8998_gpios 6 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+
+		cam_snapshot {
+			label = "cam_snapshot";
+			gpios = <&pm8998_gpios 7 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <766>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+
+		cam_focus {
+			label = "cam_focus";
+			gpios = <&pm8998_gpios 8 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <528>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+	};
+};
+
+&ufsphy_mem {
+	compatible = "qcom,ufs-phy-qmp-v3";
+
+	vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+	vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+	vdda-phy-max-microamp = <62900>;
+	vdda-pll-max-microamp = <18300>;
+
+	status = "ok";
+};
+
+&ufshc_mem {
+	vdd-hba-supply = <&ufs_phy_gdsc>;
+	vdd-hba-fixed-regulator;
+	vcc-supply = <&pm8998_l20>;
+	vccq2-supply = <&pm8998_s4>;
+	vcc-max-microamp = <600000>;
+	vccq2-max-microamp = <600000>;
+
+	qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+	qcom,vddp-ref-clk-max-microamp = <100>;
+
+	status = "ok";
+};
+
+&ufsphy_card {
+	compatible = "qcom,ufs-phy-qmp-v3";
+
+	vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+	vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+	vdda-phy-max-microamp = <62900>;
+	vdda-pll-max-microamp = <18300>;
+
+	status = "ok";
+};
+
+&ufshc_card {
+	vdd-hba-supply = <&ufs_card_gdsc>;
+	vdd-hba-fixed-regulator;
+	vcc-supply = <&pm8998_l21>;
+	vccq2-supply = <&pm8998_s4>;
+	vcc-max-microamp = <300000>;
+	vccq2-max-microamp = <300000>;
+
+	qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+	qcom,vddp-ref-clk-max-microamp = <100>;
+
+	status = "ok";
+};
+
+&pmi8998_flash2 {
+	pinctrl-names = "led_enable", "led_disable";
+	pinctrl-0 = <&flash_led3_front_en>;
+	pinctrl-1 = <&flash_led3_front_dis>;
+};
+
+&pmi8998_torch2 {
+	pinctrl-names = "led_enable", "led_disable";
+	pinctrl-0 = <&flash_led3_front_en>;
+	pinctrl-1 = <&flash_led3_front_dis>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
new file mode 100644
index 0000000..a6efb50
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -0,0 +1,287 @@
+/* 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.
+ */
+
+&soc {
+
+	msm_bus: qcom,kgsl-busmon{
+		label = "kgsl-busmon";
+		compatible = "qcom,kgsl-busmon";
+	};
+
+	gpubw: qcom,gpubw {
+		compatible = "qcom,devbw";
+		governor = "bw_vbif";
+		qcom,src-dst-ports = <26 512>;
+		/*
+		 * active-only flag is used while registering the bus
+		 * governor.It helps release the bus vote when the CPU
+		 * subsystem is inactiv3
+		 */
+		qcom,active-only;
+		qcom,bw-tbl =
+			<     0 /*  off     */ >,
+			<   762 /*  100 MHz */ >,
+			<  1144 /*  150 MHz */ >,
+			<  1525 /*  200 MHz */ >,
+			<  2288 /*  300 MHz */ >,
+			<  3143 /*  412 MHz */ >,
+			<  4173 /*  547 MHz */ >,
+			<  5195 /*  681 MHz */ >,
+			<  5859 /*  768 MHz */ >,
+			<  7759 /*  1017 MHz */ >,
+			<  9887 /*  1296 MHz */ >,
+			<  11863 /*  1555 MHz */ >,
+			<  13763 /*  1804 MHz */ >;
+	};
+
+	msm_gpu: qcom,kgsl-3d0@5000000 {
+		label = "kgsl-3d0";
+		compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+		status = "ok";
+		reg = <0x5000000 0x40000>;
+		reg-names = "kgsl_3d0_reg_memory";
+		interrupts = <0 300 0>;
+		interrupt-names = "kgsl_3d0_irq";
+		qcom,id = <0>;
+
+		qcom,chipid = <0x06030000>;
+
+		qcom,initial-pwrlevel = <2>;
+
+		qcom,gpu-quirk-hfi-use-reg;
+		qcom,gpu-quirk-two-pass-use-wfi;
+
+		qcom,idle-timeout = <100000000>; //msecs
+		qcom,no-nap;
+
+		qcom,highest-bank-bit = <15>;
+
+		qcom,min-access-length = <32>;
+
+		qcom,ubwc-mode = <2>;
+
+		qcom,snapshot-size = <1048576>; //bytes
+
+		qcom,gpu-qdss-stm = <0x161c0000 0x40000>; // base addr, size
+
+		qcom,tsens-name = "tsens_tz_sensor12";
+
+		clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK>,
+			<&clock_gcc GCC_GPU_CFG_AHB_CLK>,
+			<&clock_gpucc GPU_CC_CXO_CLK>,
+			<&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
+			<&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>;
+
+		clock-names = "core_clk", "iface_clk", "rbbmtimer_clk",
+			"mem_clk", "mem_iface_clk";
+
+		qcom,isense-clk-on-level = <1>;
+
+		/* Bus Scale Settings */
+		qcom,gpubw-dev = <&gpubw>;
+		qcom,bus-control;
+		qcom,msm-bus,name = "grp3d";
+		qcom,msm-bus,num-cases = <13>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<26 512 0 0>,
+
+				<26 512 0 800000>,      // 1 bus=100
+				<26 512 0 1200000>,     // 2 bus=150
+				<26 512 0 1600000>,     // 3 bus=200
+				<26 512 0 2400000>,     // 4 bus=300
+				<26 512 0 3296000>,     // 5 bus=412
+				<26 512 0 4376000>,     // 6 bus=547
+				<26 512 0 5448000>,     // 7 bus=681
+				<26 512 0 6144000>,     // 8 bus=768
+				<26 512 0 8136000>,     // 9 bus=1017
+				<26 512 0 10368000>,    // 10 bus=1296
+				<26 512 0 12440000>,    // 11 bus=1555
+				<26 512 0 14432000>;    // 12 bus=1804
+
+		/* GDSC regulator names */
+		regulator-names = "vddcx", "vdd";
+		/* GDSC oxili regulators */
+		vddcx-supply = <&gpu_cx_gdsc>;
+		vdd-supply = <&gpu_gx_gdsc>;
+
+		/* GPU related llc slices */
+		cache-slice-names = "gpu", "gpuhtw";
+		cache-slices = <&llcc 12>, <&llcc 11>;
+
+		/* GPU Mempools */
+		qcom,gpu-mempools {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "qcom,gpu-mempools";
+
+			/* 4K Page Pool configuration */
+			qcom,gpu-mempool@0 {
+				reg = <0>;
+				qcom,mempool-page-size = <4096>;
+				qcom,mempool-reserved = <2048>;
+				qcom,mempool-allocate;
+			};
+			/* 8K Page Pool configuration */
+			qcom,gpu-mempool@1 {
+				reg = <1>;
+				qcom,mempool-page-size = <8192>;
+				qcom,mempool-reserved = <1024>;
+				qcom,mempool-allocate;
+			};
+			/* 64K Page Pool configuration */
+			qcom,gpu-mempool@2 {
+				reg = <2>;
+				qcom,mempool-page-size = <65536>;
+				qcom,mempool-reserved = <256>;
+			};
+			/* 1M Page Pool configuration */
+			qcom,gpu-mempool@3 {
+				reg = <3>;
+				qcom,mempool-page-size = <1048576>;
+				qcom,mempool-reserved = <32>;
+			};
+		};
+
+		/* Power levels */
+		qcom,gpu-pwrlevels {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			compatible = "qcom,gpu-pwrlevels";
+
+			qcom,gpu-pwrlevel@0 {
+				reg = <0>;
+				qcom,gpu-freq = <548000000>;
+				qcom,bus-freq = <12>;
+				qcom,bus-min = <11>;
+				qcom,bus-max = <12>;
+			};
+
+
+			qcom,gpu-pwrlevel@1 {
+				reg = <1>;
+				qcom,gpu-freq = <425000000>;
+				qcom,bus-freq = <7>;
+				qcom,bus-min = <6>;
+				qcom,bus-max = <8>;
+			};
+
+			qcom,gpu-pwrlevel@2 {
+				reg = <2>;
+				qcom,gpu-freq = <280000000>;
+				qcom,bus-freq = <4>;
+				qcom,bus-min = <3>;
+				qcom,bus-max = <5>;
+			};
+
+			qcom,gpu-pwrlevel@3 {
+				reg = <3>;
+				qcom,gpu-freq = <27000000>;
+				qcom,bus-freq = <0>;
+				qcom,bus-min = <0>;
+				qcom,bus-max = <0>;
+			};
+		};
+
+	};
+
+	kgsl_msm_iommu: qcom,kgsl-iommu {
+		compatible = "qcom,kgsl-smmu-v2";
+
+		reg = <0x05040000 0x10000>;
+		qcom,protect = <0x40000 0x10000>;
+		qcom,micro-mmu-control = <0x6000>;
+
+		clocks =<&clock_gcc GCC_GPU_CFG_AHB_CLK>,
+			<&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
+			<&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>;
+
+		clock-names = "iface_clk", "mem_clk", "mem_iface_clk";
+
+		qcom,secure_align_mask = <0xfff>;
+		qcom,global_pt;
+
+		gfx3d_user: gfx3d_user {
+			compatible = "qcom,smmu-kgsl-cb";
+			label = "gfx3d_user";
+			iommus = <&kgsl_smmu 0>;
+			qcom,gpu-offset = <0x48000>;
+		};
+
+		gfx3d_secure: gfx3d_secure {
+			compatible = "qcom,smmu-kgsl-cb";
+			iommus = <&kgsl_smmu 2>;
+		};
+	};
+
+	gmu: qcom,gmu {
+		label = "kgsl-gmu";
+		compatible = "qcom,gpu-gmu";
+
+		reg = <0x506a000 0x26000>, <0xb200000 0x300000>;
+		reg-names = "kgsl_gmu_reg", "kgsl_gmu_pdc_reg";
+
+		interrupts = <0 304 0>, <0 305 0>;
+		interrupt-names = "kgsl_hfi_irq", "kgsl_gmu_irq";
+
+		qcom,msm-bus,name = "cnoc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<26 10036 0 0>,		// CNOC off
+			<26 10036 0 100>;	// CNOC on
+
+		regulator-names = "vddcx", "vdd";
+		vddcx-supply = <&gpu_cx_gdsc>;
+		vdd-supply = <&gpu_gx_gdsc>;
+
+
+		clocks = <&clock_gpucc GPU_CC_CX_GMU_CLK>,
+				<&clock_gcc GCC_GPU_CFG_AHB_CLK>,
+				<&clock_gpucc GPU_CC_CXO_CLK>,
+				<&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
+				<&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>;
+
+		clock-names = "gmu_clk", "ahb_clk", "cxo_clk",
+				"axi_clk", "memnoc_clk";
+
+		qcom,gmu-pwrlevels {
+			compatible = "qcom,gmu-pwrlevels";
+
+			qcom,gmu-pwrlevel@0 {
+				reg = <0>;
+				qcom,gmu-freq = <400000000>;
+			};
+
+			qcom,gmu-pwrlevel@1 {
+				reg = <1>;
+				qcom,gmu-freq = <19200000>;
+			};
+
+			qcom,gmu-pwrlevel@2 {
+				reg = <2>;
+				qcom,gmu-freq = <0>;
+			};
+		};
+
+		gmu_user: gmu_user {
+			compatible = "qcom,smmu-gmu-user-cb";
+			iommus = <&kgsl_smmu 4>;
+		};
+
+		gmu_kernel: gmu_kernel {
+			compatible = "qcom,smmu-gmu-kernel-cb";
+			iommus = <&kgsl_smmu 5>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index cfba6f4..6d61506 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -9,3 +9,109 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
+
+#include <dt-bindings/gpio/gpio.h>
+
+&soc {
+	gpio_keys {
+		compatible = "gpio-keys";
+		label = "gpio-keys";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&key_vol_up_default
+			     &key_cam_snapshot_default
+			     &key_cam_focus_default>;
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&pm8998_gpios 6 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+
+		cam_snapshot {
+			label = "cam_snapshot";
+			gpios = <&pm8998_gpios 7 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <766>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+
+		cam_focus {
+			label = "cam_focus";
+			gpios = <&pm8998_gpios 8 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <528>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+	};
+};
+
+&ufsphy_mem {
+	compatible = "qcom,ufs-phy-qmp-v3";
+
+	vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+	vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+	vdda-phy-max-microamp = <62900>;
+	vdda-pll-max-microamp = <18300>;
+
+	status = "ok";
+};
+
+&ufshc_mem {
+	vdd-hba-supply = <&ufs_phy_gdsc>;
+	vdd-hba-fixed-regulator;
+	vcc-supply = <&pm8998_l20>;
+	vccq2-supply = <&pm8998_s4>;
+	vcc-max-microamp = <600000>;
+	vccq2-max-microamp = <600000>;
+
+	qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+	qcom,vddp-ref-clk-max-microamp = <100>;
+
+	status = "ok";
+};
+
+&ufsphy_card {
+	compatible = "qcom,ufs-phy-qmp-v3";
+
+	vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+	vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+	vdda-phy-max-microamp = <62900>;
+	vdda-pll-max-microamp = <18300>;
+
+	status = "ok";
+};
+
+&ufshc_card {
+	vdd-hba-supply = <&ufs_card_gdsc>;
+	vdd-hba-fixed-regulator;
+	vcc-supply = <&pm8998_l21>;
+	vccq2-supply = <&pm8998_s4>;
+	vcc-max-microamp = <300000>;
+	vccq2-max-microamp = <300000>;
+
+	qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+	qcom,vddp-ref-clk-max-microamp = <100>;
+
+	status = "ok";
+};
+
+&pmi8998_flash2 {
+	pinctrl-names = "led_enable", "led_disable";
+	pinctrl-0 = <&flash_led3_front_en>;
+	pinctrl-1 = <&flash_led3_front_dis>;
+};
+
+&pmi8998_torch2 {
+	pinctrl-names = "led_enable", "led_disable";
+	pinctrl-0 = <&flash_led3_front_en>;
+	pinctrl-1 = <&flash_led3_front_dis>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index c5b53b8..f300684 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -11,15 +11,79 @@
  */
 
 &soc {
-	tlmm: pinctrl@03800000 {
+	tlmm: pinctrl@03400000 {
 		compatible = "qcom,sdm845-pinctrl";
-		reg = <0x03800000 0xc00000>;
+		reg = <0x03400000 0xc00000>;
 		interrupts = <0 208 0>;
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 
+		ufs_dev_reset_assert: ufs_dev_reset_assert {
+			config {
+				pins = "ufs_reset";
+				bias-pull-down;		/* default: pull down */
+				/*
+				 * UFS_RESET driver strengths are having
+				 * different values/steps compared to typical
+				 * GPIO drive strengths.
+				 *
+				 * Following table clarifies:
+				 *
+				 * HDRV value | UFS_RESET | Typical GPIO
+				 *   (dec)    |   (mA)    |    (mA)
+				 *     0      |   0.8     |    2
+				 *     1      |   1.55    |    4
+				 *     2      |   2.35    |    6
+				 *     3      |   3.1     |    8
+				 *     4      |   3.9     |    10
+				 *     5      |   4.65    |    12
+				 *     6      |   5.4     |    14
+				 *     7      |   6.15    |    16
+				 *
+				 * POR value for UFS_RESET HDRV is 3 which means
+				 * 3.1mA and we want to use that. Hence just
+				 * specify 8mA to "drive-strength" binding and
+				 * that should result into writing 3 to HDRV
+				 * field.
+				 */
+				drive-strength = <8>;	/* default: 3.1 mA */
+				output-low; /* active low reset */
+			};
+		};
+
+		ufs_dev_reset_deassert: ufs_dev_reset_deassert {
+			config {
+				pins = "ufs_reset";
+				bias-pull-down;		/* default: pull down */
+				/*
+				 * default: 3.1 mA
+				 * check comments under ufs_dev_reset_assert
+				 */
+				drive-strength = <8>;
+				output-high; /* active low reset */
+			};
+		};
+
+		flash_led3_front {
+			flash_led3_front_en: flash_led3_front_en {
+				mux {
+					pins = "gpio21";
+					drive_strength = <2>;
+					output-high;
+				};
+			};
+
+			flash_led3_front_dis: flash_led3_front_dis {
+				mux {
+					pins = "gpio21";
+					drive_strength = <2>;
+					output-low;
+				};
+			};
+		};
+
 		wcd9xxx_intr {
 			wcd_intr_default: wcd_intr_default{
 				mux {
@@ -1111,5 +1175,1145 @@
 				};
 			};
 		};
+
+		/* QUPv3 South SE mappings */
+		/* SE 0 pin mappings */
+		qupv3_se0_i2c_pins: qupv3_se0_i2c_pins {
+			qupv3_se0_i2c_active: qupv3_se0_i2c_active {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "qup0";
+				};
+
+				config {
+					pins = "gpio0", "gpio1";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se0_i2c_sleep: qupv3_se0_i2c_sleep {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio0", "gpio1";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se0_spi_pins: qupv3_se0_spi_pins {
+			qupv3_se0_spi_active: qupv3_se0_spi_active {
+				mux {
+					pins = "gpio0", "gpio1", "gpio2",
+								"gpio3";
+					function = "qup0";
+				};
+
+				config {
+					pins = "gpio0", "gpio1", "gpio2",
+								"gpio3";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se0_spi_sleep: qupv3_se0_spi_sleep {
+				mux {
+					pins = "gpio0", "gpio1", "gpio2",
+								"gpio3";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio0", "gpio1", "gpio2",
+								"gpio3";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 1 pin mappings */
+		qupv3_se1_i2c_pins: qupv3_se1_i2c_pins {
+			qupv3_se1_i2c_active: qupv3_se1_i2c_active {
+				mux {
+					pins = "gpio17", "gpio18";
+					function = "qup1";
+				};
+
+				config {
+					pins = "gpio17", "gpio18";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se1_i2c_sleep: qupv3_se1_i2c_sleep {
+				mux {
+					pins = "gpio17", "gpio18";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio17", "gpio18";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se1_spi_pins: qupv3_se1_spi_pins {
+			qupv3_se1_spi_active: qupv3_se1_spi_active {
+				mux {
+					pins = "gpio17", "gpio18", "gpio19",
+								"gpio20";
+					function = "qup1";
+				};
+
+				config {
+					pins = "gpio17", "gpio18", "gpio19",
+								"gpio20";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se1_spi_sleep: qupv3_se1_spi_sleep {
+				mux {
+					pins = "gpio17", "gpio18", "gpio19",
+								"gpio20";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio17", "gpio18", "gpio19",
+								"gpio20";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 2 pin mappings */
+		qupv3_se2_i2c_pins: qupv3_se2_i2c_pins {
+			qupv3_se2_i2c_active: qupv3_se2_i2c_active {
+				mux {
+					pins = "gpio27", "gpio28";
+					function = "qup2";
+				};
+
+				config {
+					pins = "gpio27", "gpio28";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se2_i2c_sleep: qupv3_se2_i2c_sleep {
+				mux {
+					pins = "gpio27", "gpio28";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio27", "gpio28";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se2_spi_pins: qupv3_se2_spi_pins {
+			qupv3_se2_spi_active: qupv3_se2_spi_active {
+				mux {
+					pins = "gpio27", "gpio28", "gpio29",
+								"gpio30";
+					function = "qup2";
+				};
+
+				config {
+					pins = "gpio27", "gpio28", "gpio29",
+								"gpio30";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se2_spi_sleep: qupv3_se2_spi_sleep {
+				mux {
+					pins = "gpio27", "gpio28", "gpio29",
+								"gpio30";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio27", "gpio28", "gpio29",
+								"gpio30";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 3 pin mappings */
+		qupv3_se3_i2c_pins: qupv3_se3_i2c_pins {
+			qupv3_se3_i2c_active: qupv3_se3_i2c_active {
+				mux {
+					pins = "gpio41", "gpio42";
+					function = "qup3";
+				};
+
+				config {
+					pins = "gpio41", "gpio42";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se3_i2c_sleep: qupv3_se3_i2c_sleep {
+				mux {
+					pins = "gpio41", "gpio42";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio41", "gpio42";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se3_spi_pins: qupv3_se3_spi_pins {
+			qupv3_se3_spi_active: qupv3_se3_spi_active {
+				mux {
+					pins = "gpio41", "gpio42", "gpio43",
+								"gpio44";
+					function = "qup3";
+				};
+
+				config {
+					pins = "gpio41", "gpio42", "gpio43",
+								"gpio44";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se3_spi_sleep: qupv3_se3_spi_sleep {
+				mux {
+					pins = "gpio41", "gpio42", "gpio43",
+								"gpio44";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio41", "gpio42", "gpio43",
+								"gpio44";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 4 pin mappings */
+		qupv3_se4_i2c_pins: qupv3_se4_i2c_pins {
+			qupv3_se4_i2c_active: qupv3_se4_i2c_active {
+				mux {
+					pins = "gpio89", "gpio90";
+					function = "qup4";
+				};
+
+				config {
+					pins = "gpio89", "gpio90";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se4_i2c_sleep: qupv3_se4_i2c_sleep {
+				mux {
+					pins = "gpio89", "gpio90";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio89", "gpio90";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se4_spi_pins: qupv3_se4_spi_pins {
+			qupv3_se4_spi_active: qupv3_se4_spi_active {
+				mux {
+					pins = "gpio89", "gpio90", "gpio91",
+								"gpio92";
+					function = "qup4";
+				};
+
+				config {
+					pins = "gpio89", "gpio90", "gpio91",
+								"gpio92";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se4_spi_sleep: qupv3_se4_spi_sleep {
+				mux {
+					pins = "gpio89", "gpio90", "gpio91",
+								"gpio92";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio89", "gpio90", "gpio91",
+								"gpio92";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 5 pin mappings */
+		qupv3_se5_i2c_pins: qupv3_se5_i2c_pins {
+			qupv3_se5_i2c_active: qupv3_se5_i2c_active {
+				mux {
+					pins = "gpio85", "gpio86";
+					function = "qup5";
+				};
+
+				config {
+					pins = "gpio85", "gpio86";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se5_i2c_sleep: qupv3_se5_i2c_sleep {
+				mux {
+					pins = "gpio85", "gpio86";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio85", "gpio86";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se5_spi_pins: qupv3_se5_spi_pins {
+			qupv3_se5_spi_active: qupv3_se5_spi_active {
+				mux {
+					pins = "gpio85", "gpio86", "gpio87",
+								"gpio88";
+					function = "qup5";
+				};
+
+				config {
+					pins = "gpio85", "gpio86", "gpio87",
+								"gpio88";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se5_spi_sleep: qupv3_se5_spi_sleep {
+				mux {
+					pins = "gpio85", "gpio86", "gpio87",
+								"gpio88";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio85", "gpio86", "gpio87",
+								"gpio88";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 6 pin mappings */
+		qupv3_se6_i2c_pins: qupv3_se6_i2c_pins {
+			qupv3_se6_i2c_active: qupv3_se6_i2c_active {
+				mux {
+					pins = "gpio45", "gpio46";
+					function = "qup6";
+				};
+
+				config {
+					pins = "gpio45", "gpio46";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se6_i2c_sleep: qupv3_se6_i2c_sleep {
+				mux {
+					pins = "gpio45", "gpio46";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio45", "gpio46";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se6_4uart_pins: qupv3_se6_4uart_pins {
+			qupv3_se6_4uart_active: qupv3_se6_4uart_active {
+				mux {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					function = "qup6";
+				};
+
+				config {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se6_4uart_sleep: qupv3_se6_4uart_sleep {
+				mux {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		qupv3_se6_spi_pins: qupv3_se6_spi_pins {
+			qupv3_se6_spi_active: qupv3_se6_spi_active {
+				mux {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					function = "qup6";
+				};
+
+				config {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se6_spi_sleep: qupv3_se6_spi_sleep {
+				mux {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 7 pin mappings */
+		qupv3_se7_i2c_pins: qupv3_se7_i2c_pins {
+			qupv3_se7_i2c_active: qupv3_se7_i2c_active {
+				mux {
+					pins = "gpio93", "gpio94";
+					function = "qup7";
+				};
+
+				config {
+					pins = "gpio93", "gpio94";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se7_i2c_sleep: qupv3_se7_i2c_sleep {
+				mux {
+					pins = "gpio93", "gpio94";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio93", "gpio94";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se7_4uart_pins: qupv3_se7_4uart_pins {
+			qupv3_se7_4uart_active: qupv3_se7_4uart_active {
+				mux {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					function = "qup7";
+				};
+
+				config {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se7_4uart_sleep: qupv3_se7_4uart_sleep {
+				mux {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		qupv3_se7_spi_pins: qupv3_se7_spi_pins {
+			qupv3_se7_spi_active: qupv3_se7_spi_active {
+				mux {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					function = "qup7";
+				};
+
+				config {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se7_spi_sleep: qupv3_se7_spi_sleep {
+				mux {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* QUPv3 North instances */
+		/* SE 8 pin mappings */
+		qupv3_se8_i2c_pins: qupv3_se8_i2c_pins {
+			qupv3_se8_i2c_active: qupv3_se8_i2c_active {
+				mux {
+					pins = "gpio65", "gpio66";
+					function = "qup8";
+				};
+
+				config {
+					pins = "gpio65", "gpio66";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se8_i2c_sleep: qupv3_se8_i2c_sleep {
+				mux {
+					pins = "gpio65", "gpio66";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio65", "gpio66";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se8_spi_pins: qupv3_se8_spi_pins {
+			qupv3_se8_spi_active: qupv3_se8_spi_active {
+				mux {
+					pins = "gpio65", "gpio66", "gpio67",
+								"gpio68";
+					function = "qup8";
+				};
+
+				config {
+					pins = "gpio65", "gpio66", "gpio67",
+								"gpio68";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se8_spi_sleep: qupv3_se8_spi_sleep {
+				mux {
+					pins = "gpio65", "gpio66", "gpio67",
+								"gpio68";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio65", "gpio66", "gpio67",
+								"gpio68";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 9 pin mappings */
+		qupv3_se9_i2c_pins: qupv3_se9_i2c_pins {
+			qupv3_se9_i2c_active: qupv3_se9_i2c_active {
+				mux {
+					pins = "gpio6", "gpio7";
+					function = "qup9";
+				};
+
+				config {
+					pins = "gpio6", "gpio7";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se9_i2c_sleep: qupv3_se9_i2c_sleep {
+				mux {
+					pins = "gpio6", "gpio7";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio6", "gpio7";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se9_2uart_pins: qupv3_se9_2uart_pins {
+			qupv3_se9_2uart_active: qupv3_se9_2uart_active {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "qup9";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se9_2uart_sleep: qupv3_se9_2uart_sleep {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		qupv3_se9_spi_pins: qupv3_se9_spi_pins {
+			qupv3_se9_spi_active: qupv3_se9_spi_active {
+				mux {
+					pins = "gpio4", "gpio5", "gpio6",
+								"gpio7";
+					function = "qup9";
+				};
+
+				config {
+					pins = "gpio4", "gpio5", "gpio6",
+								"gpio7";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se9_spi_sleep: qupv3_se9_spi_sleep {
+				mux {
+					pins = "gpio4", "gpio5", "gpio6",
+								"gpio7";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio4", "gpio5", "gpio6",
+								"gpio7";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 10 pin mappings */
+		qupv3_se10_i2c_pins: qupv3_se10_i2c_pins {
+			qupv3_se10_i2c_active: qupv3_se10_i2c_active {
+				mux {
+					pins = "gpio55", "gpio56";
+					function = "qup10";
+				};
+
+				config {
+					pins = "gpio55", "gpio56";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se10_i2c_sleep: qupv3_se10_i2c_sleep {
+				mux {
+					pins = "gpio55", "gpio56";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio55", "gpio56";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se10_2uart_pins: qupv3_se10_2uart_pins {
+			qupv3_se10_2uart_active: qupv3_se10_2uart_active {
+				mux {
+					pins = "gpio53", "gpio54";
+					function = "qup10";
+				};
+
+				config {
+					pins = "gpio53", "gpio54";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se10_2uart_sleep: qupv3_se10_2uart_sleep {
+				mux {
+					pins = "gpio53", "gpio54";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio53", "gpio54";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		qupv3_se10_spi_pins: qupv3_se10_spi_pins {
+			qupv3_se10_spi_active: qupv3_se10_spi_active {
+				mux {
+					pins = "gpio53", "gpio54", "gpio55",
+								"gpio56";
+					function = "qup10";
+				};
+
+				config {
+					pins = "gpio53", "gpio54", "gpio55",
+								"gpio56";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se10_spi_sleep: qupv3_se10_spi_sleep {
+				mux {
+					pins = "gpio53", "gpio54", "gpio55",
+								"gpio56";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio53", "gpio54", "gpio55",
+								"gpio56";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 11 pin mappings */
+		qupv3_se11_i2c_pins: qupv3_se11_i2c_pins {
+			qupv3_se11_i2c_active: qupv3_se11_i2c_active {
+				mux {
+					pins = "gpio31", "gpio32";
+					function = "qup11";
+				};
+
+				config {
+					pins = "gpio31", "gpio32";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se11_i2c_sleep: qupv3_se11_i2c_sleep {
+				mux {
+					pins = "gpio31", "gpio32";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio31", "gpio32";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se11_spi_pins: qupv3_se11_spi_pins {
+			qupv3_se11_spi_active: qupv3_se11_spi_active {
+				mux {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					function = "qup11";
+				};
+
+				config {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se11_spi_sleep: qupv3_se11_spi_sleep {
+				mux {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 12 pin mappings */
+		qupv3_se12_i2c_pins: qupv3_se12_i2c_pins {
+			qupv3_se12_i2c_active: qupv3_se12_i2c_active {
+				mux {
+					pins = "gpio49", "gpio50";
+					function = "qup12";
+				};
+
+				config {
+					pins = "gpio49", "gpio50";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se12_i2c_sleep: qupv3_se12_i2c_sleep {
+				mux {
+					pins = "gpio49", "gpio50";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio49", "gpio50";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se12_spi_pins: qupv3_se12_spi_pins {
+			qupv3_se12_spi_active: qupv3_se12_spi_active {
+				mux {
+					pins = "gpio49", "gpio50", "gpio51",
+								"gpio52";
+					function = "qup12";
+				};
+
+				config {
+					pins = "gpio49", "gpio50", "gpio51",
+								"gpio52";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se12_spi_sleep: qupv3_se12_spi_sleep {
+				mux {
+					pins = "gpio49", "gpio50", "gpio51",
+								"gpio52";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio49", "gpio50", "gpio51",
+								"gpio52";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 13 pin mappings */
+		qupv3_se13_i2c_pins: qupv3_se13_i2c_pins {
+			qupv3_se13_i2c_active: qupv3_se13_i2c_active {
+				mux {
+					pins = "gpio105", "gpio106";
+					function = "qup13";
+				};
+
+				config {
+					pins = "gpio105", "gpio106";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se13_i2c_sleep: qupv3_se13_i2c_sleep {
+				mux {
+					pins = "gpio105", "gpio106";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio105", "gpio106";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se13_spi_pins: qupv3_se13_spi_pins {
+			qupv3_se13_spi_active: qupv3_se13_spi_active {
+				mux {
+					pins = "gpio105", "gpio106", "gpio107",
+								"gpio108";
+					function = "qup13";
+				};
+
+				config {
+					pins = "gpio105", "gpio106", "gpio107",
+								"gpio108";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se13_spi_sleep: qupv3_se13_spi_sleep {
+				mux {
+					pins = "gpio105", "gpio106", "gpio107",
+								"gpio108";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio105", "gpio106", "gpio107",
+								"gpio108";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 14 pin mappings */
+		qupv3_se14_i2c_pins: qupv3_se14_i2c_pins {
+			qupv3_se14_i2c_active: qupv3_se14_i2c_active {
+				mux {
+					pins = "gpio33", "gpio34";
+					function = "qup14";
+				};
+
+				config {
+					pins = "gpio33", "gpio34";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se14_i2c_sleep: qupv3_se14_i2c_sleep {
+				mux {
+					pins = "gpio33", "gpio34";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio33", "gpio34";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se14_spi_pins: qupv3_se14_spi_pins {
+			qupv3_se14_spi_active: qupv3_se14_spi_active {
+				mux {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					function = "qup14";
+				};
+
+				config {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se14_spi_sleep: qupv3_se14_spi_sleep {
+				mux {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 15 pin mappings */
+		qupv3_se15_i2c_pins: qupv3_se15_i2c_pins {
+			qupv3_se15_i2c_active: qupv3_se15_i2c_active {
+				mux {
+					pins = "gpio81", "gpio82";
+					function = "qup15";
+				};
+
+				config {
+					pins = "gpio81", "gpio82";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se15_i2c_sleep: qupv3_se15_i2c_sleep {
+				mux {
+					pins = "gpio81", "gpio82";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio81", "gpio82";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se15_spi_pins: qupv3_se15_spi_pins {
+			qupv3_se15_spi_active: qupv3_se15_spi_active {
+				mux {
+					pins = "gpio81", "gpio82", "gpio83",
+								"gpio84";
+					function = "qup15";
+				};
+
+				config {
+					pins = "gpio81", "gpio82", "gpio83",
+								"gpio84";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se15_spi_sleep: qupv3_se15_spi_sleep {
+				mux {
+					pins = "gpio81", "gpio82", "gpio83",
+								"gpio84";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio81", "gpio82", "gpio83",
+								"gpio84";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+	};
+};
+
+&pm8998_gpios {
+	key_home {
+		key_home_default: key_home_default {
+			pins = "gpio5";
+			function = "normal";
+			input-enable;
+			bias-pull-up;
+			power-source = <0>;
+		};
+	};
+
+	key_vol_up {
+		key_vol_up_default: key_vol_up_default {
+			pins = "gpio6";
+			function = "normal";
+			input-enable;
+			bias-pull-up;
+			power-source = <0>;
+		};
+	};
+
+	key_cam_snapshot {
+		key_cam_snapshot_default: key_cam_snapshot_default {
+			pins = "gpio7";
+			function = "normal";
+			input-enable;
+			bias-pull-up;
+			power-source = <0>;
+		};
+	};
+
+	key_cam_focus {
+		key_cam_focus_default: key_cam_focus_default {
+			pins = "gpio8";
+			function = "normal";
+			input-enable;
+			bias-pull-up;
+			power-source = <0>;
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
new file mode 100644
index 0000000..1c31a7a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
@@ -0,0 +1,632 @@
+/* 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.
+ */
+
+&soc {
+	/* QUPv3 South instances */
+
+	/*
+	 * HS UART instances. HS UART usecases can be supported on these
+	 * instances only.
+	 */
+	qupv3_se6_4uart: qcom,qup_uart@0x898000 {
+		compatible = "qcom,msm-geni-serial-hs", "qcom,msm-geni-uart";
+		reg = <0x898000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se6_4uart_active>;
+		pinctrl-1 = <&qupv3_se6_4uart_sleep>;
+		interrupts = <GIC_SPI 607 0>;
+		status = "disabled";
+	};
+
+	qupv3_se7_4uart: qcom,qup_uart@0x89c000 {
+		compatible = "qcom,msm-geni-serial-hs", "qcom,msm-geni-uart";
+		reg = <0x89c000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S7_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se7_4uart_active>;
+		pinctrl-1 = <&qupv3_se7_4uart_sleep>;
+		interrupts = <GIC_SPI 608 0>;
+		status = "disabled";
+	};
+
+	/* I2C */
+	qupv3_se0_i2c: i2c@880000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x880000 0x4000>;
+		interrupts = <GIC_SPI 601 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se0_i2c_active>;
+		pinctrl-1 = <&qupv3_se0_i2c_sleep>;
+		status = "disabled";
+	};
+
+	qupv3_se1_i2c: i2c@884000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x884000 0x4000>;
+		interrupts = <GIC_SPI 602 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S1_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se1_i2c_active>;
+		pinctrl-1 = <&qupv3_se1_i2c_sleep>;
+		status = "disabled";
+	};
+
+	qupv3_se2_i2c: i2c@888000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x888000 0x4000>;
+		interrupts = <GIC_SPI 603 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S2_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se2_i2c_active>;
+		pinctrl-1 = <&qupv3_se2_i2c_sleep>;
+		status = "disabled";
+	};
+
+	qupv3_se3_i2c: i2c@88c000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x88c000 0x4000>;
+		interrupts = <GIC_SPI 604 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S3_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se3_i2c_active>;
+		pinctrl-1 = <&qupv3_se3_i2c_sleep>;
+		status = "disabled";
+	};
+
+	qupv3_se4_i2c: i2c@890000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x890000 0x4000>;
+		interrupts = <GIC_SPI 605 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S4_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se4_i2c_active>;
+		pinctrl-1 = <&qupv3_se4_i2c_sleep>;
+		status = "disabled";
+	};
+
+	qupv3_se5_i2c: i2c@894000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x894000 0x4000>;
+		interrupts = <GIC_SPI 606 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se5_i2c_active>;
+		pinctrl-1 = <&qupv3_se5_i2c_sleep>;
+		status = "disabled";
+	};
+
+	qupv3_se6_i2c: i2c@898000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x898000 0x4000>;
+		interrupts = <GIC_SPI 607 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se6_i2c_active>;
+		pinctrl-1 = <&qupv3_se6_i2c_sleep>;
+		status = "disabled";
+	};
+
+	qupv3_se7_i2c: i2c@89c000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x89c000 0x4000>;
+		interrupts = <GIC_SPI 608 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S7_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se7_i2c_active>;
+		pinctrl-1 = <&qupv3_se7_i2c_sleep>;
+		status = "disabled";
+	};
+
+	/* SPI */
+	qupv3_se0_spi: spi@880000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x880000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se0_spi_active>;
+		pinctrl-1 = <&qupv3_se0_spi_sleep>;
+		interrupts = <GIC_SPI 601 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+
+	qupv3_se1_spi: spi@884000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x884000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S1_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se1_spi_active>;
+		pinctrl-1 = <&qupv3_se1_spi_sleep>;
+		interrupts = <GIC_SPI 602 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+
+	qupv3_se2_spi: spi@888000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x888000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S2_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se2_spi_active>;
+		pinctrl-1 = <&qupv3_se2_spi_sleep>;
+		interrupts = <GIC_SPI 603 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+
+	qupv3_se3_spi: spi@88c000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x88c000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S3_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se3_spi_active>;
+		pinctrl-1 = <&qupv3_se3_spi_sleep>;
+		interrupts = <GIC_SPI 604 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+
+	qupv3_se4_spi: spi@890000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x890000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S4_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se4_spi_active>;
+		pinctrl-1 = <&qupv3_se4_spi_sleep>;
+		interrupts = <GIC_SPI 605 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+
+	qupv3_se5_spi: spi@894000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x894000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se5_spi_active>;
+		pinctrl-1 = <&qupv3_se5_spi_sleep>;
+		interrupts = <GIC_SPI 606 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+
+	qupv3_se6_spi: spi@898000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x898000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se6_spi_active>;
+		pinctrl-1 = <&qupv3_se6_spi_sleep>;
+		interrupts = <GIC_SPI 607 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+
+	qupv3_se7_spi: spi@89c000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x89c000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S7_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se7_spi_active>;
+		pinctrl-1 = <&qupv3_se7_spi_sleep>;
+		interrupts = <GIC_SPI 608 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+
+	/* QUPv3 North Instances */
+	/* 2-wire UART */
+
+	/* Debug UART Instance for CDP/MTP platform */
+	qupv3_se9_2uart: qcom,qup_uart@0xa84000 {
+		compatible = "qcom,msm-geni-console", "qcom,msm-geni-uart";
+		reg = <0xa84000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se9_2uart_active>;
+		pinctrl-1 = <&qupv3_se9_2uart_sleep>;
+		interrupts = <GIC_SPI 354 0>;
+		status = "disabled";
+	};
+
+	/* Debug UART Instance for RUMI platform */
+	qupv3_se10_2uart: qcom,qup_uart@0xa88000 {
+		compatible = "qcom,msm-geni-console", "qcom,msm-geni-uart";
+		reg = <0xa88000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se10_2uart_active>;
+		pinctrl-1 = <&qupv3_se10_2uart_sleep>;
+		interrupts = <GIC_SPI 355 0>;
+		status = "disabled";
+	};
+
+	/* I2C */
+	qupv3_se8_i2c: i2c@a80000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa80000 0x4000>;
+		interrupts = <GIC_SPI 353 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se8_i2c_active>;
+		pinctrl-1 = <&qupv3_se8_i2c_sleep>;
+		status = "disabled";
+	};
+
+	qupv3_se9_i2c: i2c@a84000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa84000 0x4000>;
+		interrupts = <GIC_SPI 354 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se9_i2c_active>;
+		pinctrl-1 = <&qupv3_se9_i2c_sleep>;
+		status = "disabled";
+	};
+
+	qupv3_se10_i2c: i2c@a88000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa88000 0x4000>;
+		interrupts = <GIC_SPI 355 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se10_i2c_active>;
+		pinctrl-1 = <&qupv3_se10_i2c_sleep>;
+		status = "disabled";
+	};
+
+	qupv3_se11_i2c: i2c@a8c000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa8c000 0x4000>;
+		interrupts = <GIC_SPI 356 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S3_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se11_i2c_active>;
+		pinctrl-1 = <&qupv3_se11_i2c_sleep>;
+		status = "disabled";
+	};
+
+	qupv3_se12_i2c: i2c@a90000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa90000 0x4000>;
+		interrupts = <GIC_SPI 357 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se12_i2c_active>;
+		pinctrl-1 = <&qupv3_se12_i2c_sleep>;
+		status = "disabled";
+	};
+
+	qupv3_se13_i2c: i2c@a94000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa94000 0x4000>;
+		interrupts = <GIC_SPI 358 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S5_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se13_i2c_active>;
+		pinctrl-1 = <&qupv3_se13_i2c_sleep>;
+		status = "disabled";
+	};
+
+	qupv3_se14_i2c: i2c@a98000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa98000 0x4000>;
+		interrupts = <GIC_SPI 359 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S6_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se14_i2c_active>;
+		pinctrl-1 = <&qupv3_se14_i2c_sleep>;
+		status = "disabled";
+	};
+
+	qupv3_se15_i2c: i2c@a9c000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa9c000 0x4000>;
+		interrupts = <GIC_SPI 360 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S7_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se15_i2c_active>;
+		pinctrl-1 = <&qupv3_se15_i2c_sleep>;
+		status = "disabled";
+	};
+
+	/* SPI */
+	qupv3_se8_spi: spi@a80000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa80000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se8_spi_active>;
+		pinctrl-1 = <&qupv3_se8_spi_sleep>;
+		interrupts = <GIC_SPI 353 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+
+	qupv3_se9_spi: spi@a84000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa84000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se9_spi_active>;
+		pinctrl-1 = <&qupv3_se9_spi_sleep>;
+		interrupts = <GIC_SPI 354 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+
+	qupv3_se10_spi: spi@a88000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa88000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se10_spi_active>;
+		pinctrl-1 = <&qupv3_se10_spi_sleep>;
+		interrupts = <GIC_SPI 355 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+
+	qupv3_se11_spi: spi@a8c000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa8c000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S3_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se11_spi_active>;
+		pinctrl-1 = <&qupv3_se11_spi_sleep>;
+		interrupts = <GIC_SPI 356 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+
+	qupv3_se12_spi: spi@a90000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa90000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se12_spi_active>;
+		pinctrl-1 = <&qupv3_se12_spi_sleep>;
+		interrupts = <GIC_SPI 357 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+
+	qupv3_se13_spi: spi@a94000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa94000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S5_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se13_spi_active>;
+		pinctrl-1 = <&qupv3_se13_spi_sleep>;
+		interrupts = <GIC_SPI 358 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+
+	qupv3_se14_spi: spi@a98000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa98000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S6_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se14_spi_active>;
+		pinctrl-1 = <&qupv3_se14_spi_sleep>;
+		interrupts = <GIC_SPI 359 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+
+	qupv3_se15_spi: spi@a9c000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa9c000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S7_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se15_spi_active>;
+		pinctrl-1 = <&qupv3_se15_spi_sleep>;
+		interrupts = <GIC_SPI 360 0>;
+		spi-max-frequency = <50000000>;
+		status = "disabled";
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index 67dd934..540f82f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -391,7 +391,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l1: regulator-l1 {
 			regulator-name = "pm8998_l1";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -409,7 +409,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 30000>;
 		pm8998_l2: regulator-l2 {
 			regulator-name = "pm8998_l2";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -427,7 +427,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l3: regulator-l3 {
 			regulator-name = "pm8998_l3";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -458,7 +458,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l5: regulator-l5 {
 			regulator-name = "pm8998_l5";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -476,7 +476,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l6: regulator-l6 {
 			regulator-name = "pm8998_l6";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -494,7 +494,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l7: regulator-l7 {
 			regulator-name = "pm8998_l7";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -512,7 +512,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l8: regulator-l8 {
 			regulator-name = "pm8998_l8";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -530,7 +530,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l9: regulator-l9 {
 			regulator-name = "pm8998_l9";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -548,7 +548,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l10: regulator-l10 {
 			regulator-name = "pm8998_l10";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -566,7 +566,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l11: regulator-l11 {
 			regulator-name = "pm8998_l11";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -584,7 +584,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l12: regulator-l12 {
 			regulator-name = "pm8998_l12";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -638,7 +638,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l15: regulator-l15 {
 			regulator-name = "pm8998_l15";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -656,7 +656,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l16: regulator-l16 {
 			regulator-name = "pm8998_l16";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -674,7 +674,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l17: regulator-l17 {
 			regulator-name = "pm8998_l17";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -692,7 +692,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l18: regulator-l18 {
 			regulator-name = "pm8998_l18";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -710,7 +710,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l19: regulator-l19 {
 			regulator-name = "pm8998_l19";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -782,7 +782,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l23: regulator-l23 {
 			regulator-name = "pm8998_l23";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -801,6 +801,7 @@
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
 		qcom,mode-threshold-currents = <0 10000>;
+		pm8998_l24-parent-supply = <&pm8998_l12>;
 		pm8998_l24: regulator-l24 {
 			regulator-name = "pm8998_l24";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -818,7 +819,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l25: regulator-l25 {
 			regulator-name = "pm8998_l25";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -836,7 +837,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l26: regulator-l26 {
 			regulator-name = "pm8998_l26";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -867,7 +868,7 @@
 		qcom,supported-modes =
 			<RPMH_REGULATOR_MODE_LDO_LPM
 			 RPMH_REGULATOR_MODE_LDO_HPM>;
-		qcom,mode-threshold-currents = <0 10000>;
+		qcom,mode-threshold-currents = <0 1>;
 		pm8998_l28: regulator-l28 {
 			regulator-name = "pm8998_l28";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
index 124ed99..80f34bf 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
@@ -17,11 +17,8 @@
 
 	vdda-phy-supply = <&pm8998_l1>;
 	vdda-pll-supply = <&pm8998_l2>;
-	vddp-ref-clk-supply = <&pm8998_l26>;
 	vdda-phy-max-microamp = <44000>;
 	vdda-pll-max-microamp = <14600>;
-	vddp-ref-clk-max-microamp = <100>;
-	vddp-ref-clk-always-on;
 
 	status = "ok";
 };
@@ -38,6 +35,9 @@
 	vcc-max-microamp = <600000>;
 	vccq2-max-microamp = <600000>;
 
+	qcom,vddp-ref-clk-supply = <&pm8998_l26>;
+	qcom,vddp-ref-clk-max-microamp = <100>;
+
 	qcom,disable-lpm;
 	rpm-level = <0>;
 	spm-level = <0>;
@@ -122,11 +122,8 @@
 
 	vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
 	vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
-	vddp-ref-clk-supply = <&pm8998_l2>;
 	vdda-phy-max-microamp = <62900>;
 	vdda-pll-max-microamp = <18300>;
-	vddp-ref-clk-max-microamp = <100>;
-	vddp-ref-clk-always-on;
 
 	status = "ok";
 };
@@ -142,6 +139,9 @@
 	vcc-max-microamp = <300000>;
 	vccq2-max-microamp = <300000>;
 
+	qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+	qcom,vddp-ref-clk-max-microamp = <100>;
+
 	qcom,disable-lpm;
 	rpm-level = <0>;
 	spm-level = <0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index 5d81487..2ff9b2f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -23,7 +23,6 @@
 #include "dsi-panel-sharp-1080p-cmd.dtsi"
 #include "dsi-panel-sharp-dualmipi-1080p-120hz.dtsi"
 #include "dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi"
-#include "sdm845-pinctrl.dtsi"
 
 &soc {
 	dsi_panel_pwr_supply: dsi_panel_pwr_supply {
@@ -102,7 +101,7 @@
 
 	dsi_sharp_4k_dsc_video_display: qcom,dsi-display@0 {
 		compatible = "qcom,dsi-display";
-		label = "dsi_sharp_4k_dsc_video";
+		label = "dsi_sharp_4k_dsc_video_display";
 		qcom,display-type = "primary";
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
@@ -125,7 +124,7 @@
 
 	dsi_sharp_4k_dsc_cmd_display: qcom,dsi-display@1 {
 		compatible = "qcom,dsi-display";
-		label = "dsi_sharp_4k_dsc_cmd";
+		label = "dsi_sharp_4k_dsc_cmd_display";
 		qcom,display-type = "primary";
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
@@ -148,7 +147,7 @@
 
 	dsi_sharp_1080_cmd_display: qcom,dsi-display@2 {
 		compatible = "qcom,dsi-display";
-		label = "dsi_sharp_1080_cmd";
+		label = "dsi_sharp_1080_cmd_display";
 		qcom,display-type = "primary";
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
@@ -171,7 +170,7 @@
 
 	dsi_dual_sharp_1080_120hz_cmd_display: qcom,dsi-display@3 {
 		compatible = "qcom,dsi-display";
-		label = "dsi_dual_sharp_1080_120hz_cmd";
+		label = "dsi_dual_sharp_1080_120hz_cmd_display";
 		qcom,display-type = "primary";
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
@@ -194,7 +193,7 @@
 
 	dsi_dual_nt35597_truly_video_display: qcom,dsi-display@4 {
 		compatible = "qcom,dsi-display";
-		label = "dsi_dual_nt35597_truly_video";
+		label = "dsi_dual_nt35597_truly_video_display";
 		qcom,display-type = "primary";
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
@@ -217,7 +216,7 @@
 
 	dsi_dual_nt35597_truly_cmd_display: qcom,dsi-display@5 {
 		compatible = "qcom,dsi-display";
-		label = "dsi_dual_nt35597_truly_cmd";
+		label = "dsi_dual_nt35597_truly_cmd_display";
 		qcom,display-type = "primary";
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
@@ -240,7 +239,7 @@
 
 	dsi_nt35597_truly_dsc_cmd_display: qcom,dsi-display@6 {
 		compatible = "qcom,dsi-display";
-		label = "dsi_nt35597_truly_dsc_cmd";
+		label = "dsi_nt35597_truly_dsc_cmd_display";
 		qcom,display-type = "primary";
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
@@ -263,7 +262,7 @@
 
 	dsi_nt35597_truly_dsc_video_display: qcom,dsi-display@7 {
 		compatible = "qcom,dsi-display";
-		label = "dsi_nt35597_truly_dsc_video";
+		label = "dsi_nt35597_truly_dsc_video_display";
 		qcom,display-type = "primary";
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
@@ -294,3 +293,45 @@
 &mdss_mdp {
 	connectors = <&sde_wb>;
 };
+
+&dsi_dual_nt35597_truly_video {
+	qcom,mdss-dsi-panel-timings = [00 1c 07 07 23 21 07 07 05 03 04];
+	qcom,mdss-dsi-t-clk-post = <0x0D>;
+	qcom,mdss-dsi-t-clk-pre = <0x2D>;
+};
+
+&dsi_dual_nt35597_truly_cmd {
+	qcom,mdss-dsi-panel-timings = [00 1c 07 07 23 21 07 07 05 03 04];
+	qcom,mdss-dsi-t-clk-post = <0x0D>;
+	qcom,mdss-dsi-t-clk-pre = <0x2D>;
+};
+
+&dsi_nt35597_truly_dsc_cmd {
+	qcom,mdss-dsi-panel-timings = [00 15 05 05 20 1f 05 05 03 03 04];
+	qcom,mdss-dsi-t-clk-post = <0x0b>;
+	qcom,mdss-dsi-t-clk-pre = <0x23>;
+};
+
+&dsi_nt35597_truly_dsc_video {
+	qcom,mdss-dsi-panel-timings = [00 15 05 05 20 1f 05 05 03 03 04];
+	qcom,mdss-dsi-t-clk-post = <0x0b>;
+	qcom,mdss-dsi-t-clk-pre = <0x23>;
+};
+
+&dsi_sharp_4k_dsc_video {
+	qcom,mdss-dsi-panel-timings = [00 12 04 04 1e 1e 04 04 02 03 04];
+	qcom,mdss-dsi-t-clk-post = <0x0a>;
+	qcom,mdss-dsi-t-clk-pre = <0x1e>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+	qcom,mdss-dsi-panel-timings = [00 12 04 04 1e 1e 04 04 02 03 04];
+	qcom,mdss-dsi-t-clk-post = <0x0a>;
+	qcom,mdss-dsi-t-clk-pre = <0x1e>;
+};
+
+&dsi_dual_sharp_1080_120hz_cmd {
+	qcom,mdss-dsi-panel-timings = [00 24 09 09 26 24 09 09 06 03 04];
+	qcom,mdss-dsi-t-clk-post = <0x0f>;
+	qcom,mdss-dsi-t-clk-pre = <0x36>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index c5340a8..ab4c253 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -112,6 +112,7 @@
 		qcom,sde-sspp-qseed-off = <0xa00>;
 		qcom,sde-mixer-linewidth = <2560>;
 		qcom,sde-sspp-linewidth = <2560>;
+		qcom,sde-wb-linewidth = <4096>;
 		qcom,sde-mixer-blendstages = <0xb>;
 		qcom,sde-highest-bank-bit = <0x2>;
 		qcom,sde-panic-per-pipe;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
index 7f090ad..1c66f89 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
@@ -20,6 +20,7 @@
 		      <0x088ee000 0x400>;
 		reg-names = "core_base", "ahb2phy_base";
 		iommus = <&apps_smmu 0x740>;
+		qcom,smmu-s1-bypass;
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
@@ -76,16 +77,26 @@
 		vdda33-supply = <&pm8998_l24>;
 		qcom,vdd-voltage-level = <0 880000 880000>;
 		qcom,qusb-phy-init-seq =
-				     /* <value reg_offset> */
-					<0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */
-					0x7c 0x18c /* PLL_CLOCK_INVERTERS */
-					0x80 0x2c  /* PLL_CMODE */
-					0x0a 0x184 /* PLL_LOCK_DELAY */
-					0x19 0xb4  /* PLL_DIGITAL_TIMERS_TWO */
-					0xa5 0x240 /* TUNE1 */
-					0x09 0x244 /* TUNE2 */
-					0x00 0x220 /* IMP_CTRL1 */
-					0x58 0x224>; /* IMP_CTRL2 */
+			/* <value reg_offset> */
+			   <0x23 0x210 /* PWR_CTRL1 */
+			    0x03 0x04  /* PLL_ANALOG_CONTROLS_TWO */
+			    0x7c 0x18c /* PLL_CLOCK_INVERTERS */
+			    0x80 0x2c  /* PLL_CMODE */
+			    0x0a 0x184 /* PLL_LOCK_DELAY */
+			    0x19 0xb4  /* PLL_DIGITAL_TIMERS_TWO */
+			    0x40 0x194 /* PLL_BIAS_CONTROL_1 */
+			    0x20 0x198 /* PLL_BIAS_CONTROL_2 */
+			    0x21 0x214 /* PWR_CTRL2 */
+			    0x00 0x220 /* IMP_CTRL1 */
+			    0x58 0x224 /* IMP_CTRL2 */
+			    0x32 0x240 /* TUNE1 */
+			    0x29 0x244 /* TUNE2 */
+			    0xca 0x248 /* TUNE3 */
+			    0x04 0x24c /* TUNE4 */
+			    0x00 0x250 /* TUNE5 */
+			    0x00 0x23c /* CHG_CTRL2 */
+			    0x22 0x210>; /* PWR_CTRL1 */
+
 		phy_type= "utmi";
 		clocks = <&clock_rpmh RPMH_CXO_CLK>,
 			 <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>;
@@ -112,6 +123,7 @@
 		      <0x088ee000 0x400>;
 		reg-names = "core_base", "ahb2phy_base";
 		iommus = <&apps_smmu 0x760>;
+		qcom,smmu-s1-bypass;
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
@@ -165,16 +177,26 @@
 		vdda33-supply = <&pm8998_l24>;
 		qcom,vdd-voltage-level = <0 880000 880000>;
 		qcom,qusb-phy-init-seq =
-				     /* <value reg_offset> */
-					<0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */
-					0x7c 0x18c /* PLL_CLOCK_INVERTERS */
-					0x80 0x2c  /* PLL_CMODE */
-					0x0a 0x184 /* PLL_LOCK_DELAY */
-					0x19 0xb4  /* PLL_DIGITAL_TIMERS_TWO */
-					0xa5 0x240 /* TUNE1 */
-					0x09 0x244 /* TUNE2 */
-					0x00 0x220 /* IMP_CTRL1 */
-					0x58 0x224>; /* IMP_CTRL2 */
+			/* <value reg_offset> */
+			   <0x23 0x210 /* PWR_CTRL1 */
+			   0x03 0x04  /* PLL_ANALOG_CONTROLS_TWO */
+			   0x7c 0x18c /* PLL_CLOCK_INVERTERS */
+			   0x80 0x2c  /* PLL_CMODE */
+			   0x0a 0x184 /* PLL_LOCK_DELAY */
+			   0x19 0xb4  /* PLL_DIGITAL_TIMERS_TWO */
+			   0x40 0x194 /* PLL_BIAS_CONTROL_1 */
+			   0x20 0x198 /* PLL_BIAS_CONTROL_2 */
+			   0x21 0x214 /* PWR_CTRL2 */
+			   0x00 0x220 /* IMP_CTRL1 */
+			   0x58 0x224 /* IMP_CTRL2 */
+			   0x32 0x240 /* TUNE1 */
+			   0x29 0x244 /* TUNE2 */
+			   0xca 0x248 /* TUNE3 */
+			   0x04 0x24c /* TUNE4 */
+			   0x00 0x250 /* TUNE5 */
+			   0x00 0x23c /* CHG_CTRL2 */
+			   0x22 0x210>; /* PWR_CTRL1 */
+
 		phy_type= "utmi";
 		clocks = <&clock_rpmh RPMH_CXO_CLK>,
 			 <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
index ed4956f..af88108 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
@@ -96,13 +96,6 @@
 			virtual-addr-pool = <0x70800000 0x6f800000>;
 		};
 
-		firmware_cb {
-			compatible = "qcom,msm-vidc,context-bank";
-			qcom,fw-context-bank;
-			iommus =
-				<&apps_smmu 0x10b2>;
-		};
-
 		secure_bitstream_cb {
 			compatible = "qcom,msm-vidc,context-bank";
 			label = "venus_sec_bitstream";
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 5c33436..2136c61 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -346,7 +346,7 @@
 			alloc-ranges = <0 0x00000000 0 0xffffffff>;
 			reusable;
 			alignment = <0 0x400000>;
-			size = <0 0x800000>;
+			size = <0 0xc00000>;
 		};
 
 		qseecom_mem: qseecom_region {
@@ -388,6 +388,7 @@
 #include "msm-gdsc-sdm845.dtsi"
 #include "sdm845-sde.dtsi"
 #include "sdm845-sde-display.dtsi"
+#include "sdm845-qupv3.dtsi"
 
 &soc {
 	#address-cells = <1>;
@@ -552,8 +553,168 @@
 			< 1958400 >;
 	};
 
+	cpubw: qcom,cpubw {
+		compatible = "qcom,devbw";
+		governor = "performance";
+		qcom,src-dst-ports = <1 512>;
+		qcom,active-only;
+		qcom,bw-tbl =
+			<  762 /*  200 MHz */ >,
+			< 1144 /*  300 MHz */ >,
+			< 1720 /*  451 MHz */ >,
+			< 2086 /*  547 MHz */ >,
+			< 2597 /*  681 MHz */ >,
+			< 2929 /*  768 MHz */ >,
+			< 3879 /* 1017 MHz */ >,
+			< 4943 /* 1296 MHz */ >,
+			< 5931 /* 1555 MHz */ >,
+			< 6881 /* 1804 MHz */ >;
+	};
+
+	bwmon: qcom,cpu-bwmon {
+		compatible = "qcom,bimc-bwmon4";
+		reg = <0x1436400 0x300>, <0x1436300 0x200>;
+		reg-names = "base", "global_base";
+		interrupts = <0 581 4>;
+		qcom,mport = <0>;
+		qcom,hw-timer-hz = <19200000>;
+		qcom,target-dev = <&cpubw>;
+	};
+
+	memlat_cpu0: qcom,memlat-cpu0 {
+		compatible = "qcom,devbw";
+		governor = "powersave";
+		qcom,src-dst-ports = <1 512>;
+		qcom,active-only;
+		qcom,bw-tbl =
+			<  762 /*  200 MHz */ >,
+			< 1144 /*  300 MHz */ >,
+			< 1720 /*  451 MHz */ >,
+			< 2086 /*  547 MHz */ >,
+			< 2597 /*  681 MHz */ >,
+			< 2929 /*  768 MHz */ >,
+			< 3879 /* 1017 MHz */ >,
+			< 4943 /* 1296 MHz */ >,
+			< 5931 /* 1555 MHz */ >,
+			< 6881 /* 1804 MHz */ >;
+	};
+
+	memlat_cpu4: qcom,memlat-cpu4 {
+		compatible = "qcom,devbw";
+		governor = "powersave";
+		qcom,src-dst-ports = <1 512>;
+		qcom,active-only;
+		status = "ok";
+		qcom,bw-tbl =
+			<  762 /*  200 MHz */ >,
+			< 1144 /*  300 MHz */ >,
+			< 1720 /*  451 MHz */ >,
+			< 2086 /*  547 MHz */ >,
+			< 2597 /*  681 MHz */ >,
+			< 2929 /*  768 MHz */ >,
+			< 3879 /* 1017 MHz */ >,
+			< 4943 /* 1296 MHz */ >,
+			< 5931 /* 1555 MHz */ >,
+			< 6881 /* 1804 MHz */ >;
+	};
+
+	devfreq_memlat_0: qcom,cpu0-memlat-mon {
+		compatible = "qcom,arm-memlat-mon";
+		qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>;
+		qcom,target-dev = <&memlat_cpu0>;
+		qcom,cachemiss-ev = <0x2A>;
+		qcom,core-dev-table =
+			<  300000  762 >,
+			<  748800 1720 >,
+			<  979200 2929 >,
+			< 1209600 3879 >,
+			< 1516800 4943 >,
+			< 1593600 5931 >;
+	};
+
+	devfreq_memlat_4: qcom,cpu4-memlat-mon {
+		compatible = "qcom,arm-memlat-mon";
+		qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>;
+		qcom,target-dev = <&memlat_cpu4>;
+		qcom,cachemiss-ev = <0x2A>;
+		qcom,core-dev-table =
+			<  300000  762 >,
+			< 1036800 2929 >,
+			< 1190400 3879 >,
+			< 1574400 4943 >,
+			< 1804800 5931 >,
+			< 1958400 6881 >;
+	};
+
+	l3_cpu0: qcom,l3-cpu0 {
+		compatible = "devfreq-simple-dev";
+		clock-names = "devfreq_clk";
+		clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>;
+		governor = "performance";
+		freq-tbl-khz =
+			< 300000 >,
+			< 422400 >,
+			< 499200 >,
+			< 576000 >,
+			< 652800 >,
+			< 729600 >,
+			< 806400 >,
+			< 883200 >,
+			< 960000 >;
+	};
+
+	l3_cpu4: qcom,l3-cpu4 {
+		compatible = "devfreq-simple-dev";
+		clock-names = "devfreq_clk";
+		clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>;
+		governor = "performance";
+		freq-tbl-khz =
+			< 300000 >,
+			< 422400 >,
+			< 499200 >,
+			< 576000 >,
+			< 652800 >,
+			< 729600 >,
+			< 806400 >,
+			< 883200 >,
+			< 960000 >;
+	};
+
+	devfreq_l3lat_0: qcom,cpu0-l3lat-mon {
+		compatible = "qcom,arm-memlat-mon";
+		qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>;
+		qcom,target-dev = <&l3_cpu0>;
+		qcom,cachemiss-ev = <0x17>;
+		qcom,core-dev-table =
+			<  300000 300000 >,
+			<  748800 576000 >,
+			<  979200 652800 >,
+			< 1209600 806400 >,
+			< 1516800 883200 >,
+			< 1593600 960000 >;
+	};
+
+	devfreq_l3lat_4: qcom,cpu4-l3lat-mon {
+		compatible = "qcom,arm-memlat-mon";
+		qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>;
+		qcom,target-dev = <&l3_cpu4>;
+		qcom,cachemiss-ev = <0x17>;
+		qcom,core-dev-table =
+			<  300000 300000 >,
+			< 1036800 652800 >,
+			< 1190400 806400 >,
+			< 1574400 883200 >,
+			< 1651200 960000 >;
+	};
+
+	cpu_pmu: cpu-pmu {
+		compatible = "arm,armv8-pmuv3";
+		qcom,irq-is-percpu;
+		interrupts = <1 5 4>;
+	};
+
 	clock_gcc: qcom,gcc@100000 {
-		compatible = "qcom,gcc-sdm845";
+		compatible = "qcom,gcc-sdm845", "syscon";
 		reg = <0x100000 0x1f0000>;
 		reg-names = "cc_base";
 		vdd_cx-supply = <&pm8998_s9_level>;
@@ -563,7 +724,7 @@
 	};
 
 	clock_videocc: qcom,videocc@ab00000 {
-		compatible = "qcom,video_cc-sdm845";
+		compatible = "qcom,video_cc-sdm845", "syscon";
 		reg = <0xab00000 0x10000>;
 		reg-names = "cc_base";
 		vdd_cx-supply = <&pm8998_s9_level>;
@@ -572,7 +733,7 @@
 	};
 
 	clock_camcc: qcom,camcc@ad00000 {
-		compatible = "qcom,cam_cc-sdm845";
+		compatible = "qcom,cam_cc-sdm845", "syscon";
 		reg = <0xad00000 0x10000>;
 		reg-names = "cc_base";
 		vdd_cx-supply = <&pm8998_s9_level>;
@@ -582,7 +743,7 @@
 	};
 
 	clock_dispcc: qcom,dispcc@af00000 {
-		compatible = "qcom,dispcc-sdm845";
+		compatible = "qcom,dispcc-sdm845", "syscon";
 		reg = <0xaf00000 0x100000>;
 		reg-names = "cc_base";
 		vdd_cx-supply = <&pm8998_s9_level>;
@@ -590,16 +751,140 @@
 		#reset-cells = <1>;
 	};
 
-	clock_gpucc: qcom,gpucc {
-		compatible = "qcom,dummycc";
-		clock-output-names = "gpucc_clocks";
+	clock_gpucc: qcom,gpucc@5090000 {
+		compatible = "qcom,gpucc-sdm845", "syscon";
+		reg = <0x5090000 0x9000>;
+		reg-names = "cc_base";
+		vdd_cx-supply = <&pm8998_s9_level>;
+		qcom,gpu_cc_gmu_clk_src-opp-handle = <&gmu>;
 		#clock-cells = <1>;
 		#reset-cells = <1>;
 	};
 
-	clock_cpucc: qcom,cpucc {
-		compatible = "qcom,dummycc";
-		clock-output-names = "cpucc_clocks";
+	clock_gfx: qcom,gfxcc@5090000 {
+		compatible = "qcom,gfxcc-sdm845";
+		reg = <0x5090000 0x9000>;
+		reg-names = "cc_base";
+		vdd_gfx-supply = <&pm8005_s1_level>;
+		vdd_mx-supply = <&pm8998_s6_level>;
+		qcom,gpu_cc_gx_gfx3d_clk_src-opp-handle = <&msm_gpu>;
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+	clock_cpucc: qcom,cpucc@0x17d41000 {
+		compatible = "qcom,clk-cpu-osm";
+		reg = <0x17d41000 0x1400>,
+			<0x17d43000 0x1400>,
+			<0x17d45800 0x1400>,
+			<0x178d0000 0x1000>,
+			<0x178c0000 0x1000>,
+			<0x178b0000 0x1000>,
+			<0x17d42400 0x0c00>,
+			<0x17d44400 0x0c00>,
+			<0x17d46c00 0x0c00>,
+			<0x17810090 0x8>;
+		reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base",
+			"l3_pll", "pwrcl_pll", "perfcl_pll",
+			"l3_sequencer", "pwrcl_sequencer",
+			"perfcl_sequencer", "apps_itm_ctl";
+
+		vdd-l3-supply = <&apc0_l3_vreg>;
+		vdd-pwrcl-supply = <&apc0_pwrcl_vreg>;
+		vdd-perfcl-supply = <&apc1_perfcl_vreg>;
+
+		qcom,l3-speedbin0-v0 =
+			<   300000000 0x000c000f 0x00002020 0x1 1 >,
+			<   422400000 0x50140116 0x00002020 0x1 2 >,
+			<   499200000 0x5014021a 0x00002020 0x1 3 >,
+			<   576000000 0x5014031e 0x00002020 0x1 4 >,
+			<   652800000 0x501c0422 0x00002020 0x1 5 >,
+			<   729600000 0x501c0526 0x00002020 0x1 6 >,
+			<   806400000 0x501c062a 0x00002222 0x1 7 >;
+
+		qcom,pwrcl-speedbin0-v0 =
+			<   300000000 0x000c000f 0x00002020 0x1 1 >,
+			<   422400000 0x50140116 0x00002020 0x1 2 >,
+			<   499200000 0x5014021a 0x00002020 0x1 3 >,
+			<   576000000 0x5014031e 0x00002020 0x1 4 >,
+			<   652800000 0x501c0422 0x00002020 0x1 5 >,
+			<   748800000 0x501c0527 0x00002020 0x1 6 >,
+			<   825600000 0x401c062b 0x00002222 0x1 7 >,
+			<   902400000 0x4024072f 0x00002626 0x1 8 >,
+			<   979200000 0x40240833 0x00002929 0x1 9 >,
+			<  1056000000 0x402c0937 0x00002c2c 0x1 10 >,
+			<  1132800000 0x402c0a3b 0x00002f2f 0x1 11 >,
+			<  1209600000 0x402c0b3f 0x00003333 0x1 12 >;
+
+		qcom,perfcl-speedbin0-v0 =
+			<   300000000 0x000c000f 0x00002020 0x1 1 >,
+			<   422400000 0x50140116 0x00002020 0x1 2 >,
+			<   499200000 0x5014021a 0x00002020 0x1 3 >,
+			<   576000000 0x5014031e 0x00002020 0x1 4 >,
+			<   652800000 0x501c0422 0x00002020 0x1 5 >,
+			<   729600000 0x501c0526 0x00002020 0x1 6 >,
+			<   806400000 0x501c062a 0x00002222 0x1 7 >,
+			<   883200000 0x4024072b 0x00002525 0x1 8 >,
+			<   960000000 0x40240832 0x00002828 0x1 9 >,
+			<  1036800000 0x40240936 0x00002b2b 0x1 10 >,
+			<  1113600000 0x402c0a3a 0x00002e2e 0x1 11 >,
+			<  1190400000 0x402c0b3e 0x00003232 0x1 12 >;
+
+		qcom,l3-min-cpr-vc-bin0 = <7>;
+		qcom,pwrcl-min-cpr-vc-bin0 = <6>;
+		qcom,perfcl-min-cpr-vc-bin0 = <7>;
+
+		qcom,up-timer =
+			<1000 1000 1000>;
+		qcom,down-timer =
+			<100000 100000 100000>;
+		qcom,pc-override-index =
+			<0 0 0>;
+		qcom,set-ret-inactive;
+		qcom,enable-llm-freq-vote;
+		qcom,llm-freq-up-timer =
+			<1000 1000 1000>;
+		qcom,llm-freq-down-timer =
+			<327675 327675 327675>;
+		qcom,enable-llm-volt-vote;
+		qcom,llm-volt-up-timer =
+			<1000 1000 1000>;
+		qcom,llm-volt-down-timer =
+			<327675 327675 327675>;
+		qcom,cc-reads = <10>;
+		qcom,cc-delay = <5>;
+		qcom,cc-factor = <100>;
+		qcom,osm-clk-rate = <100000000>;
+		qcom,xo-clk-rate = <19200000>;
+
+		qcom,l-val-base =
+			<0x178d0004 0x178c0004 0x178b0004>;
+		qcom,apcs-pll-user-ctl =
+			<0x178d000c 0x178c000c 0x178b000c>;
+		qcom,apcs-pll-min-freq =
+			<0x17d41094 0x17d43094 0x17d45894>;
+		qcom,apm-mode-ctl =
+			<0x0 0x0 0x17d20010>;
+		qcom,apm-status-ctrl =
+			<0x0 0x0 0x17d20000>;
+		qcom,perfcl-isense-addr = <0x17871480>;
+		qcom,l3-mem-acc-addr = <0x17990170 0x17990170 0x17990170>;
+		qcom,pwrcl-mem-acc-addr = <0x17990160 0x17990164 0x17990164>;
+		qcom,perfcl-mem-acc-addr = <0x17990168 0x1799016c 0x1799016c>;
+		qcom,cfg-gfmux-addr =<0x178d0084 0x178c0084 0x178b0084>;
+		qcom,apcs-cbc-addr = <0x178d008c 0x178c008c 0x178b008c>;
+		qcom,apcs-ramp-ctl-addr = <0x17840904 0x17840904 0x17830904>;
+
+		qcom,perfcl-apcs-apm-threshold-voltage = <800000>;
+		qcom,perfcl-apcs-mem-acc-threshold-voltage = <852000>;
+		qcom,boost-fsm-en;
+		qcom,safe-fsm-en;
+		qcom,ps-fsm-en;
+		qcom,droop-fsm-en;
+		qcom,osm-pll-setup;
+
+		clock-names = "xo_ao";
+		clocks = <&clock_rpmh RPMH_CXO_CLK_A>;
 		#clock-cells = <1>;
 		#reset-cells = <1>;
 	};
@@ -611,15 +896,31 @@
 		mbox-names = "apps";
 	};
 
+	clock_debug: qcom,cc-debug@100000 {
+		compatible = "qcom,debugcc-sdm845";
+		qcom,cc-count = <5>;
+		qcom,gcc = <&clock_gcc>;
+		qcom,videocc = <&clock_videocc>;
+		qcom,camcc = <&clock_camcc>;
+		qcom,dispcc = <&clock_dispcc>;
+		qcom,gpucc = <&clock_gpucc>;
+		clock-names = "xo_clk_src";
+		clocks = <&clock_rpmh RPMH_CXO_CLK>;
+		#clock-cells = <1>;
+	};
+
 	ufsphy_mem: ufsphy_mem@1d87000 {
 		reg = <0x1d87000 0xda8>; /* PHY regs */
 		reg-names = "phy_mem";
 		#phy-cells = <0>;
 
-		/* TODO: add "ref_clk_src" */
-		clock-names = "ref_clk",
+		lanes-per-direction = <2>;
+
+		clock-names = "ref_clk_src",
+			"ref_clk",
 			"ref_aux_clk";
-		clocks = <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>,
+		clocks = <&clock_rpmh RPMH_LN_BB_CLK1>,
+			<&clock_gcc GCC_UFS_MEM_CLKREF_CLK>,
 			<&clock_gcc GCC_UFS_PHY_PHY_AUX_CLK>;
 
 		status = "disabled";
@@ -635,13 +936,13 @@
 		lanes-per-direction = <2>;
 		dev-ref-clk-freq = <0>; /* 19.2 MHz */
 
-		/* TODO: add "ref_clk" */
 		clock-names =
 			"core_clk",
 			"bus_aggr_clk",
 			"iface_clk",
 			"core_clk_unipro",
 			"core_clk_ice",
+			"ref_clk",
 			"tx_lane0_sync_clk",
 			"rx_lane0_sync_clk",
 			"rx_lane1_sync_clk";
@@ -652,6 +953,7 @@
 			<&clock_gcc GCC_UFS_PHY_AHB_CLK>,
 			<&clock_gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>,
 			<&clock_gcc GCC_UFS_PHY_ICE_CORE_CLK>,
+			<&clock_rpmh RPMH_LN_BB_CLK1>,
 			<&clock_gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>,
 			<&clock_gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>,
 			<&clock_gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>;
@@ -663,34 +965,46 @@
 			<75000000 300000000>,
 			<0 0>,
 			<0 0>,
+			<0 0>,
 			<0 0>;
 
 		qcom,msm-bus,name = "ufshc_mem";
 		qcom,msm-bus,num-cases = <22>;
 		qcom,msm-bus,num-paths = <2>;
 		qcom,msm-bus,vectors-KBps =
-		<95 512 0 0>, <1 650 0 0>,          /* No vote */
-		<95 512 922 0>, <1 650 1000 0>,     /* PWM G1 */
-		<95 512 1844 0>, <1 650 1000 0>,    /* PWM G2 */
-		<95 512 3688 0>, <1 650 1000 0>,    /* PWM G3 */
-		<95 512 7376 0>, <1 650 1000 0>,    /* PWM G4 */
-		<95 512 1844 0>, <1 650 1000 0>,    /* PWM G1 L2 */
-		<95 512 3688 0>, <1 650 1000 0>,    /* PWM G2 L2 */
-		<95 512 7376 0>, <1 650 1000 0>,    /* PWM G3 L2 */
-		<95 512 14752 0>, <1 650 1000 0>,   /* PWM G4 L2 */
-		<95 512 127796 0>, <1 650 1000 0>,  /* HS G1 RA */
-		<95 512 255591 0>, <1 650 1000 0>,  /* HS G2 RA */
-		<95 512 511181 0>, <1 650 1000 0>,  /* HS G3 RA */
-		<95 512 255591 0>, <1 650 1000 0>,  /* HS G1 RA L2 */
-		<95 512 511181 0>, <1 650 1000 0>,  /* HS G2 RA L2 */
-		<95 512 1022362 0>, <1 650 1000 0>, /* HS G3 RA L2 */
-		<95 512 149422 0>, <1 650 1000 0>,  /* HS G1 RB */
-		<95 512 298189 0>, <1 650 1000 0>,  /* HS G2 RB */
-		<95 512 596378 0>, <1 650 1000 0>,  /* HS G3 RB */
-		<95 512 298189 0>, <1 650 1000 0>,  /* HS G1 RB L2 */
-		<95 512 596378 0>, <1 650 1000 0>,  /* HS G2 RB L2 */
-		<95 512 1192756 0>, <1 650 1000 0>, /* HS G3 RB L2 */
-		<95 512 4096000 0>, <1 650 1000 0>; /* Max. bandwidth */
+		/*
+		 * During HS G3 UFS runs at nominal voltage corner, vote
+		 * higher bandwidth to push other buses in the data path
+		 * to run at nominal to achieve max throughput.
+		 * 4GBps pushes BIMC to run at nominal.
+		 * 200MBps pushes CNOC to run at nominal.
+		 * Vote for half of this bandwidth for HS G3 1-lane.
+		 * For max bandwidth, vote high enough to push the buses
+		 * to run in turbo voltage corner.
+		 */
+		<123 512 0 0>, <1 757 0 0>,          /* No vote */
+		<123 512 922 0>, <1 757 1000 0>,     /* PWM G1 */
+		<123 512 1844 0>, <1 757 1000 0>,    /* PWM G2 */
+		<123 512 3688 0>, <1 757 1000 0>,    /* PWM G3 */
+		<123 512 7376 0>, <1 757 1000 0>,    /* PWM G4 */
+		<123 512 1844 0>, <1 757 1000 0>,    /* PWM G1 L2 */
+		<123 512 3688 0>, <1 757 1000 0>,    /* PWM G2 L2 */
+		<123 512 7376 0>, <1 757 1000 0>,    /* PWM G3 L2 */
+		<123 512 14752 0>, <1 757 1000 0>,   /* PWM G4 L2 */
+		<123 512 127796 0>, <1 757 1000 0>,  /* HS G1 RA */
+		<123 512 255591 0>, <1 757 1000 0>,  /* HS G2 RA */
+		<123 512 2097152 0>, <1 757 102400 0>,  /* HS G3 RA */
+		<123 512 255591 0>, <1 757 1000 0>,  /* HS G1 RA L2 */
+		<123 512 511181 0>, <1 757 1000 0>,  /* HS G2 RA L2 */
+		<123 512 4194304 0>, <1 757 204800 0>, /* HS G3 RA L2 */
+		<123 512 149422 0>, <1 757 1000 0>,  /* HS G1 RB */
+		<123 512 298189 0>, <1 757 1000 0>,  /* HS G2 RB */
+		<123 512 2097152 0>, <1 757 102400 0>,  /* HS G3 RB */
+		<123 512 298189 0>, <1 757 1000 0>,  /* HS G1 RB L2 */
+		<123 512 596378 0>, <1 757 1000 0>,  /* HS G2 RB L2 */
+		<123 512 4194304 0>, <1 757 204800 0>, /* HS G3 RB L2 */
+		<123 512 7643136 0>, <1 757 307200 0>; /* Max. bandwidth */
+
 		qcom,bus-vector-names = "MIN",
 		"PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1",
 		"PWM_G1_L2", "PWM_G2_L2", "PWM_G3_L2", "PWM_G4_L2",
@@ -700,6 +1014,18 @@
 		"HS_RB_G1_L2", "HS_RB_G2_L2", "HS_RB_G3_L2",
 		"MAX";
 
+		/* PM QoS */
+		qcom,pm-qos-cpu-groups = <0x0f 0xf0>;
+		qcom,pm-qos-cpu-group-latency-us = <70 70>;
+		qcom,pm-qos-default-cpu = <0>;
+
+		pinctrl-names = "dev-reset-assert", "dev-reset-deassert";
+		pinctrl-0 = <&ufs_dev_reset_assert>;
+		pinctrl-1 = <&ufs_dev_reset_deassert>;
+
+		resets = <&clock_gcc GCC_UFS_PHY_BCR>;
+		reset-names = "core_reset";
+
 		status = "disabled";
 	};
 
@@ -708,10 +1034,13 @@
 		reg-names = "phy_mem";
 		#phy-cells = <0>;
 
-		/* TODO: add "ref_clk_src" */
-		clock-names = "ref_clk",
+		lanes-per-direction = <1>;
+
+		clock-names = "ref_clk_src",
+			"ref_clk",
 			"ref_aux_clk";
-		clocks = <&clock_gcc GCC_UFS_CARD_CLKREF_CLK>,
+		clocks = <&clock_rpmh RPMH_LN_BB_CLK1>,
+			<&clock_gcc GCC_UFS_CARD_CLKREF_CLK>,
 			<&clock_gcc GCC_UFS_CARD_PHY_AUX_CLK>;
 
 		status = "disabled";
@@ -727,13 +1056,13 @@
 		lanes-per-direction = <1>;
 		dev-ref-clk-freq = <0>; /* 19.2 MHz */
 
-		/* TODO: add "ref_clk" */
 		clock-names =
 			"core_clk",
 			"bus_aggr_clk",
 			"iface_clk",
 			"core_clk_unipro",
 			"core_clk_ice",
+			"ref_clk",
 			"tx_lane0_sync_clk",
 			"rx_lane0_sync_clk";
 		/* TODO: add HW CTL clocks when available */
@@ -743,6 +1072,7 @@
 			<&clock_gcc GCC_UFS_CARD_AHB_CLK>,
 			<&clock_gcc GCC_UFS_CARD_UNIPRO_CORE_CLK>,
 			<&clock_gcc GCC_UFS_CARD_ICE_CORE_CLK>,
+			<&clock_rpmh RPMH_LN_BB_CLK1>,
 			<&clock_gcc GCC_UFS_CARD_TX_SYMBOL_0_CLK>,
 			<&clock_gcc GCC_UFS_CARD_RX_SYMBOL_0_CLK>;
 		freq-table-hz =
@@ -752,27 +1082,41 @@
 			<37500000 150000000>,
 			<75000000 300000000>,
 			<0 0>,
+			<0 0>,
 			<0 0>;
 
 		qcom,msm-bus,name = "ufshc_card";
 		qcom,msm-bus,num-cases = <9>;
 		qcom,msm-bus,num-paths = <2>;
 		qcom,msm-bus,vectors-KBps =
-		<95 512 0 0>, <1 650 0 0>,          /* No vote */
-		<95 512 922 0>, <1 650 1000 0>,     /* PWM G1 */
-		<95 512 127796 0>, <1 650 1000 0>,  /* HS G1 RA */
-		<95 512 255591 0>, <1 650 1000 0>,  /* HS G2 RA */
-		<95 512 511181 0>, <1 650 1000 0>,  /* HS G3 RA */
-		<95 512 149422 0>, <1 650 1000 0>,  /* HS G1 RB */
-		<95 512 298189 0>, <1 650 1000 0>,  /* HS G2 RB */
-		<95 512 596378 0>, <1 650 1000 0>,  /* HS G3 RB */
-		<95 512 4096000 0>, <1 650 1000 0>; /* Max. bandwidth */
+		<122 512 0 0>, <1 756 0 0>,          /* No vote */
+		<122 512 922 0>, <1 756 1000 0>,     /* PWM G1 */
+		<122 512 127796 0>, <1 756 1000 0>,  /* HS G1 RA */
+		<122 512 255591 0>, <1 756 1000 0>,  /* HS G2 RA */
+		<122 512 2097152 0>, <1 756 102400 0>,  /* HS G3 RA */
+		<122 512 149422 0>, <1 756 1000 0>,  /* HS G1 RB */
+		<122 512 298189 0>, <1 756 1000 0>,  /* HS G2 RB */
+		<122 512 2097152 0>, <1 756 102400 0>,  /* HS G3 RB */
+		<122 512 7643136 0>, <1 756 307200 0>; /* Max. bandwidth */
 		qcom,bus-vector-names = "MIN",
 		"PWM_G1_L1",
 		"HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1",
 		"HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1",
 		"MAX";
 
+		/* PM QoS */
+		qcom,pm-qos-cpu-groups = <0x0f 0xf0>;
+		qcom,pm-qos-cpu-group-latency-us = <70 70>;
+		qcom,pm-qos-default-cpu = <0>;
+
+		/*
+		 * Note: this instance doesn't have control over UFS device
+		 * reset
+		 */
+
+		resets = <&clock_gcc GCC_UFS_CARD_BCR>;
+		reset-names = "core_reset";
+
 		status = "disabled";
 	};
 
@@ -993,6 +1337,11 @@
 		qcom,rtb-size = <0x100000>;
 	};
 
+	qcom,msm-cdsp-loader {
+		compatible = "qcom,cdsp-loader";
+		qcom,proc-img-to-load = "cdsp";
+	};
+
 	qcom,msm_fastrpc {
 		compatible = "qcom,msm-fastrpc-compute";
 
@@ -1192,10 +1541,12 @@
 				  "l3-scu-faultirq";
 	};
 
-	qcom,llcc@1300000 {
+	qcom,llcc@1100000 {
 		compatible = "qcom,llcc-core", "syscon", "simple-mfd";
-		reg = <0x1300000 0x50000>;
+		reg = <0x1100000 0x250000>;
 		reg-names = "llcc_base";
+		qcom,llcc-banks-off = <0x0 0x80000 0x100000 0x180000>;
+		qcom,llcc-broadcast-off = <0x200000>;
 
 		llcc: qcom,sdm845-llcc {
 			compatible = "qcom,sdm845-llcc";
@@ -1263,8 +1614,21 @@
 		qcom,rx-ring-size = <0x400>;
 	};
 
+	qmp_aop: mailbox@1799000c {
+		compatible = "qcom,qmp-mbox";
+		label = "aop";
+		reg = <0xc300000 0x100000>,
+			<0x1799000c 0x4>;
+		reg-names = "msgram", "irq-reg-base";
+		qcom,irq-mask = <0x1>;
+		interrupts = <0 389 1>;
+		mbox_desc_offset = <0x0>;
+		#mbox-cells = <1>;
+	};
+
 	apps_rsc: mailbox@179e0000 {
 		compatible = "qcom,tcs-drv";
+		label = "apps_rsc";
 		reg = <0x179e0000 0x100>, <0x179e0d00 0x3000>;
 		interrupts = <0 5 0>;
 		#mbox-cells = <1>;
@@ -1277,6 +1641,7 @@
 
 	disp_rsc: mailbox@af20000 {
 		compatible = "qcom,tcs-drv";
+		label = "display_rsc";
 		reg = <0xaf20000 0x100>, <0xaf21c00 0x3000>;
 		interrupts = <0 129 0>;
 		#mbox-cells = <1>;
@@ -1516,7 +1881,6 @@
 		qcom,ipa-hw-ver = <13>; /* IPA core version = IPAv3.5.1 */
 		qcom,ipa-hw-mode = <1>;
 		qcom,ee = <0>;
-		qcom,use-gsi;
 		qcom,use-ipa-tethering-bridge;
 		qcom,modem-cfg-emb-pipe-flt;
 		qcom,ipa-wdi2;
@@ -1671,6 +2035,11 @@
 		      <0x10ae000 0x2000>;
 		reg-names = "dcc-base", "dcc-ram-base";
 	};
+
+	qcom,msm-core@780000 {
+		compatible = "qcom,apss-core-ea";
+		reg = <0x780000 0x1000>;
+	};
 };
 
 &pcie_0_gdsc {
@@ -1788,3 +2157,4 @@
 #include "sdm845-pm.dtsi"
 #include "sdm845-pinctrl.dtsi"
 #include "sdm845-audio.dtsi"
+#include "sdm845-gpu.dtsi"
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index 2e72456..4a13b7a 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -272,18 +272,21 @@
 CONFIG_HW_RANDOM=y
 CONFIG_MSM_ADSPRPC=y
 CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QCOM_GENI=y
 CONFIG_SOUNDWIRE=y
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
+CONFIG_SPI_QCOM_GENI=y
 CONFIG_SPI_SPIDEV=y
 CONFIG_SLIMBUS_MSM_NGD=y
 CONFIG_SPMI=y
 CONFIG_PINCTRL_SDM845=y
 CONFIG_PINCTRL_SDM830=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
-CONFIG_GPIO_QPNP_PIN=y
 CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
 CONFIG_POWER_RESET_XGENE=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_QPNP_FG_GEN3=y
@@ -318,6 +321,7 @@
 CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
 CONFIG_DRM=y
 CONFIG_DRM_SDE_EVTLOG_DEBUG=y
+CONFIG_DRM_SDE_RSC=y
 CONFIG_FB_VIRTUAL=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -402,7 +406,10 @@
 CONFIG_MSM_DISPCC_SDM845=y
 CONFIG_CLOCK_QPNP_DIV=y
 CONFIG_MSM_CLK_RPMH=y
+CONFIG_CLOCK_CPU_OSM=y
+CONFIG_MSM_GPUCC_SDM845=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_QMP=y
 CONFIG_IOMMU_IO_PGTABLE_FAST=y
 CONFIG_ARM_SMMU=y
 CONFIG_QCOM_LAZY_MAPPING=y
@@ -413,6 +420,8 @@
 CONFIG_QCOM_EUD=y
 CONFIG_QCOM_WATCHDOG_V2=y
 CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_BUS_CONFIG_RPMH=y
 CONFIG_QCOM_SECURE_BUFFER=y
 CONFIG_QCOM_EARLY_RANDOM=y
 CONFIG_MSM_SMEM=y
@@ -434,8 +443,10 @@
 CONFIG_MSM_PIL_MSS_QDSP6V5=y
 CONFIG_ICNSS=y
 CONFIG_QCOM_COMMAND_DB=y
+CONFIG_MSM_AVTIMER=y
 CONFIG_MSM_EVENT_TIMER=y
 CONFIG_MSM_PM=y
+CONFIG_APSS_CORE_EA=y
 CONFIG_QCOM_BIMC_BWMON=y
 CONFIG_ARM_MEMLAT_MON=y
 CONFIG_QCOMCCI_HWMON=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 688e130..7333731 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -13,13 +13,11 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
-CONFIG_CGROUPS=y
 CONFIG_CGROUP_DEBUG=y
 CONFIG_CGROUP_FREEZER=y
 CONFIG_CPUSETS=y
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_CGROUP_SCHEDTUNE=y
-CONFIG_CGROUP_SCHED=y
 CONFIG_RT_GROUP_SCHED=y
 CONFIG_SCHED_HMP=y
 CONFIG_SCHED_HMP_CSTATE_AWARE=y
@@ -27,6 +25,7 @@
 CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
+CONFIG_SCHED_AUTOGROUP=y
 CONFIG_SCHED_TUNE=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_RD_XZ is not set
@@ -276,26 +275,27 @@
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_VT is not set
 # CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_MSM=y
-CONFIG_SERIAL_MSM_CONSOLE=y
 CONFIG_DIAG_CHAR=y
 CONFIG_HVC_DCC=y
 CONFIG_HVC_DCC_SERIALIZE_SMP=y
 CONFIG_HW_RANDOM=y
 CONFIG_MSM_ADSPRPC=y
 CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QCOM_GENI=y
 CONFIG_SOUNDWIRE=y
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
+CONFIG_SPI_QCOM_GENI=y
 CONFIG_SPI_SPIDEV=y
 CONFIG_SLIMBUS_MSM_NGD=y
 CONFIG_SPMI=y
 CONFIG_PINCTRL_SDM845=y
 CONFIG_PINCTRL_SDM830=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
-CONFIG_GPIO_QPNP_PIN=y
 CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
 CONFIG_POWER_RESET_XGENE=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_QPNP_FG_GEN3=y
@@ -331,6 +331,7 @@
 CONFIG_QCOM_KGSL=y
 CONFIG_DRM=y
 CONFIG_DRM_SDE_EVTLOG_DEBUG=y
+CONFIG_DRM_SDE_RSC=y
 CONFIG_FB_VIRTUAL=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -422,7 +423,10 @@
 CONFIG_MSM_DISPCC_SDM845=y
 CONFIG_CLOCK_QPNP_DIV=y
 CONFIG_MSM_CLK_RPMH=y
+CONFIG_CLOCK_CPU_OSM=y
+CONFIG_MSM_GPUCC_SDM845=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_QMP=y
 CONFIG_IOMMU_IO_PGTABLE_FAST=y
 CONFIG_ARM_SMMU=y
 CONFIG_QCOM_LAZY_MAPPING=y
@@ -436,6 +440,8 @@
 CONFIG_QCOM_EUD=y
 CONFIG_QCOM_WATCHDOG_V2=y
 CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_BUS_CONFIG_RPMH=y
 CONFIG_QCOM_SECURE_BUFFER=y
 CONFIG_QCOM_EARLY_RANDOM=y
 CONFIG_MSM_SMEM=y
@@ -458,8 +464,10 @@
 CONFIG_ICNSS=y
 CONFIG_ICNSS_DEBUG=y
 CONFIG_QCOM_COMMAND_DB=y
+CONFIG_MSM_AVTIMER=y
 CONFIG_MSM_EVENT_TIMER=y
 CONFIG_MSM_PM=y
+CONFIG_APSS_CORE_EA=y
 CONFIG_QCOM_DCC_V2=y
 CONFIG_QCOM_BIMC_BWMON=y
 CONFIG_ARM_MEMLAT_MON=y
@@ -521,6 +529,8 @@
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
 CONFIG_WQ_WATCHDOG=y
 CONFIG_PANIC_TIMEOUT=5
+CONFIG_PANIC_ON_SCHED_BUG=y
+CONFIG_PANIC_ON_RT_THROTTLING=y
 CONFIG_SCHEDSTATS=y
 CONFIG_SCHED_STACK_END_CHECK=y
 CONFIG_TIMER_STATS=y
@@ -538,7 +548,8 @@
 CONFIG_QCOM_RTB=y
 CONFIG_QCOM_RTB_SEPARATE_CPUS=y
 CONFIG_FUNCTION_TRACER=y
-CONFIG_TRACER_SNAPSHOT=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_PREEMPT_TRACER=y
 CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_CPU_FREQ_SWITCH_PROFILER=y
 CONFIG_LKDTM=y
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index d1472eb..4ad25a5 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -47,9 +47,6 @@
 struct thread_info {
 	unsigned long		flags;		/* low level flags */
 	mm_segment_t		addr_limit;	/* address limit */
-#ifdef CONFIG_ARM64_SW_TTBR0_PAN
-	u64			ttbr0;		/* saved TTBR0_EL1 */
-#endif
 	struct task_struct	*task;		/* main task structure */
 #ifdef CONFIG_ARM64_SW_TTBR0_PAN
 	u64			ttbr0;		/* saved TTBR0_EL1 */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 7d66bba..2c03b01 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -33,7 +33,8 @@
 arm64-obj-$(CONFIG_MODULES)		+= arm64ksyms.o module.o
 arm64-obj-$(CONFIG_ARM64_MODULE_PLTS)	+= module-plts.o
 arm64-obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o perf_callchain.o
-arm64-obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o
+arm64-obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o perf_trace_counters.o   \
+					   perf_trace_user.o
 arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
 arm64-obj-$(CONFIG_CPU_PM)		+= sleep.o suspend.o
 arm64-obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
diff --git a/arch/arm64/kernel/kaslr.c b/arch/arm64/kernel/kaslr.c
index 769f24e..d7e90d9 100644
--- a/arch/arm64/kernel/kaslr.c
+++ b/arch/arm64/kernel/kaslr.c
@@ -131,11 +131,15 @@
 	/*
 	 * The kernel Image should not extend across a 1GB/32MB/512MB alignment
 	 * boundary (for 4KB/16KB/64KB granule kernels, respectively). If this
-	 * happens, increase the KASLR offset by the size of the kernel image.
+	 * happens, increase the KASLR offset by the size of the kernel image
+	 * rounded up by SWAPPER_BLOCK_SIZE.
 	 */
 	if ((((u64)_text + offset + modulo_offset) >> SWAPPER_TABLE_SHIFT) !=
-	    (((u64)_end + offset + modulo_offset) >> SWAPPER_TABLE_SHIFT))
-		offset = (offset + (u64)(_end - _text)) & mask;
+	    (((u64)_end + offset + modulo_offset) >> SWAPPER_TABLE_SHIFT)) {
+		u64 kimg_sz = _end - _text;
+		offset = (offset + round_up(kimg_sz, SWAPPER_BLOCK_SIZE))
+				& mask;
+	}
 
 	if (IS_ENABLED(CONFIG_KASAN))
 		/*
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 6d47969..852548c 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -840,12 +840,10 @@
 	struct hw_perf_event *hwc = &event->hw;
 	unsigned long evtype = hwc->config_base & ARMV8_PMU_EVTYPE_EVENT;
 
-	/* Always place a cycle counter into the cycle counter. */
+	/* Place the first cycle counter request into the cycle counter. */
 	if (evtype == ARMV8_PMUV3_PERFCTR_CPU_CYCLES) {
-		if (test_and_set_bit(ARMV8_IDX_CYCLE_COUNTER, cpuc->used_mask))
-			return -EAGAIN;
-
-		return ARMV8_IDX_CYCLE_COUNTER;
+		if (!test_and_set_bit(ARMV8_IDX_CYCLE_COUNTER, cpuc->used_mask))
+			return ARMV8_IDX_CYCLE_COUNTER;
 	}
 
 	/*
@@ -869,8 +867,6 @@
 {
 	unsigned long config_base = 0;
 
-	if (attr->exclude_idle)
-		return -EPERM;
 	if (is_kernel_in_hyp_mode() &&
 	    attr->exclude_kernel != attr->exclude_hv)
 		return -EINVAL;
@@ -977,11 +973,74 @@
 			     ARRAY_SIZE(pmceid));
 }
 
+static void armv8pmu_idle_update(struct arm_pmu *cpu_pmu)
+{
+	struct pmu_hw_events *hw_events;
+	struct perf_event *event;
+	int idx;
+
+	if (!cpu_pmu)
+		return;
+
+	hw_events = this_cpu_ptr(cpu_pmu->hw_events);
+
+	if (!hw_events)
+		return;
+
+	for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
+
+		if (!test_bit(idx, hw_events->used_mask))
+			continue;
+
+		event = hw_events->events[idx];
+
+		if (!event || !event->attr.exclude_idle ||
+				event->state != PERF_EVENT_STATE_ACTIVE)
+			continue;
+
+		cpu_pmu->pmu.read(event);
+	}
+}
+
+struct arm_pmu_and_idle_nb {
+	struct arm_pmu *cpu_pmu;
+	struct notifier_block perf_cpu_idle_nb;
+};
+
+static int perf_cpu_idle_notifier(struct notifier_block *nb,
+				unsigned long action, void *data)
+{
+	struct arm_pmu_and_idle_nb *pmu_nb = container_of(nb,
+				struct arm_pmu_and_idle_nb, perf_cpu_idle_nb);
+
+	if (action == IDLE_START)
+		armv8pmu_idle_update(pmu_nb->cpu_pmu);
+
+	return NOTIFY_OK;
+}
+
 static int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu)
 {
-	return smp_call_function_any(&cpu_pmu->supported_cpus,
+	int ret;
+	struct arm_pmu_and_idle_nb *pmu_idle_nb;
+
+	pmu_idle_nb = devm_kzalloc(&cpu_pmu->plat_device->dev,
+					sizeof(*pmu_idle_nb), GFP_KERNEL);
+	if (!pmu_idle_nb)
+		return -ENOMEM;
+
+	pmu_idle_nb->cpu_pmu = cpu_pmu;
+	pmu_idle_nb->perf_cpu_idle_nb.notifier_call = perf_cpu_idle_notifier;
+	idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb);
+
+	ret = smp_call_function_any(&cpu_pmu->supported_cpus,
 				    __armv8pmu_probe_pmu,
 				    cpu_pmu, 1);
+
+	if (ret)
+		idle_notifier_unregister(&pmu_idle_nb->perf_cpu_idle_nb);
+
+	return ret;
 }
 
 static void armv8_pmu_init(struct arm_pmu *cpu_pmu)
diff --git a/arch/arm64/kernel/perf_trace_counters.c b/arch/arm64/kernel/perf_trace_counters.c
new file mode 100644
index 0000000..1f0b74a
--- /dev/null
+++ b/arch/arm64/kernel/perf_trace_counters.c
@@ -0,0 +1,177 @@
+/* Copyright (c) 2013-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/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/cpu.h>
+#include <linux/tracepoint.h>
+#include <trace/events/sched.h>
+#define CREATE_TRACE_POINTS
+#include "perf_trace_counters.h"
+
+static unsigned int tp_pid_state;
+
+DEFINE_PER_CPU(u32, cntenset_val);
+DEFINE_PER_CPU(u32, previous_ccnt);
+DEFINE_PER_CPU(u32[NUM_L1_CTRS], previous_l1_cnts);
+DEFINE_PER_CPU(u32, old_pid);
+DEFINE_PER_CPU(u32, hotplug_flag);
+
+#define USE_CPUHP_STATE CPUHP_AP_ONLINE
+
+static int tracectr_cpu_hotplug_coming_up(unsigned int cpu)
+{
+	per_cpu(hotplug_flag, cpu) = 1;
+
+	return 0;
+}
+
+static void setup_prev_cnts(u32 cpu, u32 cnten_val)
+{
+	int i;
+
+	if (cnten_val & CC)
+		per_cpu(previous_ccnt, cpu) =
+			read_sysreg(pmccntr_el0);
+
+	for (i = 0; i < NUM_L1_CTRS; i++) {
+		if (cnten_val & (1 << i)) {
+			/* Select */
+			write_sysreg(i, pmselr_el0);
+			isb();
+			/* Read value */
+			per_cpu(previous_l1_cnts[i], cpu) =
+				read_sysreg(pmxevcntr_el0);
+		}
+	}
+}
+
+void tracectr_notifier(void *ignore, bool preempt,
+			struct task_struct *prev, struct task_struct *next)
+{
+	u32 cnten_val;
+	int current_pid;
+	u32 cpu = task_thread_info(next)->cpu;
+
+	if (tp_pid_state != 1)
+		return;
+	current_pid = next->pid;
+	if (per_cpu(old_pid, cpu) != -1) {
+		cnten_val = read_sysreg(pmcntenset_el0);
+		per_cpu(cntenset_val, cpu) = cnten_val;
+		/* Disable all the counters that were enabled */
+		write_sysreg(cnten_val, pmcntenclr_el0);
+
+		if (per_cpu(hotplug_flag, cpu) == 1) {
+			per_cpu(hotplug_flag, cpu) = 0;
+			setup_prev_cnts(cpu, cnten_val);
+		} else {
+			trace_sched_switch_with_ctrs(per_cpu(old_pid, cpu),
+						     current_pid);
+		}
+
+		/* Enable all the counters that were disabled */
+		write_sysreg(cnten_val, pmcntenset_el0);
+	}
+	per_cpu(old_pid, cpu) = current_pid;
+}
+
+static void enable_tp_pid(void)
+{
+	if (tp_pid_state == 0) {
+		tp_pid_state = 1;
+		register_trace_sched_switch(tracectr_notifier, NULL);
+	}
+}
+
+static void disable_tp_pid(void)
+{
+	if (tp_pid_state == 1) {
+		tp_pid_state = 0;
+		unregister_trace_sched_switch(tracectr_notifier, NULL);
+	}
+}
+
+static ssize_t read_enabled_perftp_file_bool(struct file *file,
+		char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[2];
+
+	buf[1] = '\n';
+	if (tp_pid_state == 0)
+		buf[0] = '0';
+	else
+		buf[0] = '1';
+	return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t write_enabled_perftp_file_bool(struct file *file,
+		const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[32];
+	size_t buf_size;
+
+	buf_size = min(count, (sizeof(buf)-1));
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+	switch (buf[0]) {
+	case 'y':
+	case 'Y':
+	case '1':
+		enable_tp_pid();
+		break;
+	case 'n':
+	case 'N':
+	case '0':
+		disable_tp_pid();
+		break;
+	}
+
+	return count;
+}
+
+static const struct file_operations fops_perftp = {
+	.read =		read_enabled_perftp_file_bool,
+	.write =	write_enabled_perftp_file_bool,
+	.llseek =	default_llseek,
+};
+
+int __init init_tracecounters(void)
+{
+	struct dentry *dir;
+	struct dentry *file;
+	unsigned int value = 1;
+	int cpu, rc;
+
+	dir = debugfs_create_dir("perf_debug_tp", NULL);
+	if (!dir)
+		return -ENOMEM;
+	file = debugfs_create_file("enabled", 0660, dir,
+		&value, &fops_perftp);
+	if (!file) {
+		debugfs_remove(dir);
+		return -ENOMEM;
+	}
+	for_each_possible_cpu(cpu)
+		per_cpu(old_pid, cpu) = -1;
+	rc = cpuhp_setup_state_nocalls(USE_CPUHP_STATE,
+		"tracectr_cpu_hotplug",
+		tracectr_cpu_hotplug_coming_up,
+		NULL);
+	return 0;
+}
+
+int __exit exit_tracecounters(void)
+{
+	cpuhp_remove_state_nocalls(USE_CPUHP_STATE);
+	return 0;
+}
+late_initcall(init_tracecounters);
diff --git a/arch/arm64/kernel/perf_trace_counters.h b/arch/arm64/kernel/perf_trace_counters.h
new file mode 100644
index 0000000..660f6ce
--- /dev/null
+++ b/arch/arm64/kernel/perf_trace_counters.h
@@ -0,0 +1,110 @@
+/* Copyright (c) 2013-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.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM perf_trace_counters
+
+#if !defined(_PERF_TRACE_COUNTERS_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _PERF_TRACE_COUNTERS_H_
+
+/* Ctr index for PMCNTENSET/CLR */
+#define CC 0x80000000
+#define C0 0x1
+#define C1 0x2
+#define C2 0x4
+#define C3 0x8
+#define C4 0x10
+#define C5 0x20
+#define C_ALL (CC | C0 | C1 | C2 | C3 | C4 | C5)
+#define NUM_L1_CTRS 6
+
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/tracepoint.h>
+
+DECLARE_PER_CPU(u32, cntenset_val);
+DECLARE_PER_CPU(u32, previous_ccnt);
+DECLARE_PER_CPU(u32[NUM_L1_CTRS], previous_l1_cnts);
+TRACE_EVENT(sched_switch_with_ctrs,
+
+		TP_PROTO(pid_t prev, pid_t next),
+
+		TP_ARGS(prev, next),
+
+		TP_STRUCT__entry(
+			__field(pid_t,	old_pid)
+			__field(pid_t,	new_pid)
+			__field(u32, cctr)
+			__field(u32, ctr0)
+			__field(u32, ctr1)
+			__field(u32, ctr2)
+			__field(u32, ctr3)
+			__field(u32, ctr4)
+			__field(u32, ctr5)
+		),
+
+		TP_fast_assign(
+			u32 cpu = smp_processor_id();
+			u32 i;
+			u32 cnten_val;
+			u32 total_ccnt = 0;
+			u32 total_cnt = 0;
+			u32 delta_l1_cnts[NUM_L1_CTRS];
+
+			__entry->old_pid	= prev;
+			__entry->new_pid	= next;
+
+			cnten_val = per_cpu(cntenset_val, cpu);
+
+			if (cnten_val & CC) {
+				/* Read value */
+				total_ccnt = read_sysreg(pmccntr_el0);
+				__entry->cctr = total_ccnt -
+					per_cpu(previous_ccnt, cpu);
+				per_cpu(previous_ccnt, cpu) = total_ccnt;
+			}
+			for (i = 0; i < NUM_L1_CTRS; i++) {
+				if (cnten_val & (1 << i)) {
+					/* Select */
+					write_sysreg(i, pmselr_el0);
+					isb();
+					/* Read value */
+					total_cnt = read_sysreg(pmxevcntr_el0);
+					delta_l1_cnts[i] = total_cnt -
+					  per_cpu(previous_l1_cnts[i], cpu);
+					per_cpu(previous_l1_cnts[i], cpu) =
+						total_cnt;
+				} else
+					delta_l1_cnts[i] = 0;
+			}
+
+			__entry->ctr0 = delta_l1_cnts[0];
+			__entry->ctr1 = delta_l1_cnts[1];
+			__entry->ctr2 = delta_l1_cnts[2];
+			__entry->ctr3 = delta_l1_cnts[3];
+			__entry->ctr4 = delta_l1_cnts[4];
+			__entry->ctr5 = delta_l1_cnts[5];
+		),
+
+		TP_printk("prev_pid=%d, next_pid=%d, CCNTR: %u, CTR0: %u, CTR1: %u, CTR2: %u, CTR3: %u, CTR4: %u, CTR5: %u",
+				__entry->old_pid, __entry->new_pid,
+				__entry->cctr,
+				__entry->ctr0, __entry->ctr1,
+				__entry->ctr2, __entry->ctr3,
+				__entry->ctr4, __entry->ctr5)
+);
+
+#endif
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../arch/arm64/kernel
+#define TRACE_INCLUDE_FILE perf_trace_counters
+#include <trace/define_trace.h>
diff --git a/arch/arm64/kernel/perf_trace_user.c b/arch/arm64/kernel/perf_trace_user.c
new file mode 100644
index 0000000..5a83cc5
--- /dev/null
+++ b/arch/arm64/kernel/perf_trace_user.c
@@ -0,0 +1,96 @@
+/* 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/perf_event.h>
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/preempt.h>
+#include <linux/stat.h>
+#include <asm/uaccess.h>
+
+#define CREATE_TRACE_POINTS
+#include "perf_trace_user.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM perf_trace_counters
+
+#define TRACE_USER_MAX_BUF_SIZE 100
+
+static ssize_t perf_trace_write(struct file *file,
+				const char __user *user_string_in,
+				size_t len, loff_t *ppos)
+{
+	u32 cnten_val;
+	int rc;
+	char buf[TRACE_USER_MAX_BUF_SIZE + 1];
+	ssize_t length;
+
+	if (len == 0)
+		return 0;
+
+	length = len > TRACE_USER_MAX_BUF_SIZE ? TRACE_USER_MAX_BUF_SIZE : len;
+
+	rc = copy_from_user(buf, user_string_in, length);
+	if (rc) {
+		pr_err("%s copy_from_user failed, rc=%d\n", __func__, rc);
+		return length;
+	}
+
+	/* Remove any trailing newline and make sure string is terminated */
+	if (buf[length - 1] == '\n')
+		buf[length - 1] = '\0';
+	else
+		buf[length] = '\0';
+
+	/*
+	 * Disable preemption to ensure that all the performance counter
+	 * accesses happen on the same cpu
+	 */
+	preempt_disable();
+	/* stop counters, call the trace function, restart them */
+
+	cnten_val = read_sysreg(pmcntenset_el0);
+	/* Disable all the counters that were enabled */
+	write_sysreg(cnten_val, pmcntenclr_el0);
+
+	trace_perf_trace_user(buf, cnten_val);
+
+	/* Enable all the counters that were disabled */
+	write_sysreg(cnten_val, pmcntenset_el0);
+	preempt_enable();
+
+	return length;
+}
+
+static const struct file_operations perf_trace_fops = {
+	.write = perf_trace_write
+};
+
+static int __init init_perf_trace(void)
+{
+	struct dentry *dir;
+	struct dentry *file;
+	unsigned int value = 1;
+
+	dir = debugfs_create_dir("msm_perf", NULL);
+	if (!dir)
+		return -ENOMEM;
+	file = debugfs_create_file("trace_marker", 0220, dir,
+		&value, &perf_trace_fops);
+	if (!file)
+		return -ENOMEM;
+
+	return 0;
+}
+
+late_initcall(init_perf_trace);
diff --git a/arch/arm64/kernel/perf_trace_user.h b/arch/arm64/kernel/perf_trace_user.h
new file mode 100644
index 0000000..d592392
--- /dev/null
+++ b/arch/arm64/kernel/perf_trace_user.h
@@ -0,0 +1,84 @@
+/* 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.
+ */
+#if !defined(_PERF_TRACE_USER_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _PERF_TRACE_USER_H_
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM perf_trace_counters
+
+#include <linux/tracepoint.h>
+
+#define CNTENSET_CC    0x80000000
+#define NUM_L1_CTRS             6
+
+TRACE_EVENT(perf_trace_user,
+	TP_PROTO(char *string, u32 cnten_val),
+	TP_ARGS(string, cnten_val),
+
+	TP_STRUCT__entry(
+		__field(u32, cctr)
+		__field(u32, ctr0)
+		__field(u32, ctr1)
+		__field(u32, ctr2)
+		__field(u32, ctr3)
+		__field(u32, ctr4)
+		__field(u32, ctr5)
+		__string(user_string, string)
+		),
+
+	TP_fast_assign(
+		u32 cnt;
+		u32 l1_cnts[NUM_L1_CTRS];
+		int i;
+
+		if (cnten_val & CNTENSET_CC) {
+			/* Read value */
+			cnt = read_sysreg(pmccntr_el0);
+			__entry->cctr = cnt;
+		} else
+			__entry->cctr = 0;
+		for (i = 0; i < NUM_L1_CTRS; i++) {
+			if (cnten_val & (1 << i)) {
+				/* Select */
+				write_sysreg(i, pmselr_el0);
+				isb();
+				/* Read value */
+				cnt = read_sysreg(pmxevcntr_el0);
+				l1_cnts[i] = cnt;
+			} else {
+				l1_cnts[i] = 0;
+			}
+		}
+
+		__entry->ctr0 = l1_cnts[0];
+		__entry->ctr1 = l1_cnts[1];
+		__entry->ctr2 = l1_cnts[2];
+		__entry->ctr3 = l1_cnts[3];
+		__entry->ctr4 = l1_cnts[4];
+		__entry->ctr5 = l1_cnts[5];
+		__assign_str(user_string, string);
+		),
+
+		TP_printk("CCNTR: %u, CTR0: %u, CTR1: %u, CTR2: %u, CTR3: %u, CTR4: %u, CTR5: %u, MSG=%s",
+				__entry->cctr,
+				__entry->ctr0, __entry->ctr1,
+				__entry->ctr2, __entry->ctr3,
+				__entry->ctr4, __entry->ctr5,
+				__get_str(user_string)
+			)
+	);
+
+#endif
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../arch/arm64/kernel
+#define TRACE_INCLUDE_FILE perf_trace_user
+#include <trace/define_trace.h>
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index d8e6635..860c3b6 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -976,7 +976,7 @@
 	 * device, and allocated the default domain for that group.
 	 */
 	if (!domain || iommu_dma_init_domain(domain, dma_base, size, dev)) {
-		pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
+		pr_debug("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
 			dev_name(dev));
 		return false;
 	}
diff --git a/arch/c6x/kernel/ptrace.c b/arch/c6x/kernel/ptrace.c
index 3c494e8..a511ac1 100644
--- a/arch/c6x/kernel/ptrace.c
+++ b/arch/c6x/kernel/ptrace.c
@@ -69,46 +69,6 @@
 				   0, sizeof(*regs));
 }
 
-static int gpr_set(struct task_struct *target,
-		   const struct user_regset *regset,
-		   unsigned int pos, unsigned int count,
-		   const void *kbuf, const void __user *ubuf)
-{
-	int ret;
-	struct pt_regs *regs = task_pt_regs(target);
-
-	/* Don't copyin TSR or CSR */
-	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-				 &regs,
-				 0, PT_TSR * sizeof(long));
-	if (ret)
-		return ret;
-
-	ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
-					PT_TSR * sizeof(long),
-					(PT_TSR + 1) * sizeof(long));
-	if (ret)
-		return ret;
-
-	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-				 &regs,
-				 (PT_TSR + 1) * sizeof(long),
-				 PT_CSR * sizeof(long));
-	if (ret)
-		return ret;
-
-	ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
-					PT_CSR * sizeof(long),
-					(PT_CSR + 1) * sizeof(long));
-	if (ret)
-		return ret;
-
-	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-				 &regs,
-				 (PT_CSR + 1) * sizeof(long), -1);
-	return ret;
-}
-
 enum c6x_regset {
 	REGSET_GPR,
 };
@@ -120,7 +80,6 @@
 		.size = sizeof(u32),
 		.align = sizeof(u32),
 		.get = gpr_get,
-		.set = gpr_set
 	},
 };
 
diff --git a/arch/h8300/kernel/ptrace.c b/arch/h8300/kernel/ptrace.c
index 9207554..0dc1c8f 100644
--- a/arch/h8300/kernel/ptrace.c
+++ b/arch/h8300/kernel/ptrace.c
@@ -95,7 +95,8 @@
 	long *reg = (long *)&regs;
 
 	/* build user regs in buffer */
-	for (r = 0; r < ARRAY_SIZE(register_offset); r++)
+	BUILD_BUG_ON(sizeof(regs) % sizeof(long) != 0);
+	for (r = 0; r < sizeof(regs) / sizeof(long); r++)
 		*reg++ = h8300_get_reg(target, r);
 
 	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
@@ -113,7 +114,8 @@
 	long *reg;
 
 	/* build user regs in buffer */
-	for (reg = (long *)&regs, r = 0; r < ARRAY_SIZE(register_offset); r++)
+	BUILD_BUG_ON(sizeof(regs) % sizeof(long) != 0);
+	for (reg = (long *)&regs, r = 0; r < sizeof(regs) / sizeof(long); r++)
 		*reg++ = h8300_get_reg(target, r);
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
@@ -122,7 +124,7 @@
 		return ret;
 
 	/* write back to pt_regs */
-	for (reg = (long *)&regs, r = 0; r < ARRAY_SIZE(register_offset); r++)
+	for (reg = (long *)&regs, r = 0; r < sizeof(regs) / sizeof(long); r++)
 		h8300_put_reg(target, r, *reg++);
 	return 0;
 }
diff --git a/arch/metag/kernel/ptrace.c b/arch/metag/kernel/ptrace.c
index 7563628..5e2dc7d 100644
--- a/arch/metag/kernel/ptrace.c
+++ b/arch/metag/kernel/ptrace.c
@@ -24,6 +24,16 @@
  * user_regset definitions.
  */
 
+static unsigned long user_txstatus(const struct pt_regs *regs)
+{
+	unsigned long data = (unsigned long)regs->ctx.Flags;
+
+	if (regs->ctx.SaveMask & TBICTX_CBUF_BIT)
+		data |= USER_GP_REGS_STATUS_CATCH_BIT;
+
+	return data;
+}
+
 int metag_gp_regs_copyout(const struct pt_regs *regs,
 			  unsigned int pos, unsigned int count,
 			  void *kbuf, void __user *ubuf)
@@ -62,9 +72,7 @@
 	if (ret)
 		goto out;
 	/* TXSTATUS */
-	data = (unsigned long)regs->ctx.Flags;
-	if (regs->ctx.SaveMask & TBICTX_CBUF_BIT)
-		data |= USER_GP_REGS_STATUS_CATCH_BIT;
+	data = user_txstatus(regs);
 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 				  &data, 4*25, 4*26);
 	if (ret)
@@ -119,6 +127,7 @@
 	if (ret)
 		goto out;
 	/* TXSTATUS */
+	data = user_txstatus(regs);
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 				 &data, 4*25, 4*26);
 	if (ret)
@@ -244,6 +253,8 @@
 	unsigned long long *ptr;
 	int ret, i;
 
+	if (count < 4*13)
+		return -EINVAL;
 	/* Read the entire pipeline before making any changes */
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 				 &rp, 0, 4*13);
@@ -303,7 +314,7 @@
 			const void *kbuf, const void __user *ubuf)
 {
 	int ret;
-	void __user *tls;
+	void __user *tls = target->thread.tls_ptr;
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
 	if (ret)
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index a92994d..bf83dc1 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -485,7 +485,8 @@
 					  &target->thread.fpu,
 					  0, sizeof(elf_fpregset_t));
 
-	for (i = 0; i < NUM_FPU_REGS; i++) {
+	BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t));
+	for (i = 0; i < NUM_FPU_REGS && count >= sizeof(elf_fpreg_t); i++) {
 		err = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 					 &fpr_val, i * sizeof(elf_fpreg_t),
 					 (i + 1) * sizeof(elf_fpreg_t));
diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S
index 72dac0b..b350ac5 100644
--- a/arch/powerpc/kernel/idle_book3s.S
+++ b/arch/powerpc/kernel/idle_book3s.S
@@ -439,9 +439,23 @@
 _GLOBAL(pnv_wakeup_tb_loss)
 	ld	r1,PACAR1(r13)
 	/*
-	 * Before entering any idle state, the NVGPRs are saved in the stack
-	 * and they are restored before switching to the process context. Hence
-	 * until they are restored, they are free to be used.
+	 * Before entering any idle state, the NVGPRs are saved in the stack.
+	 * If there was a state loss, or PACA_NAPSTATELOST was set, then the
+	 * NVGPRs are restored. If we are here, it is likely that state is lost,
+	 * but not guaranteed -- neither ISA207 nor ISA300 tests to reach
+	 * here are the same as the test to restore NVGPRS:
+	 * PACA_THREAD_IDLE_STATE test for ISA207, PSSCR test for ISA300,
+	 * and SRR1 test for restoring NVGPRs.
+	 *
+	 * We are about to clobber NVGPRs now, so set NAPSTATELOST to
+	 * guarantee they will always be restored. This might be tightened
+	 * with careful reading of specs (particularly for ISA300) but this
+	 * is already a slow wakeup path and it's simpler to be safe.
+	 */
+	li	r0,1
+	stb	r0,PACA_NAPSTATELOST(r13)
+
+	/*
 	 *
 	 * Save SRR1 and LR in NVGPRs as they might be clobbered in
 	 * opal_call() (called in CHECK_HMI_INTERRUPT). SRR1 is required
diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c
index ac082dd..7037ca3 100644
--- a/arch/sparc/kernel/ptrace_64.c
+++ b/arch/sparc/kernel/ptrace_64.c
@@ -313,7 +313,7 @@
 	}
 
 	if (!ret) {
-		unsigned long y;
+		unsigned long y = regs->y;
 
 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 					 &y,
diff --git a/arch/x86/include/asm/kvm_page_track.h b/arch/x86/include/asm/kvm_page_track.h
index c2b8d24..6226cb0e 100644
--- a/arch/x86/include/asm/kvm_page_track.h
+++ b/arch/x86/include/asm/kvm_page_track.h
@@ -35,6 +35,7 @@
 };
 
 void kvm_page_track_init(struct kvm *kvm);
+void kvm_page_track_cleanup(struct kvm *kvm);
 
 void kvm_page_track_free_memslot(struct kvm_memory_slot *free,
 				 struct kvm_memory_slot *dont);
diff --git a/arch/x86/kvm/page_track.c b/arch/x86/kvm/page_track.c
index b431539..85024e0 100644
--- a/arch/x86/kvm/page_track.c
+++ b/arch/x86/kvm/page_track.c
@@ -156,6 +156,14 @@
 	return !!ACCESS_ONCE(slot->arch.gfn_track[mode][index]);
 }
 
+void kvm_page_track_cleanup(struct kvm *kvm)
+{
+	struct kvm_page_track_notifier_head *head;
+
+	head = &kvm->arch.track_notifier_head;
+	cleanup_srcu_struct(&head->track_srcu);
+}
+
 void kvm_page_track_init(struct kvm *kvm)
 {
 	struct kvm_page_track_notifier_head *head;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 731044e..e5bc139 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -7976,6 +7976,7 @@
 	kvm_free_vcpus(kvm);
 	kvfree(rcu_dereference_check(kvm->arch.apic_map, 1));
 	kvm_mmu_uninit_vm(kvm);
+	kvm_page_track_cleanup(kvm);
 }
 
 void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free,
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 81caceb..ee54ad0 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -629,17 +629,8 @@
 {
 	struct blk_mq_timeout_data *data = priv;
 
-	if (!test_bit(REQ_ATOM_STARTED, &rq->atomic_flags)) {
-		/*
-		 * If a request wasn't started before the queue was
-		 * marked dying, kill it here or it'll go unnoticed.
-		 */
-		if (unlikely(blk_queue_dying(rq->q))) {
-			rq->errors = -EIO;
-			blk_mq_end_request(rq, rq->errors);
-		}
+	if (!test_bit(REQ_ATOM_STARTED, &rq->atomic_flags))
 		return;
-	}
 
 	if (time_after_eq(jiffies, rq->deadline)) {
 		if (!blk_mark_rq_complete(rq))
diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
index d19b09c..54fc90e 100644
--- a/crypto/algif_hash.c
+++ b/crypto/algif_hash.c
@@ -245,7 +245,7 @@
 	struct alg_sock *ask = alg_sk(sk);
 	struct hash_ctx *ctx = ask->private;
 	struct ahash_request *req = &ctx->req;
-	char state[crypto_ahash_statesize(crypto_ahash_reqtfm(req))];
+	char state[crypto_ahash_statesize(crypto_ahash_reqtfm(req)) ? : 1];
 	struct sock *sk2;
 	struct alg_sock *ask2;
 	struct hash_ctx *ctx2;
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 79902e7..d7eb419 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -2830,7 +2830,7 @@
 		} break;
 		case BINDER_WORK_TRANSACTION_COMPLETE: {
 			cmd = BR_TRANSACTION_COMPLETE;
-				if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
+			if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
 				return -EFAULT;
 			ptr += sizeof(uint32_t);
 
@@ -2872,14 +2872,14 @@
 				node->has_weak_ref = 0;
 			}
 			if (cmd != BR_NOOP) {
-					if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
+				if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
 					return -EFAULT;
 				ptr += sizeof(uint32_t);
-					if (put_user_preempt_disabled(node->ptr, (binder_uintptr_t __user *)
+				if (put_user_preempt_disabled(node->ptr, (binder_uintptr_t __user *)
 					     (binder_uintptr_t __user *)ptr))
 					return -EFAULT;
 				ptr += sizeof(binder_uintptr_t);
-					if (put_user_preempt_disabled(node->cookie, (binder_uintptr_t __user *)
+				if (put_user_preempt_disabled(node->cookie, (binder_uintptr_t __user *)
 					     (binder_uintptr_t __user *)ptr))
 					return -EFAULT;
 				ptr += sizeof(binder_uintptr_t);
@@ -2923,7 +2923,7 @@
 				cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
 			else
 				cmd = BR_DEAD_BINDER;
-				if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
+			if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
 				return -EFAULT;
 			ptr += sizeof(uint32_t);
 			if (put_user_preempt_disabled(death->cookie, (binder_uintptr_t __user *) ptr))
diff --git a/drivers/auxdisplay/img-ascii-lcd.c b/drivers/auxdisplay/img-ascii-lcd.c
index bf43b5d..83f1439 100644
--- a/drivers/auxdisplay/img-ascii-lcd.c
+++ b/drivers/auxdisplay/img-ascii-lcd.c
@@ -218,6 +218,7 @@
 	{ .compatible = "img,boston-lcd", .data = &boston_config },
 	{ .compatible = "mti,malta-lcd", .data = &malta_config },
 	{ .compatible = "mti,sead3-lcd", .data = &sead3_config },
+	{ /* sentinel */ }
 };
 
 /**
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index d82ce17..4609244 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -416,6 +416,7 @@
 	_CPU_ATTR(online, &__cpu_online_mask),
 	_CPU_ATTR(possible, &__cpu_possible_mask),
 	_CPU_ATTR(present, &__cpu_present_mask),
+	_CPU_ATTR(core_ctl_isolated, &__cpu_isolated_mask),
 };
 
 /*
@@ -651,6 +652,7 @@
 	&cpu_attrs[0].attr.attr,
 	&cpu_attrs[1].attr.attr,
 	&cpu_attrs[2].attr.attr,
+	&cpu_attrs[3].attr.attr,
 	&dev_attr_kernel_max.attr,
 	&dev_attr_offline.attr,
 	&dev_attr_isolated.attr,
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index 4a99ac7..9959c76 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -55,6 +55,7 @@
 struct amd768_priv {
 	void __iomem *iobase;
 	struct pci_dev *pcidev;
+	u32 pmbase;
 };
 
 static int amd_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
@@ -148,33 +149,58 @@
 	if (pmbase == 0)
 		return -EIO;
 
-	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
-	if (!devm_request_region(&pdev->dev, pmbase + PMBASE_OFFSET,
-				PMBASE_SIZE, DRV_NAME)) {
+	if (!request_region(pmbase + PMBASE_OFFSET, PMBASE_SIZE, DRV_NAME)) {
 		dev_err(&pdev->dev, DRV_NAME " region 0x%x already in use!\n",
 			pmbase + 0xF0);
-		return -EBUSY;
+		err = -EBUSY;
+		goto out;
 	}
 
-	priv->iobase = devm_ioport_map(&pdev->dev, pmbase + PMBASE_OFFSET,
-			PMBASE_SIZE);
+	priv->iobase = ioport_map(pmbase + PMBASE_OFFSET, PMBASE_SIZE);
 	if (!priv->iobase) {
 		pr_err(DRV_NAME "Cannot map ioport\n");
-		return -ENOMEM;
+		err = -EINVAL;
+		goto err_iomap;
 	}
 
 	amd_rng.priv = (unsigned long)priv;
+	priv->pmbase = pmbase;
 	priv->pcidev = pdev;
 
 	pr_info(DRV_NAME " detected\n");
-	return devm_hwrng_register(&pdev->dev, &amd_rng);
+	err = hwrng_register(&amd_rng);
+	if (err) {
+		pr_err(DRV_NAME " registering failed (%d)\n", err);
+		goto err_hwrng;
+	}
+	return 0;
+
+err_hwrng:
+	ioport_unmap(priv->iobase);
+err_iomap:
+	release_region(pmbase + PMBASE_OFFSET, PMBASE_SIZE);
+out:
+	kfree(priv);
+	return err;
 }
 
 static void __exit mod_exit(void)
 {
+	struct amd768_priv *priv;
+
+	priv = (struct amd768_priv *)amd_rng.priv;
+
+	hwrng_unregister(&amd_rng);
+
+	ioport_unmap(priv->iobase);
+
+	release_region(priv->pmbase + PMBASE_OFFSET, PMBASE_SIZE);
+
+	kfree(priv);
 }
 
 module_init(mod_init);
diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c
index e7a2459..e1d421a 100644
--- a/drivers/char/hw_random/geode-rng.c
+++ b/drivers/char/hw_random/geode-rng.c
@@ -31,6 +31,9 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 
+
+#define PFX	KBUILD_MODNAME ": "
+
 #define GEODE_RNG_DATA_REG   0x50
 #define GEODE_RNG_STATUS_REG 0x54
 
@@ -82,6 +85,7 @@
 
 static int __init mod_init(void)
 {
+	int err = -ENODEV;
 	struct pci_dev *pdev = NULL;
 	const struct pci_device_id *ent;
 	void __iomem *mem;
@@ -89,27 +93,43 @@
 
 	for_each_pci_dev(pdev) {
 		ent = pci_match_id(pci_tbl, pdev);
-		if (ent) {
-			rng_base = pci_resource_start(pdev, 0);
-			if (rng_base == 0)
-				return -ENODEV;
-
-			mem = devm_ioremap(&pdev->dev, rng_base, 0x58);
-			if (!mem)
-				return -ENOMEM;
-			geode_rng.priv = (unsigned long)mem;
-
-			pr_info("AMD Geode RNG detected\n");
-			return devm_hwrng_register(&pdev->dev, &geode_rng);
-		}
+		if (ent)
+			goto found;
 	}
-
 	/* Device not found. */
-	return -ENODEV;
+	goto out;
+
+found:
+	rng_base = pci_resource_start(pdev, 0);
+	if (rng_base == 0)
+		goto out;
+	err = -ENOMEM;
+	mem = ioremap(rng_base, 0x58);
+	if (!mem)
+		goto out;
+	geode_rng.priv = (unsigned long)mem;
+
+	pr_info("AMD Geode RNG detected\n");
+	err = hwrng_register(&geode_rng);
+	if (err) {
+		pr_err(PFX "RNG registering failed (%d)\n",
+		       err);
+		goto err_unmap;
+	}
+out:
+	return err;
+
+err_unmap:
+	iounmap(mem);
+	goto out;
 }
 
 static void __exit mod_exit(void)
 {
+	void __iomem *mem = (void __iomem *)geode_rng.priv;
+
+	hwrng_unregister(&geode_rng);
+	iounmap(mem);
 }
 
 module_init(mod_init);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 83db1416..ece2f00 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
  * Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
- * 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 as
@@ -2101,7 +2101,7 @@
 	/* prevent racing with updates to the clock topology */
 	clk_prepare_lock();
 
-	if (core->parent == parent)
+	if (core->parent == parent && !(core->flags & CLK_IS_MEASURE))
 		goto out;
 
 	/* verify ops for for multi-parent clks */
@@ -2599,7 +2599,7 @@
 	.release	= seq_release,
 };
 
-static void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f)
+void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f)
 {
 	if (IS_ERR_OR_NULL(clk))
 		return;
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h
index 331e086..f0db049 100644
--- a/drivers/clk/clk.h
+++ b/drivers/clk/clk.h
@@ -23,6 +23,7 @@
 
 /* Debugfs API to print the enabled clocks */
 void clock_debug_print_enabled(void);
+void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f);
 
 #else
 /* All these casts to avoid ifdefs in clkdev... */
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 31ea544..cf874a1 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -216,3 +216,11 @@
 	 frequency and voltage requests for multiple clusters via the
 	 existence of multiple OSM domains.
 	 Say Y if you want to support OSM clocks.
+
+config MSM_GPUCC_SDM845
+	tristate "SDM845 Graphics Clock Controller"
+	depends on MSM_GCC_SDM845
+	help
+	  Support for the graphics clock controller on Qualcomm Technologies, Inc.
+	  sdm845 devices.
+	  Say Y if you want to support graphics controller devices.
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index d52a751..6e13562 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -10,7 +10,7 @@
 clk-qcom-y += clk-regmap-divider.o
 clk-qcom-y += clk-regmap-mux.o
 clk-qcom-y += reset.o clk-voter.o
-clk-qcom-y += clk-dummy.o
+clk-qcom-y += clk-dummy.o clk-debug.o
 clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o gdsc-regulator.o
 
 # Keep alphabetically sorted by config
@@ -31,7 +31,8 @@
 obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o
 obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o
 obj-$(CONFIG_MSM_GCC_8996) += gcc-msm8996.o
-obj-$(CONFIG_MSM_GCC_SDM845) += gcc-sdm845.o
+obj-$(CONFIG_MSM_GCC_SDM845) += gcc-sdm845.o debugcc-sdm845.o
+obj-$(CONFIG_MSM_GPUCC_SDM845) += gpucc-sdm845.o
 obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
 obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
 obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
diff --git a/drivers/clk/qcom/camcc-sdm845.c b/drivers/clk/qcom/camcc-sdm845.c
index c49eddf..a274975 100644
--- a/drivers/clk/qcom/camcc-sdm845.c
+++ b/drivers/clk/qcom/camcc-sdm845.c
@@ -107,9 +107,11 @@
 			.parent_names = (const char *[]){ "bi_tcxo" },
 			.num_parents = 1,
 			.ops = &clk_fabia_pll_ops,
-			VDD_CX_FMAX_MAP2(
-				MIN, 19200000,
-				LOWER, 600000000),
+			VDD_CX_FMAX_MAP4(
+				MIN, 615000000,
+				LOW, 1066000000,
+				LOW_L1, 1600000000,
+				NOMINAL, 2000000000),
 		},
 	},
 };
@@ -152,9 +154,11 @@
 			.parent_names = (const char *[]){ "bi_tcxo" },
 			.num_parents = 1,
 			.ops = &clk_fabia_pll_ops,
-			VDD_CX_FMAX_MAP2(
-				MIN, 19200000,
-				LOW, 808000000),
+			VDD_CX_FMAX_MAP4(
+				MIN, 615000000,
+				LOW, 1066000000,
+				LOW_L1, 1600000000,
+				NOMINAL, 2000000000),
 		},
 	},
 };
@@ -189,9 +193,11 @@
 			.parent_names = (const char *[]){ "bi_tcxo" },
 			.num_parents = 1,
 			.ops = &clk_fabia_pll_ops,
-			VDD_MX_FMAX_MAP2(
-				MIN, 19200000,
-				LOWER, 960000000),
+			VDD_MX_FMAX_MAP4(
+				MIN, 615000000,
+				LOW, 1066000000,
+				LOW_L1, 1600000000,
+				NOMINAL, 2000000000),
 		},
 	},
 };
@@ -248,9 +254,11 @@
 			.parent_names = (const char *[]){ "bi_tcxo" },
 			.num_parents = 1,
 			.ops = &clk_fabia_pll_ops,
-			VDD_CX_FMAX_MAP2(
-				MIN, 19200000,
-				LOWER, 384000000),
+			VDD_CX_FMAX_MAP4(
+				MIN, 615000000,
+				LOW, 1066000000,
+				LOW_L1, 1600000000,
+				NOMINAL, 2000000000),
 		},
 	},
 };
diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c
index 53f736c..51a5e0b 100644
--- a/drivers/clk/qcom/clk-branch.c
+++ b/drivers/clk/qcom/clk-branch.c
@@ -23,6 +23,7 @@
 
 #include "clk-branch.h"
 #include "clk-regmap.h"
+#include "clk-debug.h"
 
 static bool clk_branch_in_hwcg_mode(const struct clk_branch *br)
 {
@@ -338,6 +339,7 @@
 	.recalc_rate = clk_branch2_recalc_rate,
 	.set_flags = clk_branch_set_flags,
 	.list_registers = clk_branch2_list_registers,
+	.debug_init = clk_debug_measure_add,
 };
 EXPORT_SYMBOL_GPL(clk_branch2_ops);
 
@@ -393,6 +395,7 @@
 	.disable = clk_gate2_disable,
 	.is_enabled = clk_is_enabled_regmap,
 	.list_registers = clk_gate2_list_registers,
+	.debug_init = clk_debug_measure_add,
 };
 EXPORT_SYMBOL_GPL(clk_gate2_ops);
 
diff --git a/drivers/clk/qcom/clk-debug.c b/drivers/clk/qcom/clk-debug.c
new file mode 100644
index 0000000..53288f7
--- /dev/null
+++ b/drivers/clk/qcom/clk-debug.c
@@ -0,0 +1,285 @@
+/*
+ * 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 <linux/clk.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+
+#include "clk-regmap.h"
+#include "clk-debug.h"
+#include "common.h"
+
+static struct clk_hw *measure;
+
+static DEFINE_SPINLOCK(clk_reg_lock);
+static DEFINE_MUTEX(clk_debug_lock);
+
+#define TCXO_DIV_4_HZ		4800000
+#define SAMPLE_TICKS_1_MS	0x1000
+#define SAMPLE_TICKS_14_MS	0x10000
+
+#define XO_DIV4_CNT_DONE	BIT(25)
+#define CNT_EN			BIT(20)
+#define MEASURE_CNT		BM(24, 0)
+
+/* Sample clock for 'ticks' reference clock ticks. */
+static u32 run_measurement(unsigned int ticks, struct regmap *regmap,
+		u32 ctl_reg, u32 status_reg)
+{
+	u32 regval;
+
+	/* Stop counters and set the XO4 counter start value. */
+	regmap_write(regmap, ctl_reg, ticks);
+
+	regmap_read(regmap, status_reg, &regval);
+
+	/* Wait for timer to become ready. */
+	while ((regval & XO_DIV4_CNT_DONE) != 0) {
+		cpu_relax();
+		regmap_read(regmap, status_reg, &regval);
+	}
+
+	/* Run measurement and wait for completion. */
+	regmap_write(regmap, ctl_reg, (CNT_EN|ticks));
+
+	regmap_read(regmap, status_reg, &regval);
+
+	while ((regval & XO_DIV4_CNT_DONE) == 0) {
+		cpu_relax();
+		regmap_read(regmap, status_reg, &regval);
+	}
+
+	/* Return measured ticks. */
+	regmap_read(regmap, status_reg, &regval);
+	regval &= MEASURE_CNT;
+
+	/* Stop the counters */
+	regmap_write(regmap, ctl_reg, ticks);
+
+	return regval;
+}
+
+/*
+ * Perform a hardware rate measurement for a given clock.
+ * FOR DEBUG USE ONLY: Measurements take ~15 ms!
+ */
+static unsigned long clk_debug_mux_measure_rate(struct clk_hw *hw)
+{
+	unsigned long flags, ret = 0;
+	u32 gcc_xo4_reg, multiplier = 1;
+	u64 raw_count_short, raw_count_full;
+	struct clk_debug_mux *meas = to_clk_measure(hw);
+	struct measure_clk_data *data = meas->priv;
+
+	clk_prepare_enable(data->cxo);
+
+	spin_lock_irqsave(&clk_reg_lock, flags);
+
+	/* Enable CXO/4 and RINGOSC branch. */
+	regmap_read(meas->regmap[GCC], data->xo_div4_cbcr, &gcc_xo4_reg);
+	gcc_xo4_reg |= BIT(0);
+	regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg);
+
+	/*
+	 * The ring oscillator counter will not reset if the measured clock
+	 * is not running.  To detect this, run a short measurement before
+	 * the full measurement.  If the raw results of the two are the same
+	 * then the clock must be off.
+	 */
+
+	/* Run a short measurement. (~1 ms) */
+	raw_count_short = run_measurement(SAMPLE_TICKS_1_MS, meas->regmap[GCC],
+				data->ctl_reg, data->status_reg);
+
+	/* Run a full measurement. (~14 ms) */
+	raw_count_full = run_measurement(SAMPLE_TICKS_14_MS, meas->regmap[GCC],
+				data->ctl_reg, data->status_reg);
+
+	gcc_xo4_reg &= ~BIT(0);
+	regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg);
+
+	/* Return 0 if the clock is off. */
+	if (raw_count_full == raw_count_short)
+		ret = 0;
+	else {
+		/* Compute rate in Hz. */
+		raw_count_full = ((raw_count_full * 10) + 15) * TCXO_DIV_4_HZ;
+		do_div(raw_count_full, ((SAMPLE_TICKS_14_MS * 10) + 35));
+		ret = (raw_count_full * multiplier);
+	}
+
+	spin_unlock_irqrestore(&clk_reg_lock, flags);
+
+	clk_disable_unprepare(data->cxo);
+
+	return ret;
+}
+
+static u8 clk_debug_mux_get_parent(struct clk_hw *hw)
+{
+	struct clk_debug_mux *meas = to_clk_measure(hw);
+	int i, num_parents = clk_hw_get_num_parents(hw);
+
+	for (i = 0; i < num_parents; i++) {
+		if (!strcmp(meas->parent[i].parents,
+					hw->init->parent_names[i])) {
+			pr_debug("%s: Clock name %s index %d\n", __func__,
+					hw->init->name, i);
+			return i;
+		}
+	}
+
+	return 0;
+}
+
+static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_debug_mux *meas = to_clk_measure(hw);
+	u32 regval = 0;
+	int dbg_cc = 0;
+
+	dbg_cc = meas->parent[index].dbg_cc;
+
+	if (dbg_cc != GCC) {
+		/* Update the recursive debug mux */
+		regmap_read(meas->regmap[dbg_cc],
+				meas->parent[index].mux_offset, &regval);
+		regval &= ~meas->parent[index].mux_sel_mask <<
+				meas->parent[index].mux_sel_shift;
+		regval |= (meas->parent[index].dbg_cc_mux_sel &
+				meas->parent[index].mux_sel_mask) <<
+				meas->parent[index].mux_sel_shift;
+		regmap_write(meas->regmap[dbg_cc],
+				meas->parent[index].mux_offset, regval);
+
+		regmap_read(meas->regmap[dbg_cc],
+				meas->parent[index].post_div_offset, &regval);
+		regval &= ~meas->parent[index].post_div_mask <<
+				meas->parent[index].post_div_shift;
+		regval |= ((meas->parent[index].post_div_val - 1) &
+				meas->parent[index].post_div_mask) <<
+				meas->parent[index].post_div_shift;
+		regmap_write(meas->regmap[dbg_cc],
+				meas->parent[index].post_div_offset, regval);
+
+		regmap_read(meas->regmap[dbg_cc],
+				meas->parent[index].cbcr_offset, &regval);
+		regval |= BIT(0);
+		regmap_write(meas->regmap[dbg_cc],
+				meas->parent[index].cbcr_offset, regval);
+	}
+
+	/* Update the debug sel for GCC */
+	regmap_read(meas->regmap[GCC], meas->debug_offset, &regval);
+	regval &= ~meas->src_sel_mask << meas->src_sel_shift;
+	regval |= (meas->parent[index].prim_mux_sel & meas->src_sel_mask) <<
+			meas->src_sel_shift;
+	regmap_write(meas->regmap[GCC], meas->debug_offset, regval);
+
+	/* Set the GCC mux's post divider bits */
+	regmap_read(meas->regmap[GCC], meas->post_div_offset, &regval);
+	regval &= ~meas->post_div_mask << meas->post_div_shift;
+	regval |= ((meas->parent[index].prim_mux_div_val - 1) &
+			meas->post_div_mask) << meas->post_div_shift;
+	regmap_write(meas->regmap[GCC], meas->post_div_offset, regval);
+
+	/* Turn on the GCC_DEBUG_CBCR */
+	regmap_read(meas->regmap[GCC], meas->cbcr_offset, &regval);
+	regval |= BIT(0);
+	regmap_write(meas->regmap[GCC], meas->cbcr_offset, regval);
+
+	return 0;
+}
+
+const struct clk_ops clk_debug_mux_ops = {
+	.get_parent = clk_debug_mux_get_parent,
+	.set_parent = clk_debug_mux_set_parent,
+};
+EXPORT_SYMBOL(clk_debug_mux_ops);
+
+static int clk_debug_measure_get(void *data, u64 *val)
+{
+	struct clk_hw *hw = data, *par;
+	struct clk_debug_mux *meas = to_clk_measure(measure);
+	int index;
+	int ret = 0;
+	unsigned long meas_rate, sw_rate;
+
+	mutex_lock(&clk_debug_lock);
+
+	ret = clk_set_parent(measure->clk, hw->clk);
+	if (!ret) {
+		par = measure;
+		index =  clk_debug_mux_get_parent(measure);
+		while (par && par != hw) {
+			if (par->init->ops->enable)
+				par->init->ops->enable(par);
+			par = clk_hw_get_parent(par);
+		}
+		*val = clk_debug_mux_measure_rate(measure);
+		if (meas->parent[index].dbg_cc != GCC)
+			*val *= meas->parent[index].post_div_val;
+		*val *= meas->parent[index].prim_mux_div_val;
+	}
+
+	meas_rate = clk_get_rate(hw->clk);
+	par = clk_hw_get_parent(measure);
+	if (!par)
+		return -EINVAL;
+
+	sw_rate = clk_get_rate(par->clk);
+	if (sw_rate && meas_rate >= (sw_rate * 2))
+		*val *= DIV_ROUND_CLOSEST(meas_rate, sw_rate);
+
+	mutex_unlock(&clk_debug_lock);
+
+	return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(clk_measure_fops, clk_debug_measure_get,
+							NULL, "%lld\n");
+
+int clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry)
+{
+	if (IS_ERR_OR_NULL(measure)) {
+		pr_err_once("Please check if `measure` clk is registered.\n");
+		return 0;
+	}
+
+	if (clk_set_parent(measure->clk, hw->clk))
+		return 0;
+
+	debugfs_create_file("clk_measure", 0x444, dentry, hw,
+					&clk_measure_fops);
+	return 0;
+}
+EXPORT_SYMBOL(clk_debug_measure_add);
+
+int clk_debug_measure_register(struct clk_hw *hw)
+{
+	if (IS_ERR_OR_NULL(measure)) {
+		if (hw->init->flags & CLK_IS_MEASURE) {
+			measure = hw;
+			return 0;
+		}
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(clk_debug_measure_register);
+
diff --git a/drivers/clk/qcom/clk-debug.h b/drivers/clk/qcom/clk-debug.h
new file mode 100644
index 0000000..280704e
--- /dev/null
+++ b/drivers/clk/qcom/clk-debug.h
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+#ifndef __QCOM_CLK_DEBUG_H__
+#define __QCOM_CLK_DEBUG_H__
+
+#include "../clk.h"
+
+/* Debugfs Measure Clocks */
+
+/**
+ * struct measure_clk_data - Structure of clk measure
+ *
+ * @cxo:		XO clock.
+ * @xo_div4_cbcr:	offset of debug XO/4 div register.
+ * @ctl_reg:		offset of debug control register.
+ * @status_reg:		offset of debug status register.
+ * @cbcr_offset:	branch register to turn on debug mux.
+ */
+struct measure_clk_data {
+	struct clk *cxo;
+	u32 ctl_reg;
+	u32 status_reg;
+	u32 xo_div4_cbcr;
+};
+
+/**
+ * List of Debug clock controllers.
+ */
+enum debug_cc {
+	GCC,
+	CAM_CC,
+	DISP_CC,
+	GPU_CC,
+	VIDEO_CC,
+	CPU,
+};
+
+/**
+ * struct clk_src - Structure of clock source for debug mux
+ *
+ * @parents:		clock name to be used as parent for debug mux.
+ * @prim_mux_sel:	debug mux index at global clock controller.
+ * @prim_mux_div_val:	PLL post-divider setting for the primary mux.
+ * @dbg_cc:		indicates the clock controller for recursive debug
+ *			clock controllers.
+ * @dbg_cc_mux_sel:	indicates the debug mux index at recursive debug mux.
+ * @mux_sel_mask:	indicates the mask for the mux selection.
+ * @mux_sel_shift:	indicates the shift required for mux selection.
+ * @post_div_mask:	indicates the post div mask to be used at recursive
+ *			debug mux.
+ * @post_div_shift:	indicates the shift required for post divider
+ *			configuration.
+ * @post_div_val:	indicates the post div value to be used at recursive
+ *			debug mux.
+ * @mux_offset:		the debug mux offset.
+ * @post_div_offset:	register with post-divider settings for the debug mux.
+ * @cbcr_offset:	branch register to turn on debug mux.
+ */
+struct clk_src {
+	const char *parents;
+	int prim_mux_sel;
+	u32 prim_mux_div_val;
+	enum debug_cc dbg_cc;
+	int dbg_cc_mux_sel;
+	u32 mux_sel_mask;
+	u32 mux_sel_shift;
+	u32 post_div_mask;
+	u32 post_div_shift;
+	u32 post_div_val;
+	u32 mux_offset;
+	u32 post_div_offset;
+	u32 cbcr_offset;
+};
+
+#define MUX_SRC_LIST(...) \
+	.parent = (struct clk_src[]){__VA_ARGS__}, \
+	.num_parents = ARRAY_SIZE(((struct clk_src[]){__VA_ARGS__}))
+
+/**
+ * struct clk_debug_mux - Structure of clock debug mux
+ *
+ * @parent:		structure of clk_src
+ * @num_parents:	number of parents
+ * @regmap:		regmaps of debug mux
+ * @priv:		private measure_clk_data to be used by debug mux
+ * @debug_offset:	debug mux offset.
+ * @post_div_offset:	register with post-divider settings for the debug mux.
+ * @cbcr_offset:	branch register to turn on debug mux.
+ * @src_sel_mask:	indicates the mask to be used for src selection in
+			primary mux.
+ * @src_sel_shift:	indicates the shift required for source selection in
+			primary mux.
+ * @post_div_mask:	indicates the post div mask to be used for the primary
+			mux.
+ * @post_div_shift:	indicates the shift required for post divider
+			selection in primary mux.
+ * @hw:			handle between common and hardware-specific interfaces.
+ */
+struct clk_debug_mux {
+	struct clk_src *parent;
+	int num_parents;
+	struct regmap **regmap;
+	void *priv;
+	u32 debug_offset;
+	u32 post_div_offset;
+	u32 cbcr_offset;
+	u32 src_sel_mask;
+	u32 src_sel_shift;
+	u32 post_div_mask;
+	u32 post_div_shift;
+	struct clk_hw hw;
+};
+
+#define to_clk_measure(_hw) container_of((_hw), struct clk_debug_mux, hw)
+
+extern const struct clk_ops clk_debug_mux_ops;
+
+int clk_debug_measure_register(struct clk_hw *hw);
+int clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry);
+
+#endif
diff --git a/drivers/clk/qcom/clk-dummy.c b/drivers/clk/qcom/clk-dummy.c
index e2465c4..3435999 100644
--- a/drivers/clk/qcom/clk-dummy.c
+++ b/drivers/clk/qcom/clk-dummy.c
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 
 #include "common.h"
+#include "clk-debug.h"
 
 #define to_clk_dummy(_hw)	container_of(_hw, struct clk_dummy, hw)
 
@@ -60,6 +61,7 @@
 	.round_rate = dummy_clk_round_rate,
 	.recalc_rate = dummy_clk_recalc_rate,
 	.set_flags = dummy_clk_set_flags,
+	.debug_init = clk_debug_measure_add,
 };
 EXPORT_SYMBOL_GPL(clk_dummy_ops);
 
diff --git a/drivers/clk/qcom/debugcc-sdm845.c b/drivers/clk/qcom/debugcc-sdm845.c
new file mode 100644
index 0000000..d74db61
--- /dev/null
+++ b/drivers/clk/qcom/debugcc-sdm845.c
@@ -0,0 +1,885 @@
+/*
+ * 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 <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include "clk-debug.h"
+
+static struct measure_clk_data debug_mux_priv = {
+	.ctl_reg = 0x62024,
+	.status_reg = 0x62028,
+	.xo_div4_cbcr = 0x43008,
+};
+
+static const char *const debug_mux_parent_names[] = {
+	"cam_cc_bps_ahb_clk",
+	"cam_cc_bps_areg_clk",
+	"cam_cc_bps_axi_clk",
+	"cam_cc_bps_clk",
+	"cam_cc_camnoc_atb_clk",
+	"cam_cc_camnoc_axi_clk",
+	"cam_cc_cci_clk",
+	"cam_cc_cpas_ahb_clk",
+	"cam_cc_csi0phytimer_clk",
+	"cam_cc_csi1phytimer_clk",
+	"cam_cc_csi2phytimer_clk",
+	"cam_cc_csiphy0_clk",
+	"cam_cc_csiphy1_clk",
+	"cam_cc_csiphy2_clk",
+	"cam_cc_fd_core_clk",
+	"cam_cc_fd_core_uar_clk",
+	"cam_cc_icp_apb_clk",
+	"cam_cc_icp_atb_clk",
+	"cam_cc_icp_clk",
+	"cam_cc_icp_cti_clk",
+	"cam_cc_icp_ts_clk",
+	"cam_cc_ife_0_axi_clk",
+	"cam_cc_ife_0_clk",
+	"cam_cc_ife_0_cphy_rx_clk",
+	"cam_cc_ife_0_csid_clk",
+	"cam_cc_ife_0_dsp_clk",
+	"cam_cc_ife_1_axi_clk",
+	"cam_cc_ife_1_clk",
+	"cam_cc_ife_1_cphy_rx_clk",
+	"cam_cc_ife_1_csid_clk",
+	"cam_cc_ife_1_dsp_clk",
+	"cam_cc_ife_lite_clk",
+	"cam_cc_ife_lite_cphy_rx_clk",
+	"cam_cc_ife_lite_csid_clk",
+	"cam_cc_ipe_0_ahb_clk",
+	"cam_cc_ipe_0_areg_clk",
+	"cam_cc_ipe_0_axi_clk",
+	"cam_cc_ipe_0_clk",
+	"cam_cc_ipe_1_ahb_clk",
+	"cam_cc_ipe_1_areg_clk",
+	"cam_cc_ipe_1_axi_clk",
+	"cam_cc_ipe_1_clk",
+	"cam_cc_jpeg_clk",
+	"cam_cc_lrme_clk",
+	"cam_cc_mclk0_clk",
+	"cam_cc_mclk1_clk",
+	"cam_cc_mclk2_clk",
+	"cam_cc_mclk3_clk",
+	"cam_cc_soc_ahb_clk",
+	"cam_cc_sys_tmr_clk",
+	"disp_cc_mdss_ahb_clk",
+	"disp_cc_mdss_axi_clk",
+	"disp_cc_mdss_byte0_clk",
+	"disp_cc_mdss_byte0_intf_clk",
+	"disp_cc_mdss_byte1_clk",
+	"disp_cc_mdss_byte1_intf_clk",
+	"disp_cc_mdss_dp_aux_clk",
+	"disp_cc_mdss_dp_crypto_clk",
+	"disp_cc_mdss_dp_link_clk",
+	"disp_cc_mdss_dp_link_intf_clk",
+	"disp_cc_mdss_dp_pixel1_clk",
+	"disp_cc_mdss_dp_pixel_clk",
+	"disp_cc_mdss_esc0_clk",
+	"disp_cc_mdss_esc1_clk",
+	"disp_cc_mdss_mdp_clk",
+	"disp_cc_mdss_mdp_lut_clk",
+	"disp_cc_mdss_pclk0_clk",
+	"disp_cc_mdss_pclk1_clk",
+	"disp_cc_mdss_qdss_at_clk",
+	"disp_cc_mdss_qdss_tsctr_div8_clk",
+	"disp_cc_mdss_rot_clk",
+	"disp_cc_mdss_rscc_ahb_clk",
+	"disp_cc_mdss_rscc_vsync_clk",
+	"disp_cc_mdss_spdm_debug_clk",
+	"disp_cc_mdss_spdm_dp_crypto_clk",
+	"disp_cc_mdss_spdm_dp_pixel1_clk",
+	"disp_cc_mdss_spdm_dp_pixel_clk",
+	"disp_cc_mdss_spdm_mdp_clk",
+	"disp_cc_mdss_spdm_pclk0_clk",
+	"disp_cc_mdss_spdm_pclk1_clk",
+	"disp_cc_mdss_spdm_rot_clk",
+	"disp_cc_mdss_vsync_clk",
+	"gcc_aggre_noc_pcie_tbu_clk",
+	"gcc_aggre_ufs_card_axi_clk",
+	"gcc_aggre_ufs_phy_axi_clk",
+	"gcc_aggre_usb3_prim_axi_clk",
+	"gcc_aggre_usb3_sec_axi_clk",
+	"gcc_boot_rom_ahb_clk",
+	"gcc_camera_ahb_clk",
+	"gcc_camera_axi_clk",
+	"gcc_camera_xo_clk",
+	"gcc_ce1_ahb_clk",
+	"gcc_ce1_axi_clk",
+	"gcc_ce1_clk",
+	"gcc_cfg_noc_usb3_prim_axi_clk",
+	"gcc_cfg_noc_usb3_sec_axi_clk",
+	"gcc_cpuss_ahb_clk",
+	"gcc_cpuss_dvm_bus_clk",
+	"gcc_cpuss_gnoc_clk",
+	"gcc_cpuss_rbcpr_clk",
+	"gcc_ddrss_gpu_axi_clk",
+	"gcc_disp_ahb_clk",
+	"gcc_disp_axi_clk",
+	"gcc_disp_gpll0_clk_src",
+	"gcc_disp_gpll0_div_clk_src",
+	"gcc_disp_xo_clk",
+	"gcc_gp1_clk",
+	"gcc_gp2_clk",
+	"gcc_gp3_clk",
+	"gcc_gpu_cfg_ahb_clk",
+	"gcc_gpu_gpll0_clk_src",
+	"gcc_gpu_gpll0_div_clk_src",
+	"gcc_gpu_memnoc_gfx_clk",
+	"gcc_gpu_snoc_dvm_gfx_clk",
+	"gcc_mss_axis2_clk",
+	"gcc_mss_cfg_ahb_clk",
+	"gcc_mss_gpll0_div_clk_src",
+	"gcc_mss_mfab_axis_clk",
+	"gcc_mss_q6_memnoc_axi_clk",
+	"gcc_mss_snoc_axi_clk",
+	"gcc_pcie_0_aux_clk",
+	"gcc_pcie_0_cfg_ahb_clk",
+	"gcc_pcie_0_mstr_axi_clk",
+	"gcc_pcie_0_pipe_clk",
+	"gcc_pcie_0_slv_axi_clk",
+	"gcc_pcie_0_slv_q2a_axi_clk",
+	"gcc_pcie_1_aux_clk",
+	"gcc_pcie_1_cfg_ahb_clk",
+	"gcc_pcie_1_mstr_axi_clk",
+	"gcc_pcie_1_pipe_clk",
+	"gcc_pcie_1_slv_axi_clk",
+	"gcc_pcie_1_slv_q2a_axi_clk",
+	"gcc_pcie_phy_aux_clk",
+	"gcc_pcie_phy_refgen_clk",
+	"gcc_pdm2_clk",
+	"gcc_pdm_ahb_clk",
+	"gcc_pdm_xo4_clk",
+	"gcc_prng_ahb_clk",
+	"gcc_qmip_camera_ahb_clk",
+	"gcc_qmip_disp_ahb_clk",
+	"gcc_qmip_video_ahb_clk",
+	"gcc_qupv3_wrap0_core_2x_clk",
+	"gcc_qupv3_wrap0_core_clk",
+	"gcc_qupv3_wrap0_s0_clk",
+	"gcc_qupv3_wrap0_s1_clk",
+	"gcc_qupv3_wrap0_s2_clk",
+	"gcc_qupv3_wrap0_s3_clk",
+	"gcc_qupv3_wrap0_s4_clk",
+	"gcc_qupv3_wrap0_s5_clk",
+	"gcc_qupv3_wrap0_s6_clk",
+	"gcc_qupv3_wrap0_s7_clk",
+	"gcc_qupv3_wrap1_core_2x_clk",
+	"gcc_qupv3_wrap1_core_clk",
+	"gcc_qupv3_wrap1_s0_clk",
+	"gcc_qupv3_wrap1_s1_clk",
+	"gcc_qupv3_wrap1_s2_clk",
+	"gcc_qupv3_wrap1_s3_clk",
+	"gcc_qupv3_wrap1_s4_clk",
+	"gcc_qupv3_wrap1_s5_clk",
+	"gcc_qupv3_wrap1_s6_clk",
+	"gcc_qupv3_wrap1_s7_clk",
+	"gcc_qupv3_wrap_0_m_ahb_clk",
+	"gcc_qupv3_wrap_0_s_ahb_clk",
+	"gcc_qupv3_wrap_1_m_ahb_clk",
+	"gcc_qupv3_wrap_1_s_ahb_clk",
+	"gcc_sdcc2_ahb_clk",
+	"gcc_sdcc2_apps_clk",
+	"gcc_sdcc4_ahb_clk",
+	"gcc_sdcc4_apps_clk",
+	"gcc_sys_noc_cpuss_ahb_clk",
+	"gcc_tsif_ahb_clk",
+	"gcc_tsif_inactivity_timers_clk",
+	"gcc_tsif_ref_clk",
+	"gcc_ufs_card_ahb_clk",
+	"gcc_ufs_card_axi_clk",
+	"gcc_ufs_card_ice_core_clk",
+	"gcc_ufs_card_phy_aux_clk",
+	"gcc_ufs_card_rx_symbol_0_clk",
+	"gcc_ufs_card_rx_symbol_1_clk",
+	"gcc_ufs_card_tx_symbol_0_clk",
+	"gcc_ufs_card_unipro_core_clk",
+	"gcc_ufs_phy_ahb_clk",
+	"gcc_ufs_phy_axi_clk",
+	"gcc_ufs_phy_ice_core_clk",
+	"gcc_ufs_phy_phy_aux_clk",
+	"gcc_ufs_phy_rx_symbol_0_clk",
+	"gcc_ufs_phy_rx_symbol_1_clk",
+	"gcc_ufs_phy_tx_symbol_0_clk",
+	"gcc_ufs_phy_unipro_core_clk",
+	"gcc_usb30_prim_master_clk",
+	"gcc_usb30_prim_mock_utmi_clk",
+	"gcc_usb30_prim_sleep_clk",
+	"gcc_usb30_sec_master_clk",
+	"gcc_usb30_sec_mock_utmi_clk",
+	"gcc_usb30_sec_sleep_clk",
+	"gcc_usb3_prim_phy_aux_clk",
+	"gcc_usb3_prim_phy_com_aux_clk",
+	"gcc_usb3_prim_phy_pipe_clk",
+	"gcc_usb3_sec_phy_aux_clk",
+	"gcc_usb3_sec_phy_com_aux_clk",
+	"gcc_usb3_sec_phy_pipe_clk",
+	"gcc_usb_phy_cfg_ahb2phy_clk",
+	"gcc_video_ahb_clk",
+	"gcc_video_axi_clk",
+	"gcc_video_xo_clk",
+	"gpu_cc_acd_cxo_clk",
+	"gpu_cc_ahb_clk",
+	"gpu_cc_crc_ahb_clk",
+	"gpu_cc_cx_apb_clk",
+	"gpu_cc_cx_gfx3d_clk",
+	"gpu_cc_cx_gfx3d_slv_clk",
+	"gpu_cc_cx_gmu_clk",
+	"gpu_cc_cx_qdss_at_clk",
+	"gpu_cc_cx_qdss_trig_clk",
+	"gpu_cc_cx_qdss_tsctr_clk",
+	"gpu_cc_cx_snoc_dvm_clk",
+	"gpu_cc_cxo_aon_clk",
+	"gpu_cc_cxo_clk",
+	"gpu_cc_gx_cxo_clk",
+	"gpu_cc_gx_gmu_clk",
+	"gpu_cc_gx_qdss_tsctr_clk",
+	"gpu_cc_gx_vsense_clk",
+	"gpu_cc_rbcpr_ahb_clk",
+	"gpu_cc_rbcpr_clk",
+	"gpu_cc_sleep_clk",
+	"gpu_cc_spdm_gx_gfx3d_div_clk",
+	"video_cc_apb_clk",
+	"video_cc_at_clk",
+	"video_cc_qdss_trig_clk",
+	"video_cc_qdss_tsctr_div8_clk",
+	"video_cc_vcodec0_axi_clk",
+	"video_cc_vcodec0_core_clk",
+	"video_cc_vcodec1_axi_clk",
+	"video_cc_vcodec1_core_clk",
+	"video_cc_venus_ahb_clk",
+	"video_cc_venus_ctl_axi_clk",
+	"video_cc_venus_ctl_core_clk",
+};
+
+static struct clk_debug_mux gcc_debug_mux = {
+	.priv = &debug_mux_priv,
+	.debug_offset = 0x62008,
+	.post_div_offset = 0x62000,
+	.cbcr_offset = 0x62004,
+	.src_sel_mask = 0x3FF,
+	.src_sel_shift = 0,
+	.post_div_mask = 0xF,
+	.post_div_shift = 0,
+	MUX_SRC_LIST(
+		{ "cam_cc_bps_ahb_clk", 0x46, 4, CAM_CC,
+			0xE, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_bps_areg_clk", 0x46, 4, CAM_CC,
+			0xD, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_bps_axi_clk", 0x46, 4, CAM_CC,
+			0xC, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_bps_clk", 0x46, 4, CAM_CC,
+			0xB, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_camnoc_atb_clk", 0x46, 4, CAM_CC,
+			0x34, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_camnoc_axi_clk", 0x46, 4, CAM_CC,
+			0x2D, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_cci_clk", 0x46, 4, CAM_CC,
+			0x2A, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_cpas_ahb_clk", 0x46, 4, CAM_CC,
+			0x2C, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_csi0phytimer_clk", 0x46, 4, CAM_CC,
+			0x5, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_csi1phytimer_clk", 0x46, 4, CAM_CC,
+			0x7, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_csi2phytimer_clk", 0x46, 4, CAM_CC,
+			0x9, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_csiphy0_clk", 0x46, 4, CAM_CC,
+			0x6, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_csiphy1_clk", 0x46, 4, CAM_CC,
+			0x8, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_csiphy2_clk", 0x46, 4, CAM_CC,
+			0xA, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_fd_core_clk", 0x46, 4, CAM_CC,
+			0x28, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_fd_core_uar_clk", 0x46, 4, CAM_CC,
+			0x29, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_icp_apb_clk", 0x46, 4, CAM_CC,
+			0x32, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_icp_atb_clk", 0x46, 4, CAM_CC,
+			0x2F, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_icp_clk", 0x46, 4, CAM_CC,
+			0x26, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_icp_cti_clk", 0x46, 4, CAM_CC,
+			0x30, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_icp_ts_clk", 0x46, 4, CAM_CC,
+			0x31, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ife_0_axi_clk", 0x46, 4, CAM_CC,
+			0x1B, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ife_0_clk", 0x46, 4, CAM_CC,
+			0x17, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ife_0_cphy_rx_clk", 0x46, 4, CAM_CC,
+			0x1A, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ife_0_csid_clk", 0x46, 4, CAM_CC,
+			0x19, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ife_0_dsp_clk", 0x46, 4, CAM_CC,
+			0x18, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ife_1_axi_clk", 0x46, 4, CAM_CC,
+			0x21, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ife_1_clk", 0x46, 4, CAM_CC,
+			0x1D, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ife_1_cphy_rx_clk", 0x46, 4, CAM_CC,
+			0x20, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ife_1_csid_clk", 0x46, 4, CAM_CC,
+			0x1F, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ife_1_dsp_clk", 0x46, 4, CAM_CC,
+			0x1E, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ife_lite_clk", 0x46, 4, CAM_CC,
+			0x22, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ife_lite_cphy_rx_clk", 0x46, 4, CAM_CC,
+			0x24, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ife_lite_csid_clk", 0x46, 4, CAM_CC,
+			0x23, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ipe_0_ahb_clk", 0x46, 4, CAM_CC,
+			0x12, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ipe_0_areg_clk", 0x46, 4, CAM_CC,
+			0x11, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ipe_0_axi_clk", 0x46, 4, CAM_CC,
+			0x10, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ipe_0_clk", 0x46, 4, CAM_CC,
+			0xF, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ipe_1_ahb_clk", 0x46, 4, CAM_CC,
+			0x16, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ipe_1_areg_clk", 0x46, 4, CAM_CC,
+			0x15, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ipe_1_axi_clk", 0x46, 4, CAM_CC,
+			0x14, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_ipe_1_clk", 0x46, 4, CAM_CC,
+			0x13, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_jpeg_clk", 0x46, 4, CAM_CC,
+			0x25, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_lrme_clk", 0x46, 4, CAM_CC,
+			0x2B, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_mclk0_clk", 0x46, 4, CAM_CC,
+			0x1, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_mclk1_clk", 0x46, 4, CAM_CC,
+			0x2, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_mclk2_clk", 0x46, 4, CAM_CC,
+			0x3, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_mclk3_clk", 0x46, 4, CAM_CC,
+			0x4, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_soc_ahb_clk", 0x46, 4, CAM_CC,
+			0x2E, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_sys_tmr_clk", 0x46, 4, CAM_CC,
+			0x33, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "disp_cc_mdss_ahb_clk", 0x47, 4, DISP_CC,
+			0x13, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_axi_clk", 0x47, 4, DISP_CC,
+			0x14, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_byte0_clk", 0x47, 4, DISP_CC,
+			0x7, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_byte0_intf_clk", 0x47, 4, DISP_CC,
+			0x8, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_byte1_clk", 0x47, 4, DISP_CC,
+			0x9, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_byte1_intf_clk", 0x47, 4, DISP_CC,
+			0xA, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_dp_aux_clk", 0x47, 4, DISP_CC,
+			0x12, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_dp_crypto_clk", 0x47, 4, DISP_CC,
+			0xF, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_dp_link_clk", 0x47, 4, DISP_CC,
+			0xD, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_dp_link_intf_clk", 0x47, 4, DISP_CC,
+			0xE, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_dp_pixel1_clk", 0x47, 4, DISP_CC,
+			0x11, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_dp_pixel_clk", 0x47, 4, DISP_CC,
+			0x10, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_esc0_clk", 0x47, 4, DISP_CC,
+			0xB, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_esc1_clk", 0x47, 4, DISP_CC,
+			0xC, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_mdp_clk", 0x47, 4, DISP_CC,
+			0x3, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_mdp_lut_clk", 0x47, 4, DISP_CC,
+			0x5, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_pclk0_clk", 0x47, 4, DISP_CC,
+			0x1, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_pclk1_clk", 0x47, 4, DISP_CC,
+			0x2, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_qdss_at_clk", 0x47, 4, DISP_CC,
+			0x15, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_qdss_tsctr_div8_clk", 0x47, 4, DISP_CC,
+			0x16, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_rot_clk", 0x47, 4, DISP_CC,
+			0x4, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_rscc_ahb_clk", 0x47, 4, DISP_CC,
+			0x17, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_rscc_vsync_clk", 0x47, 4, DISP_CC,
+			0x18, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_spdm_debug_clk", 0x47, 4, DISP_CC,
+			0x20, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_spdm_dp_crypto_clk", 0x47, 4, DISP_CC,
+			0x1D, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_spdm_dp_pixel1_clk", 0x47, 4, DISP_CC,
+			0x1F, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_spdm_dp_pixel_clk", 0x47, 4, DISP_CC,
+			0x1E, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_spdm_mdp_clk", 0x47, 4, DISP_CC,
+			0x1B, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_spdm_pclk0_clk", 0x47, 4, DISP_CC,
+			0x19, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_spdm_pclk1_clk", 0x47, 4, DISP_CC,
+			0x1A, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_spdm_rot_clk", 0x47, 4, DISP_CC,
+			0x1C, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "disp_cc_mdss_vsync_clk", 0x47, 4, DISP_CC,
+			0x6, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+		{ "gcc_aggre_noc_pcie_tbu_clk", 0x2D, 4, GCC,
+			0x2D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_aggre_ufs_card_axi_clk", 0x11E, 4, GCC,
+			0x11E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_aggre_ufs_phy_axi_clk", 0x11D, 4, GCC,
+			0x11D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_aggre_usb3_prim_axi_clk", 0x11B, 4, GCC,
+			0x11B, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_aggre_usb3_sec_axi_clk", 0x11C, 4, GCC,
+			0x11C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_boot_rom_ahb_clk", 0x94, 4, GCC,
+			0x94, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_camera_ahb_clk", 0x3A, 4, GCC,
+			0x3A, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_camera_axi_clk", 0x40, 4, GCC,
+			0x40, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_camera_xo_clk", 0x43, 4, GCC,
+			0x43, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ce1_ahb_clk", 0xA9, 4, GCC,
+			0xA9, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ce1_axi_clk", 0xA8, 4, GCC,
+			0xA8, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ce1_clk", 0xA7, 4, GCC,
+			0xA7, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_cfg_noc_usb3_prim_axi_clk", 0x1D, 4, GCC,
+			0x1D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_cfg_noc_usb3_sec_axi_clk", 0x1E, 4, GCC,
+			0x1E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_cpuss_ahb_clk", 0xCE, 4, GCC,
+			0xCE, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_cpuss_dvm_bus_clk", 0xD3, 4, GCC,
+			0xD3, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_cpuss_gnoc_clk", 0xCF, 4, GCC,
+			0xCF, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_cpuss_rbcpr_clk", 0xD0, 4, GCC,
+			0xD0, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ddrss_gpu_axi_clk", 0xBB, 4, GCC,
+			0xBB, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_disp_ahb_clk", 0x3B, 4, GCC,
+			0x3B, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_disp_axi_clk", 0x41, 4, GCC,
+			0x41, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_disp_gpll0_clk_src", 0x4C, 4, GCC,
+			0x4C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_disp_gpll0_div_clk_src", 0x4D, 4, GCC,
+			0x4D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_disp_xo_clk", 0x44, 4, GCC,
+			0x44, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_gp1_clk", 0xDE, 4, GCC,
+			0xDE, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_gp2_clk", 0xDF, 4, GCC,
+			0xDF, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_gp3_clk", 0xE0, 4, GCC,
+			0xE0, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_gpu_cfg_ahb_clk", 0x142, 4, GCC,
+			0x142, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_gpu_gpll0_clk_src", 0x148, 4, GCC,
+			0x148, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_gpu_gpll0_div_clk_src", 0x149, 4, GCC,
+			0x149, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_gpu_memnoc_gfx_clk", 0x145, 4, GCC,
+			0x145, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_gpu_snoc_dvm_gfx_clk", 0x147, 4, GCC,
+			0x147, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_mss_axis2_clk", 0x12F, 4, GCC,
+			0x12F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_mss_cfg_ahb_clk", 0x12D, 4, GCC,
+			0x12D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_mss_gpll0_div_clk_src", 0x133, 4, GCC,
+			0x133, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_mss_mfab_axis_clk", 0x12E, 4, GCC,
+			0x12E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_mss_q6_memnoc_axi_clk", 0x135, 4, GCC,
+			0x135, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_mss_snoc_axi_clk", 0x134, 4, GCC,
+			0x134, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pcie_0_aux_clk", 0xE5, 4, GCC,
+			0xE5, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pcie_0_cfg_ahb_clk", 0xE4, 4, GCC,
+			0xE4, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pcie_0_mstr_axi_clk", 0xE3, 4, GCC,
+			0xE3, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pcie_0_pipe_clk", 0xE6, 4, GCC,
+			0xE6, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pcie_0_slv_axi_clk", 0xE2, 4, GCC,
+			0xE2, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pcie_0_slv_q2a_axi_clk", 0xE1, 4, GCC,
+			0xE1, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pcie_1_aux_clk", 0xEC, 4, GCC,
+			0xEC, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pcie_1_cfg_ahb_clk", 0xEB, 4, GCC,
+			0xEB, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pcie_1_mstr_axi_clk", 0xEA, 4, GCC,
+			0xEA, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pcie_1_pipe_clk", 0xED, 4, GCC,
+			0xED, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pcie_1_slv_axi_clk", 0xE9, 4, GCC,
+			0xE9, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pcie_1_slv_q2a_axi_clk", 0xE8, 4, GCC,
+			0xE8, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pcie_phy_aux_clk", 0xEF, 4, GCC,
+			0xEF, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pcie_phy_refgen_clk", 0x160, 4, GCC,
+			0x160, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pdm2_clk", 0x8E, 4, GCC,
+			0x8E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pdm_ahb_clk", 0x8C, 4, GCC,
+			0x8C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_pdm_xo4_clk", 0x8D, 4, GCC,
+			0x8D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_prng_ahb_clk", 0x8F, 4, GCC,
+			0x8F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qmip_camera_ahb_clk", 0x3D, 4, GCC,
+			0x3D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qmip_disp_ahb_clk", 0x3E, 4, GCC,
+			0x3E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qmip_video_ahb_clk", 0x3C, 4, GCC,
+			0x3C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap0_core_2x_clk", 0x77, 4, GCC,
+			0x77, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap0_core_clk", 0x76, 4, GCC,
+			0x76, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap0_s0_clk", 0x78, 4, GCC,
+			0x78, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap0_s1_clk", 0x79, 4, GCC,
+			0x79, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap0_s2_clk", 0x7A, 4, GCC,
+			0x7A, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap0_s3_clk", 0x7B, 4, GCC,
+			0x7B, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap0_s4_clk", 0x7C, 4, GCC,
+			0x7C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap0_s5_clk", 0x7D, 4, GCC,
+			0x7D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap0_s6_clk", 0x7E, 4, GCC,
+			0x7E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap0_s7_clk", 0x7F, 4, GCC,
+			0x7F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap1_core_2x_clk", 0x80, 4, GCC,
+			0x80, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap1_core_clk", 0x81, 4, GCC,
+			0x81, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap1_s0_clk", 0x84, 4, GCC,
+			0x84, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap1_s1_clk", 0x85, 4, GCC,
+			0x85, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap1_s2_clk", 0x86, 4, GCC,
+			0x86, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap1_s3_clk", 0x87, 4, GCC,
+			0x87, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap1_s4_clk", 0x88, 4, GCC,
+			0x88, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap1_s5_clk", 0x89, 4, GCC,
+			0x89, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap1_s6_clk", 0x8A, 4, GCC,
+			0x8A, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap1_s7_clk", 0x8B, 4, GCC,
+			0x8B, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap_0_m_ahb_clk", 0x74, 4, GCC,
+			0x74, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap_0_s_ahb_clk", 0x75, 4, GCC,
+			0x75, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap_1_m_ahb_clk", 0x82, 4, GCC,
+			0x82, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_qupv3_wrap_1_s_ahb_clk", 0x83, 4, GCC,
+			0x83, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_sdcc2_ahb_clk", 0x71, 4, GCC,
+			0x71, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_sdcc2_apps_clk", 0x70, 4, GCC,
+			0x70, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_sdcc4_ahb_clk", 0x73, 4, GCC,
+			0x73, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_sdcc4_apps_clk", 0x72, 4, GCC,
+			0x72, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_sys_noc_cpuss_ahb_clk", 0xC, 4, GCC,
+			0xC, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_tsif_ahb_clk", 0x90, 4, GCC,
+			0x90, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_tsif_inactivity_timers_clk", 0x92, 4, GCC,
+			0x92, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_tsif_ref_clk", 0x91, 4, GCC,
+			0x91, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_card_ahb_clk", 0xF1, 4, GCC,
+			0xF1, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_card_axi_clk", 0xF0, 4, GCC,
+			0xF0, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_card_ice_core_clk", 0xF7, 4, GCC,
+			0xF7, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_card_phy_aux_clk", 0xF8, 4, GCC,
+			0xF8, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_card_rx_symbol_0_clk", 0xF3, 4, GCC,
+			0xF3, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_card_rx_symbol_1_clk", 0xF9, 4, GCC,
+			0xF9, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_card_tx_symbol_0_clk", 0xF2, 4, GCC,
+			0xF2, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_card_unipro_core_clk", 0xF6, 4, GCC,
+			0xF6, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_phy_ahb_clk", 0xFC, 4, GCC,
+			0xFC, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_phy_axi_clk", 0xFB, 4, GCC,
+			0xFB, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_phy_ice_core_clk", 0x102, 4, GCC,
+			0x102, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_phy_phy_aux_clk", 0x103, 4, GCC,
+			0x103, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_phy_rx_symbol_0_clk", 0xFE, 4, GCC,
+			0xFE, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_phy_rx_symbol_1_clk", 0x104, 4, GCC,
+			0x104, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_phy_tx_symbol_0_clk", 0xFD, 4, GCC,
+			0xFD, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_ufs_phy_unipro_core_clk", 0x101, 4, GCC,
+			0x101, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_usb30_prim_master_clk", 0x5F, 4, GCC,
+			0x5F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_usb30_prim_mock_utmi_clk", 0x61, 4, GCC,
+			0x61, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_usb30_prim_sleep_clk", 0x60, 4, GCC,
+			0x60, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_usb30_sec_master_clk", 0x65, 4, GCC,
+			0x65, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_usb30_sec_mock_utmi_clk", 0x67, 4, GCC,
+			0x67, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_usb30_sec_sleep_clk", 0x66, 4, GCC,
+			0x66, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_usb3_prim_phy_aux_clk", 0x62, 4, GCC,
+			0x62, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_usb3_prim_phy_com_aux_clk", 0x63, 4, GCC,
+			0x63, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_usb3_prim_phy_pipe_clk", 0x64, 4, GCC,
+			0x64, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_usb3_sec_phy_aux_clk", 0x68, 4, GCC,
+			0x68, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_usb3_sec_phy_com_aux_clk", 0x69, 4, GCC,
+			0x69, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_usb3_sec_phy_pipe_clk", 0x6A, 4, GCC,
+			0x6A, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_usb_phy_cfg_ahb2phy_clk", 0x6F, 4, GCC,
+			0x6F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_video_ahb_clk", 0x39, 4, GCC,
+			0x39, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_video_axi_clk", 0x3F, 4, GCC,
+			0x3F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_video_xo_clk", 0x42, 4, GCC,
+			0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gpu_cc_acd_cxo_clk", 0x144, 4, GPU_CC,
+			0x1F, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_ahb_clk", 0x144, 4, GPU_CC,
+			0x11, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_crc_ahb_clk", 0x144, 4, GPU_CC,
+			0x12, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_cx_apb_clk", 0x144, 4, GPU_CC,
+			0x15, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_cx_gfx3d_clk", 0x144, 4, GPU_CC,
+			0x1A, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_cx_gfx3d_slv_clk", 0x144, 4, GPU_CC,
+			0x1B, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_cx_gmu_clk", 0x144, 4, GPU_CC,
+			0x19, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_cx_qdss_at_clk", 0x144, 4, GPU_CC,
+			0x13, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_cx_qdss_trig_clk", 0x144, 4, GPU_CC,
+			0x18, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_cx_qdss_tsctr_clk", 0x144, 4, GPU_CC,
+			0x14, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_cx_snoc_dvm_clk", 0x144, 4, GPU_CC,
+			0x16, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_cxo_aon_clk", 0x144, 4, GPU_CC,
+			0xB, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_cxo_clk", 0x144, 4, GPU_CC,
+			0xA, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_gx_cxo_clk", 0x144, 4, GPU_CC,
+			0xF, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_gx_gmu_clk", 0x144, 4, GPU_CC,
+			0x10, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_gx_qdss_tsctr_clk", 0x144, 4, GPU_CC,
+			0xE, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_gx_vsense_clk", 0x144, 4, GPU_CC,
+			0xD, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_rbcpr_ahb_clk", 0x144, 4, GPU_CC,
+			0x1D, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_rbcpr_clk", 0x144, 4, GPU_CC,
+			0x1C, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_sleep_clk", 0x144, 4, GPU_CC,
+			0x17, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "gpu_cc_spdm_gx_gfx3d_div_clk", 0x144, 4, GPU_CC,
+			0x1E, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+		{ "video_cc_apb_clk", 0x48, 4, VIDEO_CC,
+			0x8, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+		{ "video_cc_at_clk", 0x48, 4, VIDEO_CC,
+			0xB, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+		{ "video_cc_qdss_trig_clk", 0x48, 4, VIDEO_CC,
+			0x7, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+		{ "video_cc_qdss_tsctr_div8_clk", 0x48, 4, VIDEO_CC,
+			0xA, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+		{ "video_cc_vcodec0_axi_clk", 0x48, 4, VIDEO_CC,
+			0x5, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+		{ "video_cc_vcodec0_core_clk", 0x48, 4, VIDEO_CC,
+			0x2, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+		{ "video_cc_vcodec1_axi_clk", 0x48, 4, VIDEO_CC,
+			0x6, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+		{ "video_cc_vcodec1_core_clk", 0x48, 4, VIDEO_CC,
+			0x3, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+		{ "video_cc_venus_ahb_clk", 0x48, 4, VIDEO_CC,
+			0x9, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+		{ "video_cc_venus_ctl_axi_clk", 0x48, 4, VIDEO_CC,
+			0x4, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+		{ "video_cc_venus_ctl_core_clk", 0x48, 4, VIDEO_CC,
+			0x1, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+	),
+	.hw.init = &(struct clk_init_data){
+		.name = "gcc_debug_mux",
+		.ops = &clk_debug_mux_ops,
+		.parent_names = debug_mux_parent_names,
+		.num_parents = ARRAY_SIZE(debug_mux_parent_names),
+		.flags = CLK_IS_MEASURE,
+	},
+};
+
+static const struct of_device_id clk_debug_match_table[] = {
+	{ .compatible = "qcom,debugcc-sdm845" },
+	{}
+};
+
+static int clk_debug_845_probe(struct platform_device *pdev)
+{
+	struct clk *clk;
+	int ret = 0, count;
+
+	clk = devm_clk_get(&pdev->dev, "xo_clk_src");
+	if (IS_ERR(clk)) {
+		if (PTR_ERR(clk) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Unable to get xo clock\n");
+		return PTR_ERR(clk);
+	}
+
+	debug_mux_priv.cxo = clk;
+
+	ret = of_property_read_u32(pdev->dev.of_node, "qcom,cc-count",
+								&count);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Num of debug clock controller not specified\n");
+		return ret;
+	}
+
+	if (!count) {
+		dev_err(&pdev->dev, "Count of CC cannot be zero\n");
+		return -EINVAL;
+	}
+
+	gcc_debug_mux.regmap = devm_kzalloc(&pdev->dev,
+				sizeof(struct regmap *) * count, GFP_KERNEL);
+	if (!gcc_debug_mux.regmap)
+		return -ENOMEM;
+
+	if (of_get_property(pdev->dev.of_node, "qcom,gcc", NULL)) {
+		gcc_debug_mux.regmap[GCC] =
+			syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+					"qcom,gcc");
+		if (IS_ERR(gcc_debug_mux.regmap[GCC])) {
+			pr_err("Failed to map qcom,gcc\n");
+			return PTR_ERR(gcc_debug_mux.regmap[GCC]);
+		}
+	}
+
+	if (of_get_property(pdev->dev.of_node, "qcom,dispcc", NULL)) {
+		gcc_debug_mux.regmap[DISP_CC] =
+			syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+					"qcom,dispcc");
+		if (IS_ERR(gcc_debug_mux.regmap[DISP_CC])) {
+			pr_err("Failed to map qcom,dispcc\n");
+			return PTR_ERR(gcc_debug_mux.regmap[DISP_CC]);
+		}
+	}
+
+	if (of_get_property(pdev->dev.of_node, "qcom,videocc", NULL)) {
+		gcc_debug_mux.regmap[VIDEO_CC] =
+			syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+					"qcom,videocc");
+		if (IS_ERR(gcc_debug_mux.regmap[VIDEO_CC])) {
+			pr_err("Failed to map qcom,videocc\n");
+			return PTR_ERR(gcc_debug_mux.regmap[VIDEO_CC]);
+		}
+	}
+
+	if (of_get_property(pdev->dev.of_node, "qcom,camcc", NULL)) {
+		gcc_debug_mux.regmap[CAM_CC] =
+			syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+					"qcom,camcc");
+		if (IS_ERR(gcc_debug_mux.regmap[CAM_CC])) {
+			pr_err("Failed to map qcom,camcc\n");
+			return PTR_ERR(gcc_debug_mux.regmap[CAM_CC]);
+		}
+	}
+
+	if (of_get_property(pdev->dev.of_node, "qcom,gpucc", NULL)) {
+		gcc_debug_mux.regmap[GPU_CC] =
+			syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+					"qcom,gpucc");
+		if (IS_ERR(gcc_debug_mux.regmap[GPU_CC])) {
+			pr_err("Failed to map qcom,gpucc\n");
+			return PTR_ERR(gcc_debug_mux.regmap[GPU_CC]);
+		}
+	}
+
+	clk = devm_clk_register(&pdev->dev, &gcc_debug_mux.hw);
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "Unable to register GCC debug mux\n");
+		return PTR_ERR(clk);
+	}
+
+	ret = clk_debug_measure_register(&gcc_debug_mux.hw);
+	if (ret)
+		dev_err(&pdev->dev, "Could not register Measure clock\n");
+	else
+		dev_info(&pdev->dev, "Registered debug mux successfully\n");
+
+	return ret;
+}
+
+static struct platform_driver clk_debug_driver = {
+	.probe = clk_debug_845_probe,
+	.driver = {
+		.name = "debugcc-sdm845",
+		.of_match_table = clk_debug_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+int __init clk_debug_845_init(void)
+{
+	return platform_driver_register(&clk_debug_driver);
+}
+fs_initcall(clk_debug_845_init);
+
+MODULE_DESCRIPTION("QTI DEBUG CC SDM845 Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:debugcc-sdm845");
diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c
index 44c9b48..6b1eca8 100644
--- a/drivers/clk/qcom/dispcc-sdm845.c
+++ b/drivers/clk/qcom/dispcc-sdm845.c
@@ -146,10 +146,11 @@
 			.parent_names = (const char *[]){ "bi_tcxo" },
 			.num_parents = 1,
 			.ops = &clk_fabia_pll_ops,
-			VDD_CX_FMAX_MAP2(
-				MIN, 430000000,
-				LOW, 860000000
-			),
+			VDD_CX_FMAX_MAP4(
+				MIN, 615000000,
+				LOW, 1066000000,
+				LOW_L1, 1600000000,
+				NOMINAL, 2000000000),
 		},
 	},
 };
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index 0f6039e..08dce3f 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -168,6 +168,11 @@
 			.parent_names = (const char *[]){ "bi_tcxo" },
 			.num_parents = 1,
 			.ops = &clk_fabia_fixed_pll_ops,
+			VDD_CX_FMAX_MAP4(
+				MIN, 615000000,
+				LOW, 1066000000,
+				LOW_L1, 1600000000,
+				NOMINAL, 2000000000),
 		},
 	},
 };
@@ -207,7 +212,11 @@
 			.parent_names = (const char *[]){ "bi_tcxo" },
 			.num_parents = 1,
 			.ops = &clk_fabia_fixed_pll_ops,
-			VDD_CX_FMAX_MAP1(MIN, 1066000000),
+			VDD_CX_FMAX_MAP4(
+				MIN, 615000000,
+				LOW, 1066000000,
+				LOW_L1, 1600000000,
+				NOMINAL, 2000000000),
 		},
 	},
 };
diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c
new file mode 100644
index 0000000..a5a7488
--- /dev/null
+++ b/drivers/clk/qcom/gpucc-sdm845.c
@@ -0,0 +1,739 @@
+/*
+ * 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 <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+#include <linux/clk.h>
+#include <linux/clk/qcom.h>
+#include <dt-bindings/clock/qcom,gpucc-sdm845.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "reset.h"
+#include "clk-alpha-pll.h"
+#include "vdd-level-sdm845.h"
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+#define F_SLEW(f, s, h, m, n, sf) { (f), (s), (2 * (h) - 1), (m), (n), (sf) }
+
+static int vdd_gx_corner[] = {
+	RPMH_REGULATOR_LEVEL_OFF,		/* VDD_GX_NONE */
+	RPMH_REGULATOR_LEVEL_MIN_SVS,		/* VDD_GX_MIN */
+	RPMH_REGULATOR_LEVEL_LOW_SVS,		/* VDD_GX_LOWER */
+	RPMH_REGULATOR_LEVEL_SVS,		/* VDD_GX_LOW */
+	RPMH_REGULATOR_LEVEL_SVS_L1,		/* VDD_GX_LOW_L1 */
+	RPMH_REGULATOR_LEVEL_NOM,		/* VDD_GX_NOMINAL */
+	RPMH_REGULATOR_LEVEL_NOM_L1,		/* VDD_GX_NOMINAL_L1 */
+	RPMH_REGULATOR_LEVEL_TURBO,		/* VDD_GX_HIGH */
+	RPMH_REGULATOR_LEVEL_TURBO_L1,		/* VDD_GX_HIGH_L1 */
+	RPMH_REGULATOR_LEVEL_MAX,		/* VDD_GX_MAX */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_cx, VDD_CX_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_mx, VDD_CX_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_gfx, VDD_GX_NUM, 1, vdd_gx_corner);
+
+enum {
+	P_BI_TCXO,
+	P_CORE_BI_PLL_TEST_SE,
+	P_GPLL0_OUT_MAIN,
+	P_GPLL0_OUT_MAIN_DIV,
+	P_GPU_CC_PLL0_OUT_EVEN,
+	P_GPU_CC_PLL0_OUT_MAIN,
+	P_GPU_CC_PLL0_OUT_ODD,
+	P_GPU_CC_PLL1_OUT_EVEN,
+	P_GPU_CC_PLL1_OUT_MAIN,
+	P_GPU_CC_PLL1_OUT_ODD,
+};
+
+static const struct parent_map gpu_cc_parent_map_0[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_GPU_CC_PLL0_OUT_MAIN, 1 },
+	{ P_GPU_CC_PLL1_OUT_MAIN, 3 },
+	{ P_GPLL0_OUT_MAIN, 5 },
+	{ P_GPLL0_OUT_MAIN_DIV, 6 },
+	{ P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gpu_cc_parent_names_0[] = {
+	"bi_tcxo",
+	"gpu_cc_pll0",
+	"gpu_cc_pll1",
+	"gpll0",
+	"gpll0_out_even",
+	"core_bi_pll_test_se",
+};
+
+static const struct parent_map gpu_cc_parent_map_1[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_GPU_CC_PLL0_OUT_EVEN, 1 },
+	{ P_GPU_CC_PLL0_OUT_ODD, 2 },
+	{ P_GPU_CC_PLL1_OUT_EVEN, 3 },
+	{ P_GPU_CC_PLL1_OUT_ODD, 4 },
+	{ P_GPLL0_OUT_MAIN, 5 },
+	{ P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gpu_cc_parent_names_1[] = {
+	"bi_tcxo",
+	"gpu_cc_pll0_out_even",
+	"gpu_cc_pll0_out_odd",
+	"gpu_cc_pll1_out_even",
+	"gpu_cc_pll1_out_odd",
+	"gpll0",
+	"core_bi_pll_test_se",
+};
+
+static const struct parent_map gpu_cc_parent_map_2[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_GPLL0_OUT_MAIN, 5 },
+	{ P_GPLL0_OUT_MAIN_DIV, 6 },
+	{ P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gpu_cc_parent_names_2[] = {
+	"bi_tcxo",
+	"gpll0",
+	"gpll0",
+	"core_bi_pll_test_se",
+};
+
+static struct pll_vco fabia_vco[] = {
+	{ 250000000, 2000000000, 0 },
+	{ 125000000, 1000000000, 1 },
+};
+
+static const struct pll_config gpu_cc_pll0_config = {
+	.l = 0x1d,
+	.frac = 0x2aaa,
+};
+
+static struct clk_alpha_pll gpu_cc_pll0 = {
+	.offset = 0x0,
+	.vco_table = fabia_vco,
+	.num_vco = ARRAY_SIZE(fabia_vco),
+	.type = FABIA_PLL,
+	.clkr = {
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_pll0",
+			.parent_names = (const char *[]){ "bi_tcxo" },
+			.num_parents = 1,
+			.ops = &clk_fabia_pll_ops,
+			VDD_MX_FMAX_MAP4(
+				MIN, 615000000,
+				LOW, 1066000000,
+				LOW_L1, 1600000000,
+				NOMINAL, 2000000000),
+		},
+	},
+};
+
+static const struct clk_div_table post_div_table_fabia_even[] = {
+	{ 0x0, 1 },
+	{ 0x1, 2 },
+	{ 0x3, 4 },
+	{ 0x7, 8 },
+	{},
+};
+
+static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_even = {
+	.offset = 0x0,
+	.post_div_shift = 8,
+	.post_div_table = post_div_table_fabia_even,
+	.num_post_div = ARRAY_SIZE(post_div_table_fabia_even),
+	.width = 4,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gpu_cc_pll0_out_even",
+		.parent_names = (const char *[]){ "gpu_cc_pll0" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_generic_pll_postdiv_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
+	F(400000000, P_GPLL0_OUT_MAIN, 1.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 gpu_cc_gmu_clk_src = {
+	.cmd_rcgr = 0x1120,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.enable_safe_config = true,
+	.parent_map = gpu_cc_parent_map_0,
+	.freq_tbl = ftbl_gpu_cc_gmu_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gpu_cc_gmu_clk_src",
+		.parent_names = gpu_cc_parent_names_0,
+		.num_parents = 6,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_ops,
+		VDD_CX_FMAX_MAP2(
+			MIN, 200000000,
+			LOW, 400000000),
+	},
+};
+
+static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src[] = {
+	F_SLEW(147000000, P_GPU_CC_PLL0_OUT_EVEN,  1, 0, 0,  294000000),
+	F_SLEW(210000000, P_GPU_CC_PLL0_OUT_EVEN,  1, 0, 0,  420000000),
+	F_SLEW(338000000, P_GPU_CC_PLL0_OUT_EVEN,  1, 0, 0,  676000000),
+	F_SLEW(425000000, P_GPU_CC_PLL0_OUT_EVEN,  1, 0, 0,  850000000),
+	F_SLEW(600000000, P_GPU_CC_PLL0_OUT_EVEN,  1, 0, 0, 1200000000),
+	{ }
+};
+
+static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = {
+	.cmd_rcgr = 0x101c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.enable_safe_config = true,
+	.parent_map = gpu_cc_parent_map_1,
+	.freq_tbl = ftbl_gpu_cc_gx_gfx3d_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gpu_cc_gx_gfx3d_clk_src",
+		.parent_names = gpu_cc_parent_names_1,
+		.num_parents = 7,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops =  &clk_rcg2_ops,
+		VDD_GX_FMAX_MAP8(
+			MIN, 147000000,
+			LOWER, 210000000,
+			LOW, 280000000,
+			LOW_L1, 338000000,
+			NOMINAL, 425000000,
+			NOMINAL_L1, 487000000,
+			HIGH, 548000000,
+			HIGH_L1, 600000000),
+	},
+};
+
+static const struct freq_tbl ftbl_gpu_cc_rbcpr_clk_src[] = {
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 gpu_cc_rbcpr_clk_src = {
+	.cmd_rcgr = 0x10b0,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gpu_cc_parent_map_2,
+	.freq_tbl = ftbl_gpu_cc_rbcpr_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gpu_cc_rbcpr_clk_src",
+		.parent_names = gpu_cc_parent_names_2,
+		.num_parents = 4,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_ops,
+		VDD_CX_FMAX_MAP2(
+			MIN, 19200000,
+			NOMINAL, 50000000),
+	},
+};
+
+static struct clk_branch gpu_cc_acd_ahb_clk = {
+	.halt_reg = 0x1168,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1168,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_acd_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_acd_cxo_clk = {
+	.halt_reg = 0x1164,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1164,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_acd_cxo_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_ahb_clk = {
+	.halt_reg = 0x1078,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1078,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_crc_ahb_clk = {
+	.halt_reg = 0x107c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x107c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_crc_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_cx_apb_clk = {
+	.halt_reg = 0x1088,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1088,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_cx_apb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_cx_gfx3d_clk = {
+	.halt_reg = 0x10a4,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x10a4,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_cx_gfx3d_clk",
+			.parent_names = (const char *[]){
+				"gpu_cc_gx_gfx3d_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_cx_gfx3d_slv_clk = {
+	.halt_reg = 0x10a8,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x10a8,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_cx_gfx3d_slv_clk",
+			.parent_names = (const char *[]){
+				"gpu_cc_gx_gfx3d_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_cx_gmu_clk = {
+	.halt_reg = 0x1098,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1098,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_cx_gmu_clk",
+			.parent_names = (const char *[]){
+				"gpu_cc_gmu_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_cx_snoc_dvm_clk = {
+	.halt_reg = 0x108c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x108c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_cx_snoc_dvm_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_cxo_aon_clk = {
+	.halt_reg = 0x1004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_cxo_aon_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_cxo_clk = {
+	.halt_reg = 0x109c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x109c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_cxo_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_debug_clk = {
+	.halt_reg = 0x1100,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1100,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_debug_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_gx_cxo_clk = {
+	.halt_reg = 0x1060,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1060,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_gx_cxo_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_gx_gfx3d_clk = {
+	.halt_reg = 0x1054,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1054,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_gx_gfx3d_clk",
+			.parent_names = (const char *[]){
+				"gpu_cc_gx_gfx3d_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_gx_gmu_clk = {
+	.halt_reg = 0x1064,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1064,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_gx_gmu_clk",
+			.parent_names = (const char *[]){
+				"gpu_cc_gmu_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_gx_vsense_clk = {
+	.halt_reg = 0x1058,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1058,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_gx_vsense_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_pll_test_clk = {
+	.halt_reg = 0x110c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x110c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_pll_test_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_rbcpr_ahb_clk = {
+	.halt_reg = 0x10f4,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x10f4,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_rbcpr_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_cc_rbcpr_clk = {
+	.halt_reg = 0x10f0,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x10f0,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_cc_rbcpr_clk",
+			.parent_names = (const char *[]){
+				"gpu_cc_rbcpr_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_regmap *gpu_cc_sdm845_clocks[] = {
+	[GPU_CC_ACD_AHB_CLK] = &gpu_cc_acd_ahb_clk.clkr,
+	[GPU_CC_ACD_CXO_CLK] = &gpu_cc_acd_cxo_clk.clkr,
+	[GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr,
+	[GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr,
+	[GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr,
+	[GPU_CC_CX_GFX3D_CLK] = &gpu_cc_cx_gfx3d_clk.clkr,
+	[GPU_CC_CX_GFX3D_SLV_CLK] = &gpu_cc_cx_gfx3d_slv_clk.clkr,
+	[GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr,
+	[GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr,
+	[GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr,
+	[GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr,
+	[GPU_CC_DEBUG_CLK] = &gpu_cc_debug_clk.clkr,
+	[GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,
+	[GPU_CC_GX_CXO_CLK] = &gpu_cc_gx_cxo_clk.clkr,
+	[GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,
+	[GPU_CC_GX_VSENSE_CLK] = &gpu_cc_gx_vsense_clk.clkr,
+	[GPU_CC_PLL_TEST_CLK] = &gpu_cc_pll_test_clk.clkr,
+	[GPU_CC_RBCPR_AHB_CLK] = &gpu_cc_rbcpr_ahb_clk.clkr,
+	[GPU_CC_RBCPR_CLK] = &gpu_cc_rbcpr_clk.clkr,
+	[GPU_CC_RBCPR_CLK_SRC] = &gpu_cc_rbcpr_clk_src.clkr,
+};
+
+static struct clk_regmap *gpu_cc_gfx_sdm845_clocks[] = {
+	[GPU_CC_PLL0] = &gpu_cc_pll0.clkr,
+	[GPU_CC_PLL0_OUT_EVEN] = &gpu_cc_pll0_out_even.clkr,
+	[GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr,
+	[GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr,
+};
+
+static const struct qcom_reset_map gpu_cc_sdm845_resets[] = {
+	[GPUCC_GPU_CC_ACD_BCR] = { 0x1160 },
+	[GPUCC_GPU_CC_CX_BCR] = { 0x1068 },
+	[GPUCC_GPU_CC_GFX3D_AON_BCR] = { 0x10a0 },
+	[GPUCC_GPU_CC_GMU_BCR] = { 0x111c },
+	[GPUCC_GPU_CC_GX_BCR] = { 0x1008 },
+	[GPUCC_GPU_CC_RBCPR_BCR] = { 0x10ac },
+	[GPUCC_GPU_CC_SPDM_BCR] = { 0x1110 },
+	[GPUCC_GPU_CC_XO_BCR] = { 0x1000 },
+};
+
+static const struct regmap_config gpu_cc_sdm845_regmap_config = {
+	.reg_bits	= 32,
+	.reg_stride	= 4,
+	.val_bits	= 32,
+	.max_register	= 0x8008,
+	.fast_io	= true,
+};
+
+static const struct qcom_cc_desc gpu_cc_sdm845_desc = {
+	.config = &gpu_cc_sdm845_regmap_config,
+	.clks = gpu_cc_sdm845_clocks,
+	.num_clks = ARRAY_SIZE(gpu_cc_sdm845_clocks),
+	.resets = gpu_cc_sdm845_resets,
+	.num_resets = ARRAY_SIZE(gpu_cc_sdm845_resets),
+};
+
+static const struct qcom_cc_desc gpu_cc_gfx_sdm845_desc = {
+	.config = &gpu_cc_sdm845_regmap_config,
+	.clks = gpu_cc_gfx_sdm845_clocks,
+	.num_clks = ARRAY_SIZE(gpu_cc_gfx_sdm845_clocks),
+};
+
+static const struct of_device_id gpu_cc_sdm845_match_table[] = {
+	{ .compatible = "qcom,gpucc-sdm845" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, gpu_cc_sdm845_match_table);
+
+static const struct of_device_id gpu_cc_gfx_sdm845_match_table[] = {
+	{ .compatible = "qcom,gfxcc-sdm845" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, gpu_cc_gfx_sdm845_match_table);
+
+static int gpu_cc_gfx_sdm845_probe(struct platform_device *pdev)
+{
+	struct regmap *regmap;
+	struct resource *res;
+	void __iomem *base;
+	int ret = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "Failed to get resources for clock_gfxcc.\n");
+		return -EINVAL;
+	}
+
+	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (IS_ERR(base)) {
+		dev_err(&pdev->dev, "Failed to ioremap the GFX CC base.\n");
+		return PTR_ERR(base);
+	}
+
+	regmap = devm_regmap_init_mmio(&pdev->dev, base,
+				gpu_cc_gfx_sdm845_desc.config);
+	if (IS_ERR(regmap)) {
+		dev_err(&pdev->dev, "Failed to init regmap\n");
+		return PTR_ERR(regmap);
+	}
+
+	/* Get MX voltage regulator for GPU PLL graphic clock. */
+	vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx");
+	if (IS_ERR(vdd_mx.regulator[0])) {
+		if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER))
+			dev_err(&pdev->dev,
+				"Unable to get vdd_mx regulator\n");
+		return PTR_ERR(vdd_mx.regulator[0]);
+	}
+
+	/* GFX voltage regulators for GFX3D  graphic clock. */
+	vdd_gfx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_gfx");
+	if (IS_ERR(vdd_gfx.regulator[0])) {
+		if (PTR_ERR(vdd_gfx.regulator[0]) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Unable to get vdd_gfx regulator\n");
+		return PTR_ERR(vdd_gfx.regulator[0]);
+	}
+
+	clk_fabia_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config);
+
+	ret = qcom_cc_really_probe(pdev, &gpu_cc_gfx_sdm845_desc, regmap);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register GFX CC clocks\n");
+		return ret;
+	}
+
+	clk_prepare_enable(gpu_cc_cxo_clk.clkr.hw.clk);
+
+	dev_info(&pdev->dev, "Registered GFX CC clocks.\n");
+
+	return ret;
+}
+
+static struct platform_driver gpu_cc_gfx_sdm845_driver = {
+	.probe = gpu_cc_gfx_sdm845_probe,
+	.driver = {
+		.name = "gfxcc-sdm845",
+		.of_match_table = gpu_cc_gfx_sdm845_match_table,
+	},
+};
+
+static int __init gpu_cc_gfx_sdm845_init(void)
+{
+	return platform_driver_register(&gpu_cc_gfx_sdm845_driver);
+}
+arch_initcall(gpu_cc_gfx_sdm845_init);
+
+static void __exit gpu_cc_gfx_sdm845_exit(void)
+{
+	platform_driver_unregister(&gpu_cc_gfx_sdm845_driver);
+}
+module_exit(gpu_cc_gfx_sdm845_exit);
+
+static int gpu_cc_sdm845_probe(struct platform_device *pdev)
+{
+	struct regmap *regmap;
+	int ret = 0;
+
+	regmap = qcom_cc_map(pdev, &gpu_cc_sdm845_desc);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	/* Get CX voltage regulator for CX and GMU clocks. */
+	vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx");
+	if (IS_ERR(vdd_cx.regulator[0])) {
+		if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER))
+			dev_err(&pdev->dev,
+				"Unable to get vdd_cx regulator\n");
+		return PTR_ERR(vdd_cx.regulator[0]);
+	}
+
+	ret = qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register GPU CC clocks\n");
+		return ret;
+	}
+
+	dev_info(&pdev->dev, "Registered GPU CC clocks.\n");
+
+	return ret;
+}
+
+static struct platform_driver gpu_cc_sdm845_driver = {
+	.probe = gpu_cc_sdm845_probe,
+	.driver = {
+		.name = "gpu_cc-sdm845",
+		.of_match_table = gpu_cc_sdm845_match_table,
+	},
+};
+
+static int __init gpu_cc_sdm845_init(void)
+{
+	return platform_driver_register(&gpu_cc_sdm845_driver);
+}
+core_initcall(gpu_cc_sdm845_init);
+
+static void __exit gpu_cc_sdm845_exit(void)
+{
+	platform_driver_unregister(&gpu_cc_sdm845_driver);
+}
+module_exit(gpu_cc_sdm845_exit);
+
+MODULE_DESCRIPTION("QTI GPU_CC SDM845 Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:gpu_cc-sdm845");
diff --git a/drivers/clk/qcom/vdd-level-sdm845.h b/drivers/clk/qcom/vdd-level-sdm845.h
index 1771c15..a8d08b3 100644
--- a/drivers/clk/qcom/vdd-level-sdm845.h
+++ b/drivers/clk/qcom/vdd-level-sdm845.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -90,14 +90,31 @@
 	},					\
 	.num_rate_max = VDD_CX_NUM
 
-#define VDD_MX_FMAX_MAP2(l1, f1, l2, f2) \
+#define VDD_MX_FMAX_MAP4(l1, f1, l2, f2, l3, f3, l4, f4) \
 	.vdd_class = &vdd_mx,			\
 	.rate_max = (unsigned long[VDD_CX_NUM]) {	\
 		[VDD_CX_##l1] = (f1),		\
 		[VDD_CX_##l2] = (f2),		\
+		[VDD_CX_##l3] = (f3),		\
+		[VDD_CX_##l4] = (f4),		\
 	},					\
 	.num_rate_max = VDD_CX_NUM
 
+#define VDD_GX_FMAX_MAP8(l1, f1, l2, f2, l3, f3, l4, f4, l5, f5, l6, f6, \
+				l7, f7, l8, f8) \
+	.vdd_class = &vdd_gfx,			\
+	.rate_max = (unsigned long[VDD_GX_NUM]) {	\
+		[VDD_GX_##l1] = (f1),		\
+		[VDD_GX_##l2] = (f2),		\
+		[VDD_GX_##l3] = (f3),		\
+		[VDD_GX_##l4] = (f4),		\
+		[VDD_GX_##l5] = (f5),		\
+		[VDD_GX_##l6] = (f6),		\
+		[VDD_GX_##l7] = (f7),		\
+		[VDD_GX_##l8] = (f8),		\
+	},					\
+	.num_rate_max = VDD_GX_NUM
+
 enum vdd_cx_levels {
 	VDD_CX_NONE,
 	VDD_CX_MIN,		/* MIN SVS */
@@ -109,6 +126,19 @@
 	VDD_CX_NUM,
 };
 
+enum vdd_gx_levels {
+	VDD_GX_NONE,
+	VDD_GX_MIN,		/* MIN SVS */
+	VDD_GX_LOWER,		/* SVS2 */
+	VDD_GX_LOW,		/* SVS */
+	VDD_GX_LOW_L1,		/* SVSL1 */
+	VDD_GX_NOMINAL,		/* NOM */
+	VDD_GX_NOMINAL_L1,		/* NOM1 */
+	VDD_GX_HIGH,		/* TURBO */
+	VDD_GX_HIGH_L1,		/* TURBO1 */
+	VDD_GX_NUM,
+};
+
 /* Need to use the correct VI/VL mappings */
 static int vdd_corner[] = {
 	RPMH_REGULATOR_LEVEL_OFF,		/* VDD_CX_NONE */
diff --git a/drivers/clk/qcom/videocc-sdm845.c b/drivers/clk/qcom/videocc-sdm845.c
index 0e9cf88..8b63979 100644
--- a/drivers/clk/qcom/videocc-sdm845.c
+++ b/drivers/clk/qcom/videocc-sdm845.c
@@ -83,13 +83,11 @@
 			.parent_names = (const char *[]){ "bi_tcxo" },
 			.num_parents = 1,
 			.ops = &clk_fabia_pll_ops,
-			VDD_CX_FMAX_MAP5(
-				MIN, 200000000,
-				LOW, 640000000,
-				LOW_L1, 760000000,
-				NOMINAL, 1332000000,
-				HIGH, 1599000000),
-
+			VDD_CX_FMAX_MAP4(
+				MIN, 615000000,
+				LOW, 1066000000,
+				LOW_L1, 1600000000,
+				NOMINAL, 2000000000),
 		},
 	},
 };
diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
index fc75a33..8ca07fe 100644
--- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
+++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
@@ -608,7 +608,7 @@
 				 0x150, 0, 4, 24, 2, BIT(31),
 				 CLK_SET_RATE_PARENT);
 
-static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", 0x150, BIT(31), 0);
+static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", 0x150, BIT(30), 0);
 
 static SUNXI_CCU_GATE(ps_clk, "ps", "lcd1-ch1", 0x140, BIT(31), 0);
 
diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c
index ebb1b31..ee78104 100644
--- a/drivers/clk/sunxi-ng/ccu_mp.c
+++ b/drivers/clk/sunxi-ng/ccu_mp.c
@@ -85,6 +85,10 @@
 	unsigned int m, p;
 	u32 reg;
 
+	/* Adjust parent_rate according to pre-dividers */
+	ccu_mux_helper_adjust_parent_for_prediv(&cmp->common, &cmp->mux,
+						-1, &parent_rate);
+
 	reg = readl(cmp->common.base + cmp->common.reg);
 
 	m = reg >> cmp->m.shift;
@@ -114,6 +118,10 @@
 	unsigned int m, p;
 	u32 reg;
 
+	/* Adjust parent_rate according to pre-dividers */
+	ccu_mux_helper_adjust_parent_for_prediv(&cmp->common, &cmp->mux,
+						-1, &parent_rate);
+
 	max_m = cmp->m.max ?: 1 << cmp->m.width;
 	max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1);
 
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 96e18162..e2023bd 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -263,4 +263,4 @@
 	bool "MSM CPUFreq support"
 	depends on CPU_FREQ
 	help
-	  This enables the CPUFreq driver for Qualcomm CPUs.
+	  This enables the CPUFreq driver for Qualcomm Technologies, Inc. CPUs.
diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c
index cafa633..f796e36 100644
--- a/drivers/crypto/ccp/ccp-dev.c
+++ b/drivers/crypto/ccp/ccp-dev.c
@@ -283,11 +283,14 @@
  */
 int ccp_enqueue_cmd(struct ccp_cmd *cmd)
 {
-	struct ccp_device *ccp = ccp_get_device();
+	struct ccp_device *ccp;
 	unsigned long flags;
 	unsigned int i;
 	int ret;
 
+	/* Some commands might need to be sent to a specific device */
+	ccp = cmd->ccp ? cmd->ccp : ccp_get_device();
+
 	if (!ccp)
 		return -ENODEV;
 
diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dmaengine.c
index e5d9278..8d0eeb4 100644
--- a/drivers/crypto/ccp/ccp-dmaengine.c
+++ b/drivers/crypto/ccp/ccp-dmaengine.c
@@ -390,6 +390,7 @@
 			goto err;
 
 		ccp_cmd = &cmd->ccp_cmd;
+		ccp_cmd->ccp = chan->ccp;
 		ccp_pt = &ccp_cmd->u.passthru_nomap;
 		ccp_cmd->flags = CCP_CMD_MAY_BACKLOG;
 		ccp_cmd->flags |= CCP_CMD_PASSTHRU_NO_DMA_MAP;
diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c
index 286447a..152552d 100644
--- a/drivers/dax/dax.c
+++ b/drivers/dax/dax.c
@@ -334,6 +334,7 @@
 	int rc = VM_FAULT_SIGBUS;
 	phys_addr_t phys;
 	pfn_t pfn;
+	unsigned int fault_size = PAGE_SIZE;
 
 	if (check_vma(dax_dev, vma, __func__))
 		return VM_FAULT_SIGBUS;
@@ -344,6 +345,9 @@
 		return VM_FAULT_SIGBUS;
 	}
 
+	if (fault_size != dax_region->align)
+		return VM_FAULT_SIGBUS;
+
 	phys = pgoff_to_phys(dax_dev, vmf->pgoff, PAGE_SIZE);
 	if (phys == -1) {
 		dev_dbg(dev, "%s: phys_to_pgoff(%#lx) failed\n", __func__,
@@ -389,6 +393,7 @@
 	phys_addr_t phys;
 	pgoff_t pgoff;
 	pfn_t pfn;
+	unsigned int fault_size = PMD_SIZE;
 
 	if (check_vma(dax_dev, vma, __func__))
 		return VM_FAULT_SIGBUS;
@@ -405,6 +410,16 @@
 		return VM_FAULT_SIGBUS;
 	}
 
+	if (fault_size < dax_region->align)
+		return VM_FAULT_SIGBUS;
+	else if (fault_size > dax_region->align)
+		return VM_FAULT_FALLBACK;
+
+	/* if we are outside of the VMA */
+	if (pmd_addr < vma->vm_start ||
+			(pmd_addr + PMD_SIZE) > vma->vm_end)
+		return VM_FAULT_SIGBUS;
+
 	pgoff = linear_page_index(vma, pmd_addr);
 	phys = pgoff_to_phys(dax_dev, pgoff, PMD_SIZE);
 	if (phys == -1) {
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 3c02541..6476c5e 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -99,11 +99,11 @@
 	  the mem_latency devfreq governor.
 
 config QCOMCCI_HWMON
-	tristate "QCOM CCI Cache monitor hardware"
+	tristate "QTI CCI Cache monitor hardware"
 	depends on ARCH_QCOM
 	help
-	  QCOM CCI has additional PMU counters that can be used to monitor
-	  cache requests. QCOM CCI hardware monitor device configures these
+	  QTI CCI has additional PMU counters that can be used to monitor
+	  cache requests. QTI CCI hardware monitor device configures these
 	  registers to monitor cache and inform governor. It can also set an
 	  IRQ when count exceeds a programmable limit.
 
@@ -205,7 +205,7 @@
 	  clock APIs and don't have any form of status reporting.
 
 config QCOM_DEVFREQ_DEVBW
-	bool "QCOM DEVFREQ device for device master <-> slave IB/AB BW voting"
+	bool "Qualcomm Technologies Inc. DEVFREQ device for device master <-> slave IB/AB BW voting"
 	depends on ARCH_QCOM
 	select DEVFREQ_GOV_PERFORMANCE
 	select DEVFREQ_GOV_POWERSAVE
diff --git a/drivers/devfreq/arm-memlat-mon.c b/drivers/devfreq/arm-memlat-mon.c
index 0fb63e9..ed83185 100644
--- a/drivers/devfreq/arm-memlat-mon.c
+++ b/drivers/devfreq/arm-memlat-mon.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
@@ -34,7 +34,7 @@
 
 enum ev_index {
 	INST_IDX,
-	L2DM_IDX,
+	CM_IDX,
 	CYC_IDX,
 	NUM_EVENTS
 };
@@ -51,6 +51,8 @@
 	struct event_data events[NUM_EVENTS];
 	ktime_t prev_ts;
 	bool init_pending;
+	unsigned long cache_miss_event;
+	unsigned long inst_event;
 };
 static DEFINE_PER_CPU(struct memlat_hwmon_data, pm_data);
 
@@ -111,7 +113,7 @@
 			read_event(&hw_data->events[INST_IDX]);
 
 	hw->core_stats[cpu_idx].mem_count =
-			read_event(&hw_data->events[L2DM_IDX]);
+			read_event(&hw_data->events[CM_IDX]);
 
 	cyc_cnt = read_event(&hw_data->events[CYC_IDX]);
 	hw->core_stats[cpu_idx].freq = compute_freq(hw_data, cyc_cnt);
@@ -192,19 +194,19 @@
 	if (IS_ERR(attr))
 		return PTR_ERR(attr);
 
-	attr->config = INST_EV;
+	attr->config = hw_data->inst_event;
 	pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL);
 	if (IS_ERR(pevent))
 		goto err_out;
 	hw_data->events[INST_IDX].pevent = pevent;
 	perf_event_enable(hw_data->events[INST_IDX].pevent);
 
-	attr->config = L2DM_EV;
+	attr->config = hw_data->cache_miss_event;
 	pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL);
 	if (IS_ERR(pevent))
 		goto err_out;
-	hw_data->events[L2DM_IDX].pevent = pevent;
-	perf_event_enable(hw_data->events[L2DM_IDX].pevent);
+	hw_data->events[CM_IDX].pevent = pevent;
+	perf_event_enable(hw_data->events[CM_IDX].pevent);
 
 	attr->config = CYC_EV;
 	pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL);
@@ -300,6 +302,7 @@
 	struct memlat_hwmon *hw;
 	struct cpu_grp_info *cpu_grp;
 	int cpu, ret;
+	u32 cachemiss_ev, inst_ev;
 
 	cpu_grp = devm_kzalloc(dev, sizeof(*cpu_grp), GFP_KERNEL);
 	if (!cpu_grp)
@@ -325,8 +328,26 @@
 	if (!hw->core_stats)
 		return -ENOMEM;
 
-	for_each_cpu(cpu, &cpu_grp->cpus)
+	ret = of_property_read_u32(dev->of_node, "qcom,cachemiss-ev",
+			&cachemiss_ev);
+	if (ret) {
+		dev_dbg(dev, "Cache Miss event not specified. Using def:0x%x\n",
+				L2DM_EV);
+		cachemiss_ev = L2DM_EV;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "qcom,inst-ev", &inst_ev);
+	if (ret) {
+		dev_dbg(dev, "Inst event not specified. Using def:0x%x\n",
+				INST_EV);
+		inst_ev = INST_EV;
+	}
+
+	for_each_cpu(cpu, &cpu_grp->cpus) {
 		hw->core_stats[cpu - cpumask_first(&cpu_grp->cpus)].id = cpu;
+		(&per_cpu(pm_data, cpu))->cache_miss_event = cachemiss_ev;
+		(&per_cpu(pm_data, cpu))->inst_event = inst_ev;
+	}
 
 	hw->start_hwmon = &start_hwmon;
 	hw->stop_hwmon = &stop_hwmon;
diff --git a/drivers/edac/qcom_llcc_edac.c b/drivers/edac/qcom_llcc_edac.c
index d469869..6bec860 100644
--- a/drivers/edac/qcom_llcc_edac.c
+++ b/drivers/edac/qcom_llcc_edac.c
@@ -39,6 +39,10 @@
 
 #define DRP_SYN_REG_CNT	8
 
+#define LLCC_COMMON_STATUS0		0x0003000C
+#define LLCC_LB_CNT_MASK		0xf0000000
+#define LLCC_LB_CNT_SHIFT		28
+
 /* single & Double Bit syndrome register offsets */
 #define TRP_ECC_SB_ERR_SYN0		0x0002304C
 #define TRP_ECC_DB_ERR_SYN0		0x00020370
@@ -97,7 +101,10 @@
 
 struct erp_drvdata {
 	struct regmap *llcc_map;
+	phys_addr_t *llcc_banks;
 	u32 ecc_irq;
+	u32 num_banks;
+	u32 b_off;
 };
 
 static const struct errors_edac errors[] = {
@@ -108,29 +115,32 @@
 };
 
 /* Clear the error interrupt and counter registers */
-static void qcom_llcc_clear_errors(int err_type, struct regmap *llcc_map)
+static void qcom_llcc_clear_errors(int err_type, struct erp_drvdata *drv)
 {
 	switch (err_type) {
 	case LLCC_DRAM_CE:
 	case LLCC_DRAM_UE:
 		/* Clear the interrupt */
-		regmap_write(llcc_map, DRP_INTERRUPT_CLEAR, DRP_TRP_INT_CLEAR);
+		regmap_write(drv->llcc_map, drv->b_off + DRP_INTERRUPT_CLEAR,
+			DRP_TRP_INT_CLEAR);
 		/* Clear the counters */
-		regmap_write(llcc_map, DRP_ECC_ERROR_CNTR_CLEAR,
+		regmap_write(drv->llcc_map,
+			drv->b_off + DRP_ECC_ERROR_CNTR_CLEAR,
 			DRP_TRP_CNT_CLEAR);
 		break;
 	case LLCC_TRAM_CE:
 	case LLCC_TRAM_UE:
-		regmap_write(llcc_map, TRP_INTERRUPT_0_CLEAR,
+		regmap_write(drv->llcc_map, drv->b_off + TRP_INTERRUPT_0_CLEAR,
 			     DRP_TRP_INT_CLEAR);
-		regmap_write(llcc_map, TRP_ECC_ERROR_CNTR_CLEAR,
-			     DRP_TRP_CNT_CLEAR);
+		regmap_write(drv->llcc_map,
+			drv->b_off + TRP_ECC_ERROR_CNTR_CLEAR,
+			DRP_TRP_CNT_CLEAR);
 		break;
 	}
 }
 
 /* Dump syndrome registers for tag Ram Double bit errors */
-static void dump_trp_db_syn_reg(struct regmap *llcc_map)
+static void dump_trp_db_syn_reg(struct erp_drvdata *drv, u32 bank)
 {
 	int i;
 	int db_err_cnt;
@@ -140,17 +150,20 @@
 
 	for (i = 0; i < TRP_SYN_REG_CNT; i++) {
 		synd_reg = TRP_ECC_DB_ERR_SYN0 + (i * 4);
-		regmap_read(llcc_map, synd_reg, &synd_val);
+		regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg,
+			&synd_val);
 		edac_printk(KERN_CRIT, EDAC_LLCC, "TRP_ECC_SYN%d: 0x%8x\n",
 			i, synd_val);
 	}
 
-	regmap_read(llcc_map, TRP_ECC_ERROR_STATUS1, &db_err_cnt);
+	regmap_read(drv->llcc_map,
+		drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS1, &db_err_cnt);
 	db_err_cnt = (db_err_cnt & ECC_DB_ERR_COUNT_MASK);
 	edac_printk(KERN_CRIT, EDAC_LLCC, "Double-Bit error count: 0x%4x\n",
 		db_err_cnt);
 
-	regmap_read(llcc_map, TRP_ECC_ERROR_STATUS0, &db_err_ways);
+	regmap_read(drv->llcc_map,
+		drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS0, &db_err_ways);
 	db_err_ways = (db_err_ways & ECC_DB_ERR_WAYS_MASK);
 	db_err_ways >>= ECC_DB_ERR_WAYS_SHIFT;
 
@@ -159,7 +172,7 @@
 }
 
 /* Dump syndrome register for tag Ram Single Bit Errors */
-static void dump_trp_sb_syn_reg(struct regmap *llcc_map)
+static void dump_trp_sb_syn_reg(struct erp_drvdata *drv, u32 bank)
 {
 	int i;
 	int sb_err_cnt;
@@ -169,18 +182,21 @@
 
 	for (i = 0; i < TRP_SYN_REG_CNT; i++) {
 		synd_reg = TRP_ECC_SB_ERR_SYN0 + (i * 4);
-		regmap_read(llcc_map, synd_reg, &synd_val);
+		regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg,
+			&synd_val);
 		edac_printk(KERN_CRIT, EDAC_LLCC, "TRP_ECC_SYN%d: 0x%8x\n",
 			i, synd_val);
 	}
 
-	regmap_read(llcc_map, TRP_ECC_ERROR_STATUS1, &sb_err_cnt);
+	regmap_read(drv->llcc_map,
+		drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS1, &sb_err_cnt);
 	sb_err_cnt = (sb_err_cnt & ECC_SB_ERR_COUNT_MASK);
 	sb_err_cnt >>= ECC_SB_ERR_COUNT_SHIFT;
 	edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error count: 0x%4x\n",
 		sb_err_cnt);
 
-	regmap_read(llcc_map, TRP_ECC_ERROR_STATUS0, &sb_err_ways);
+	regmap_read(drv->llcc_map,
+		drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS0, &sb_err_ways);
 	sb_err_ways = sb_err_ways & ECC_SB_ERR_WAYS_MASK;
 
 	edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error ways: 0x%4x\n",
@@ -188,7 +204,7 @@
 }
 
 /* Dump syndrome registers for Data Ram Double bit errors */
-static void dump_drp_db_syn_reg(struct regmap *llcc_map)
+static void dump_drp_db_syn_reg(struct erp_drvdata *drv, u32 bank)
 {
 	int i;
 	int db_err_cnt;
@@ -198,17 +214,20 @@
 
 	for (i = 0; i < DRP_SYN_REG_CNT; i++) {
 		synd_reg = DRP_ECC_DB_ERR_SYN0 + (i * 4);
-		regmap_read(llcc_map, synd_reg, &synd_val);
+		regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg,
+			&synd_val);
 		edac_printk(KERN_CRIT, EDAC_LLCC, "DRP_ECC_SYN%d: 0x%8x\n",
 			i, synd_val);
 	}
 
-	regmap_read(llcc_map, DRP_ECC_ERROR_STATUS1, &db_err_cnt);
+	regmap_read(drv->llcc_map,
+		drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS1, &db_err_cnt);
 	db_err_cnt = (db_err_cnt & ECC_DB_ERR_COUNT_MASK);
 	edac_printk(KERN_CRIT, EDAC_LLCC, "Double-Bit error count: 0x%4x\n",
 		db_err_cnt);
 
-	regmap_read(llcc_map, DRP_ECC_ERROR_STATUS0, &db_err_ways);
+	regmap_read(drv->llcc_map,
+		drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS0, &db_err_ways);
 	db_err_ways &= ECC_DB_ERR_WAYS_MASK;
 	db_err_ways >>= ECC_DB_ERR_WAYS_SHIFT;
 	edac_printk(KERN_CRIT, EDAC_LLCC, "Double-Bit error ways: 0x%4x\n",
@@ -216,7 +235,7 @@
 }
 
 /* Dump Syndrome registers for Data Ram Single bit errors*/
-static void dump_drp_sb_syn_reg(struct regmap *llcc_map)
+static void dump_drp_sb_syn_reg(struct erp_drvdata *drv, u32 bank)
 {
 	int i;
 	int sb_err_cnt;
@@ -226,18 +245,21 @@
 
 	for (i = 0; i < DRP_SYN_REG_CNT; i++) {
 		synd_reg = DRP_ECC_SB_ERR_SYN0 + (i * 4);
-		regmap_read(llcc_map, synd_reg, &synd_val);
+		regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg,
+			&synd_val);
 		edac_printk(KERN_CRIT, EDAC_LLCC, "DRP_ECC_SYN%d: 0x%8x\n",
 			i, synd_val);
 	}
 
-	regmap_read(llcc_map, DRP_ECC_ERROR_STATUS1, &sb_err_cnt);
+	regmap_read(drv->llcc_map,
+		drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS1, &sb_err_cnt);
 	sb_err_cnt &= ECC_SB_ERR_COUNT_MASK;
 	sb_err_cnt >>= ECC_SB_ERR_COUNT_SHIFT;
 	edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error count: 0x%4x\n",
 		sb_err_cnt);
 
-	regmap_read(llcc_map, DRP_ECC_ERROR_STATUS0, &sb_err_ways);
+	regmap_read(drv->llcc_map,
+		drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS0, &sb_err_ways);
 	sb_err_ways = sb_err_ways & ECC_SB_ERR_WAYS_MASK;
 
 	edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error ways: 0x%4x\n",
@@ -246,24 +268,26 @@
 
 
 static void dump_syn_reg(struct edac_device_ctl_info *edev_ctl,
-			 int err_type, struct regmap *llcc_map)
+			 int err_type, u32 bank)
 {
+	struct erp_drvdata *drv = edev_ctl->pvt_info;
+
 	switch (err_type) {
 	case LLCC_DRAM_CE:
-		dump_drp_sb_syn_reg(llcc_map);
+		dump_drp_sb_syn_reg(drv, bank);
 		break;
 	case LLCC_DRAM_UE:
-		dump_drp_db_syn_reg(llcc_map);
+		dump_drp_db_syn_reg(drv, bank);
 		break;
 	case LLCC_TRAM_CE:
-		dump_trp_sb_syn_reg(llcc_map);
+		dump_trp_sb_syn_reg(drv, bank);
 		break;
 	case LLCC_TRAM_UE:
-		dump_trp_db_syn_reg(llcc_map);
+		dump_trp_db_syn_reg(drv, bank);
 		break;
 	}
 
-	qcom_llcc_clear_errors(err_type, llcc_map);
+	qcom_llcc_clear_errors(err_type, drv);
 
 	errors[err_type].func(edev_ctl, 0, 0, errors[err_type].msg);
 }
@@ -274,30 +298,36 @@
 	u32 drp_error;
 	u32 trp_error;
 	struct erp_drvdata *drv = edev_ctl->pvt_info;
+	u32 i;
 
-	/* Look for Data RAM errors */
-	regmap_read(drv->llcc_map, DRP_INTERRUPT_STATUS, &drp_error);
+	for (i = 0; i < drv->num_banks; i++) {
+		/* Look for Data RAM errors */
+		regmap_read(drv->llcc_map,
+			drv->llcc_banks[i] + DRP_INTERRUPT_STATUS, &drp_error);
 
-	if (drp_error & SB_ECC_ERROR) {
-		edac_printk(KERN_CRIT, EDAC_LLCC,
-			"Single Bit Error detected in Data Ram\n");
-		dump_syn_reg(edev_ctl, LLCC_DRAM_CE, drv->llcc_map);
-	} else if (drp_error & DB_ECC_ERROR) {
-		edac_printk(KERN_CRIT, EDAC_LLCC,
-			"Double Bit Error detected in Data Ram\n");
-		dump_syn_reg(edev_ctl, LLCC_DRAM_UE, drv->llcc_map);
-	}
+		if (drp_error & SB_ECC_ERROR) {
+			edac_printk(KERN_CRIT, EDAC_LLCC,
+				"Single Bit Error detected in Data Ram\n");
+			dump_syn_reg(edev_ctl, LLCC_DRAM_CE, i);
+		} else if (drp_error & DB_ECC_ERROR) {
+			edac_printk(KERN_CRIT, EDAC_LLCC,
+				"Double Bit Error detected in Data Ram\n");
+			dump_syn_reg(edev_ctl, LLCC_DRAM_UE, i);
+		}
 
-	/* Look for Tag RAM errors */
-	regmap_read(drv->llcc_map, TRP_INTERRUPT_0_STATUS, &trp_error);
-	if (trp_error & SB_ECC_ERROR) {
-		edac_printk(KERN_CRIT, EDAC_LLCC,
-			"Single Bit Error detected in Tag Ram\n");
-		dump_syn_reg(edev_ctl, LLCC_TRAM_CE, drv->llcc_map);
-	} else if (trp_error & DB_ECC_ERROR) {
-		edac_printk(KERN_CRIT, EDAC_LLCC,
-			"Double Bit Error detected in Tag Ram\n");
-		dump_syn_reg(edev_ctl, LLCC_TRAM_UE, drv->llcc_map);
+		/* Look for Tag RAM errors */
+		regmap_read(drv->llcc_map,
+			drv->llcc_banks[i] + TRP_INTERRUPT_0_STATUS,
+			&trp_error);
+		if (trp_error & SB_ECC_ERROR) {
+			edac_printk(KERN_CRIT, EDAC_LLCC,
+				"Single Bit Error detected in Tag Ram\n");
+			dump_syn_reg(edev_ctl, LLCC_TRAM_CE, i);
+		} else if (trp_error & DB_ECC_ERROR) {
+			edac_printk(KERN_CRIT, EDAC_LLCC,
+				"Double Bit Error detected in Tag Ram\n");
+			dump_syn_reg(edev_ctl, LLCC_TRAM_UE, i);
+		}
 	}
 }
 
@@ -319,6 +349,8 @@
 	struct erp_drvdata *drv;
 	struct edac_device_ctl_info *edev_ctl;
 	struct device *dev = &pdev->dev;
+	u32 *banks;
+	u32 i;
 
 	/* Allocate edac control info */
 	edev_ctl = edac_device_alloc_ctl_info(sizeof(*drv), "qcom-llcc", 1,
@@ -358,6 +390,43 @@
 		}
 	}
 
+	/* Find the number of LLC banks supported */
+	regmap_read(drv->llcc_map, LLCC_COMMON_STATUS0,
+		    &drv->num_banks);
+
+	drv->num_banks &= LLCC_LB_CNT_MASK;
+	drv->num_banks >>= LLCC_LB_CNT_SHIFT;
+
+	drv->llcc_banks = devm_kzalloc(&pdev->dev,
+		sizeof(phys_addr_t) * drv->num_banks, GFP_KERNEL);
+
+	if (!drv->num_banks) {
+		dev_err(dev, "Cannot allocate memory for llcc_banks\n");
+		return -ENOMEM;
+	}
+
+	banks = devm_kzalloc(&pdev->dev,
+		sizeof(u32) * drv->num_banks, GFP_KERNEL);
+	if (!banks)
+		return -ENOMEM;
+
+	rc = of_property_read_u32_array(dev->parent->of_node,
+			"qcom,llcc-banks-off", banks, drv->num_banks);
+	if (rc) {
+		dev_err(dev, "Cannot read llcc-banks-off property\n");
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32(dev->parent->of_node,
+			"qcom,llcc-broadcast-off", &drv->b_off);
+	if (rc) {
+		dev_err(dev, "Cannot read llcc-broadcast-off property\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < drv->num_banks; i++)
+		drv->llcc_banks[i] = banks[i];
+
 	platform_set_drvdata(pdev, edev_ctl);
 
 	rc = edac_device_add_device(edev_ctl);
diff --git a/drivers/esoc/esoc_dev.c b/drivers/esoc/esoc_dev.c
index 39090dc..0c9e428 100644
--- a/drivers/esoc/esoc_dev.c
+++ b/drivers/esoc/esoc_dev.c
@@ -215,7 +215,7 @@
 							esoc_clink->name);
 				return -EIO;
 			}
-			put_user(req, (unsigned long __user *)uarg);
+			put_user(req, (unsigned int __user *)uarg);
 
 		}
 		return err;
@@ -227,7 +227,7 @@
 		err = clink_ops->get_status(&status, esoc_clink);
 		if (err)
 			return err;
-		put_user(status, (unsigned long __user *)uarg);
+		put_user(status, (unsigned int __user *)uarg);
 		break;
 	case ESOC_WAIT_FOR_CRASH:
 		err = wait_event_interruptible(esoc_udev->evt_wait,
@@ -241,7 +241,7 @@
 							esoc_clink->name);
 				return -EIO;
 			}
-			put_user(evt, (unsigned long __user *)uarg);
+			put_user(evt, (unsigned int __user *)uarg);
 		}
 		return err;
 	default:
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c
index 09e6a73..6f3c891 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c
@@ -3507,9 +3507,13 @@
 			max_mclk = 80000;
 		}
 	} else if (adev->asic_type == CHIP_OLAND) {
-		if ((adev->pdev->device == 0x6604) &&
-		    (adev->pdev->subsystem_vendor == 0x1028) &&
-		    (adev->pdev->subsystem_device == 0x066F)) {
+		if ((adev->pdev->revision == 0xC7) ||
+		    (adev->pdev->revision == 0x80) ||
+		    (adev->pdev->revision == 0x81) ||
+		    (adev->pdev->revision == 0x83) ||
+		    (adev->pdev->revision == 0x87) ||
+		    (adev->pdev->device == 0x6604) ||
+		    (adev->pdev->device == 0x6605)) {
 			max_sclk = 75000;
 		}
 	}
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 6e0447f..72ec93d 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1382,6 +1382,7 @@
 
 	pm_runtime_enable(dev);
 
+	pm_runtime_get_sync(dev);
 	phy_power_on(dp->phy);
 
 	analogix_dp_init_dp(dp);
@@ -1414,9 +1415,15 @@
 		goto err_disable_pm_runtime;
 	}
 
+	phy_power_off(dp->phy);
+	pm_runtime_put(dev);
+
 	return 0;
 
 err_disable_pm_runtime:
+
+	phy_power_off(dp->phy);
+	pm_runtime_put(dev);
 	pm_runtime_disable(dev);
 
 	return ret;
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 2e42a05..50acd79 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1382,6 +1382,15 @@
 	return ret < 0 ? ret : 0;
 }
 
+void release_crtc_commit(struct completion *completion)
+{
+	struct drm_crtc_commit *commit = container_of(completion,
+						      typeof(*commit),
+						      flip_done);
+
+	drm_crtc_commit_put(commit);
+}
+
 /**
  * drm_atomic_helper_setup_commit - setup possibly nonblocking commit
  * @state: new modeset state to be committed
@@ -1474,6 +1483,8 @@
 		}
 
 		crtc_state->event->base.completion = &commit->flip_done;
+		crtc_state->event->base.completion_release = release_crtc_commit;
+		drm_crtc_commit_get(commit);
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index e84faec..f5815e1 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -686,8 +686,8 @@
 	assert_spin_locked(&dev->event_lock);
 
 	if (e->completion) {
-		/* ->completion might disappear as soon as it signalled. */
 		complete_all(e->completion);
+		e->completion_release(e->completion);
 		e->completion = NULL;
 	}
 
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 71000d5..70b47ca 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -113,3 +113,13 @@
           driver during fatal errors and enable some display-driver logging
           into an internal buffer (this avoids logging overhead).
 
+config DRM_SDE_RSC
+	bool "Enable sde resource state coordinator(rsc) driver"
+	depends on DRM_MSM
+	help
+          The SDE DRM RSC provides display Resource State Coordinator support
+          to vote the ab/ib bandwidth for primary display. Each rsc client
+          can vote their active state. Any active request from any client
+          avoids the display core power collapse. A client can also register
+          for display core power collapse events on rsc.
+
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index d9a49f8..b5d78b1 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -50,10 +50,11 @@
 	sde_io_util.o \
 	sde/sde_hw_reg_dma_v1_color_proc.o \
 	sde/sde_hw_color_proc_v4.o \
-	sde_rsc.o \
-	sde_rsc_hw.o \
 	sde/sde_hw_ad4.o \
 
+msm_drm-$(CONFIG_DRM_SDE_RSC) += sde_rsc.o \
+	sde_rsc_hw.o \
+
 # use drm gpu driver only if qcom_kgsl driver not available
 ifneq ($(CONFIG_QCOM_KGSL),y)
 msm_drm-y += adreno/adreno_device.o \
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 600b250..9d2e95b 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -1065,6 +1065,262 @@
 	return ret;
 }
 
+static int msm_drm_object_supports_event(struct drm_device *dev,
+		struct drm_msm_event_req *req)
+{
+	int ret = -EINVAL;
+	struct drm_mode_object *arg_obj;
+
+	arg_obj = drm_mode_object_find(dev, req->object_id, req->object_type);
+	if (!arg_obj)
+		return -ENOENT;
+
+	switch (arg_obj->type) {
+	case DRM_MODE_OBJECT_CRTC:
+	case DRM_MODE_OBJECT_CONNECTOR:
+		ret = 0;
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+static int msm_register_event(struct drm_device *dev,
+	struct drm_msm_event_req *req, struct drm_file *file, bool en)
+{
+	int ret = -EINVAL;
+	struct msm_drm_private *priv = dev->dev_private;
+	struct msm_kms *kms = priv->kms;
+	struct drm_mode_object *arg_obj;
+
+	arg_obj = drm_mode_object_find(dev, req->object_id, req->object_type);
+	if (!arg_obj)
+		return -ENOENT;
+
+	ret = kms->funcs->register_events(kms, arg_obj, req->event, en);
+	return ret;
+}
+
+static int msm_event_client_count(struct drm_device *dev,
+		struct drm_msm_event_req *req_event, bool locked)
+{
+	struct msm_drm_private *priv = dev->dev_private;
+	unsigned long flag = 0;
+	struct msm_drm_event *node;
+	int count = 0;
+
+	if (!locked)
+		spin_lock_irqsave(&dev->event_lock, flag);
+	list_for_each_entry(node, &priv->client_event_list, base.link) {
+		if (node->event.type == req_event->event &&
+			node->info.object_id == req_event->object_id)
+			count++;
+	}
+	if (!locked)
+		spin_unlock_irqrestore(&dev->event_lock, flag);
+
+	return count;
+}
+
+static int msm_ioctl_register_event(struct drm_device *dev, void *data,
+				    struct drm_file *file)
+{
+	struct msm_drm_private *priv = dev->dev_private;
+	struct drm_msm_event_req *req_event = data;
+	struct msm_drm_event *client, *node;
+	unsigned long flag = 0;
+	bool dup_request = false;
+	int ret = 0, count = 0;
+
+	ret = msm_drm_object_supports_event(dev, req_event);
+	if (ret) {
+		DRM_ERROR("unsupported event %x object %x object id %d\n",
+			req_event->event, req_event->object_type,
+			req_event->object_id);
+		return ret;
+	}
+
+	spin_lock_irqsave(&dev->event_lock, flag);
+	list_for_each_entry(node, &priv->client_event_list, base.link) {
+		if (node->base.file_priv != file)
+			continue;
+		if (node->event.type == req_event->event &&
+			node->info.object_id == req_event->object_id) {
+			DRM_DEBUG("duplicate request for event %x obj id %d\n",
+				node->event.type, node->info.object_id);
+			dup_request = true;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flag);
+
+	if (dup_request)
+		return -EALREADY;
+
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	if (!client)
+		return -ENOMEM;
+
+	client->base.file_priv = file;
+	client->base.pid = current->pid;
+	client->base.event = &client->event;
+	client->event.type = req_event->event;
+	memcpy(&client->info, req_event, sizeof(client->info));
+
+	/* Get the count of clients that have registered for event.
+	 * Event should be enabled for first client, for subsequent enable
+	 * calls add to client list and return.
+	 */
+	count = msm_event_client_count(dev, req_event, false);
+	/* Add current client to list */
+	spin_lock_irqsave(&dev->event_lock, flag);
+	list_add_tail(&client->base.link, &priv->client_event_list);
+	spin_unlock_irqrestore(&dev->event_lock, flag);
+
+	if (count)
+		return 0;
+
+	ret = msm_register_event(dev, req_event, file, true);
+	if (ret) {
+		DRM_ERROR("failed to enable event %x object %x object id %d\n",
+			req_event->event, req_event->object_type,
+			req_event->object_id);
+		spin_lock_irqsave(&dev->event_lock, flag);
+		list_del(&client->base.link);
+		spin_unlock_irqrestore(&dev->event_lock, flag);
+		kfree(client);
+	}
+	return ret;
+}
+
+static int msm_ioctl_deregister_event(struct drm_device *dev, void *data,
+				      struct drm_file *file)
+{
+	struct msm_drm_private *priv = dev->dev_private;
+	struct drm_msm_event_req *req_event = data;
+	struct msm_drm_event *client = NULL, *node, *temp;
+	unsigned long flag = 0;
+	int count = 0;
+	bool found = false;
+	int ret = 0;
+
+	ret = msm_drm_object_supports_event(dev, req_event);
+	if (ret) {
+		DRM_ERROR("unsupported event %x object %x object id %d\n",
+			req_event->event, req_event->object_type,
+			req_event->object_id);
+		return ret;
+	}
+
+	spin_lock_irqsave(&dev->event_lock, flag);
+	list_for_each_entry_safe(node, temp, &priv->client_event_list,
+			base.link) {
+		if (node->event.type == req_event->event &&
+		    node->info.object_id == req_event->object_id &&
+		    node->base.file_priv == file) {
+			client = node;
+			list_del(&client->base.link);
+			found = true;
+			kfree(client);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flag);
+
+	if (!found)
+		return -ENOENT;
+
+	count = msm_event_client_count(dev, req_event, false);
+	if (!count)
+		ret = msm_register_event(dev, req_event, file, false);
+
+	return ret;
+}
+
+void msm_send_crtc_notification(struct drm_crtc *crtc,
+				struct drm_event *event, u8 *payload)
+{
+	struct drm_device *dev = NULL;
+	struct msm_drm_private *priv = NULL;
+	unsigned long flags;
+	struct msm_drm_event *notify, *node;
+	int len = 0, ret;
+
+	if (!crtc || !event || !event->length || !payload) {
+		DRM_ERROR("err param crtc %pK event %pK len %d payload %pK\n",
+			crtc, event, ((event) ? (event->length) : -1),
+			payload);
+		return;
+	}
+	dev = crtc->dev;
+	priv = (dev) ? dev->dev_private : NULL;
+	if (!dev || !priv) {
+		DRM_ERROR("invalid dev %pK priv %pK\n", dev, priv);
+		return;
+	}
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	list_for_each_entry(node, &priv->client_event_list, base.link) {
+		if (node->event.type != event->type ||
+			crtc->base.id != node->info.object_id)
+			continue;
+		len = event->length + sizeof(struct drm_msm_event_resp);
+		if (node->base.file_priv->event_space < len) {
+			DRM_ERROR("Insufficient space to notify\n");
+			continue;
+		}
+		notify = kzalloc(len, GFP_ATOMIC);
+		if (!notify)
+			continue;
+		notify->base.file_priv = node->base.file_priv;
+		notify->base.event = &notify->event;
+		notify->base.pid = node->base.pid;
+		notify->event.type = node->event.type;
+		notify->event.length = len;
+		memcpy(&notify->info, &node->info, sizeof(notify->info));
+		memcpy(notify->data, payload, event->length);
+		ret = drm_event_reserve_init_locked(dev, node->base.file_priv,
+			&notify->base, &notify->event);
+		if (ret) {
+			kfree(notify);
+			continue;
+		}
+		drm_send_event_locked(dev, &notify->base);
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+static int msm_release(struct inode *inode, struct file *filp)
+{
+	struct drm_file *file_priv = filp->private_data;
+	struct drm_minor *minor = file_priv->minor;
+	struct drm_device *dev = minor->dev;
+	struct msm_drm_private *priv = dev->dev_private;
+	struct msm_drm_event *node, *temp;
+	u32 count;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	list_for_each_entry_safe(node, temp, &priv->client_event_list,
+			base.link) {
+		if (node->base.file_priv != file_priv)
+			continue;
+		list_del(&node->base.link);
+		spin_unlock_irqrestore(&dev->event_lock, flags);
+		count = msm_event_client_count(dev, &node->info, true);
+		if (!count)
+			msm_register_event(dev, &node->info, file_priv, false);
+		kfree(node);
+		spin_lock_irqsave(&dev->event_lock, flags);
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	return drm_release(inode, filp);
+}
+
 static const struct drm_ioctl_desc msm_ioctls[] = {
 	DRM_IOCTL_DEF_DRV(MSM_GET_PARAM,    msm_ioctl_get_param,    DRM_AUTH|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(MSM_GEM_NEW,      msm_ioctl_gem_new,      DRM_AUTH|DRM_RENDER_ALLOW),
@@ -1075,6 +1331,10 @@
 	DRM_IOCTL_DEF_DRV(MSM_WAIT_FENCE,   msm_ioctl_wait_fence,   DRM_AUTH|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(MSM_GEM_MADVISE,  msm_ioctl_gem_madvise,  DRM_AUTH|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(SDE_WB_CONFIG, sde_wb_config, DRM_UNLOCKED|DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(MSM_REGISTER_EVENT,  msm_ioctl_register_event,
+			  DRM_UNLOCKED|DRM_CONTROL_ALLOW),
+	DRM_IOCTL_DEF_DRV(MSM_DEREGISTER_EVENT,  msm_ioctl_deregister_event,
+			  DRM_UNLOCKED|DRM_CONTROL_ALLOW),
 };
 
 static const struct vm_operations_struct vm_ops = {
@@ -1086,7 +1346,7 @@
 static const struct file_operations fops = {
 	.owner              = THIS_MODULE,
 	.open               = drm_open,
-	.release            = drm_release,
+	.release            = msm_release,
 	.unlocked_ioctl     = drm_ioctl,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl       = drm_compat_ioctl,
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index b51187d..f2fccd7 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -134,7 +134,10 @@
 	CRTC_PROP_CORE_CLK,
 	CRTC_PROP_CORE_AB,
 	CRTC_PROP_CORE_IB,
+	CRTC_PROP_MEM_AB,
+	CRTC_PROP_MEM_IB,
 	CRTC_PROP_ROT_PREFILL_BW,
+	CRTC_PROP_ROT_CLK,
 
 	/* total # of properties */
 	CRTC_PROP_COUNT
@@ -371,6 +374,7 @@
 struct msm_drm_event {
 	struct drm_pending_event base;
 	struct drm_event event;
+	struct drm_msm_event_req info;
 	u8 data[];
 };
 
@@ -620,6 +624,15 @@
 	MSM_DSI_CMD_ENCODER_ID = 1,
 	MSM_DSI_ENCODER_NUM = 2
 };
+
+/* *
+ * msm_send_crtc_notification - notify user-space clients of crtc events.
+ * @crtc: crtc that is generating the event.
+ * @event: event that needs to be notified.
+ * @payload: payload for the event.
+ */
+void msm_send_crtc_notification(struct drm_crtc *crtc,
+		struct drm_event *event, u8 *payload);
 #ifdef CONFIG_DRM_MSM_DSI
 void __init msm_dsi_register(void);
 void __exit msm_dsi_unregister(void);
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index 4ebbc58..aa1b090 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -83,6 +83,8 @@
 	void (*preclose)(struct msm_kms *kms, struct drm_file *file);
 	void (*postclose)(struct msm_kms *kms, struct drm_file *file);
 	void (*lastclose)(struct msm_kms *kms);
+	int (*register_events)(struct msm_kms *kms,
+			struct drm_mode_object *obj, u32 event, bool en);
 	/* cleanup: */
 	void (*destroy)(struct msm_kms *kms);
 };
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 9caadca..1f39180 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -399,9 +399,12 @@
 		/* convert fb val to drm framebuffer and prepare it */
 		c_state->out_fb =
 			drm_framebuffer_lookup(connector->dev, val);
-		if (!c_state->out_fb) {
+		if (!c_state->out_fb && val) {
 			SDE_ERROR("failed to look up fb %lld\n", val);
 			rc = -EFAULT;
+		} else if (!c_state->out_fb && !val) {
+			SDE_DEBUG("cleared fb_id\n");
+			rc = 0;
 		} else {
 			msm_framebuffer_set_kmap(c_state->out_fb,
 					c_conn->fb_kmap);
@@ -843,3 +846,9 @@
 
 	return ERR_PTR(rc);
 }
+
+int sde_connector_register_custom_event(struct sde_kms *kms,
+		struct drm_connector *conn_drm, u32 event, bool val)
+{
+	return -EINVAL;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 0ece0d2..9d36851 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -392,5 +392,16 @@
 void sde_connector_unregister_event(struct drm_connector *connector,
 		uint32_t event_idx);
 
+/**
+ * sde_connector_register_custom_event - register for async events
+ * @kms: Pointer to sde_kms
+ * @conn_drm: Pointer to drm connector object
+ * @event: Event for which request is being sent
+ * @en: Flag to enable/disable the event
+ * Returns: Zero on success
+ */
+int sde_connector_register_custom_event(struct sde_kms *kms,
+		struct drm_connector *conn_drm, u32 event, bool en);
+
 #endif /* _SDE_CONNECTOR_H_ */
 
diff --git a/drivers/gpu/drm/msm/sde/sde_core_perf.c b/drivers/gpu/drm/msm/sde/sde_core_perf.c
index 307c617..db2c515 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_perf.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_perf.c
@@ -18,13 +18,13 @@
 #include <linux/sort.h>
 #include <linux/clk.h>
 #include <linux/bitmap.h>
+#include <linux/sde_rsc.h>
 
 #include "msm_prop.h"
 
 #include "sde_kms.h"
 #include "sde_trace.h"
 #include "sde_crtc.h"
-#include "sde_rsc.h"
 #include "sde_core_perf.h"
 
 static struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index b6a37b7..acb5695 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -37,6 +37,14 @@
 #include "sde_power_handle.h"
 #include "sde_core_perf.h"
 
+struct sde_crtc_irq_info {
+	struct sde_irq_callback irq;
+	u32 event;
+	int (*func)(struct drm_crtc *crtc, bool en,
+			struct sde_irq_callback *irq);
+	struct list_head list;
+};
+
 /* default input fence timeout, in ms */
 #define SDE_CRTC_INPUT_FENCE_TIMEOUT    2000
 
@@ -51,6 +59,8 @@
 #define LEFT_MIXER 0
 #define RIGHT_MIXER 1
 
+#define MISR_BUFF_SIZE			256
+
 static inline struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc)
 {
 	struct msm_drm_private *priv;
@@ -68,6 +78,35 @@
 	return to_sde_kms(priv->kms);
 }
 
+static inline int _sde_crtc_power_enable(struct sde_crtc *sde_crtc, bool enable)
+{
+	struct drm_crtc *crtc;
+	struct msm_drm_private *priv;
+	struct sde_kms *sde_kms;
+
+	if (!sde_crtc) {
+		SDE_ERROR("invalid sde crtc\n");
+		return -EINVAL;
+	}
+
+	crtc = &sde_crtc->base;
+	if (!crtc->dev || !crtc->dev->dev_private) {
+		SDE_ERROR("invalid drm device\n");
+		return -EINVAL;
+	}
+
+	priv = crtc->dev->dev_private;
+	if (!priv->kms) {
+		SDE_ERROR("invalid kms\n");
+		return -EINVAL;
+	}
+
+	sde_kms = to_sde_kms(priv->kms);
+
+	return sde_power_resource_enable(&priv->phandle, sde_kms->core_client,
+									enable);
+}
+
 static void _sde_crtc_deinit_events(struct sde_crtc *sde_crtc)
 {
 	if (!sde_crtc)
@@ -467,12 +506,6 @@
 			sde_connector_prepare_fence(conn);
 		}
 
-	if (cstate->num_connectors > 0 && cstate->connectors[0]->encoder)
-		cstate->intf_mode = sde_encoder_get_intf_mode(
-				cstate->connectors[0]->encoder);
-	else
-		cstate->intf_mode = INTF_MODE_NONE;
-
 	/* prepare main output fence */
 	sde_fence_prepare(&sde_crtc->output_fence);
 }
@@ -514,6 +547,22 @@
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
+enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc)
+{
+	struct drm_encoder *encoder;
+
+	if (!crtc || !crtc->dev) {
+		SDE_ERROR("invalid crtc\n");
+		return INTF_MODE_NONE;
+	}
+
+	drm_for_each_encoder(encoder, crtc->dev)
+		if (encoder->crtc == crtc)
+			return sde_encoder_get_intf_mode(encoder);
+
+	return INTF_MODE_NONE;
+}
+
 static void sde_crtc_vblank_cb(void *data)
 {
 	struct drm_crtc *crtc = (struct drm_crtc *)data;
@@ -1086,8 +1135,6 @@
 	struct drm_device *dev;
 	struct drm_crtc *crtc;
 	struct drm_encoder *enc;
-	struct msm_drm_private *priv;
-	struct sde_kms *sde_kms;
 
 	if (!sde_crtc) {
 		SDE_ERROR("invalid crtc\n");
@@ -1096,17 +1143,11 @@
 
 	crtc = &sde_crtc->base;
 	dev = crtc->dev;
-	priv = dev->dev_private;
-
-	if (!priv->kms) {
-		SDE_ERROR("invalid kms\n");
-		return;
-	}
-	sde_kms = to_sde_kms(priv->kms);
 
 	if (enable) {
-		sde_power_resource_enable(&priv->phandle,
-				sde_kms->core_client, true);
+		if (_sde_crtc_power_enable(sde_crtc, true))
+			return;
+
 		list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
 			if (enc->crtc != crtc)
 				continue;
@@ -1125,8 +1166,7 @@
 
 			sde_encoder_register_vblank_callback(enc, NULL, NULL);
 		}
-		sde_power_resource_enable(&priv->phandle,
-				sde_kms->core_client, false);
+		_sde_crtc_power_enable(sde_crtc, false);
 	}
 }
 
@@ -1263,6 +1303,9 @@
 	struct sde_crtc *sde_crtc;
 	struct sde_crtc_state *cstate;
 	struct drm_encoder *encoder;
+	unsigned long flags;
+	struct sde_crtc_irq_info *node = NULL;
+	int ret;
 
 	if (!crtc || !crtc->dev || !crtc->state) {
 		SDE_ERROR("invalid crtc\n");
@@ -1314,6 +1357,18 @@
 
 	memset(sde_crtc->mixers, 0, sizeof(sde_crtc->mixers));
 	sde_crtc->num_mixers = 0;
+
+	spin_lock_irqsave(&sde_crtc->spin_lock, flags);
+	list_for_each_entry(node, &sde_crtc->user_event_list, list) {
+		ret = 0;
+		if (node->func)
+			ret = node->func(crtc, false, &node->irq);
+		if (ret)
+			SDE_ERROR("%s failed to disable event %x\n",
+					sde_crtc->name, node->event);
+	}
+	spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
+
 	mutex_unlock(&sde_crtc->crtc_lock);
 }
 
@@ -1324,7 +1379,9 @@
 	struct sde_hw_mixer *lm;
 	struct drm_display_mode *mode;
 	struct drm_encoder *encoder;
-	int i;
+	unsigned long flags;
+	struct sde_crtc_irq_info *node = NULL;
+	int i, ret;
 
 	if (!crtc) {
 		SDE_ERROR("invalid crtc\n");
@@ -1359,6 +1416,17 @@
 		lm->cfg.flags = 0;
 		lm->ops.setup_mixer_out(lm, &lm->cfg);
 	}
+
+	spin_lock_irqsave(&sde_crtc->spin_lock, flags);
+	list_for_each_entry(node, &sde_crtc->user_event_list, list) {
+		ret = 0;
+		if (node->func)
+			ret = node->func(crtc, true, &node->irq);
+		if (ret)
+			SDE_ERROR("%s failed to enable event %x\n",
+				sde_crtc->name, node->event);
+	}
+	spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
 }
 
 struct plane_state {
@@ -1723,9 +1791,21 @@
 			SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA,
 			CRTC_PROP_CORE_IB);
 	msm_property_install_range(&sde_crtc->property_info,
+			"mem_ab", 0x0, 0, U64_MAX,
+			SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA,
+			CRTC_PROP_MEM_AB);
+	msm_property_install_range(&sde_crtc->property_info,
+			"mem_ib", 0x0, 0, U64_MAX,
+			SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA,
+			CRTC_PROP_MEM_IB);
+	msm_property_install_range(&sde_crtc->property_info,
 			"rot_prefill_bw", 0, 0, U64_MAX,
 			catalog->perf.max_bw_high * 1000ULL,
 			CRTC_PROP_ROT_PREFILL_BW);
+	msm_property_install_range(&sde_crtc->property_info,
+			"rot_clk", 0, 0, U64_MAX,
+			sde_kms->perf.max_core_clk_rate,
+			CRTC_PROP_ROT_CLK);
 
 	msm_property_install_blob(&sde_crtc->property_info, "capabilities",
 		DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO);
@@ -2001,7 +2081,108 @@
 	return single_open(file, _sde_debugfs_status_show, inode->i_private);
 }
 
-#define DEFINE_SDE_DEBUGFS_SEQ_FOPS(__prefix)				\
+static ssize_t _sde_crtc_misr_setup(struct file *file,
+		const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct sde_crtc *sde_crtc;
+	struct sde_crtc_mixer *m;
+	int i = 0, rc;
+	char buf[MISR_BUFF_SIZE + 1];
+	u32 frame_count, enable;
+	size_t buff_copy;
+
+	if (!file || !file->private_data)
+		return -EINVAL;
+
+	sde_crtc = file->private_data;
+	buff_copy = min_t(size_t, count, MISR_BUFF_SIZE);
+	if (copy_from_user(buf, user_buf, buff_copy)) {
+		SDE_ERROR("buffer copy failed\n");
+		return -EINVAL;
+	}
+
+	buf[buff_copy] = 0; /* end of string */
+
+	if (sscanf(buf, "%u %u", &enable, &frame_count) != 2)
+		return -EINVAL;
+
+	rc = _sde_crtc_power_enable(sde_crtc, true);
+	if (rc)
+		return rc;
+
+	mutex_lock(&sde_crtc->crtc_lock);
+	sde_crtc->misr_enable = enable;
+	for (i = 0; i < sde_crtc->num_mixers; ++i) {
+		m = &sde_crtc->mixers[i];
+		if (!m->hw_lm)
+			continue;
+
+		m->hw_lm->ops.setup_misr(m->hw_lm, enable, frame_count);
+	}
+	mutex_unlock(&sde_crtc->crtc_lock);
+	_sde_crtc_power_enable(sde_crtc, false);
+
+	return count;
+}
+
+static ssize_t _sde_crtc_misr_read(struct file *file,
+		char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct sde_crtc *sde_crtc;
+	struct sde_crtc_mixer *m;
+	int i = 0, rc;
+	ssize_t len = 0;
+	char buf[MISR_BUFF_SIZE + 1] = {'\0'};
+
+	if (*ppos)
+		return 0;
+
+	if (!file || !file->private_data)
+		return -EINVAL;
+
+	sde_crtc = file->private_data;
+	rc = _sde_crtc_power_enable(sde_crtc, true);
+	if (rc)
+		return rc;
+
+	mutex_lock(&sde_crtc->crtc_lock);
+	if (!sde_crtc->misr_enable) {
+		len += snprintf(buf + len, MISR_BUFF_SIZE - len,
+			"disabled\n");
+		goto buff_check;
+	}
+
+	for (i = 0; i < sde_crtc->num_mixers; ++i) {
+		m = &sde_crtc->mixers[i];
+		if (!m->hw_lm)
+			continue;
+
+		len += snprintf(buf + len, MISR_BUFF_SIZE - len, "lm idx:%d\n",
+					m->hw_lm->idx - LM_0);
+		len += snprintf(buf + len, MISR_BUFF_SIZE - len, "0x%x\n",
+				m->hw_lm->ops.collect_misr(m->hw_lm));
+	}
+
+buff_check:
+	if (count <= len) {
+		len = 0;
+		goto end;
+	}
+
+	if (copy_to_user(user_buff, buf, len)) {
+		len = -EFAULT;
+		goto end;
+	}
+
+	*ppos += len;   /* increase offset */
+
+end:
+	mutex_unlock(&sde_crtc->crtc_lock);
+	_sde_crtc_power_enable(sde_crtc, false);
+	return len;
+}
+
+#define DEFINE_SDE_DEBUGFS_SEQ_FOPS(__prefix)                          \
 static int __prefix ## _open(struct inode *inode, struct file *file)	\
 {									\
 	return single_open(file, __prefix ## _show, inode->i_private);	\
@@ -2021,7 +2202,7 @@
 
 	seq_printf(s, "num_connectors: %d\n", cstate->num_connectors);
 	seq_printf(s, "client type: %d\n", sde_crtc_get_client_type(crtc));
-	seq_printf(s, "intf_mode: %d\n", cstate->intf_mode);
+	seq_printf(s, "intf_mode: %d\n", sde_crtc_get_intf_mode(crtc));
 	seq_printf(s, "bw_ctl: %llu\n", cstate->cur_perf.bw_ctl);
 	seq_printf(s, "core_clk_rate: %u\n", cstate->cur_perf.core_clk_rate);
 	seq_printf(s, "max_per_pipe_ib: %llu\n",
@@ -2042,6 +2223,11 @@
 		.llseek =	seq_lseek,
 		.release =	single_release,
 	};
+	static const struct file_operations debugfs_misr_fops = {
+		.open =		simple_open,
+		.read =		_sde_crtc_misr_read,
+		.write =	_sde_crtc_misr_setup,
+	};
 
 	if (!crtc)
 		return -EINVAL;
@@ -2064,6 +2250,8 @@
 			sde_crtc->debugfs_root,
 			&sde_crtc->base,
 			&sde_crtc_debugfs_state_fops);
+	debugfs_create_file("misr_data", 0644, sde_crtc->debugfs_root,
+					sde_crtc, &debugfs_misr_fops);
 
 	return 0;
 }
@@ -2241,6 +2429,7 @@
 	atomic_set(&sde_crtc->frame_pending, 0);
 
 	INIT_LIST_HEAD(&sde_crtc->frame_event_list);
+	INIT_LIST_HEAD(&sde_crtc->user_event_list);
 	for (i = 0; i < ARRAY_SIZE(sde_crtc->frame_events); i++) {
 		INIT_LIST_HEAD(&sde_crtc->frame_events[i].list);
 		list_add(&sde_crtc->frame_events[i].list,
@@ -2284,3 +2473,9 @@
 	SDE_DEBUG("%s: successfully initialized crtc\n", sde_crtc->name);
 	return crtc;
 }
+
+int sde_crtc_register_custom_event(struct sde_kms *kms,
+		struct drm_crtc *crtc_drm, u32 event, bool val)
+{
+	return -EINVAL;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index f389196..5934405 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -136,6 +136,7 @@
  * @event_cache   : Local cache of event worker structures
  * @event_free_list : List of available event structures
  * @event_lock    : Spinlock around event handling code
+ * @misr_enable   : boolean entry indicates misr enable/disable status.
  */
 struct sde_crtc {
 	struct drm_crtc base;
@@ -169,6 +170,7 @@
 	struct list_head dirty_list;
 	struct list_head ad_dirty;
 	struct list_head ad_active;
+	struct list_head user_event_list;
 
 	struct mutex crtc_lock;
 
@@ -183,6 +185,7 @@
 	struct sde_crtc_event event_cache[SDE_CRTC_MAX_EVENT_COUNT];
 	struct list_head event_free_list;
 	spinlock_t event_lock;
+	bool misr_enable;
 };
 
 #define to_sde_crtc(x) container_of(x, struct sde_crtc, base)
@@ -316,16 +319,20 @@
 void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file);
 
 /**
+ * sde_crtc_register_custom_event - api for enabling/disabling crtc event
+ * @kms: Pointer to sde_kms
+ * @crtc_drm: Pointer to crtc object
+ * @event: Event that client is interested
+ * @en: Flag to enable/disable the event
+ */
+int sde_crtc_register_custom_event(struct sde_kms *kms,
+		struct drm_crtc *crtc_drm, u32 event, bool en);
+
+/**
  * sde_crtc_get_intf_mode - get interface mode of the given crtc
  * @crtc: Pointert to crtc
  */
-static inline enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc)
-{
-	struct sde_crtc_state *cstate =
-			crtc ? to_sde_crtc_state(crtc->state) : NULL;
-
-	return cstate ? cstate->intf_mode : INTF_MODE_NONE;
-}
+enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc);
 
 /**
  * sde_crtc_get_client_type - check the crtc type- rt, nrt, rsc, etc.
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 69d21fb..7ab4f8d 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -19,6 +19,7 @@
 #define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <linux/sde_rsc.h>
 
 #include "msm_drv.h"
 #include "sde_kms.h"
@@ -32,7 +33,6 @@
 #include "sde_formats.h"
 #include "sde_encoder_phys.h"
 #include "sde_color_processing.h"
-#include "sde_rsc.h"
 #include "sde_power_handle.h"
 #include "sde_hw_dsc.h"
 
@@ -57,6 +57,8 @@
 
 #define MAX_CHANNELS_PER_ENC 2
 
+#define MISR_BUFF_SIZE			256
+
 /**
  * struct sde_encoder_virt - virtual encoder. Container of one or more physical
  *	encoders. Virtual encoder manages one "logical" display. Physical
@@ -90,6 +92,7 @@
  * @crtc_frame_event:		callback event
  * @frame_done_timeout:		frame done timeout in Hz
  * @frame_done_timer:		watchdog timer for frame done event
+ * @misr_enable:		misr enable/disable status
  */
 struct sde_encoder_virt {
 	struct drm_encoder base;
@@ -120,6 +123,7 @@
 	struct sde_rsc_client *rsc_client;
 	struct msm_display_info disp_info;
 	bool rsc_state_update;
+	bool misr_enable;
 };
 
 #define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base)
@@ -131,6 +135,36 @@
 	return (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC);
 }
 
+static inline int _sde_encoder_power_enable(struct sde_encoder_virt *sde_enc,
+								bool enable)
+{
+	struct drm_encoder *drm_enc;
+	struct msm_drm_private *priv;
+	struct sde_kms *sde_kms;
+
+	if (!sde_enc) {
+		SDE_ERROR("invalid sde enc\n");
+		return -EINVAL;
+	}
+
+	drm_enc = &sde_enc->base;
+	if (!drm_enc->dev || !drm_enc->dev->dev_private) {
+		SDE_ERROR("drm device invalid\n");
+		return -EINVAL;
+	}
+
+	priv = drm_enc->dev->dev_private;
+	if (!priv->kms) {
+		SDE_ERROR("invalid kms\n");
+		return -EINVAL;
+	}
+
+	sde_kms = to_sde_kms(priv->kms);
+
+	return sde_power_resource_enable(&priv->phandle, sde_kms->core_client,
+									enable);
+}
+
 void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc,
 		struct sde_encoder_hw_resources *hw_res,
 		struct drm_connector_state *conn_state)
@@ -706,8 +740,6 @@
 static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
 {
 	struct sde_encoder_virt *sde_enc = NULL;
-	struct msm_drm_private *priv;
-	struct sde_kms *sde_kms;
 	int i = 0;
 	int ret = 0;
 
@@ -723,13 +755,13 @@
 	}
 
 	sde_enc = to_sde_encoder_virt(drm_enc);
-	priv = drm_enc->dev->dev_private;
-	sde_kms = to_sde_kms(priv->kms);
 
 	SDE_DEBUG_ENC(sde_enc, "\n");
 	SDE_EVT32(DRMID(drm_enc));
 
-	sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
+	ret = _sde_encoder_power_enable(sde_enc, true);
+	if (ret)
+		return;
 
 	sde_enc->cur_master = NULL;
 
@@ -810,7 +842,7 @@
 
 	sde_rm_release(&sde_kms->rm, drm_enc);
 
-	sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
+	_sde_encoder_power_enable(sde_enc, false);
 }
 
 static enum sde_intf sde_encoder_get_intf(struct sde_mdss_cfg *catalog,
@@ -1389,105 +1421,108 @@
 	return single_open(file, _sde_encoder_status_show, inode->i_private);
 }
 
-static void _sde_set_misr_params(struct sde_encoder_phys *phys, u32 enable,
-					u32 frame_count)
-{
-	int j;
-
-	if (!phys->misr_map)
-		return;
-
-	phys->misr_map->enable = enable;
-
-	if (frame_count <= SDE_CRC_BATCH_SIZE)
-		phys->misr_map->frame_count = frame_count;
-	else if (frame_count <= 0)
-		phys->misr_map->frame_count = 0;
-	else
-		phys->misr_map->frame_count = SDE_CRC_BATCH_SIZE;
-
-	if (!enable) {
-		phys->misr_map->last_idx = 0;
-		phys->misr_map->frame_count = 0;
-		for (j = 0; j < SDE_CRC_BATCH_SIZE; j++)
-			phys->misr_map->crc_value[j] = 0;
-	}
-}
-
-static ssize_t _sde_encoder_misr_set(struct file *file,
+static ssize_t _sde_encoder_misr_setup(struct file *file,
 		const char __user *user_buf, size_t count, loff_t *ppos)
 {
 	struct sde_encoder_virt *sde_enc;
-	struct drm_encoder *drm_enc;
-	int i = 0;
-	char buf[10];
-	u32 enable, frame_count;
+	int i = 0, rc;
+	char buf[MISR_BUFF_SIZE + 1];
+	size_t buff_copy;
+	u32 frame_count, enable;
 
-	drm_enc = file->private_data;
-	sde_enc = to_sde_encoder_virt(drm_enc);
+	if (!file || !file->private_data)
+		return -EINVAL;
 
-	if (copy_from_user(buf, user_buf, count))
-		return -EFAULT;
+	sde_enc = file->private_data;
 
-	buf[count] = 0; /* end of string */
+	buff_copy = min_t(size_t, count, MISR_BUFF_SIZE);
+	if (copy_from_user(buf, user_buf, buff_copy))
+		return -EINVAL;
+
+	buf[buff_copy] = 0; /* end of string */
 
 	if (sscanf(buf, "%u %u", &enable, &frame_count) != 2)
-		return -EFAULT;
+		return -EINVAL;
+
+	rc = _sde_encoder_power_enable(sde_enc, true);
+	if (rc)
+		return rc;
 
 	mutex_lock(&sde_enc->enc_lock);
+	sde_enc->misr_enable = enable;
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
 
-		if (!phys || !phys->misr_map || !phys->ops.setup_misr)
+		if (!phys || !phys->ops.setup_misr)
 			continue;
 
-		_sde_set_misr_params(phys, enable, frame_count);
-		phys->ops.setup_misr(phys, phys->misr_map);
+		phys->ops.setup_misr(phys, enable, frame_count);
 	}
 	mutex_unlock(&sde_enc->enc_lock);
+	_sde_encoder_power_enable(sde_enc, false);
+
 	return count;
 }
 
-static ssize_t _sde_encoder_misr_read(
-		struct file *file,
-		char __user *buff, size_t count, loff_t *ppos)
+static ssize_t _sde_encoder_misr_read(struct file *file,
+		char __user *user_buff, size_t count, loff_t *ppos)
 {
 	struct sde_encoder_virt *sde_enc;
-	struct drm_encoder *drm_enc;
-	int i = 0, j = 0, len = 0;
-	char buf[512] = {'\0'};
+	int i = 0, len = 0;
+	char buf[MISR_BUFF_SIZE + 1] = {'\0'};
+	int rc;
 
 	if (*ppos)
 		return 0;
 
-	drm_enc = file->private_data;
-	sde_enc = to_sde_encoder_virt(drm_enc);
+	if (!file || !file->private_data)
+		return -EINVAL;
+
+	sde_enc = file->private_data;
+
+	rc = _sde_encoder_power_enable(sde_enc, true);
+	if (rc)
+		return rc;
 
 	mutex_lock(&sde_enc->enc_lock);
-	for (i = 0; i < sde_enc->num_phys_encs; i++) {
-		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
-		struct sde_misr_params *misr_map;
-
-		if (!phys || !phys->misr_map)
-			continue;
-
-		misr_map = phys->misr_map;
-
-		len += snprintf(buf+len, sizeof(buf), "INTF%d\n", i);
-		for (j = 0; j < SDE_CRC_BATCH_SIZE; j++)
-			len += snprintf(buf+len, sizeof(buf), "%x\n",
-						misr_map->crc_value[j]);
+	if (!sde_enc->misr_enable) {
+		len += snprintf(buf + len, MISR_BUFF_SIZE - len,
+			"disabled\n");
+		goto buff_check;
+	} else if (sde_enc->disp_info.capabilities &
+						~MSM_DISPLAY_CAP_VID_MODE) {
+		len += snprintf(buf + len, MISR_BUFF_SIZE - len,
+			"unsupported\n");
+		goto buff_check;
 	}
 
-	if (len < 0 || len >= sizeof(buf))
-		return 0;
+	for (i = 0; i < sde_enc->num_phys_encs; i++) {
+		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
+		if (!phys || !phys->ops.collect_misr)
+			continue;
 
-	if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
-		return -EFAULT;
+		len += snprintf(buf + len, MISR_BUFF_SIZE - len,
+			"Intf idx:%d\n", phys->intf_idx - INTF_0);
+		len += snprintf(buf + len, MISR_BUFF_SIZE - len, "0x%x\n",
+					phys->ops.collect_misr(phys));
+	}
+
+buff_check:
+	if (count <= len) {
+		len = 0;
+		goto end;
+	}
+
+	if (copy_to_user(user_buff, buf, len)) {
+		len = -EFAULT;
+		goto end;
+	}
 
 	*ppos += len;   /* increase offset */
-	mutex_unlock(&sde_enc->enc_lock);
 
+end:
+	mutex_unlock(&sde_enc->enc_lock);
+	_sde_encoder_power_enable(sde_enc, false);
 	return len;
 }
 
@@ -1507,7 +1542,7 @@
 	static const struct file_operations debugfs_misr_fops = {
 		.open = simple_open,
 		.read = _sde_encoder_misr_read,
-		.write = _sde_encoder_misr_set,
+		.write = _sde_encoder_misr_setup,
 	};
 
 	char name[SDE_NAME_SIZE];
@@ -1534,7 +1569,7 @@
 		sde_enc->debugfs_root, sde_enc, &debugfs_status_fops);
 
 	debugfs_create_file("misr_data", 0644,
-		sde_enc->debugfs_root, drm_enc, &debugfs_misr_fops);
+		sde_enc->debugfs_root, sde_enc, &debugfs_misr_fops);
 
 	return 0;
 }
@@ -1857,7 +1892,7 @@
 	sde_enc->rsc_client = sde_rsc_client_create(SDE_RSC_INDEX, name,
 					disp_info->is_primary);
 	if (IS_ERR_OR_NULL(sde_enc->rsc_client)) {
-		SDE_ERROR("sde rsc client create failed :%ld\n",
+		SDE_DEBUG("sde rsc client create failed :%ld\n",
 						PTR_ERR(sde_enc->rsc_client));
 		sde_enc->rsc_client = NULL;
 	}
@@ -1896,10 +1931,6 @@
 			if (ret)
 				return ret;
 		}
-
-		if (phys && phys->ops.collect_misr)
-			if (phys->misr_map && phys->misr_map->enable)
-				phys->ops.collect_misr(phys, phys->misr_map);
 	}
 
 	return ret;
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index 7aa9a29..da155b0 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -16,6 +16,7 @@
 #define __SDE_ENCODER_PHYS_H__
 
 #include <linux/jiffies.h>
+#include <linux/sde_rsc.h>
 
 #include "sde_kms.h"
 #include "sde_hw_intf.h"
@@ -27,8 +28,6 @@
 #include "sde_encoder.h"
 #include "sde_connector.h"
 
-#include "sde_rsc.h"
-
 #define SDE_ENCODER_NAME_MAX	16
 
 /* wait for at most 2 vsync for lowest refresh rate (24hz) */
@@ -148,9 +147,8 @@
 	bool (*needs_single_flush)(struct sde_encoder_phys *phys_enc);
 
 	void (*setup_misr)(struct sde_encoder_phys *phys_encs,
-			struct sde_misr_params *misr_map);
-	void (*collect_misr)(struct sde_encoder_phys *phys_enc,
-			struct sde_misr_params *misr_map);
+				bool enable, u32 frame_count);
+	u32 (*collect_misr)(struct sde_encoder_phys *phys_enc);
 	void (*hw_reset)(struct sde_encoder_phys *phys_enc);
 };
 
@@ -184,7 +182,6 @@
  * @hw_pp:		Hardware interface to the ping pong registers
  * @sde_kms:		Pointer to the sde_kms top level
  * @cached_mode:	DRM mode cached at mode_set time, acted on in enable
- * @misr_map:		Interface for setting and collecting MISR data
  * @enabled:		Whether the encoder has enabled and running a mode
  * @split_role:		Role to play in a split-panel configuration
  * @intf_mode:		Interface mode
@@ -213,7 +210,6 @@
 	struct sde_hw_pingpong *hw_pp;
 	struct sde_kms *sde_kms;
 	struct drm_display_mode cached_mode;
-	struct sde_misr_params *misr_map;
 	enum sde_enc_split_role split_role;
 	enum sde_intf_mode intf_mode;
 	enum sde_intf intf_idx;
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 82d32dc..39dfd5d 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -830,23 +830,29 @@
 }
 
 static void sde_encoder_phys_vid_setup_misr(struct sde_encoder_phys *phys_enc,
-			struct sde_misr_params *misr_map)
+						bool enable, u32 frame_count)
 {
-	struct sde_encoder_phys_vid *vid_enc =
-		to_sde_encoder_phys_vid(phys_enc);
+	struct sde_encoder_phys_vid *vid_enc;
 
-	if (vid_enc && vid_enc->hw_intf && vid_enc->hw_intf->ops.setup_misr)
-		vid_enc->hw_intf->ops.setup_misr(vid_enc->hw_intf, misr_map);
+	if (!phys_enc)
+		return;
+	vid_enc = to_sde_encoder_phys_vid(phys_enc);
+
+	if (vid_enc->hw_intf && vid_enc->hw_intf->ops.setup_misr)
+		vid_enc->hw_intf->ops.setup_misr(vid_enc->hw_intf,
+							enable, frame_count);
 }
 
-static void sde_encoder_phys_vid_collect_misr(struct sde_encoder_phys *phys_enc,
-			struct sde_misr_params *misr_map)
+static u32 sde_encoder_phys_vid_collect_misr(struct sde_encoder_phys *phys_enc)
 {
-	struct sde_encoder_phys_vid *vid_enc =
-			to_sde_encoder_phys_vid(phys_enc);
+	struct sde_encoder_phys_vid *vid_enc;
 
-	if (vid_enc && vid_enc->hw_intf && vid_enc->hw_intf->ops.collect_misr)
-		vid_enc->hw_intf->ops.collect_misr(vid_enc->hw_intf, misr_map);
+	if (!phys_enc)
+		return 0;
+	vid_enc = to_sde_encoder_phys_vid(phys_enc);
+
+	return vid_enc->hw_intf && vid_enc->hw_intf->ops.collect_misr ?
+		vid_enc->hw_intf->ops.collect_misr(vid_enc->hw_intf) : 0;
 }
 
 static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops)
@@ -919,13 +925,6 @@
 		goto fail;
 	}
 
-	phys_enc->misr_map = kzalloc(sizeof(struct sde_misr_params),
-						GFP_KERNEL);
-	if (!phys_enc->misr_map) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
 	SDE_DEBUG_VIDENC(vid_enc, "\n");
 
 	sde_encoder_phys_vid_init_ops(&phys_enc->ops);
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c
index 00b6c85..01d0d20 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.c
+++ b/drivers/gpu/drm/msm/sde/sde_formats.c
@@ -134,217 +134,217 @@
 static const struct sde_format sde_format_map[] = {
 	INTERLEAVED_RGB_FMT(ARGB8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
 		true, 4, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(ABGR8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		true, 4, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(XBGR8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		true, 4, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(RGBA8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
 		true, 4, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(BGRA8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
 		true, 4, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(BGRX8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
 		false, 4, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(XRGB8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
 		false, 4, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(RGBX8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
 		false, 4, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(RGB888,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
 		false, 3, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(BGR888,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
 		false, 3, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(RGB565,
 		0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
-		C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
 		false, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(BGR565,
 		0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
-		C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
 		false, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(ARGB1555,
 		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
-		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
 		true, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(ABGR1555,
 		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
-		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		true, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(RGBA5551,
 		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
-		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
 		true, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(BGRA5551,
 		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
-		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
 		true, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(XRGB1555,
 		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
-		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
 		false, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(XBGR1555,
 		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
-		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		false, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(RGBX5551,
 		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
-		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
 		false, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(BGRX5551,
 		COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
-		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
 		false, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(ARGB4444,
 		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
-		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
 		true, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(ABGR4444,
 		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
-		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		true, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(RGBA4444,
 		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
-		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
 		true, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(BGRA4444,
 		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
-		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
 		true, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(XRGB4444,
 		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
-		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
 		false, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(XBGR4444,
 		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
-		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		false, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(RGBX4444,
 		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
-		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
 		false, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(BGRX4444,
 		COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
-		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
 		false, 2, 0,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(BGRA1010102,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
 		true, 4, SDE_FORMAT_FLAG_DX,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(RGBA1010102,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
 		true, 4, SDE_FORMAT_FLAG_DX,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(ABGR2101010,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		true, 4, SDE_FORMAT_FLAG_DX,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(ARGB2101010,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
 		true, 4, SDE_FORMAT_FLAG_DX,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(XRGB2101010,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
 		false, 4, SDE_FORMAT_FLAG_DX,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(BGRX1010102,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
 		false, 4, SDE_FORMAT_FLAG_DX,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(XBGR2101010,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		false, 4, SDE_FORMAT_FLAG_DX,
 		SDE_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(RGBX1010102,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
-		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
 		false, 4, SDE_FORMAT_FLAG_DX,
 		SDE_FETCH_LINEAR, 1),
 
@@ -492,31 +492,31 @@
  * the data will be passed by user-space.
  */
 static const struct sde_format sde_format_map_ubwc[] = {
-	INTERLEAVED_RGB_FMT(RGB565,
+	INTERLEAVED_RGB_FMT(BGR565,
 		0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
 		false, 2, SDE_FORMAT_FLAG_COMPRESSED,
 		SDE_FETCH_UBWC, 2),
 
-	INTERLEAVED_RGB_FMT(RGBA8888,
+	INTERLEAVED_RGB_FMT(ABGR8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		true, 4, SDE_FORMAT_FLAG_COMPRESSED,
 		SDE_FETCH_UBWC, 2),
 
-	INTERLEAVED_RGB_FMT(RGBX8888,
+	INTERLEAVED_RGB_FMT(XBGR8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		false, 4, SDE_FORMAT_FLAG_COMPRESSED,
 		SDE_FETCH_UBWC, 2),
 
-	INTERLEAVED_RGB_FMT(RGBA1010102,
+	INTERLEAVED_RGB_FMT(ABGR2101010,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		true, 4, SDE_FORMAT_FLAG_DX | SDE_FORMAT_FLAG_COMPRESSED,
 		SDE_FETCH_UBWC, 2),
 
-	INTERLEAVED_RGB_FMT(RGBX1010102,
+	INTERLEAVED_RGB_FMT(XBGR2101010,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		true, 4, SDE_FORMAT_FLAG_DX | SDE_FORMAT_FLAG_COMPRESSED,
@@ -590,11 +590,11 @@
 static int _sde_format_get_media_color_ubwc(const struct sde_format *fmt)
 {
 	static const struct sde_media_color_map sde_media_ubwc_map[] = {
-		{DRM_FORMAT_RGBA8888, COLOR_FMT_RGBA8888_UBWC},
-		{DRM_FORMAT_RGBX8888, COLOR_FMT_RGBA8888_UBWC},
-		{DRM_FORMAT_RGBA1010102, COLOR_FMT_RGBA1010102_UBWC},
-		{DRM_FORMAT_RGBX1010102, COLOR_FMT_RGBA1010102_UBWC},
-		{DRM_FORMAT_RGB565, COLOR_FMT_RGB565_UBWC},
+		{DRM_FORMAT_ABGR8888, COLOR_FMT_RGBA8888_UBWC},
+		{DRM_FORMAT_XBGR8888, COLOR_FMT_RGBA8888_UBWC},
+		{DRM_FORMAT_ABGR2101010, COLOR_FMT_RGBA1010102_UBWC},
+		{DRM_FORMAT_XBGR2101010, COLOR_FMT_RGBA1010102_UBWC},
+		{DRM_FORMAT_BGR565, COLOR_FMT_RGB565_UBWC},
 	};
 	int color_fmt = -1;
 	int i;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h
index 354b892..cdb3450 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h
@@ -16,17 +16,17 @@
 	{DRM_FORMAT_ARGB8888, 0},
 	{DRM_FORMAT_ABGR8888, 0},
 	{DRM_FORMAT_RGBA8888, 0},
-	{DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
 	{DRM_FORMAT_BGRA8888, 0},
 	{DRM_FORMAT_XRGB8888, 0},
 	{DRM_FORMAT_RGBX8888, 0},
 	{DRM_FORMAT_BGRX8888, 0},
 	{DRM_FORMAT_XBGR8888, 0},
-	{DRM_FORMAT_RGBX8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
 	{DRM_FORMAT_RGB888, 0},
 	{DRM_FORMAT_BGR888, 0},
 	{DRM_FORMAT_RGB565, 0},
-	{DRM_FORMAT_RGB565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
 	{DRM_FORMAT_BGR565, 0},
 	{DRM_FORMAT_ARGB1555, 0},
 	{DRM_FORMAT_ABGR1555, 0},
@@ -52,16 +52,16 @@
 	{DRM_FORMAT_ABGR8888, 0},
 	{DRM_FORMAT_RGBA8888, 0},
 	{DRM_FORMAT_BGRX8888, 0},
-	{DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
 	{DRM_FORMAT_BGRA8888, 0},
 	{DRM_FORMAT_XRGB8888, 0},
 	{DRM_FORMAT_XBGR8888, 0},
 	{DRM_FORMAT_RGBX8888, 0},
-	{DRM_FORMAT_RGBX8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
 	{DRM_FORMAT_RGB888, 0},
 	{DRM_FORMAT_BGR888, 0},
 	{DRM_FORMAT_RGB565, 0},
-	{DRM_FORMAT_RGB565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
 	{DRM_FORMAT_BGR565, 0},
 	{DRM_FORMAT_ARGB1555, 0},
 	{DRM_FORMAT_ABGR1555, 0},
@@ -113,14 +113,14 @@
 
 static const struct sde_format_extended wb2_formats[] = {
 	{DRM_FORMAT_RGB565, 0},
-	{DRM_FORMAT_RGB565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
 	{DRM_FORMAT_RGB888, 0},
 	{DRM_FORMAT_ARGB8888, 0},
 	{DRM_FORMAT_RGBA8888, 0},
-	{DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
 	{DRM_FORMAT_XRGB8888, 0},
 	{DRM_FORMAT_RGBX8888, 0},
-	{DRM_FORMAT_RGBX8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+	{DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
 	{DRM_FORMAT_ARGB1555, 0},
 	{DRM_FORMAT_RGBA5551, 0},
 	{DRM_FORMAT_XRGB1555, 0},
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.c b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
index d96e49a..1f17378 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
@@ -67,12 +67,6 @@
 #define INTF_MISR_CTRL			0x180
 #define INTF_MISR_SIGNATURE		0x184
 
-#define MISR_FRAME_COUNT_MASK		0xFF
-#define MISR_CTRL_ENABLE		BIT(8)
-#define MISR_CTRL_STATUS		BIT(9)
-#define MISR_CTRL_STATUS_CLEAR		BIT(10)
-#define INTF_MISR_CTRL_FREE_RUN_MASK	BIT(31)
-
 static struct sde_intf_cfg *_intf_offset(enum sde_intf intf,
 		struct sde_mdss_cfg *m,
 		void __iomem *addr,
@@ -270,48 +264,28 @@
 	}
 }
 
-static void sde_hw_intf_set_misr(struct sde_hw_intf *intf,
-		struct sde_misr_params *misr_map)
+static void sde_hw_intf_setup_misr(struct sde_hw_intf *intf,
+						bool enable, u32 frame_count)
 {
 	struct sde_hw_blk_reg_map *c = &intf->hw;
 	u32 config = 0;
 
-	if (!misr_map)
-		return;
-
 	SDE_REG_WRITE(c, INTF_MISR_CTRL, MISR_CTRL_STATUS_CLEAR);
-	/* Clear data */
+	/* clear misr data */
 	wmb();
 
-	if (misr_map->enable) {
-		config = (MISR_FRAME_COUNT_MASK & 1) |
-			(MISR_CTRL_ENABLE);
+	if (enable)
+		config = (frame_count & MISR_FRAME_COUNT_MASK) |
+			MISR_CTRL_ENABLE | INTF_MISR_CTRL_FREE_RUN_MASK;
 
-		SDE_REG_WRITE(c, INTF_MISR_CTRL, config);
-	} else {
-		SDE_REG_WRITE(c, INTF_MISR_CTRL, 0);
-	}
+	SDE_REG_WRITE(c, INTF_MISR_CTRL, config);
 }
 
-static void sde_hw_intf_collect_misr(struct sde_hw_intf *intf,
-		struct sde_misr_params *misr_map)
+static u32 sde_hw_intf_collect_misr(struct sde_hw_intf *intf)
 {
 	struct sde_hw_blk_reg_map *c = &intf->hw;
 
-	if (!misr_map)
-		return;
-
-	if (misr_map->enable) {
-		if (misr_map->last_idx < misr_map->frame_count &&
-			misr_map->last_idx < SDE_CRC_BATCH_SIZE)
-			misr_map->crc_value[misr_map->last_idx] =
-				SDE_REG_READ(c, INTF_MISR_SIGNATURE);
-	}
-
-	misr_map->enable =
-		misr_map->enable & (misr_map->last_idx <= SDE_CRC_BATCH_SIZE);
-
-	misr_map->last_idx++;
+	return SDE_REG_READ(c, INTF_MISR_SIGNATURE);
 }
 
 static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
@@ -321,7 +295,7 @@
 	ops->setup_prg_fetch  = sde_hw_intf_setup_prg_fetch;
 	ops->get_status = sde_hw_intf_get_status;
 	ops->enable_timing = sde_hw_intf_enable_timing_engine;
-	ops->setup_misr = sde_hw_intf_set_misr;
+	ops->setup_misr = sde_hw_intf_setup_misr;
 	ops->collect_misr = sde_hw_intf_collect_misr;
 	if (cap & BIT(SDE_INTF_ROT_START))
 		ops->setup_rot_start = sde_hw_intf_setup_rot_start;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.h b/drivers/gpu/drm/msm/sde/sde_hw_intf.h
index c6428ca..d24e83a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.h
@@ -19,24 +19,6 @@
 
 struct sde_hw_intf;
 
-/* Batch size of frames for collecting MISR data */
-#define SDE_CRC_BATCH_SIZE 16
-
-/**
- * struct sde_misr_params : Interface for getting and setting MISR data
- *  Assumption is these functions will be called after clocks are enabled
- * @ enable : enables/disables MISR
- * @ frame_count : represents number of frames for which MISR is enabled
- * @ last_idx: number of frames for which MISR data is collected
- * @ crc_value: stores the collected MISR data
- */
-struct sde_misr_params {
-	bool enable;
-	u32 frame_count;
-	u32 last_idx;
-	u32 crc_value[SDE_CRC_BATCH_SIZE];
-};
-
 /* intf timing settings */
 struct intf_timing_params {
 	u32 width;		/* active width */
@@ -98,10 +80,9 @@
 			struct intf_status *status);
 
 	void (*setup_misr)(struct sde_hw_intf *intf,
-			struct sde_misr_params *misr_map);
+			bool enable, u32 frame_count);
 
-	void (*collect_misr)(struct sde_hw_intf *intf,
-			struct sde_misr_params *misr_map);
+	u32 (*collect_misr)(struct sde_hw_intf *intf);
 };
 
 struct sde_hw_intf {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
index 520c7b1..7780c5b 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
@@ -33,6 +33,9 @@
 #define LM_BLEND0_FG_ALPHA               0x04
 #define LM_BLEND0_BG_ALPHA               0x08
 
+#define LM_MISR_CTRL			0x310
+#define LM_MISR_SIGNATURE		0x314
+
 static struct sde_lm_cfg *_lm_offset(enum sde_lm mixer,
 		struct sde_mdss_cfg *m,
 		void __iomem *addr,
@@ -224,6 +227,30 @@
 	SDE_REG_WRITE(c, LM_BLEND0_OP + stage_off, val);
 }
 
+static void sde_hw_lm_setup_misr(struct sde_hw_mixer *ctx,
+				bool enable, u32 frame_count)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	u32 config = 0;
+
+	SDE_REG_WRITE(c, LM_MISR_CTRL, MISR_CTRL_STATUS_CLEAR);
+	/* clear misr data */
+	wmb();
+
+	if (enable)
+		config = (frame_count & MISR_FRAME_COUNT_MASK) |
+			MISR_CTRL_ENABLE | INTF_MISR_CTRL_FREE_RUN_MASK;
+
+	SDE_REG_WRITE(c, LM_MISR_CTRL, config);
+}
+
+static u32 sde_hw_lm_collect_misr(struct sde_hw_mixer *ctx)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+
+	return SDE_REG_READ(c, LM_MISR_SIGNATURE);
+}
+
 static void _setup_mixer_ops(struct sde_mdss_cfg *m,
 		struct sde_hw_lm_ops *ops,
 		unsigned long features)
@@ -236,6 +263,8 @@
 	ops->setup_alpha_out = sde_hw_lm_setup_color3;
 	ops->setup_border_color = sde_hw_lm_setup_border_color;
 	ops->setup_gc = sde_hw_lm_gc;
+	ops->setup_misr = sde_hw_lm_setup_misr;
+	ops->collect_misr = sde_hw_lm_collect_misr;
 
 	if (test_bit(SDE_DIM_LAYER, &features)) {
 		ops->setup_dim_layer = sde_hw_lm_setup_dim_layer;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.h b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
index 1ef36ac..45c0fc9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
@@ -79,6 +79,13 @@
 	 * @ctx: Pointer to layer mixer context
 	 */
 	void (*clear_dim_layer)(struct sde_hw_mixer *ctx);
+
+	/* setup_misr: enables/disables MISR in HW register */
+	void (*setup_misr)(struct sde_hw_mixer *ctx,
+			bool enable, u32 frame_count);
+
+	/* collect_misr: reads and stores MISR data from HW register */
+	u32 (*collect_misr)(struct sde_hw_mixer *ctx);
 };
 
 struct sde_hw_mixer {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_util.h b/drivers/gpu/drm/msm/sde/sde_hw_util.h
index 008b657..c1bfb79 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_util.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_util.h
@@ -47,6 +47,12 @@
 #define SDE_REG_WRITE(c, off, val) sde_reg_write(c, off, val, #off)
 #define SDE_REG_READ(c, off) sde_reg_read(c, off)
 
+#define MISR_FRAME_COUNT_MASK		0xFF
+#define MISR_CTRL_ENABLE		BIT(8)
+#define MISR_CTRL_STATUS		BIT(9)
+#define MISR_CTRL_STATUS_CLEAR		BIT(10)
+#define INTF_MISR_CTRL_FREE_RUN_MASK	BIT(31)
+
 void *sde_hw_util_get_dir(void);
 
 void sde_hw_csc_setup(struct sde_hw_blk_reg_map  *c,
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index ef2c80e..b6a9f42 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -81,7 +81,8 @@
 
 static int sde_kms_hw_init(struct msm_kms *kms);
 static int _sde_kms_mmu_destroy(struct sde_kms *sde_kms);
-
+static int _sde_kms_register_events(struct msm_kms *kms,
+		struct drm_mode_object *obj, u32 event, bool en);
 bool sde_is_custom_client(void)
 {
 	return sdecustom;
@@ -1231,6 +1232,7 @@
 	.get_format      = sde_get_msm_format,
 	.round_pixclk    = sde_kms_round_pixclk,
 	.destroy         = sde_kms_destroy,
+	.register_events = _sde_kms_register_events,
 };
 
 /* the caller api needs to turn on clock before calling it */
@@ -1596,3 +1598,32 @@
 
 	return &sde_kms->base;
 }
+
+static int _sde_kms_register_events(struct msm_kms *kms,
+		struct drm_mode_object *obj, u32 event, bool en)
+{
+	int ret = 0;
+	struct drm_crtc *crtc = NULL;
+	struct drm_connector *conn = NULL;
+	struct sde_kms *sde_kms = NULL;
+
+	if (!kms || !obj) {
+		SDE_ERROR("invalid argument kms %pK obj %pK\n", kms, obj);
+		return -EINVAL;
+	}
+
+	sde_kms = to_sde_kms(kms);
+	switch (obj->type) {
+	case DRM_MODE_OBJECT_CRTC:
+		crtc = obj_to_crtc(obj);
+		ret = sde_crtc_register_custom_event(sde_kms, crtc, event, en);
+		break;
+	case DRM_MODE_OBJECT_CONNECTOR:
+		conn = obj_to_connector(obj);
+		ret = sde_connector_register_custom_event(sde_kms, conn, event,
+				en);
+		break;
+	}
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 2eb947d..0be17e4 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -769,8 +769,6 @@
 				psde->pipe_cfg.horz_decimation);
 		scale_cfg->src_height[i] = DECIMATED_DIMENSION(src_h,
 				psde->pipe_cfg.vert_decimation);
-		if (SDE_FORMAT_IS_YUV(fmt))
-			scale_cfg->src_width[i] &= ~0x1;
 		if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2) {
 			scale_cfg->src_width[i] /= chroma_subsmpl_h;
 			scale_cfg->src_height[i] /= chroma_subsmpl_v;
@@ -1201,6 +1199,7 @@
 		psde->pipe_cfg.src_rect.y = 0;
 		psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
 		psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
+		_sde_plane_setup_scaler(psde, fmt, 0);
 
 		if (psde->pipe_hw->ops.setup_format)
 			psde->pipe_hw->ops.setup_format(psde->pipe_hw,
@@ -1212,7 +1211,6 @@
 					&psde->pipe_cfg,
 					pstate->multirect_index);
 
-		_sde_plane_setup_scaler(psde, fmt, 0);
 		if (psde->pipe_hw->ops.setup_pe)
 			psde->pipe_hw->ops.setup_pe(psde->pipe_hw,
 					&psde->pixel_ext);
@@ -1500,6 +1498,8 @@
 	rot_cmd->secure = state->fb->flags & DRM_MODE_FB_SECURE ? true : false;
 	rot_cmd->prefill_bw = sde_crtc_get_property(sde_cstate,
 			CRTC_PROP_ROT_PREFILL_BW);
+	rot_cmd->clkrate = sde_crtc_get_property(sde_cstate,
+			CRTC_PROP_ROT_CLK);
 	rot_cmd->dst_writeback = psde->sbuf_writeback;
 
 	if (sde_crtc_get_intf_mode(state->crtc) == INTF_MODE_VIDEO)
@@ -2294,6 +2294,8 @@
 		psde->pipe_cfg.src_rect = src;
 		psde->pipe_cfg.dst_rect = dst;
 
+		_sde_plane_setup_scaler(psde, fmt, pstate);
+
 		/* check for color fill */
 		psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
 				PLANE_PROP_COLOR_FILL);
@@ -2306,7 +2308,6 @@
 					pstate->multirect_index);
 		}
 
-		_sde_plane_setup_scaler(psde, fmt, pstate);
 		if (psde->pipe_hw->ops.setup_pe)
 			psde->pipe_hw->ops.setup_pe(psde->pipe_hw,
 					&psde->pixel_ext);
diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c
index 697b7f7..9977d10 100644
--- a/drivers/gpu/drm/msm/sde_dbg.c
+++ b/drivers/gpu/drm/msm/sde_dbg.c
@@ -2436,7 +2436,7 @@
 	struct sde_dbg_reg_base **blk_arr;
 	u32 blk_len;
 
-	if (!sde_evtlog_is_enabled(sde_dbg_base.evtlog, SDE_EVTLOG_DEFAULT))
+	if (!sde_evtlog_is_enabled(sde_dbg_base.evtlog, SDE_EVTLOG_ALWAYS))
 		return;
 
 	if (queue_work && work_pending(&sde_dbg_base.dump_work))
@@ -2558,6 +2558,82 @@
 	.write = sde_evtlog_dump_write,
 };
 
+/*
+ * sde_evtlog_filter_show - read callback for evtlog filter
+ * @s: pointer to seq_file object
+ * @data: pointer to private data
+ */
+static int sde_evtlog_filter_show(struct seq_file *s, void *data)
+{
+	struct sde_dbg_evtlog *evtlog;
+	char buffer[64];
+	int i;
+
+	if (!s || !s->private)
+		return -EINVAL;
+
+	evtlog = s->private;
+
+	for (i = 0; !sde_evtlog_get_filter(
+				evtlog, i, buffer, ARRAY_SIZE(buffer)); ++i)
+		seq_printf(s, "*%s*\n", buffer);
+	return 0;
+}
+
+/*
+ * sde_evtlog_filter_open - debugfs open handler for evtlog filter
+ * @inode: debugfs inode
+ * @file: file handle
+ * Returns: zero on success
+ */
+static int sde_evtlog_filter_open(struct inode *inode, struct file *file)
+{
+	if (!file)
+		return -EINVAL;
+
+	return single_open(file, sde_evtlog_filter_show, inode->i_private);
+}
+
+/*
+ * sde_evtlog_filter_write - write callback for evtlog filter
+ * @file: pointer to file structure
+ * @user_buf: pointer to incoming user data
+ * @count: size of incoming user buffer
+ * @ppos: pointer to file offset
+ */
+static ssize_t sde_evtlog_filter_write(struct file *file,
+	const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char *tmp_filter = NULL;
+	ssize_t rc = 0;
+
+	if (count > 0) {
+		/* copy user provided string and null terminate it */
+		tmp_filter = kzalloc(count + 1, GFP_KERNEL);
+		if (!tmp_filter)
+			rc = -ENOMEM;
+		else if (copy_from_user(tmp_filter, user_buf, count))
+			rc = -EFAULT;
+	}
+
+	/* update actual filter configuration on success */
+	if (!rc) {
+		sde_evtlog_set_filter(sde_dbg_base.evtlog, tmp_filter);
+		rc = count;
+	}
+	kfree(tmp_filter);
+
+	return rc;
+}
+
+static const struct file_operations sde_evtlog_filter_fops = {
+	.open =		sde_evtlog_filter_open,
+	.write =	sde_evtlog_filter_write,
+	.read =		seq_read,
+	.llseek =	seq_lseek,
+	.release =	seq_release
+};
+
 /**
  * sde_dbg_reg_base_release - release allocated reg dump file private data
  * @inode: debugfs inode
@@ -2799,12 +2875,14 @@
 			&sde_evtlog_fops);
 	debugfs_create_u32("enable", 0644, sde_dbg_base.root,
 			&(sde_dbg_base.evtlog->enable));
+	debugfs_create_file("filter", 0644, sde_dbg_base.root,
+			sde_dbg_base.evtlog,
+			&sde_evtlog_filter_fops);
 	debugfs_create_u32("panic", 0644, sde_dbg_base.root,
 			&sde_dbg_base.panic_on_err);
 	debugfs_create_u32("reg_dump", 0644, sde_dbg_base.root,
 			&sde_dbg_base.enable_reg_dump);
 
-
 	if (dbg->dbgbus_sde.entries) {
 		dbg->dbgbus_sde.cmn.name = DBGBUS_NAME_SDE;
 		snprintf(debug_name, sizeof(debug_name), "%s_dbgbus",
diff --git a/drivers/gpu/drm/msm/sde_dbg.h b/drivers/gpu/drm/msm/sde_dbg.h
index 7a940f4..4344eb8 100644
--- a/drivers/gpu/drm/msm/sde_dbg.h
+++ b/drivers/gpu/drm/msm/sde_dbg.h
@@ -24,9 +24,10 @@
 #define SDE_DBG_DUMP_DATA_LIMITER (NULL)
 
 enum sde_dbg_evtlog_flag {
-	SDE_EVTLOG_DEFAULT = BIT(0),
+	SDE_EVTLOG_CRITICAL = BIT(0),
 	SDE_EVTLOG_IRQ = BIT(1),
-	SDE_EVTLOG_ALL = BIT(7)
+	SDE_EVTLOG_VERBOSE = BIT(2),
+	SDE_EVTLOG_ALWAYS = -1
 };
 
 enum sde_dbg_dump_flag {
@@ -35,7 +36,7 @@
 };
 
 #ifdef CONFIG_DRM_SDE_EVTLOG_DEBUG
-#define SDE_EVTLOG_DEFAULT_ENABLE 1
+#define SDE_EVTLOG_DEFAULT_ENABLE SDE_EVTLOG_CRITICAL
 #else
 #define SDE_EVTLOG_DEFAULT_ENABLE 0
 #endif
@@ -72,6 +73,9 @@
 	int pid;
 };
 
+/**
+ * @filter_list: Linked list of currently active filter strings
+ */
 struct sde_dbg_evtlog {
 	struct sde_dbg_evtlog_log logs[SDE_EVTLOG_ENTRY];
 	u32 first;
@@ -80,6 +84,7 @@
 	u32 next;
 	u32 enable;
 	spinlock_t spin_lock;
+	struct list_head filter_list;
 };
 
 extern struct sde_dbg_evtlog *sde_dbg_base_evtlog;
@@ -89,7 +94,15 @@
  * ... - variable arguments
  */
 #define SDE_EVT32(...) sde_evtlog_log(sde_dbg_base_evtlog, __func__, \
-		__LINE__, SDE_EVTLOG_DEFAULT, ##__VA_ARGS__, \
+		__LINE__, SDE_EVTLOG_ALWAYS, ##__VA_ARGS__, \
+		SDE_EVTLOG_DATA_LIMITER)
+
+/**
+ * SDE_EVT32_VERBOSE - Write a list of 32bit values for verbose event logging
+ * ... - variable arguments
+ */
+#define SDE_EVT32_VERBOSE(...) sde_evtlog_log(sde_dbg_base_evtlog, __func__, \
+		__LINE__, SDE_EVTLOG_VERBOSE, ##__VA_ARGS__, \
 		SDE_EVTLOG_DATA_LIMITER)
 
 /**
@@ -244,6 +257,24 @@
 		const char *range_name, u32 offset_start, u32 offset_end,
 		uint32_t xin_id);
 
+/**
+ * sde_evtlog_set_filter - update evtlog filtering
+ * @evtlog:	pointer to evtlog
+ * @filter:     pointer to optional function name filter, set to NULL to disable
+ */
+void sde_evtlog_set_filter(struct sde_dbg_evtlog *evtlog, char *filter);
+
+/**
+ * sde_evtlog_get_filter - query configured evtlog filters
+ * @evtlog:	pointer to evtlog
+ * @index:	filter index to retrieve
+ * @buf:	pointer to output filter buffer
+ * @bufsz:	size of output filter buffer
+ * Returns:	zero if a filter string was returned
+ */
+int sde_evtlog_get_filter(struct sde_dbg_evtlog *evtlog, int index,
+		char *buf, size_t bufsz);
+
 #else
 static inline struct sde_dbg_evtlog *sde_evtlog_init(void)
 {
@@ -275,7 +306,7 @@
 	return 0;
 }
 
-void sde_dbg_init_dbg_buses(u32 hwversion)
+static inline void sde_dbg_init_dbg_buses(u32 hwversion)
 {
 }
 
@@ -285,7 +316,7 @@
 	return 0;
 }
 
-int sde_dbg_debugfs_register(struct dentry *debugfs_root)
+static inline int sde_dbg_debugfs_register(struct dentry *debugfs_root)
 {
 	return 0;
 }
@@ -310,6 +341,17 @@
 {
 }
 
+static inline void sde_evtlog_set_filter(
+		struct sde_dbg_evtlog *evtlog, char *filter)
+{
+}
+
+static inline int sde_evtlog_get_filter(struct sde_dbg_evtlog *evtlog,
+		int index, char *buf, size_t bufsz)
+{
+	return -EINVAL;
+}
+
 #endif /* defined(CONFIG_DEBUG_FS) */
 
 
diff --git a/drivers/gpu/drm/msm/sde_dbg_evtlog.c b/drivers/gpu/drm/msm/sde_dbg_evtlog.c
index 759bdab..699396f 100644
--- a/drivers/gpu/drm/msm/sde_dbg_evtlog.c
+++ b/drivers/gpu/drm/msm/sde_dbg_evtlog.c
@@ -23,13 +23,40 @@
 #include "sde_dbg.h"
 #include "sde_trace.h"
 
+#define SDE_EVTLOG_FILTER_STRSIZE	64
+
+struct sde_evtlog_filter {
+	struct list_head list;
+	char filter[SDE_EVTLOG_FILTER_STRSIZE];
+};
+
+static bool _sde_evtlog_is_filtered_no_lock(
+		struct sde_dbg_evtlog *evtlog, const char *str)
+{
+	struct sde_evtlog_filter *filter_node;
+	bool rc;
+
+	if (!str)
+		return true;
+
+	/*
+	 * Filter the incoming string IFF the list is not empty AND
+	 * a matching entry is not in the list.
+	 */
+	rc = !list_empty(&evtlog->filter_list);
+	list_for_each_entry(filter_node, &evtlog->filter_list, list)
+		if (strnstr(str, filter_node->filter,
+					SDE_EVTLOG_FILTER_STRSIZE - 1)) {
+			rc = false;
+			break;
+		}
+
+	return rc;
+}
+
 bool sde_evtlog_is_enabled(struct sde_dbg_evtlog *evtlog, u32 flag)
 {
-	if (!evtlog)
-		return false;
-
-	return (flag & evtlog->enable) ||
-		(flag == SDE_EVTLOG_ALL && evtlog->enable);
+	return evtlog && (evtlog->enable & flag);
 }
 
 void sde_evtlog_log(struct sde_dbg_evtlog *evtlog, const char *name, int line,
@@ -47,6 +74,10 @@
 		return;
 
 	spin_lock_irqsave(&evtlog->spin_lock, flags);
+
+	if (_sde_evtlog_is_filtered_no_lock(evtlog, name))
+		goto exit;
+
 	log = &evtlog->logs[evtlog->curr];
 	log->time = ktime_to_us(ktime_get());
 	log->name = name;
@@ -70,27 +101,20 @@
 
 	trace_sde_evtlog(name, line, i > 0 ? log->data[0] : 0,
 			i > 1 ? log->data[1] : 0);
-
+exit:
 	spin_unlock_irqrestore(&evtlog->spin_lock, flags);
 }
 
 /* always dump the last entries which are not dumped yet */
 static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog)
 {
-	bool need_dump = true;
-	unsigned long flags;
-
 	if (!evtlog)
 		return false;
 
-	spin_lock_irqsave(&evtlog->spin_lock, flags);
-
 	evtlog->first = evtlog->next;
 
-	if (evtlog->last == evtlog->first) {
-		need_dump = false;
-		goto dump_exit;
-	}
+	if (evtlog->last == evtlog->first)
+		return false;
 
 	if (evtlog->last < evtlog->first) {
 		evtlog->first %= SDE_EVTLOG_ENTRY;
@@ -99,16 +123,14 @@
 	}
 
 	if ((evtlog->last - evtlog->first) > SDE_EVTLOG_PRINT_ENTRY) {
-		pr_warn("evtlog buffer overflow before dump: %d\n",
-			evtlog->last - evtlog->first);
+		pr_info("evtlog skipping %d entries, last=%d\n",
+			evtlog->last - evtlog->first - SDE_EVTLOG_PRINT_ENTRY,
+			evtlog->last - 1);
 		evtlog->first = evtlog->last - SDE_EVTLOG_PRINT_ENTRY;
 	}
 	evtlog->next = evtlog->first + 1;
 
-dump_exit:
-	spin_unlock_irqrestore(&evtlog->spin_lock, flags);
-
-	return need_dump;
+	return true;
 }
 
 ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog,
@@ -122,16 +144,15 @@
 	if (!evtlog || !evtlog_buf)
 		return 0;
 
+	spin_lock_irqsave(&evtlog->spin_lock, flags);
+
 	/* update markers, exit if nothing to print */
 	if (!_sde_evtlog_dump_calc_range(evtlog))
-		return 0;
-
-	spin_lock_irqsave(&evtlog->spin_lock, flags);
+		goto exit;
 
 	log = &evtlog->logs[evtlog->first % SDE_EVTLOG_ENTRY];
 
-	prev_log = &evtlog->logs[(evtlog->first - 1) %
-		SDE_EVTLOG_ENTRY];
+	prev_log = &evtlog->logs[(evtlog->first - 1) % SDE_EVTLOG_ENTRY];
 
 	off = snprintf((evtlog_buf + off), (evtlog_buf_size - off), "%s:%-4d",
 		log->name, log->line);
@@ -150,7 +171,7 @@
 			"%x ", log->data[i]);
 
 	off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), "\n");
-
+exit:
 	spin_unlock_irqrestore(&evtlog->spin_lock, flags);
 
 	return off;
@@ -178,10 +199,109 @@
 	spin_lock_init(&evtlog->spin_lock);
 	evtlog->enable = SDE_EVTLOG_DEFAULT_ENABLE;
 
+	INIT_LIST_HEAD(&evtlog->filter_list);
+
 	return evtlog;
 }
 
+int sde_evtlog_get_filter(struct sde_dbg_evtlog *evtlog, int index,
+		char *buf, size_t bufsz)
+{
+	struct sde_evtlog_filter *filter_node;
+	unsigned long flags;
+	int rc = -EFAULT;
+
+	if (!evtlog || !buf || !bufsz || index < 0)
+		return -EINVAL;
+
+	spin_lock_irqsave(&evtlog->spin_lock, flags);
+	list_for_each_entry(filter_node, &evtlog->filter_list, list) {
+		if (index--)
+			continue;
+
+		/* don't care about return value */
+		(void)strlcpy(buf, filter_node->filter, bufsz);
+		rc = 0;
+		break;
+	}
+	spin_unlock_irqrestore(&evtlog->spin_lock, flags);
+
+	return rc;
+}
+
+void sde_evtlog_set_filter(struct sde_dbg_evtlog *evtlog, char *filter)
+{
+	struct sde_evtlog_filter *filter_node, *tmp;
+	struct list_head free_list;
+	unsigned long flags;
+	char *flt;
+
+	if (!evtlog)
+		return;
+
+	INIT_LIST_HEAD(&free_list);
+
+	/*
+	 * Clear active filter list and cache filter_nodes locally
+	 * to reduce memory fragmentation.
+	 */
+	spin_lock_irqsave(&evtlog->spin_lock, flags);
+	list_for_each_entry_safe(filter_node, tmp, &evtlog->filter_list, list) {
+		list_del_init(&filter_node->list);
+		list_add_tail(&filter_node->list, &free_list);
+	}
+	spin_unlock_irqrestore(&evtlog->spin_lock, flags);
+
+	/*
+	 * Parse incoming filter request string and build up a new
+	 * filter list. New filter nodes are taken from the local
+	 * free list, if available, and allocated from the system
+	 * heap once the free list is empty.
+	 */
+	while (filter && (flt = strsep(&filter, "|\r\n\t ")) != NULL) {
+		if (!*flt)
+			continue;
+
+		if (list_empty(&free_list)) {
+			filter_node = kzalloc(sizeof(*filter_node), GFP_KERNEL);
+			if (!filter_node)
+				break;
+
+			INIT_LIST_HEAD(&filter_node->list);
+		} else {
+			filter_node = list_first_entry(&free_list,
+					struct sde_evtlog_filter, list);
+			list_del_init(&filter_node->list);
+		}
+
+		/* don't care if copy truncated */
+		(void)strlcpy(filter_node->filter, flt,
+				SDE_EVTLOG_FILTER_STRSIZE);
+
+		spin_lock_irqsave(&evtlog->spin_lock, flags);
+		list_add_tail(&filter_node->list, &evtlog->filter_list);
+		spin_unlock_irqrestore(&evtlog->spin_lock, flags);
+	}
+
+	/*
+	 * Free any unused filter_nodes back to the system.
+	 */
+	list_for_each_entry_safe(filter_node, tmp, &free_list, list) {
+		list_del(&filter_node->list);
+		kfree(filter_node);
+	}
+}
+
 void sde_evtlog_destroy(struct sde_dbg_evtlog *evtlog)
 {
+	struct sde_evtlog_filter *filter_node, *tmp;
+
+	if (!evtlog)
+		return;
+
+	list_for_each_entry_safe(filter_node, tmp, &evtlog->filter_list, list) {
+		list_del(&filter_node->list);
+		kfree(filter_node);
+	}
 	kfree(evtlog);
 }
diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c
index 2464551..a9a7d4f 100644
--- a/drivers/gpu/drm/msm/sde_rsc.c
+++ b/drivers/gpu/drm/msm/sde_rsc.c
@@ -27,7 +27,7 @@
 #include <soc/qcom/rpmh.h>
 #include <drm/drmP.h>
 #include <drm/drm_irq.h>
-#include "sde_rsc.h"
+#include "sde_rsc_priv.h"
 
 /* this time is ~0.02ms */
 #define RSC_BACKOFF_TIME_NS		 20000
@@ -105,6 +105,7 @@
 
 	return client;
 }
+EXPORT_SYMBOL(sde_rsc_client_create);
 
 /**
  * sde_rsc_client_destroy() - Destroy the sde rsc client.
@@ -141,6 +142,7 @@
 end:
 	return;
 }
+EXPORT_SYMBOL(sde_rsc_client_destroy);
 
 struct sde_rsc_event *sde_rsc_register_event(int rsc_index, uint32_t event_type,
 		void (*cb_func)(uint32_t event_type, void *usr), void *usr)
@@ -178,6 +180,7 @@
 
 	return evt;
 }
+EXPORT_SYMBOL(sde_rsc_register_event);
 
 void sde_rsc_unregister_event(struct sde_rsc_event *event)
 {
@@ -204,6 +207,7 @@
 end:
 	return;
 }
+EXPORT_SYMBOL(sde_rsc_unregister_event);
 
 static int sde_rsc_clk_enable(struct sde_power_handle *phandle,
 	struct sde_power_client *pclient, bool enable)
@@ -583,6 +587,7 @@
 	mutex_unlock(&rsc->client_lock);
 	return rc;
 }
+EXPORT_SYMBOL(sde_rsc_client_state_update);
 
 /**
  * sde_rsc_client_vote() - ab/ib vote from rsc client
@@ -661,6 +666,7 @@
 	mutex_unlock(&rsc->client_lock);
 	return rc;
 }
+EXPORT_SYMBOL(sde_rsc_client_vote);
 
 static int _sde_debugfs_status_show(struct seq_file *s, void *data)
 {
diff --git a/drivers/gpu/drm/msm/sde_rsc.h b/drivers/gpu/drm/msm/sde_rsc.h
deleted file mode 100644
index 2775d21..0000000
--- a/drivers/gpu/drm/msm/sde_rsc.h
+++ /dev/null
@@ -1,368 +0,0 @@
-/* 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef _SDE_RSC_H_
-#define _SDE_RSC_H_
-
-#include <linux/kernel.h>
-#include <linux/sde_io_util.h>
-
-#include <soc/qcom/tcs.h>
-#include "sde_power_handle.h"
-
-#define SDE_RSC_COMPATIBLE "disp_rscc"
-
-#define MAX_RSC_CLIENT_NAME_LEN 128
-
-/* primary display rsc index */
-#define SDE_RSC_INDEX		0
-
-/* rsc index max count */
-#define MAX_RSC_COUNT		5
-
-struct sde_rsc_priv;
-
-/**
- * event will be triggered before sde core power collapse,
- * mdss gdsc is still on
- */
-#define SDE_RSC_EVENT_PRE_CORE_PC 0x1
-/**
- * event will be triggered after sde core collapse complete,
- * mdss gdsc is off now
- */
-#define SDE_RSC_EVENT_POST_CORE_PC 0x2
-/**
- * event will be triggered before restoring the sde core from power collapse,
- * mdss gdsc is still off
- */
-#define SDE_RSC_EVENT_PRE_CORE_RESTORE 0x4
-/**
- * event will be triggered after restoring the sde core from power collapse,
- * mdss gdsc is on now
- */
-#define SDE_RSC_EVENT_POST_CORE_RESTORE 0x8
-/**
- * event attached with solver state enabled
- * all clients in clk_state or cmd_state
- */
-#define SDE_RSC_EVENT_SOLVER_ENABLED 0x10
-/**
- * event attached with solver state disabled
- * one of the client requested for vid state
- */
-#define SDE_RSC_EVENT_SOLVER_DISABLED 0x20
-
-/**
- * rsc_mode_req: sde rsc mode request information
- * MODE_READ: read vsync status
- * MODE0_UPDATE: mode0 status , this should be 0x0
- * MODE1_UPDATE: mode1 status , this should be 0x1
- * MODE2_UPDATE: mode2 status , this should be 0x2
- */
-enum rsc_mode_req {
-	MODE_READ,
-	MODE0_UPDATE = 0x1,
-	MODE1_UPDATE = 0x2,
-	MODE2_UPDATE = 0x3,
-};
-
-/**
- * rsc_vsync_req: sde rsc vsync request information
- * VSYNC_READ: read vsync status
- * VSYNC_ENABLE: enable rsc wrapper vsync status
- * VSYNC_DISABLE: disable rsc wrapper vsync status
- */
-enum rsc_vsync_req {
-	VSYNC_READ,
-	VSYNC_ENABLE,
-	VSYNC_DISABLE,
-};
-
-/**
- * sde_rsc_state: sde rsc state information
- * SDE_RSC_IDLE_STATE: A client requests for idle state when there is no
- *                    pixel or cmd transfer expected. An idle vote from
- *                    all clients lead to power collapse state.
- * SDE_RSC_CLK_STATE:  A client requests for clk state when it wants to
- *                    only avoid mode-2 entry/exit. For ex: V4L2 driver,
- *                    sde power handle, etc.
- * SDE_RSC_CMD_STATE:  A client requests for cmd state when it wants to
- *                    enable the solver mode.
- * SDE_RSC_VID_STATE:  A client requests for vid state it wants to avoid
- *                    solver enable because client is fetching data from
- *                    continuously.
- */
-enum sde_rsc_state {
-	SDE_RSC_IDLE_STATE,
-	SDE_RSC_CLK_STATE,
-	SDE_RSC_CMD_STATE,
-	SDE_RSC_VID_STATE,
-};
-
-/**
- * struct sde_rsc_client: stores the rsc client for sde driver
- * @name:	name of the client
- * @current_state:   current client state
- * @crtc_id:		crtc_id associated with this rsc client.
- * @rsc_index:	rsc index of a client - only index "0" valid.
- * @list:	list to attach client master list
- */
-struct sde_rsc_client {
-	char name[MAX_RSC_CLIENT_NAME_LEN];
-	short current_state;
-	int crtc_id;
-	u32 rsc_index;
-	struct list_head list;
-};
-
-/**
- * struct sde_rsc_event: local event registration entry structure
- * @cb_func:	Pointer to desired callback function
- * @usr:	User pointer to pass to callback on event trigger
- * @rsc_index:	rsc index of a client - only index "0" valid.
- * @event_type:	refer comments in event_register
- * @list:	list to attach event master list
- */
-struct sde_rsc_event {
-	void (*cb_func)(uint32_t event_type, void *usr);
-	void *usr;
-	u32 rsc_index;
-	uint32_t event_type;
-	struct list_head list;
-};
-
-/**
- * struct sde_rsc_hw_ops - sde resource state coordinator hardware ops
- * @init:			Initialize the sequencer, solver, qtimer,
-				etc. hardware blocks on RSC.
- * @tcs_wait:			Waits for TCS block OK to allow sending a
- *				TCS command.
- * @hw_vsync:			Enables the vsync on RSC block.
- * @tcs_use_ok:			set TCS set to high to allow RSC to use it.
- * @mode2_entry:		Request to entry mode2 when all clients are
- *                              requesting power collapse.
- * @mode2_exit:			Request to exit mode2 when one of the client
- *                              is requesting against the power collapse
- * @is_amc_mode:		Check current amc mode status
- * @state_update:		Enable/override the solver based on rsc state
- *                              status (command/video)
- * @mode_show:			shows current mode status, mode0/1/2
- * @debug_show:			Show current debug status.
- */
-
-struct sde_rsc_hw_ops {
-	int (*init)(struct sde_rsc_priv *rsc);
-	int (*tcs_wait)(struct sde_rsc_priv *rsc);
-	int (*hw_vsync)(struct sde_rsc_priv *rsc, enum rsc_vsync_req request,
-		char *buffer, int buffer_size, u32 mode);
-	int (*tcs_use_ok)(struct sde_rsc_priv *rsc);
-	int (*mode2_entry)(struct sde_rsc_priv *rsc);
-	int (*mode2_exit)(struct sde_rsc_priv *rsc);
-	bool (*is_amc_mode)(struct sde_rsc_priv *rsc);
-	int (*state_update)(struct sde_rsc_priv *rsc, enum sde_rsc_state state);
-	int (*debug_show)(struct seq_file *s, struct sde_rsc_priv *rsc);
-	int (*mode_ctrl)(struct sde_rsc_priv *rsc, enum rsc_mode_req request,
-		char *buffer, int buffer_size, bool mode);
-};
-
-/**
- * struct sde_rsc_cmd_config: provides panel configuration to rsc
- * when client is command mode. It is not required to set it during
- * video mode.
- *
- * @fps:	panel te interval
- * @vtotal:	current vertical total (height + vbp + vfp)
- * @jitter:	panel can set the jitter to wake up rsc/solver early
- *              This value causes mdp core to exit certain mode
- *              early. Default is 10% jitter
- * @prefill_lines:	max prefill lines based on panel
- */
-struct sde_rsc_cmd_config {
-	u32 fps;
-	u32 vtotal;
-	u32 jitter;
-	u32 prefill_lines;
-};
-
-/**
- * struct sde_rsc_timer_config: this is internal configuration between
- * rsc and rsc_hw API.
- *
- * @static_wakeup_time_ns:	wrapper backoff time in nano seconds
- * @rsc_backoff_time_ns:	rsc backoff time in nano seconds
- * @pdc_backoff_time_ns:	pdc backoff time in nano seconds
- * @rsc_mode_threshold_time_ns:	rsc mode threshold time in nano seconds
- * @rsc_time_slot_0_ns:		mode-0 time slot threshold in nano seconds
- * @rsc_time_slot_1_ns:		mode-1 time slot threshold in nano seconds
- * @rsc_time_slot_2_ns:		mode-2 time slot threshold in nano seconds
- */
-struct sde_rsc_timer_config {
-	u32 static_wakeup_time_ns;
-
-	u32 rsc_backoff_time_ns;
-	u32 pdc_backoff_time_ns;
-	u32 rsc_mode_threshold_time_ns;
-	u32 rsc_time_slot_0_ns;
-	u32 rsc_time_slot_1_ns;
-	u32 rsc_time_slot_2_ns;
-};
-
-/**
- * struct sde_rsc_priv: sde resource state coordinator(rsc) private handle
- * @version:		rsc sequence version
- * @phandle:		module power handle for clocks
- * @pclient:		module power client of phandle
- * @fs:			"MDSS GDSC" handle
- *
- * @drv_io:		sde drv io data mapping
- * @wrapper_io:		wrapper io data mapping
- *
- * @client_list:	current rsc client list handle
- * @event_list:		current rsc event list handle
- * @client_lock:	current rsc client synchronization lock
- *
- * timer_config:	current rsc timer configuration
- * cmd_config:		current panel config
- * current_state:	current rsc state (video/command), solver
- *                      override/enabled.
- * debug_mode:		enables the logging for each register read/write
- * debugfs_root:	debugfs file system root node
- *
- * hw_ops:		sde rsc hardware operations
- * power_collapse:	if all clients are in IDLE state then it enters in
- *			mode2 state and enable the power collapse state
- * power_collapse_block:By default, rsc move to mode-2 if all clients are in
- *			invalid state. It can be blocked by this boolean entry.
- * primary_client:	A client which is allowed to make command state request
- *			and ab/ib vote on display rsc
- * master_drm:		Primary client waits for vsync on this drm object based
- *			on crtc id
- */
-struct sde_rsc_priv {
-	u32 version;
-	struct sde_power_handle phandle;
-	struct sde_power_client *pclient;
-	struct regulator *fs;
-
-	struct dss_io_data drv_io;
-	struct dss_io_data wrapper_io;
-
-	struct list_head client_list;
-	struct list_head event_list;
-	struct mutex client_lock;
-
-	struct sde_rsc_timer_config timer_config;
-	struct sde_rsc_cmd_config cmd_config;
-	u32	current_state;
-
-	u32 debug_mode;
-	struct dentry *debugfs_root;
-
-	struct sde_rsc_hw_ops hw_ops;
-	bool power_collapse;
-	bool power_collapse_block;
-	struct sde_rsc_client *primary_client;
-
-	struct drm_device *master_drm;
-};
-
-/**
- * sde_rsc_client_create() - create the client for sde rsc.
- * Different displays like DSI, HDMI, DP, WB, etc should call this
- * api to register their vote for rpmh. They still need to vote for
- * power handle to get the clocks.
-
- * @rsc_index:   A client will be created on this RSC. As of now only
- *               SDE_RSC_INDEX is valid rsc index.
- * @name:	 Caller needs to provide some valid string to identify
- *               the client. "primary", "dp", "hdmi" are suggested name.
- * @is_primary:	 Caller needs to provide information if client is primary
- *               or not. Primary client votes will be redirected to
- *               display rsc.
- * @config:	 fps, vtotal, porches, etc configuration for command mode
- *               panel
- *
- * Return: client node pointer.
- */
-struct sde_rsc_client *sde_rsc_client_create(u32 rsc_index, char *name,
-		bool is_primary_display);
-
-/**
- * sde_rsc_client_destroy() - Destroy the sde rsc client.
- *
- * @client:	 Client pointer provided by sde_rsc_client_create().
- *
- * Return: none
- */
-void sde_rsc_client_destroy(struct sde_rsc_client *client);
-
-/**
- * sde_rsc_client_state_update() - rsc client state update
- * Video mode, cmd mode and clk state are supported as modes. A client need to
- * set this property during panel time. A switching client can set the
- * property to change the state
- *
- * @client:	 Client pointer provided by sde_rsc_client_create().
- * @state:	 Client state - video/cmd
- * @config:	 fps, vtotal, porches, etc configuration for command mode
- *               panel
- * @crtc_id:	 current client's crtc id
- *
- * Return: error code.
- */
-int sde_rsc_client_state_update(struct sde_rsc_client *client,
-	enum sde_rsc_state state,
-	struct sde_rsc_cmd_config *config, int crtc_id);
-
-/**
- * sde_rsc_client_vote() - ab/ib vote from rsc client
- *
- * @client:	 Client pointer provided by sde_rsc_client_create().
- * @ab:		 aggregated bandwidth vote from client.
- * @ib:		 instant bandwidth vote from client.
- *
- * Return: error code.
- */
-int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
-	u64 ab_vote, u64 ib_vote);
-
-/**
- * sde_rsc_hw_register() - register hardware API
- *
- * @client:	 Client pointer provided by sde_rsc_client_create().
- *
- * Return: error code.
- */
-int sde_rsc_hw_register(struct sde_rsc_priv *rsc);
-
-/**
- * sde_rsc_register_event - register a callback function for an event
- * @rsc_index:   A client will be created on this RSC. As of now only
- *               SDE_RSC_INDEX is valid rsc index.
- * @event_type:  event type to register; client sets 0x3 if it wants
- *               to register for CORE_PC and CORE_RESTORE - both events.
- * @cb_func:     Pointer to desired callback function
- * @usr:         User pointer to pass to callback on event trigger
- * Returns: sde_rsc_event pointer on success
- */
-struct sde_rsc_event *sde_rsc_register_event(int rsc_index, uint32_t event_type,
-		void (*cb_func)(uint32_t event_type, void *usr), void *usr);
-
-/**
- * sde_rsc_unregister_event - unregister callback for an event
- * @sde_rsc_event: event returned by sde_rsc_register_event
- */
-void sde_rsc_unregister_event(struct sde_rsc_event *event);
-
-#endif /* _SDE_RSC_H_ */
diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c
index dd7f37a..fb963ee 100644
--- a/drivers/gpu/drm/msm/sde_rsc_hw.c
+++ b/drivers/gpu/drm/msm/sde_rsc_hw.c
@@ -17,7 +17,7 @@
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 
-#include "sde_rsc.h"
+#include "sde_rsc_priv.h"
 
 /* display rsc offset */
 #define SDE_RSCC_PDC_SEQ_START_ADDR_REG_OFFSET_DRV0	0x020
diff --git a/drivers/gpu/drm/msm/sde_rsc_priv.h b/drivers/gpu/drm/msm/sde_rsc_priv.h
new file mode 100644
index 0000000..2563c85
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde_rsc_priv.h
@@ -0,0 +1,181 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _SDE_RSC_PRIV_H_
+#define _SDE_RSC_PRIV_H_
+
+#include <linux/kernel.h>
+#include <linux/sde_io_util.h>
+#include <linux/sde_rsc.h>
+
+#include <soc/qcom/tcs.h>
+#include "sde_power_handle.h"
+
+#define SDE_RSC_COMPATIBLE "disp_rscc"
+
+#define MAX_RSC_COUNT		5
+
+struct sde_rsc_priv;
+
+/**
+ * rsc_mode_req: sde rsc mode request information
+ * MODE_READ: read vsync status
+ * MODE0_UPDATE: mode0 status , this should be 0x0
+ * MODE1_UPDATE: mode1 status , this should be 0x1
+ * MODE2_UPDATE: mode2 status , this should be 0x2
+ */
+enum rsc_mode_req {
+	MODE_READ,
+	MODE0_UPDATE = 0x1,
+	MODE1_UPDATE = 0x2,
+	MODE2_UPDATE = 0x3,
+};
+
+/**
+ * rsc_vsync_req: sde rsc vsync request information
+ * VSYNC_READ: read vsync status
+ * VSYNC_ENABLE: enable rsc wrapper vsync status
+ * VSYNC_DISABLE: disable rsc wrapper vsync status
+ */
+enum rsc_vsync_req {
+	VSYNC_READ,
+	VSYNC_ENABLE,
+	VSYNC_DISABLE,
+};
+
+/**
+ * struct sde_rsc_hw_ops - sde resource state coordinator hardware ops
+ * @init:			Initialize the sequencer, solver, qtimer,
+				etc. hardware blocks on RSC.
+ * @tcs_wait:			Waits for TCS block OK to allow sending a
+ *				TCS command.
+ * @hw_vsync:			Enables the vsync on RSC block.
+ * @tcs_use_ok:			set TCS set to high to allow RSC to use it.
+ * @mode2_entry:		Request to entry mode2 when all clients are
+ *                              requesting power collapse.
+ * @mode2_exit:			Request to exit mode2 when one of the client
+ *                              is requesting against the power collapse
+ * @is_amc_mode:		Check current amc mode status
+ * @state_update:		Enable/override the solver based on rsc state
+ *                              status (command/video)
+ * @mode_show:			shows current mode status, mode0/1/2
+ * @debug_show:			Show current debug status.
+ */
+
+struct sde_rsc_hw_ops {
+	int (*init)(struct sde_rsc_priv *rsc);
+	int (*tcs_wait)(struct sde_rsc_priv *rsc);
+	int (*hw_vsync)(struct sde_rsc_priv *rsc, enum rsc_vsync_req request,
+		char *buffer, int buffer_size, u32 mode);
+	int (*tcs_use_ok)(struct sde_rsc_priv *rsc);
+	int (*mode2_entry)(struct sde_rsc_priv *rsc);
+	int (*mode2_exit)(struct sde_rsc_priv *rsc);
+	bool (*is_amc_mode)(struct sde_rsc_priv *rsc);
+	int (*state_update)(struct sde_rsc_priv *rsc, enum sde_rsc_state state);
+	int (*debug_show)(struct seq_file *s, struct sde_rsc_priv *rsc);
+	int (*mode_ctrl)(struct sde_rsc_priv *rsc, enum rsc_mode_req request,
+		char *buffer, int buffer_size, bool mode);
+};
+
+/**
+ * struct sde_rsc_timer_config: this is internal configuration between
+ * rsc and rsc_hw API.
+ *
+ * @static_wakeup_time_ns:	wrapper backoff time in nano seconds
+ * @rsc_backoff_time_ns:	rsc backoff time in nano seconds
+ * @pdc_backoff_time_ns:	pdc backoff time in nano seconds
+ * @rsc_mode_threshold_time_ns:	rsc mode threshold time in nano seconds
+ * @rsc_time_slot_0_ns:		mode-0 time slot threshold in nano seconds
+ * @rsc_time_slot_1_ns:		mode-1 time slot threshold in nano seconds
+ * @rsc_time_slot_2_ns:		mode-2 time slot threshold in nano seconds
+ */
+struct sde_rsc_timer_config {
+	u32 static_wakeup_time_ns;
+
+	u32 rsc_backoff_time_ns;
+	u32 pdc_backoff_time_ns;
+	u32 rsc_mode_threshold_time_ns;
+	u32 rsc_time_slot_0_ns;
+	u32 rsc_time_slot_1_ns;
+	u32 rsc_time_slot_2_ns;
+};
+
+/**
+ * struct sde_rsc_priv: sde resource state coordinator(rsc) private handle
+ * @version:		rsc sequence version
+ * @phandle:		module power handle for clocks
+ * @pclient:		module power client of phandle
+ * @fs:			"MDSS GDSC" handle
+ *
+ * @drv_io:		sde drv io data mapping
+ * @wrapper_io:		wrapper io data mapping
+ *
+ * @client_list:	current rsc client list handle
+ * @event_list:		current rsc event list handle
+ * @client_lock:	current rsc client synchronization lock
+ *
+ * timer_config:	current rsc timer configuration
+ * cmd_config:		current panel config
+ * current_state:	current rsc state (video/command), solver
+ *                      override/enabled.
+ * debug_mode:		enables the logging for each register read/write
+ * debugfs_root:	debugfs file system root node
+ *
+ * hw_ops:		sde rsc hardware operations
+ * power_collapse:	if all clients are in IDLE state then it enters in
+ *			mode2 state and enable the power collapse state
+ * power_collapse_block:By default, rsc move to mode-2 if all clients are in
+ *			invalid state. It can be blocked by this boolean entry.
+ * primary_client:	A client which is allowed to make command state request
+ *			and ab/ib vote on display rsc
+ * master_drm:		Primary client waits for vsync on this drm object based
+ *			on crtc id
+ */
+struct sde_rsc_priv {
+	u32 version;
+	struct sde_power_handle phandle;
+	struct sde_power_client *pclient;
+	struct regulator *fs;
+
+	struct dss_io_data drv_io;
+	struct dss_io_data wrapper_io;
+
+	struct list_head client_list;
+	struct list_head event_list;
+	struct mutex client_lock;
+
+	struct sde_rsc_timer_config timer_config;
+	struct sde_rsc_cmd_config cmd_config;
+	u32	current_state;
+
+	u32 debug_mode;
+	struct dentry *debugfs_root;
+
+	struct sde_rsc_hw_ops hw_ops;
+	bool power_collapse;
+	bool power_collapse_block;
+	struct sde_rsc_client *primary_client;
+
+	struct drm_device *master_drm;
+};
+
+/**
+ * sde_rsc_hw_register() - register hardware API
+ *
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: error code.
+ */
+int sde_rsc_hw_register(struct sde_rsc_priv *rsc);
+
+#endif /* _SDE_RSC_PRIV_H_ */
diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h
index 7cdd2b2..2709aca 100644
--- a/drivers/gpu/msm/a6xx_reg.h
+++ b/drivers/gpu/msm/a6xx_reg.h
@@ -621,6 +621,48 @@
 #define A6XX_VBIF_PERF_PWR_CNT_HIGH1            0x3119
 #define A6XX_VBIF_PERF_PWR_CNT_HIGH2            0x311a
 
+/* CX_DBGC_CFG registers */
+#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_A                   0x18400
+#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_B                   0x18401
+#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_C                   0x18402
+#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_D                   0x18403
+#define A6XX_CX_DBGC_CFG_DBGBUS_CNTLT                   0x18404
+#define A6XX_CX_DBGC_CFG_DBGBUS_CNTLT_TRACEEN_SHIFT     0x0
+#define A6XX_CX_DBGC_CFG_DBGBUS_CNTLT_GRANU_SHIFT       0xC
+#define A6XX_CX_DBGC_CFG_DBGBUS_CNTLT_SEGT_SHIFT        0x1C
+#define A6XX_CX_DBGC_CFG_DBGBUS_CNTLM                   0x18405
+#define A6XX_CX_DBGC_CFG_DBGBUS_CNTLM_ENABLE_SHIFT      0x18
+#define A6XX_CX_DBGC_CFG_DBGBUS_IVTL_0                  0x18408
+#define A6XX_CX_DBGC_CFG_DBGBUS_IVTL_1                  0x18409
+#define A6XX_CX_DBGC_CFG_DBGBUS_IVTL_2                  0x1840A
+#define A6XX_CX_DBGC_CFG_DBGBUS_IVTL_3                  0x1840B
+#define A6XX_CX_DBGC_CFG_DBGBUS_MASKL_0                 0x1840C
+#define A6XX_CX_DBGC_CFG_DBGBUS_MASKL_1                 0x1840D
+#define A6XX_CX_DBGC_CFG_DBGBUS_MASKL_2                 0x1840E
+#define A6XX_CX_DBGC_CFG_DBGBUS_MASKL_3                 0x1840F
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL_0                 0x18410
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL_1                 0x18411
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL0_SHIFT            0x0
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL1_SHIFT            0x4
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL2_SHIFT            0x8
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL3_SHIFT            0xC
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL4_SHIFT            0x10
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL5_SHIFT            0x14
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL6_SHIFT            0x18
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL7_SHIFT            0x1C
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL8_SHIFT            0x0
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL9_SHIFT            0x4
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL10_SHIFT           0x8
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL11_SHIFT           0xC
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL12_SHIFT           0x10
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL13_SHIFT           0x14
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL14_SHIFT           0x18
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL15_SHIFT           0x1C
+#define A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF1              0x1842F
+#define A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF2              0x18430
+#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_PING_INDEX_SHIFT    0x0
+#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_PING_BLK_SEL_SHIFT  0x8
+
 /* GMU control registers */
 #define A6XX_GMU_GX_SPTPRAC_POWER_CONTROL	0x1A881
 #define A6XX_GMU_CM3_ITCM_START			0x1B400
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index f0d8746..68d7653 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1854,6 +1854,30 @@
 			status = 0;
 		}
 		break;
+	case KGSL_PROP_DEVICE_QTIMER:
+		{
+			struct kgsl_qtimer_prop qtimerprop = {0};
+			struct kgsl_memdesc *qtimer_desc =
+				kgsl_mmu_get_qtimer_global_entry(device);
+
+			if (sizebytes != sizeof(qtimerprop)) {
+				status = -EINVAL;
+				break;
+			}
+
+			if (qtimer_desc) {
+				qtimerprop.gpuaddr = qtimer_desc->gpuaddr;
+				qtimerprop.size = qtimer_desc->size;
+			}
+
+			if (copy_to_user(value, &qtimerprop,
+						sizeof(qtimerprop))) {
+				status = -EFAULT;
+				break;
+			}
+			status = 0;
+		}
+		break;
 	case KGSL_PROP_MMU_ENABLE:
 		{
 			/* Report MMU only if we can handle paged memory */
@@ -3039,6 +3063,7 @@
 	.regulator_disable_poll = adreno_regulator_disable_poll,
 	.clk_set_options = adreno_clk_set_options,
 	.gpu_model = adreno_gpu_model,
+	.stop_fault_timer = adreno_dispatcher_stop_fault_timer,
 };
 
 static struct platform_driver adreno_platform_driver = {
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 0211a17..54d4bf7 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -899,6 +899,72 @@
 }
 
 /*
+ * a6xx_hm_sptprac_enable() - Turn on HM and SPTPRAC
+ * @device: Pointer to KGSL device
+ */
+static int a6xx_hm_sptprac_enable(struct kgsl_device *device)
+{
+	int ret = 0;
+	struct gmu_device *gmu = &device->gmu;
+
+	/* If GMU does not control HM we must */
+	if (gmu->idle_level < GPU_HW_IFPC) {
+		ret = a6xx_hm_enable(ADRENO_DEVICE(device));
+		if (ret) {
+			dev_err(&gmu->pdev->dev, "Failed to power on GPU HM\n");
+			return ret;
+		}
+	}
+
+	/* If GMU does not control SPTPRAC we must */
+	if (gmu->idle_level < GPU_HW_SPTP_PC) {
+		ret = a6xx_sptprac_enable(ADRENO_DEVICE(device));
+		if (ret) {
+			a6xx_hm_disable(ADRENO_DEVICE(device));
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * a6xx_hm_sptprac_disable() - Turn off SPTPRAC and HM
+ * @device: Pointer to KGSL device
+ */
+static int a6xx_hm_sptprac_disable(struct kgsl_device *device)
+{
+	int ret = 0;
+	struct gmu_device *gmu = &device->gmu;
+
+	/* If GMU does not control SPTPRAC we must */
+	if (gmu->idle_level < GPU_HW_SPTP_PC)
+		a6xx_sptprac_disable(ADRENO_DEVICE(device));
+
+	/* If GMU does not control HM we must */
+	if (gmu->idle_level < GPU_HW_IFPC) {
+		ret = a6xx_hm_disable(ADRENO_DEVICE(device));
+		if (ret)
+			dev_err(&gmu->pdev->dev, "Failed to power off GPU HM\n");
+	}
+
+	return ret;
+}
+
+/*
+ * a6xx_hm_sptprac_control() - Turn HM and SPTPRAC on or off
+ * @device: Pointer to KGSL device
+ * @on: True to turn on or false to turn off
+ */
+static int a6xx_hm_sptprac_control(struct kgsl_device *device, bool on)
+{
+	if (on)
+		return a6xx_hm_sptprac_enable(device);
+	else
+		return a6xx_hm_sptprac_disable(device);
+}
+
+/*
  * a6xx_gfx_rail_on() - request GMU to power GPU at given OPP.
  * @device: Pointer to KGSL device
  *
@@ -976,7 +1042,7 @@
 {
 	struct gmu_device *gmu = &device->gmu;
 	struct device *dev = &gmu->pdev->dev;
-	int ret;
+	int ret = 0;
 
 	if (device->state != KGSL_STATE_INIT &&
 		device->state != KGSL_STATE_SUSPEND) {
@@ -1002,26 +1068,11 @@
 				0xFFFFFFFF))
 			goto error_rsc;
 
-		/* If GMU does not control HM we must */
-		if (gmu->idle_level < GPU_HW_IFPC) {
-			ret = a6xx_hm_enable(ADRENO_DEVICE(device));
-			if (ret) {
-				dev_err(dev, "Failed to power on GPU HM\n");
-				return ret;
-			}
-		}
-
-		/* If GMU does not control SPTP we must */
-		if (gmu->idle_level < GPU_HW_SPTP_PC) {
-			ret = a6xx_sptprac_enable(ADRENO_DEVICE(device));
-			if (ret) {
-				a6xx_hm_disable(ADRENO_DEVICE(device));
-				return ret;
-			}
-		}
+		/* Turn on the HM and SPTP head switches */
+		ret = a6xx_hm_sptprac_control(device, true);
 	}
 
-	return 0;
+	return ret;
 
 error_rsc:
 	dev_err(dev, "GPU RSC sequence stuck in waking up GPU\n");
@@ -1031,19 +1082,10 @@
 static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device)
 {
 	struct gmu_device *gmu = &device->gmu;
-	struct device *dev = &gmu->pdev->dev;
-	int val, ret;
+	int val, ret = 0;
 
-	/* If GMU does not control SPTP we must */
-	if (gmu->idle_level < GPU_HW_SPTP_PC)
-		a6xx_sptprac_disable(ADRENO_DEVICE(device));
-
-	/* If GMU does not control HM we must */
-	if (gmu->idle_level < GPU_HW_IFPC) {
-		ret = a6xx_hm_disable(ADRENO_DEVICE(device));
-		if (ret)
-			dev_err(dev, "Failed to power off GPU HM\n");
-	}
+	/* Turn off the SPTP and HM head switches */
+	ret = a6xx_hm_sptprac_control(device, false);
 
 	/* RSC sleep sequence */
 	_regwrite(gmu->pdc_reg_virt, PDC_GPU_TIMESTAMP_UNIT1_EN_DRV0, 1);
@@ -1069,7 +1111,7 @@
 
 	/* FIXME: v2 has different procedure to trigger sequence */
 
-	return 0;
+	return ret;
 }
 
 /*
@@ -1083,30 +1125,16 @@
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct gmu_device *gmu = &device->gmu;
 	struct gmu_memdesc *mem_addr = gmu->hfi_mem;
-	struct device *dev = &gmu->pdev->dev;
 	int ret, i;
 
 	a6xx_gmu_power_config(device);
 
-	/* If GMU does not control HM then we must */
-	if (gmu->idle_level < GPU_HW_IFPC) {
-		ret = a6xx_hm_enable(adreno_dev);
-		if (ret) {
-			dev_err(dev, "Failed to power on GPU HM\n");
-			return ret;
-		}
-	}
-
-	/* If GMU does not control SPTP then we must */
-	if (gmu->idle_level < GPU_HW_SPTP_PC) {
-		ret = a6xx_sptprac_enable(adreno_dev);
-		if (ret) {
-			a6xx_hm_disable(adreno_dev);
-			return ret;
-		}
-	}
-
 	if (boot_state == GMU_COLD_BOOT || boot_state == GMU_RESET) {
+		/* Turn on the HM and SPTP head switches */
+		ret = a6xx_hm_sptprac_control(device, true);
+		if (ret)
+			return ret;
+
 		/* Turn on TCM retention */
 		kgsl_gmu_regwrite(device, A6XX_GMU_GENERAL_7, 1);
 
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index 12485a8..e501a68 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -342,6 +342,13 @@
 	{ A6XX_DBGBUS_TPL1_3, 0x100, },
 };
 
+static void __iomem *a6xx_cx_dbgc;
+static const struct adreno_debugbus_block a6xx_cx_dbgc_debugbus_blocks[] = {
+	{ A6XX_DBGBUS_VBIF, 0x100, },
+	{ A6XX_DBGBUS_GMU, 0x100, },
+	{ A6XX_DBGBUS_CX, 0x100, },
+};
+
 #define A6XX_NUM_SHADER_BANKS 3
 #define A6XX_SHADER_STATETYPE_SHIFT 8
 
@@ -904,6 +911,100 @@
 	return size;
 }
 
+static void _cx_dbgc_regread(unsigned int offsetwords, unsigned int *value)
+{
+	void __iomem *reg;
+
+	if (WARN((offsetwords < A6XX_CX_DBGC_CFG_DBGBUS_SEL_A) ||
+		(offsetwords > A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF2),
+		"Read beyond CX_DBGC block: 0x%x\n", offsetwords))
+		return;
+
+	reg = a6xx_cx_dbgc +
+		((offsetwords - A6XX_CX_DBGC_CFG_DBGBUS_SEL_A) << 2);
+	*value = __raw_readl(reg);
+
+	/*
+	 * ensure this read finishes before the next one.
+	 * i.e. act like normal readl()
+	 */
+	rmb();
+}
+
+static void _cx_dbgc_regwrite(unsigned int offsetwords, unsigned int value)
+{
+	void __iomem *reg;
+
+	if (WARN((offsetwords < A6XX_CX_DBGC_CFG_DBGBUS_SEL_A) ||
+		(offsetwords > A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF2),
+		"Write beyond CX_DBGC block: 0x%x\n", offsetwords))
+		return;
+
+	reg = a6xx_cx_dbgc +
+		((offsetwords - A6XX_CX_DBGC_CFG_DBGBUS_SEL_A) << 2);
+
+	/*
+	 * ensure previous writes post before this one,
+	 * i.e. act like normal writel()
+	 */
+	wmb();
+	__raw_writel(value, reg);
+}
+
+/* a6xx_cx_dbgc_debug_bus_read() - Read data from trace bus */
+static void a6xx_cx_debug_bus_read(struct kgsl_device *device,
+	unsigned int block_id, unsigned int index, unsigned int *val)
+{
+	unsigned int reg;
+
+	reg = (block_id << A6XX_CX_DBGC_CFG_DBGBUS_SEL_PING_BLK_SEL_SHIFT) |
+			(index << A6XX_CX_DBGC_CFG_DBGBUS_SEL_PING_INDEX_SHIFT);
+
+	_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_SEL_A, reg);
+	_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_SEL_B, reg);
+	_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_SEL_C, reg);
+	_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_SEL_D, reg);
+
+	_cx_dbgc_regread(A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF2, val);
+	val++;
+	_cx_dbgc_regread(A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF1, val);
+}
+
+/*
+ * a6xx_snapshot_cx_dbgc_debugbus_block() - Capture debug data for a gpu
+ * block from the CX DBGC block
+ */
+static size_t a6xx_snapshot_cx_dbgc_debugbus_block(struct kgsl_device *device,
+	u8 *buf, size_t remain, void *priv)
+{
+	struct kgsl_snapshot_debugbus *header =
+		(struct kgsl_snapshot_debugbus *)buf;
+	struct adreno_debugbus_block *block = priv;
+	int i;
+	unsigned int *data = (unsigned int *)(buf + sizeof(*header));
+	unsigned int dwords;
+	size_t size;
+
+	dwords = block->dwords;
+
+	/* For a6xx each debug bus data unit is 2 DWRODS */
+	size = (dwords * sizeof(unsigned int) * 2) + sizeof(*header);
+
+	if (remain < size) {
+		SNAPSHOT_ERR_NOMEM(device, "DEBUGBUS");
+		return 0;
+	}
+
+	header->id = block->block_id;
+	header->count = dwords * 2;
+
+	for (i = 0; i < dwords; i++)
+		a6xx_cx_debug_bus_read(device, block->block_id, i,
+					&data[i*2]);
+
+	return size;
+}
+
 /* a6xx_snapshot_debugbus() - Capture debug bus data */
 static void a6xx_snapshot_debugbus(struct kgsl_device *device,
 		struct kgsl_snapshot *snapshot)
@@ -947,12 +1048,67 @@
 	kgsl_regwrite(device, A6XX_DBGC_CFG_DBGBUS_MASKL_2, 0);
 	kgsl_regwrite(device, A6XX_DBGC_CFG_DBGBUS_MASKL_3, 0);
 
+	a6xx_cx_dbgc = ioremap(device->reg_phys +
+			(A6XX_CX_DBGC_CFG_DBGBUS_SEL_A << 2),
+			(A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF2 -
+				A6XX_CX_DBGC_CFG_DBGBUS_SEL_A + 1) << 2);
+
+	if (a6xx_cx_dbgc) {
+		_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_CNTLT,
+		(0xf << A6XX_DBGC_CFG_DBGBUS_CNTLT_SEGT_SHIFT) |
+		(0x4 << A6XX_DBGC_CFG_DBGBUS_CNTLT_GRANU_SHIFT) |
+		(0x20 << A6XX_DBGC_CFG_DBGBUS_CNTLT_TRACEEN_SHIFT));
+
+		_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_CNTLM,
+			0xf << A6XX_CX_DBGC_CFG_DBGBUS_CNTLM_ENABLE_SHIFT);
+
+		_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_IVTL_0, 0);
+		_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_IVTL_1, 0);
+		_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_IVTL_2, 0);
+		_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_IVTL_3, 0);
+
+		_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_BYTEL_0,
+			(0 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL0_SHIFT) |
+			(1 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL1_SHIFT) |
+			(2 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL2_SHIFT) |
+			(3 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL3_SHIFT) |
+			(4 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL4_SHIFT) |
+			(5 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL5_SHIFT) |
+			(6 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL6_SHIFT) |
+			(7 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL7_SHIFT));
+		_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_BYTEL_1,
+			(8 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL8_SHIFT) |
+			(9 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL9_SHIFT) |
+			(10 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL10_SHIFT) |
+			(11 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL11_SHIFT) |
+			(12 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL12_SHIFT) |
+			(13 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL13_SHIFT) |
+			(14 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL14_SHIFT) |
+			(15 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL15_SHIFT));
+
+		_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_MASKL_0, 0);
+		_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_MASKL_1, 0);
+		_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_MASKL_2, 0);
+		_cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_MASKL_3, 0);
+	} else
+		KGSL_DRV_ERR(device, "Unable to ioremap CX_DBGC_CFG block\n");
+
 	for (i = 0; i < ARRAY_SIZE(a6xx_dbgc_debugbus_blocks); i++) {
 		kgsl_snapshot_add_section(device,
 			KGSL_SNAPSHOT_SECTION_DEBUGBUS,
 			snapshot, a6xx_snapshot_dbgc_debugbus_block,
 			(void *) &a6xx_dbgc_debugbus_blocks[i]);
 	}
+
+	if (a6xx_cx_dbgc) {
+		for (i = 0; i < ARRAY_SIZE(a6xx_cx_dbgc_debugbus_blocks); i++) {
+			kgsl_snapshot_add_section(device,
+				KGSL_SNAPSHOT_SECTION_DEBUGBUS,
+				snapshot, a6xx_snapshot_cx_dbgc_debugbus_block,
+				(void *) &a6xx_cx_dbgc_debugbus_blocks[i]);
+		}
+		iounmap(a6xx_cx_dbgc);
+	}
 }
 
 static size_t a6xx_snapshot_dump_gmu_registers(struct kgsl_device *device,
diff --git a/drivers/gpu/msm/adreno_compat.c b/drivers/gpu/msm/adreno_compat.c
index d86a0c6..5a8d587 100644
--- a/drivers/gpu/msm/adreno_compat.c
+++ b/drivers/gpu/msm/adreno_compat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
@@ -113,6 +113,30 @@
 			status = 0;
 		}
 		break;
+	case KGSL_PROP_DEVICE_QTIMER:
+		{
+			struct kgsl_qtimer_prop qtimerprop = {0};
+			struct kgsl_memdesc *qtimer_desc =
+				kgsl_mmu_get_qtimer_global_entry(device);
+
+			if (sizebytes != sizeof(qtimerprop)) {
+				status = -EINVAL;
+				break;
+			}
+
+			if (qtimer_desc) {
+				qtimerprop.gpuaddr = qtimer_desc->gpuaddr;
+				qtimerprop.size = qtimer_desc->size;
+			}
+
+			if (copy_to_user(value, &qtimerprop,
+						sizeof(qtimerprop))) {
+				status = -EFAULT;
+				break;
+			}
+			status = 0;
+		}
+		break;
 	default:
 		/*
 		 * Call the adreno_getproperty to check if the property type
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 3fa38fa..ed5b714 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -208,6 +208,9 @@
 	if (!kgsl_state_is_awake(KGSL_DEVICE(adreno_dev)))
 		goto ret;
 
+	if (adreno_rb_empty(adreno_dev->cur_rb))
+		goto ret;
+
 	/* only check rbbm status to determine if GPU is idle */
 	adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS, &reg_rbbm_status);
 
@@ -2055,12 +2058,25 @@
 		return 0;
 
 	/*
-	 * On A5xx, read RBBM_STATUS3:SMMU_STALLED_ON_FAULT (BIT 24) to
-	 * tell if this function was entered after a pagefault. If so, only
+	 * In the very unlikely case that the power is off, do nothing - the
+	 * state will be reset on power up and everybody will be happy
+	 */
+
+	if (!kgsl_state_is_awake(device) && (fault & ADRENO_SOFT_FAULT)) {
+		/* Clear the existing register values */
+		memset(adreno_ft_regs_val, 0,
+				adreno_ft_regs_num * sizeof(unsigned int));
+		return 0;
+	}
+
+	/*
+	 * On A5xx and A6xx, read RBBM_STATUS3:SMMU_STALLED_ON_FAULT (BIT 24)
+	 * to tell if this function was entered after a pagefault. If so, only
 	 * proceed if the fault handler has already run in the IRQ thread,
 	 * else return early to give the fault handler a chance to run.
 	 */
-	if (!(fault & ADRENO_IOMMU_PAGE_FAULT) && adreno_is_a5xx(adreno_dev)) {
+	if (!(fault & ADRENO_IOMMU_PAGE_FAULT) &&
+		(adreno_is_a5xx(adreno_dev) || adreno_is_a6xx(adreno_dev))) {
 		unsigned int val;
 
 		mutex_lock(&device->mutex);
@@ -2086,7 +2102,7 @@
 	 */
 	if (!(fault & ADRENO_HARD_FAULT)) {
 		adreno_readreg(adreno_dev, ADRENO_REG_CP_ME_CNTL, &reg);
-		if (adreno_is_a5xx(adreno_dev))
+		if (adreno_is_a5xx(adreno_dev) || adreno_is_a6xx(adreno_dev))
 			reg |= 1 | (1 << 1);
 		else
 			reg |= (1 << 27) | (1 << 28);
@@ -2508,7 +2524,7 @@
 	if (!fault_detect_read_compare(adreno_dev)) {
 		adreno_set_gpu_fault(adreno_dev, ADRENO_SOFT_FAULT);
 		adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev));
-	} else {
+	} else if (dispatcher->inflight > 0) {
 		mod_timer(&dispatcher->fault_timer,
 			jiffies + msecs_to_jiffies(_fault_timer_interval));
 	}
@@ -2553,6 +2569,20 @@
 }
 
 /**
+ * adreno_dispatcher_stop_fault_timer() - stop the dispatcher fault timer
+ * @device: pointer to the KGSL device structure
+ *
+ * Stop the dispatcher fault timer
+ */
+void adreno_dispatcher_stop_fault_timer(struct kgsl_device *device)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
+
+	del_timer_sync(&dispatcher->fault_timer);
+}
+
+/**
  * adreno_dispatcher_close() - close the dispatcher
  * @adreno_dev: pointer to the adreno device structure
  *
diff --git a/drivers/gpu/msm/adreno_dispatch.h b/drivers/gpu/msm/adreno_dispatch.h
index cb9106f..72545db 100644
--- a/drivers/gpu/msm/adreno_dispatch.h
+++ b/drivers/gpu/msm/adreno_dispatch.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -108,6 +108,7 @@
 int adreno_dispatcher_idle(struct adreno_device *adreno_dev);
 void adreno_dispatcher_irq_fault(struct adreno_device *adreno_dev);
 void adreno_dispatcher_stop(struct adreno_device *adreno_dev);
+void adreno_dispatcher_stop_fault_timer(struct kgsl_device *device);
 
 int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv,
 		struct kgsl_context *context, struct kgsl_drawobj *drawobj[],
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 78182b7..32175f5 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -796,10 +796,10 @@
 		dwords += 6;
 
 		/*
-		 * REG_TO_MEM packet on A5xx needs another ordinal.
+		 * REG_TO_MEM packet on A5xx and above needs another ordinal.
 		 * Add 2 more dwords since we do profiling before and after.
 		 */
-		if (adreno_is_a5xx(adreno_dev))
+		if (!ADRENO_LEGACY_PM4(adreno_dev))
 			dwords += 2;
 
 		/*
@@ -816,7 +816,7 @@
 	if (test_bit(CMDOBJ_PROFILE, &cmdobj->priv)) {
 		kernel_profiling = true;
 		dwords += 6;
-		if (adreno_is_a5xx(adreno_dev))
+		if (!ADRENO_LEGACY_PM4(adreno_dev))
 			dwords += 2;
 	}
 
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index b4725c1..bf31c00 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -178,6 +178,7 @@
 		const char *name, struct clk *clk);
 	void (*gpu_model)(struct kgsl_device *device, char *str,
 		size_t bufsz);
+	void (*stop_fault_timer)(struct kgsl_device *device);
 };
 
 struct kgsl_ioctl {
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index cfd5cd1..0325db8 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -113,6 +113,7 @@
 static int global_pt_count;
 uint64_t global_pt_alloc;
 static struct kgsl_memdesc gpu_qdss_desc;
+static struct kgsl_memdesc gpu_qtimer_desc;
 
 void kgsl_print_global_pt_entries(struct seq_file *s)
 {
@@ -272,6 +273,50 @@
 	kgsl_sharedmem_free(&gpu_qdss_desc);
 }
 
+struct kgsl_memdesc *kgsl_iommu_get_qtimer_global_entry(void)
+{
+	return &gpu_qtimer_desc;
+}
+
+static void kgsl_setup_qtimer_desc(struct kgsl_device *device)
+{
+	int result = 0;
+	uint32_t gpu_qtimer_entry[2];
+
+	if (!of_find_property(device->pdev->dev.of_node,
+		"qcom,gpu-qtimer", NULL))
+		return;
+
+	if (of_property_read_u32_array(device->pdev->dev.of_node,
+				"qcom,gpu-qtimer", gpu_qtimer_entry, 2)) {
+		KGSL_CORE_ERR("Failed to read gpu qtimer dts entry\n");
+		return;
+	}
+
+	gpu_qtimer_desc.flags = 0;
+	gpu_qtimer_desc.priv = 0;
+	gpu_qtimer_desc.physaddr = gpu_qtimer_entry[0];
+	gpu_qtimer_desc.size = gpu_qtimer_entry[1];
+	gpu_qtimer_desc.pagetable = NULL;
+	gpu_qtimer_desc.ops = NULL;
+	gpu_qtimer_desc.dev = device->dev->parent;
+	gpu_qtimer_desc.hostptr = NULL;
+
+	result = memdesc_sg_dma(&gpu_qtimer_desc, gpu_qtimer_desc.physaddr,
+			gpu_qtimer_desc.size);
+	if (result) {
+		KGSL_CORE_ERR("memdesc_sg_dma failed: %d\n", result);
+		return;
+	}
+
+	kgsl_mmu_add_global(device, &gpu_qtimer_desc, "gpu-qtimer");
+}
+
+static inline void kgsl_cleanup_qtimer_desc(struct kgsl_mmu *mmu)
+{
+	kgsl_iommu_remove_global(mmu, &gpu_qtimer_desc);
+	kgsl_sharedmem_free(&gpu_qtimer_desc);
+}
 
 static inline void _iommu_sync_mmu_pc(bool lock)
 {
@@ -1452,6 +1497,7 @@
 	kgsl_iommu_remove_global(mmu, &iommu->setstate);
 	kgsl_sharedmem_free(&iommu->setstate);
 	kgsl_cleanup_qdss_desc(mmu);
+	kgsl_cleanup_qtimer_desc(mmu);
 }
 
 static int _setstate_alloc(struct kgsl_device *device,
@@ -1523,6 +1569,7 @@
 
 	kgsl_iommu_add_global(mmu, &iommu->setstate, "setstate");
 	kgsl_setup_qdss_desc(device);
+	kgsl_setup_qtimer_desc(device);
 
 done:
 	if (status)
@@ -2671,6 +2718,7 @@
 	.mmu_remove_global = kgsl_iommu_remove_global,
 	.mmu_getpagetable = kgsl_iommu_getpagetable,
 	.mmu_get_qdss_global_entry = kgsl_iommu_get_qdss_global_entry,
+	.mmu_get_qtimer_global_entry = kgsl_iommu_get_qtimer_global_entry,
 	.probe = kgsl_iommu_probe,
 };
 
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 9e516e1..8ea4492 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -617,6 +617,18 @@
 }
 EXPORT_SYMBOL(kgsl_mmu_get_qdss_global_entry);
 
+struct kgsl_memdesc *kgsl_mmu_get_qtimer_global_entry(
+		struct kgsl_device *device)
+{
+	struct kgsl_mmu *mmu = &device->mmu;
+
+	if (MMU_OP_VALID(mmu, mmu_get_qtimer_global_entry))
+		return mmu->mmu_ops->mmu_get_qtimer_global_entry();
+
+	return NULL;
+}
+EXPORT_SYMBOL(kgsl_mmu_get_qtimer_global_entry);
+
 /*
  * NOMMU definitions - NOMMU really just means that the MMU is kept in pass
  * through and the GPU directly accesses physical memory. Used in debug mode
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 0f9f486..56bb317 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -83,6 +83,7 @@
 	struct kgsl_pagetable * (*mmu_getpagetable)(struct kgsl_mmu *mmu,
 			unsigned long name);
 	struct kgsl_memdesc* (*mmu_get_qdss_global_entry)(void);
+	struct kgsl_memdesc* (*mmu_get_qtimer_global_entry)(void);
 };
 
 struct kgsl_mmu_pt_ops {
@@ -233,6 +234,9 @@
 
 struct kgsl_memdesc *kgsl_mmu_get_qdss_global_entry(struct kgsl_device *device);
 
+struct kgsl_memdesc *kgsl_mmu_get_qtimer_global_entry(
+		struct kgsl_device *device);
+
 int kgsl_mmu_sparse_dummy_map(struct kgsl_pagetable *pagetable,
 		struct kgsl_memdesc *memdesc, uint64_t offset, uint64_t size);
 
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 4d38794..b3e2b6a 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -2621,6 +2621,7 @@
 			return -EBUSY;
 		}
 
+		device->ftbl->stop_fault_timer(device);
 		kgsl_pwrscale_midframe_timer_cancel(device);
 
 		/*
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index fc5f5a8..07a54d9 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -14,6 +14,7 @@
 #include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/hrtimer.h>
+#include <linux/devfreq_cooling.h>
 
 #include "kgsl.h"
 #include "kgsl_pwrscale.h"
@@ -530,7 +531,8 @@
 	struct kgsl_pwrctrl *pwr;
 	struct kgsl_pwrlevel *pwr_level;
 	int level, i;
-	unsigned long cur_freq;
+	unsigned long cur_freq, rec_freq;
+	struct dev_pm_opp *opp;
 
 	if (device == NULL)
 		return -ENODEV;
@@ -549,16 +551,31 @@
 		return 0;
 	}
 
+	/*
+	 * Thermal framework might have disabled/enabled OPP entries
+	 * for mitigation. So find the recommended frequency matching
+	 * the available opp entries
+	 */
+	rcu_read_lock();
+	rec_freq = *freq;
+	opp = devfreq_recommended_opp(dev, &rec_freq, flags);
+	if (IS_ERR(opp)) {
+		rcu_read_unlock();
+		return PTR_ERR(opp);
+	}
+	rec_freq = dev_pm_opp_get_freq(opp);
+	rcu_read_unlock();
+
 	mutex_lock(&device->mutex);
 	cur_freq = kgsl_pwrctrl_active_freq(pwr);
 	level = pwr->active_pwrlevel;
 	pwr_level = &pwr->pwrlevels[level];
 
 	/* If the governor recommends a new frequency, update it here */
-	if (*freq != cur_freq) {
+	if (rec_freq != cur_freq) {
 		level = pwr->max_pwrlevel;
 		for (i = pwr->min_pwrlevel; i >= pwr->max_pwrlevel; i--)
-			if (*freq <= pwr->pwrlevels[i].gpu_freq) {
+			if (rec_freq <= pwr->pwrlevels[i].gpu_freq) {
 				if (pwr->thermal_cycle == CYCLE_ACTIVE)
 					level = _thermal_adjust(pwr, i);
 				else
@@ -963,6 +980,10 @@
 	}
 
 	pwrscale->devfreqptr = devfreq;
+	pwrscale->cooling_dev = of_devfreq_cooling_register(
+					device->pdev->dev.of_node, devfreq);
+	if (IS_ERR(pwrscale->cooling_dev))
+		pwrscale->cooling_dev = NULL;
 
 	pwrscale->gpu_profile.bus_devfreq = NULL;
 	if (data->bus.num) {
@@ -1025,6 +1046,8 @@
 	pwrscale = &device->pwrscale;
 	if (!pwrscale->devfreqptr)
 		return;
+	if (pwrscale->cooling_dev)
+		devfreq_cooling_unregister(pwrscale->cooling_dev);
 
 	kgsl_pwrscale_midframe_timer_cancel(device);
 	flush_workqueue(pwrscale->devfreq_wq);
diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h
index e3d3dc7..7e906a0 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.h
+++ b/drivers/gpu/msm/kgsl_pwrscale.h
@@ -90,6 +90,7 @@
  * @history - History of power events with timestamps and durations
  * @popp_level - Current level of POPP mitigation
  * @popp_state - Control state for POPP, on/off, recently pushed, etc
+ * @cooling_dev - Thermal cooling device handle
  */
 struct kgsl_pwrscale {
 	struct devfreq *devfreqptr;
@@ -111,6 +112,7 @@
 	struct kgsl_pwr_history history[KGSL_PWREVENT_MAX];
 	int popp_level;
 	unsigned long popp_state;
+	struct thermal_cooling_device *cooling_dev;
 };
 
 int kgsl_pwrscale_init(struct device *dev, const char *governor);
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index be34547..1606e7f 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -506,12 +506,15 @@
 
 	wait_for_completion(&info->waitevent);
 
-	if (channel->rescind) {
-		ret = -ENODEV;
-		goto post_msg_err;
-	}
-
 post_msg_err:
+	/*
+	 * If the channel has been rescinded;
+	 * we will be awakened by the rescind
+	 * handler; set the error code to zero so we don't leak memory.
+	 */
+	if (channel->rescind)
+		ret = 0;
+
 	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
 	list_del(&info->msglistentry);
 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index cb95315..d8bc4b9 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -779,6 +779,7 @@
 	/* Allocate the channel object and save this offer. */
 	newchannel = alloc_channel();
 	if (!newchannel) {
+		vmbus_release_relid(offer->child_relid);
 		pr_err("Unable to allocate channel object\n");
 		return;
 	}
diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c
index 6f0a51a..d439736 100644
--- a/drivers/hwtracing/intel_th/core.c
+++ b/drivers/hwtracing/intel_th/core.c
@@ -218,8 +218,10 @@
 	else
 		intel_th_trace_enable(thdev);
 
-	if (ret)
+	if (ret) {
 		pm_runtime_put(&thdev->dev);
+		module_put(thdrv->driver.owner);
+	}
 
 	return ret;
 }
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index d7b4363..58e8850 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -173,7 +173,7 @@
 		u32 m_param = 0;
 		u32 m_cmd = 0;
 
-		m_param |= (stretch ? STOP_STRETCH : ~(STOP_STRETCH));
+		m_param |= (stretch ? STOP_STRETCH : 0);
 		m_param |= ((msgs[i].addr & 0x7F) << SLV_ADDR_SHFT);
 
 		gi2c->cur = &msgs[i];
diff --git a/drivers/iio/adc/qcom-rradc.c b/drivers/iio/adc/qcom-rradc.c
index 302cf14..e412230 100644
--- a/drivers/iio/adc/qcom-rradc.c
+++ b/drivers/iio/adc/qcom-rradc.c
@@ -163,12 +163,16 @@
 #define FG_ADC_RR_DIE_TEMP_SLOPE		2
 #define FG_ADC_RR_DIE_TEMP_OFFSET_MILLI_DEGC	25000
 
-#define FAB_ID_GF				0x30
-#define FAB_ID_SMIC				0x11
 #define FG_ADC_RR_CHG_TEMP_GF_OFFSET_UV		1303168
 #define FG_ADC_RR_CHG_TEMP_GF_SLOPE_UV_PER_C	3784
 #define FG_ADC_RR_CHG_TEMP_SMIC_OFFSET_UV	1338433
 #define FG_ADC_RR_CHG_TEMP_SMIC_SLOPE_UV_PER_C	3655
+#define FG_ADC_RR_CHG_TEMP_660_GF_OFFSET_UV	1309001
+#define FG_RR_CHG_TEMP_660_GF_SLOPE_UV_PER_C	3403
+#define FG_ADC_RR_CHG_TEMP_660_SMIC_OFFSET_UV	1295898
+#define FG_RR_CHG_TEMP_660_SMIC_SLOPE_UV_PER_C	3596
+#define FG_ADC_RR_CHG_TEMP_660_MGNA_OFFSET_UV	1314779
+#define FG_RR_CHG_TEMP_660_MGNA_SLOPE_UV_PER_C	3496
 #define FG_ADC_RR_CHG_TEMP_OFFSET_MILLI_DEGC	25000
 #define FG_ADC_RR_CHG_THRESHOLD_SCALE		4
 
@@ -388,23 +392,70 @@
 	return 0;
 }
 
+static int rradc_get_660_fab_coeff(struct rradc_chip *chip,
+		int64_t *offset, int64_t *slope)
+{
+	switch (chip->pmic_fab_id->fab_id) {
+	case PM660_FAB_ID_GF:
+		*offset = FG_ADC_RR_CHG_TEMP_660_GF_OFFSET_UV;
+		*slope = FG_RR_CHG_TEMP_660_GF_SLOPE_UV_PER_C;
+		break;
+	case PM660_FAB_ID_TSMC:
+		*offset = FG_ADC_RR_CHG_TEMP_660_SMIC_OFFSET_UV;
+		*slope = FG_RR_CHG_TEMP_660_SMIC_SLOPE_UV_PER_C;
+		break;
+	default:
+		*offset = FG_ADC_RR_CHG_TEMP_660_MGNA_OFFSET_UV;
+		*slope = FG_RR_CHG_TEMP_660_MGNA_SLOPE_UV_PER_C;
+	}
+
+	return 0;
+}
+
+static int rradc_get_8998_fab_coeff(struct rradc_chip *chip,
+		int64_t *offset, int64_t *slope)
+{
+	switch (chip->pmic_fab_id->fab_id) {
+	case PMI8998_FAB_ID_GF:
+		*offset = FG_ADC_RR_CHG_TEMP_GF_OFFSET_UV;
+		*slope = FG_ADC_RR_CHG_TEMP_GF_SLOPE_UV_PER_C;
+		break;
+	case PMI8998_FAB_ID_SMIC:
+		*offset = FG_ADC_RR_CHG_TEMP_SMIC_OFFSET_UV;
+		*slope = FG_ADC_RR_CHG_TEMP_SMIC_SLOPE_UV_PER_C;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int rradc_post_process_chg_temp_hot(struct rradc_chip *chip,
 			struct rradc_chan_prop *prop, u16 adc_code,
 			int *result_millidegc)
 {
 	int64_t uv = 0, offset = 0, slope = 0;
+	int rc = 0;
 
 	if (chip->revid_dev_node) {
-		switch (chip->pmic_fab_id->fab_id) {
-		case FAB_ID_GF:
-			offset = FG_ADC_RR_CHG_TEMP_GF_OFFSET_UV;
-			slope = FG_ADC_RR_CHG_TEMP_GF_SLOPE_UV_PER_C;
+		switch (chip->pmic_fab_id->pmic_subtype) {
+		case PM660_SUBTYPE:
+			rc = rradc_get_660_fab_coeff(chip, &offset, &slope);
+			if (rc < 0) {
+				pr_err("Unable to get fab id coefficients\n");
+				return -EINVAL;
+			}
 			break;
-		case FAB_ID_SMIC:
-			offset = FG_ADC_RR_CHG_TEMP_SMIC_OFFSET_UV;
-			slope = FG_ADC_RR_CHG_TEMP_SMIC_SLOPE_UV_PER_C;
+		case PMI8998_SUBTYPE:
+			rc = rradc_get_8998_fab_coeff(chip, &offset, &slope);
+			if (rc < 0) {
+				pr_err("Unable to get fab id coefficients\n");
+				return -EINVAL;
+			}
 			break;
 		default:
+			pr_err("No PMIC subtype found\n");
 			return -EINVAL;
 		}
 	} else {
@@ -444,18 +495,26 @@
 			int *result_millidegc)
 {
 	int64_t uv = 0, offset = 0, slope = 0;
+	int rc = 0;
 
 	if (chip->revid_dev_node) {
-		switch (chip->pmic_fab_id->fab_id) {
-		case FAB_ID_GF:
-			offset = FG_ADC_RR_CHG_TEMP_GF_OFFSET_UV;
-			slope = FG_ADC_RR_CHG_TEMP_GF_SLOPE_UV_PER_C;
+		switch (chip->pmic_fab_id->pmic_subtype) {
+		case PM660_SUBTYPE:
+			rc = rradc_get_660_fab_coeff(chip, &offset, &slope);
+			if (rc < 0) {
+				pr_err("Unable to get fab id coefficients\n");
+				return -EINVAL;
+			}
 			break;
-		case FAB_ID_SMIC:
-			offset = FG_ADC_RR_CHG_TEMP_SMIC_OFFSET_UV;
-			slope = FG_ADC_RR_CHG_TEMP_SMIC_SLOPE_UV_PER_C;
+		case PMI8998_SUBTYPE:
+			rc = rradc_get_8998_fab_coeff(chip, &offset, &slope);
+			if (rc < 0) {
+				pr_err("Unable to get fab id coefficients\n");
+				return -EINVAL;
+			}
 			break;
 		default:
+			pr_err("No PMIC subtype found\n");
 			return -EINVAL;
 		}
 	} else {
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index c3cfacc..2de1f52 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -151,7 +151,9 @@
 {
 	struct iio_dev *indio_dev = private;
 	struct tiadc_device *adc_dev = iio_priv(indio_dev);
-	unsigned int status, config;
+	unsigned int status, config, adc_fsm;
+	unsigned short count = 0;
+
 	status = tiadc_readl(adc_dev, REG_IRQSTATUS);
 
 	/*
@@ -165,6 +167,15 @@
 		tiadc_writel(adc_dev, REG_CTRL, config);
 		tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1OVRRUN
 				| IRQENB_FIFO1UNDRFLW | IRQENB_FIFO1THRES);
+
+		/* wait for idle state.
+		 * ADC needs to finish the current conversion
+		 * before disabling the module
+		 */
+		do {
+			adc_fsm = tiadc_readl(adc_dev, REG_ADCFSM);
+		} while (adc_fsm != 0x10 && count++ < 100);
+
 		tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB));
 		return IRQ_HANDLED;
 	} else if (status & IRQENB_FIFO1THRES) {
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index a3cce3a..ecf592d 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -51,8 +51,6 @@
 			st->report_state.report_id,
 			st->report_state.index,
 			HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM);
-
-		poll_value = hid_sensor_read_poll_value(st);
 	} else {
 		int val;
 
@@ -89,7 +87,9 @@
 	sensor_hub_get_feature(st->hsdev, st->power_state.report_id,
 			       st->power_state.index,
 			       sizeof(state_val), &state_val);
-	if (state && poll_value)
+	if (state)
+		poll_value = hid_sensor_read_poll_value(st);
+	if (poll_value > 0)
 		msleep_interruptible(poll_value * 2);
 
 	return 0;
diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c
index 2173531..dd3fcd1 100644
--- a/drivers/iio/magnetometer/ak8974.c
+++ b/drivers/iio/magnetometer/ak8974.c
@@ -767,7 +767,7 @@
 	return ret;
 }
 
-static int __exit ak8974_remove(struct i2c_client *i2c)
+static int ak8974_remove(struct i2c_client *i2c)
 {
 	struct iio_dev *indio_dev = i2c_get_clientdata(i2c);
 	struct ak8974 *ak8974 = iio_priv(indio_dev);
@@ -849,7 +849,7 @@
 		.of_match_table = of_match_ptr(ak8974_of_match),
 	},
 	.probe	  = ak8974_probe,
-	.remove	  = __exit_p(ak8974_remove),
+	.remove	  = ak8974_remove,
 	.id_table = ak8974_id,
 };
 module_i2c_driver(ak8974_driver);
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index d96aa27..db64adf 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -141,6 +141,9 @@
 
 	interface = intf->cur_altsetting;
 
+	if (interface->desc.bNumEndpoints < 2)
+		return -ENODEV;
+
 	epirq = &interface->endpoint[0].desc;
 	epout = &interface->endpoint[1].desc;
 
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
index 9cc6d05..23c191a 100644
--- a/drivers/input/misc/cm109.c
+++ b/drivers/input/misc/cm109.c
@@ -700,6 +700,10 @@
 	int error = -ENOMEM;
 
 	interface = intf->cur_altsetting;
+
+	if (interface->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	endpoint = &interface->endpoint[0].desc;
 
 	if (!usb_endpoint_is_int_in(endpoint))
diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
index 9c0ea36..f4e8fbe 100644
--- a/drivers/input/misc/ims-pcu.c
+++ b/drivers/input/misc/ims-pcu.c
@@ -1667,6 +1667,10 @@
 		return -EINVAL;
 
 	alt = pcu->ctrl_intf->cur_altsetting;
+
+	if (alt->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	pcu->ep_ctrl = &alt->endpoint[0].desc;
 	pcu->max_ctrl_size = usb_endpoint_maxp(pcu->ep_ctrl);
 
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c
index 79c964c..6e7ff95 100644
--- a/drivers/input/misc/yealink.c
+++ b/drivers/input/misc/yealink.c
@@ -875,6 +875,10 @@
 	int ret, pipe, i;
 
 	interface = intf->cur_altsetting;
+
+	if (interface->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	endpoint = &interface->endpoint[0].desc;
 	if (!usb_endpoint_is_int_in(endpoint))
 		return -ENODEV;
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index b93fe83..518e8a7 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1290,10 +1290,8 @@
 	/* handle buttons */
 	if (pkt_id == SS4_PACKET_ID_STICK) {
 		f->ts_left = !!(SS4_BTN_V2(p) & 0x01);
-		if (!(priv->flags & ALPS_BUTTONPAD)) {
-			f->ts_right = !!(SS4_BTN_V2(p) & 0x02);
-			f->ts_middle = !!(SS4_BTN_V2(p) & 0x04);
-		}
+		f->ts_right = !!(SS4_BTN_V2(p) & 0x02);
+		f->ts_middle = !!(SS4_BTN_V2(p) & 0x04);
 	} else {
 		f->left = !!(SS4_BTN_V2(p) & 0x01);
 		if (!(priv->flags & ALPS_BUTTONPAD)) {
@@ -2461,14 +2459,34 @@
 	int num_y_electrode;
 	int x_pitch, y_pitch, x_phys, y_phys;
 
-	num_x_electrode = SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F);
-	num_y_electrode = SS4_NUMSENSOR_YOFFSET + ((otp[1][0] >> 4) & 0x0F);
+	if (IS_SS4PLUS_DEV(priv->dev_id)) {
+		num_x_electrode =
+			SS4PLUS_NUMSENSOR_XOFFSET + (otp[0][2] & 0x0F);
+		num_y_electrode =
+			SS4PLUS_NUMSENSOR_YOFFSET + ((otp[0][2] >> 4) & 0x0F);
 
-	priv->x_max = (num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
-	priv->y_max = (num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+		priv->x_max =
+			(num_x_electrode - 1) * SS4PLUS_COUNT_PER_ELECTRODE;
+		priv->y_max =
+			(num_y_electrode - 1) * SS4PLUS_COUNT_PER_ELECTRODE;
 
-	x_pitch = ((otp[1][2] >> 2) & 0x07) + SS4_MIN_PITCH_MM;
-	y_pitch = ((otp[1][2] >> 5) & 0x07) + SS4_MIN_PITCH_MM;
+		x_pitch = (otp[0][1] & 0x0F) + SS4PLUS_MIN_PITCH_MM;
+		y_pitch = ((otp[0][1] >> 4) & 0x0F) + SS4PLUS_MIN_PITCH_MM;
+
+	} else {
+		num_x_electrode =
+			SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F);
+		num_y_electrode =
+			SS4_NUMSENSOR_YOFFSET + ((otp[1][0] >> 4) & 0x0F);
+
+		priv->x_max =
+			(num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+		priv->y_max =
+			(num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+
+		x_pitch = ((otp[1][2] >> 2) & 0x07) + SS4_MIN_PITCH_MM;
+		y_pitch = ((otp[1][2] >> 5) & 0x07) + SS4_MIN_PITCH_MM;
+	}
 
 	x_phys = x_pitch * (num_x_electrode - 1); /* In 0.1 mm units */
 	y_phys = y_pitch * (num_y_electrode - 1); /* In 0.1 mm units */
@@ -2484,7 +2502,10 @@
 {
 	unsigned char is_btnless;
 
-	is_btnless = (otp[1][1] >> 3) & 0x01;
+	if (IS_SS4PLUS_DEV(priv->dev_id))
+		is_btnless = (otp[1][0] >> 1) & 0x01;
+	else
+		is_btnless = (otp[1][1] >> 3) & 0x01;
 
 	if (is_btnless)
 		priv->flags |= ALPS_BUTTONPAD;
@@ -2492,6 +2513,21 @@
 	return 0;
 }
 
+static int alps_update_dual_info_ss4_v2(unsigned char otp[][4],
+				       struct alps_data *priv)
+{
+	bool is_dual = false;
+
+	if (IS_SS4PLUS_DEV(priv->dev_id))
+		is_dual = (otp[0][0] >> 4) & 0x01;
+
+	if (is_dual)
+		priv->flags |= ALPS_DUALPOINT |
+					ALPS_DUALPOINT_WITH_PRESSURE;
+
+	return 0;
+}
+
 static int alps_set_defaults_ss4_v2(struct psmouse *psmouse,
 				    struct alps_data *priv)
 {
@@ -2507,6 +2543,8 @@
 
 	alps_update_btn_info_ss4_v2(otp, priv);
 
+	alps_update_dual_info_ss4_v2(otp, priv);
+
 	return 0;
 }
 
@@ -2752,10 +2790,6 @@
 		if (alps_set_defaults_ss4_v2(psmouse, priv))
 			return -EIO;
 
-		if (priv->fw_ver[1] == 0x1)
-			priv->flags |= ALPS_DUALPOINT |
-					ALPS_DUALPOINT_WITH_PRESSURE;
-
 		break;
 	}
 
@@ -2826,10 +2860,7 @@
 			   ec[2] >= 0x90 && ec[2] <= 0x9d) {
 			protocol = &alps_v3_protocol_data;
 		} else if (e7[0] == 0x73 && e7[1] == 0x03 &&
-			   e7[2] == 0x14 && ec[1] == 0x02) {
-			protocol = &alps_v8_protocol_data;
-		} else if (e7[0] == 0x73 && e7[1] == 0x03 &&
-			   e7[2] == 0x28 && ec[1] == 0x01) {
+			   (e7[2] == 0x14 || e7[2] == 0x28)) {
 			protocol = &alps_v8_protocol_data;
 		} else {
 			psmouse_dbg(psmouse,
@@ -2839,7 +2870,8 @@
 	}
 
 	if (priv) {
-		/* Save the Firmware version */
+		/* Save Device ID and Firmware version */
+		memcpy(priv->dev_id, e7, 3);
 		memcpy(priv->fw_ver, ec, 3);
 		error = alps_set_protocol(psmouse, priv, protocol);
 		if (error)
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index b9417e2..dbfd260 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -54,6 +54,16 @@
 
 #define SS4_MASK_NORMAL_BUTTONS		0x07
 
+#define SS4PLUS_COUNT_PER_ELECTRODE	128
+#define SS4PLUS_NUMSENSOR_XOFFSET	16
+#define SS4PLUS_NUMSENSOR_YOFFSET	5
+#define SS4PLUS_MIN_PITCH_MM		37
+
+#define IS_SS4PLUS_DEV(_b)	(((_b[0]) == 0x73) &&	\
+				 ((_b[1]) == 0x03) &&	\
+				 ((_b[2]) == 0x28)		\
+				)
+
 #define SS4_1F_X_V2(_b)		((_b[0] & 0x0007) |		\
 				 ((_b[1] << 3) & 0x0078) |	\
 				 ((_b[1] << 2) & 0x0380) |	\
@@ -263,6 +273,7 @@
 	int addr_command;
 	u16 proto_version;
 	u8 byte0, mask0;
+	u8 dev_id[3];
 	u8 fw_ver[3];
 	int flags;
 	int x_max;
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index ed1935f..da5458d 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -218,17 +218,19 @@
 
 static int elan_check_ASUS_special_fw(struct elan_tp_data *data)
 {
-	if (data->ic_type != 0x0E)
-		return false;
-
-	switch (data->product_id) {
-	case 0x05 ... 0x07:
-	case 0x09:
-	case 0x13:
+	if (data->ic_type == 0x0E) {
+		switch (data->product_id) {
+		case 0x05 ... 0x07:
+		case 0x09:
+		case 0x13:
+			return true;
+		}
+	} else if (data->ic_type == 0x08 && data->product_id == 0x26) {
+		/* ASUS EeeBook X205TA */
 		return true;
-	default:
-		return false;
 	}
+
+	return false;
 }
 
 static int __elan_initialize(struct elan_tp_data *data)
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 0cdd958..25eab45 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -120,6 +120,13 @@
 		},
 	},
 	{
+		/* Dell Embedded Box PC 3000 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Embedded Box PC 3000"),
+		},
+	},
+	{
 		/* OQO Model 01 */
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
diff --git a/drivers/input/tablet/hanwang.c b/drivers/input/tablet/hanwang.c
index cd85205..df4bea9 100644
--- a/drivers/input/tablet/hanwang.c
+++ b/drivers/input/tablet/hanwang.c
@@ -340,6 +340,9 @@
 	int error;
 	int i;
 
+	if (intf->cur_altsetting->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	hanwang = kzalloc(sizeof(struct hanwang), GFP_KERNEL);
 	input_dev = input_allocate_device();
 	if (!hanwang || !input_dev) {
diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c
index e850d7e..4d9d649 100644
--- a/drivers/input/tablet/kbtab.c
+++ b/drivers/input/tablet/kbtab.c
@@ -122,6 +122,9 @@
 	struct input_dev *input_dev;
 	int error = -ENOMEM;
 
+	if (intf->cur_altsetting->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL);
 	input_dev = input_allocate_device();
 	if (!kbtab || !input_dev)
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index aefb6e1..4c0eeca 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -527,6 +527,9 @@
 	if (iface_desc->desc.bInterfaceClass != 0xFF)
 		return -ENODEV;
 
+	if (iface_desc->desc.bNumEndpoints < 5)
+		return -ENODEV;
+
 	/* Use endpoint #4 (0x86). */
 	endpoint = &iface_desc->endpoint[4].desc;
 	if (endpoint->bEndpointAddress != TOUCH_ENDPOINT)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 37dfe0a..34df44c 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -322,9 +322,6 @@
 	void (*device_reset)(struct arm_smmu_device *smmu);
 	phys_addr_t (*iova_to_phys_hard)(struct iommu_domain *domain,
 					 dma_addr_t iova);
-	void (*iova_to_phys_fault)(struct iommu_domain *domain,
-				dma_addr_t iova, phys_addr_t *phys1,
-				phys_addr_t *phys_post_tlbiall);
 };
 
 struct arm_smmu_impl_def_reg {
@@ -499,6 +496,7 @@
 
 struct arm_smmu_domain {
 	struct arm_smmu_device		*smmu;
+	struct device			*dev;
 	struct io_pgtable_ops		*pgtbl_ops;
 	struct io_pgtable_cfg		pgtbl_cfg;
 	spinlock_t			pgtbl_lock;
@@ -1141,32 +1139,21 @@
 					 dma_addr_t iova, u32 fsr)
 {
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
-	struct arm_smmu_device *smmu;
+	struct arm_smmu_device *smmu = smmu_domain->smmu;
 	phys_addr_t phys;
 	phys_addr_t phys_post_tlbiall;
 
-	smmu = smmu_domain->smmu;
-
-	if (smmu->arch_ops && smmu->arch_ops->iova_to_phys_fault) {
-		smmu->arch_ops->iova_to_phys_fault(domain, iova, &phys,
-		&phys_post_tlbiall);
-	} else {
-		phys = arm_smmu_iova_to_phys_hard(domain, iova);
-		arm_smmu_tlb_inv_context(smmu_domain);
-		phys_post_tlbiall = arm_smmu_iova_to_phys_hard(domain, iova);
-	}
+	phys = arm_smmu_iova_to_phys_hard(domain, iova);
+	arm_smmu_tlb_inv_context(smmu_domain);
+	phys_post_tlbiall = arm_smmu_iova_to_phys_hard(domain, iova);
 
 	if (phys != phys_post_tlbiall) {
 		dev_err(smmu->dev,
 			"ATOS results differed across TLBIALL...\n"
 			"Before: %pa After: %pa\n", &phys, &phys_post_tlbiall);
 	}
-	if (!phys_post_tlbiall) {
-		dev_err(smmu->dev,
-			"ATOS still failed. If the page tables look good (check the software table walk) then hardware might be misbehaving.\n");
-	}
 
-	return phys_post_tlbiall;
+	return (phys == 0 ? phys_post_tlbiall : phys);
 }
 
 static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
@@ -1260,8 +1247,11 @@
 				dev_err(smmu->dev,
 					"SOFTWARE TABLE WALK FAILED! Looks like %s accessed an unmapped address!\n",
 					dev_name(smmu->dev));
-			dev_err(smmu->dev,
-				"hard iova-to-phys (ATOS)=%pa\n", &phys_atos);
+			if (phys_atos)
+				dev_err(smmu->dev, "hard iova-to-phys (ATOS)=%pa\n",
+					&phys_atos);
+			else
+				dev_err(smmu->dev, "hard iova-to-phys (ATOS) failed\n");
 			dev_err(smmu->dev, "SID=0x%x\n", frsynra);
 		}
 		ret = IRQ_NONE;
@@ -1493,7 +1483,8 @@
 }
 
 static int arm_smmu_init_domain_context(struct iommu_domain *domain,
-					struct arm_smmu_device *smmu)
+					struct arm_smmu_device *smmu,
+					struct device *dev)
 {
 	int irq, start, ret = 0;
 	unsigned long ias, oas;
@@ -1642,6 +1633,7 @@
 	};
 
 	smmu_domain->smmu = smmu;
+	smmu_domain->dev = dev;
 	pgtbl_ops = alloc_io_pgtable_ops(fmt, &smmu_domain->pgtbl_cfg,
 					smmu_domain);
 	if (!pgtbl_ops) {
@@ -2130,7 +2122,7 @@
 		return ret;
 
 	/* Ensure that the domain is finalised */
-	ret = arm_smmu_init_domain_context(domain, smmu);
+	ret = arm_smmu_init_domain_context(domain, smmu, dev);
 	if (ret < 0)
 		goto out_power_off;
 
@@ -2331,9 +2323,11 @@
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
 
 	if (smmu_domain->smmu->arch_ops &&
-	    smmu_domain->smmu->arch_ops->iova_to_phys_hard)
-		return smmu_domain->smmu->arch_ops->iova_to_phys_hard(
+	    smmu_domain->smmu->arch_ops->iova_to_phys_hard) {
+		ret = smmu_domain->smmu->arch_ops->iova_to_phys_hard(
 						domain, iova);
+		return ret;
+	}
 
 	spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
 	if (smmu_domain->smmu->features & ARM_SMMU_FEAT_TRANS_OPS &&
@@ -3068,64 +3062,27 @@
 	qsmmuv2_resume(smmu);
 }
 
-static phys_addr_t __qsmmuv2_iova_to_phys_hard(struct iommu_domain *domain,
-					      dma_addr_t iova, bool halt)
+static phys_addr_t qsmmuv2_iova_to_phys_hard(struct iommu_domain *domain,
+				dma_addr_t iova)
 {
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
 	struct arm_smmu_device *smmu = smmu_domain->smmu;
 	int ret;
 	phys_addr_t phys = 0;
 	unsigned long flags;
+	u32 sctlr, sctlr_orig, fsr;
+	void __iomem *cb_base;
 
 	ret = arm_smmu_power_on(smmu_domain->smmu->pwr);
 	if (ret)
-		return 0;
+		return ret;
 
-	if (halt) {
-		ret = qsmmuv2_halt(smmu);
-		if (ret)
-			goto out_power_off;
-	}
-
-	spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
-	spin_lock(&smmu->atos_lock);
-	phys = __arm_smmu_iova_to_phys_hard(domain, iova);
-	spin_unlock(&smmu->atos_lock);
-	spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
-
-	if (halt)
-		qsmmuv2_resume(smmu);
-
-out_power_off:
-	arm_smmu_power_off(smmu_domain->smmu->pwr);
-	return phys;
-}
-
-static phys_addr_t qsmmuv2_iova_to_phys_hard(struct iommu_domain *domain,
-					      dma_addr_t iova)
-{
-	return __qsmmuv2_iova_to_phys_hard(domain, iova, true);
-}
-
-static void qsmmuv2_iova_to_phys_fault(
-				struct iommu_domain *domain,
-				dma_addr_t iova, phys_addr_t *phys,
-				phys_addr_t *phys_post_tlbiall)
-{
-	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
-	struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
-	struct arm_smmu_device *smmu;
-	void __iomem *cb_base;
-	u64 sctlr, sctlr_orig;
-	u32 fsr;
-
-	smmu = smmu_domain->smmu;
-	cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
+	spin_lock_irqsave(&smmu->atos_lock, flags);
+	cb_base = ARM_SMMU_CB_BASE(smmu) +
+			ARM_SMMU_CB(smmu, smmu_domain->cfg.cbndx);
 
 	qsmmuv2_halt_nowait(smmu);
-
 	writel_relaxed(RESUME_TERMINATE, cb_base + ARM_SMMU_CB_RESUME);
-
 	qsmmuv2_wait_for_halt(smmu);
 
 	/* clear FSR to allow ATOS to log any faults */
@@ -3137,20 +3094,21 @@
 	sctlr = sctlr_orig & ~SCTLR_CFCFG;
 	writel_relaxed(sctlr, cb_base + ARM_SMMU_CB_SCTLR);
 
-	*phys = __qsmmuv2_iova_to_phys_hard(domain, iova, false);
-	arm_smmu_tlb_inv_context(smmu_domain);
-	*phys_post_tlbiall = __qsmmuv2_iova_to_phys_hard(domain, iova, false);
+	phys = __arm_smmu_iova_to_phys_hard(domain, iova);
 
 	/* restore SCTLR */
 	writel_relaxed(sctlr_orig, cb_base + ARM_SMMU_CB_SCTLR);
 
 	qsmmuv2_resume(smmu);
+	spin_unlock_irqrestore(&smmu->atos_lock, flags);
+
+	arm_smmu_power_off(smmu_domain->smmu->pwr);
+	return phys;
 }
 
 struct arm_smmu_arch_ops qsmmuv2_arch_ops = {
 	.device_reset = qsmmuv2_device_reset,
 	.iova_to_phys_hard = qsmmuv2_iova_to_phys_hard,
-	.iova_to_phys_fault = qsmmuv2_iova_to_phys_fault,
 };
 
 static void arm_smmu_context_bank_reset(struct arm_smmu_device *smmu)
@@ -3988,14 +3946,38 @@
 IOMMU_OF_DECLARE(arm_mmu500, "arm,mmu-500", arm_smmu_of_init);
 IOMMU_OF_DECLARE(cavium_smmuv2, "cavium,smmu-v2", arm_smmu_of_init);
 
+#define TCU_HW_VERSION_HLOS1		(0x18)
+
 #define DEBUG_SID_HALT_REG		0x0
 #define DEBUG_SID_HALT_VAL		(0x1 << 16)
+#define DEBUG_SID_HALT_SID_MASK		0x3ff
+
+#define DEBUG_VA_ADDR_REG		0x8
+
+#define DEBUG_TXN_TRIGG_REG		0x18
+#define DEBUG_TXN_AXPROT_SHIFT		6
+#define DEBUG_TXN_AXCACHE_SHIFT		2
+#define DEBUG_TRX_WRITE			(0x1 << 1)
+#define DEBUG_TXN_READ			(0x0 << 1)
+#define DEBUG_TXN_TRIGGER		0x1
 
 #define DEBUG_SR_HALT_ACK_REG		0x20
 #define DEBUG_SR_HALT_ACK_VAL		(0x1 << 1)
+#define DEBUG_SR_ECATS_RUNNING_VAL	(0x1 << 0)
+
+#define DEBUG_PAR_REG			0x28
+#define DEBUG_PAR_PA_MASK		((0x1ULL << 36) - 1)
+#define DEBUG_PAR_PA_SHIFT		12
+#define DEBUG_PAR_FAULT_VAL		0x1
 
 #define TBU_DBG_TIMEOUT_US		30000
 
+struct qsmmuv500_archdata {
+	struct list_head		tbus;
+	void __iomem			*tcu_base;
+	u32				version;
+};
+
 struct qsmmuv500_tbu_device {
 	struct list_head		list;
 	struct device			*dev;
@@ -4004,6 +3986,8 @@
 	void __iomem			*status_reg;
 
 	struct arm_smmu_power_resources *pwr;
+	u32				sid_start;
+	u32				num_sids;
 
 	/* Protects halt count */
 	spinlock_t			halt_lock;
@@ -4013,10 +3997,10 @@
 static int qsmmuv500_tbu_power_on_all(struct arm_smmu_device *smmu)
 {
 	struct qsmmuv500_tbu_device *tbu;
-	struct list_head *list = smmu->archdata;
+	struct qsmmuv500_archdata *data = smmu->archdata;
 	int ret = 0;
 
-	list_for_each_entry(tbu, list, list) {
+	list_for_each_entry(tbu, &data->tbus, list) {
 		ret = arm_smmu_power_on(tbu->pwr);
 		if (ret)
 			break;
@@ -4024,7 +4008,7 @@
 	if (!ret)
 		return 0;
 
-	list_for_each_entry_continue_reverse(tbu, list, list) {
+	list_for_each_entry_continue_reverse(tbu, &data->tbus, list) {
 		arm_smmu_power_off(tbu->pwr);
 	}
 	return ret;
@@ -4033,9 +4017,9 @@
 static void qsmmuv500_tbu_power_off_all(struct arm_smmu_device *smmu)
 {
 	struct qsmmuv500_tbu_device *tbu;
-	struct list_head *list = smmu->archdata;
+	struct qsmmuv500_archdata *data = smmu->archdata;
 
-	list_for_each_entry_reverse(tbu, list, list) {
+	list_for_each_entry_reverse(tbu, &data->tbus, list) {
 		arm_smmu_power_off(tbu->pwr);
 	}
 }
@@ -4101,10 +4085,10 @@
 static int qsmmuv500_halt_all(struct arm_smmu_device *smmu)
 {
 	struct qsmmuv500_tbu_device *tbu;
-	struct list_head *list = smmu->archdata;
+	struct qsmmuv500_archdata *data = smmu->archdata;
 	int ret = 0;
 
-	list_for_each_entry(tbu, list, list) {
+	list_for_each_entry(tbu, &data->tbus, list) {
 		ret = qsmmuv500_tbu_halt(tbu);
 		if (ret)
 			break;
@@ -4113,7 +4097,7 @@
 	if (!ret)
 		return 0;
 
-	list_for_each_entry_continue_reverse(tbu, list, list) {
+	list_for_each_entry_continue_reverse(tbu, &data->tbus, list) {
 		qsmmuv500_tbu_resume(tbu);
 	}
 	return ret;
@@ -4122,13 +4106,27 @@
 static void qsmmuv500_resume_all(struct arm_smmu_device *smmu)
 {
 	struct qsmmuv500_tbu_device *tbu;
-	struct list_head *list = smmu->archdata;
+	struct qsmmuv500_archdata *data = smmu->archdata;
 
-	list_for_each_entry(tbu, list, list) {
+	list_for_each_entry(tbu, &data->tbus, list) {
 		qsmmuv500_tbu_resume(tbu);
 	}
 }
 
+static struct qsmmuv500_tbu_device *qsmmuv500_find_tbu(
+	struct arm_smmu_device *smmu, u32 sid)
+{
+	struct qsmmuv500_tbu_device *tbu = NULL;
+	struct qsmmuv500_archdata *data = smmu->archdata;
+
+	list_for_each_entry(tbu, &data->tbus, list) {
+		if (tbu->sid_start <= sid &&
+		    sid < tbu->sid_start + tbu->num_sids)
+			break;
+	}
+	return tbu;
+}
+
 static void qsmmuv500_device_reset(struct arm_smmu_device *smmu)
 {
 	int i, ret;
@@ -4147,6 +4145,187 @@
 	qsmmuv500_tbu_power_off_all(smmu);
 }
 
+static int qsmmuv500_ecats_lock(struct arm_smmu_domain *smmu_domain,
+				struct qsmmuv500_tbu_device *tbu,
+				unsigned long *flags)
+{
+	struct arm_smmu_device *smmu = tbu->smmu;
+	struct qsmmuv500_archdata *data = smmu->archdata;
+	u32 val;
+
+	spin_lock_irqsave(&smmu->atos_lock, *flags);
+	/* The status register is not accessible on version 1.0 */
+	if (data->version == 0x01000000)
+		return 0;
+
+	if (readl_poll_timeout_atomic(tbu->status_reg,
+					val, (val == 0x1), 0,
+					TBU_DBG_TIMEOUT_US)) {
+		dev_err(tbu->dev, "ECATS hw busy!\n");
+		spin_unlock_irqrestore(&smmu->atos_lock, *flags);
+		return  -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static void qsmmuv500_ecats_unlock(struct arm_smmu_domain *smmu_domain,
+					struct qsmmuv500_tbu_device *tbu,
+					unsigned long *flags)
+{
+	struct arm_smmu_device *smmu = tbu->smmu;
+	struct qsmmuv500_archdata *data = smmu->archdata;
+
+	/* The status register is not accessible on version 1.0 */
+	if (data->version != 0x01000000)
+		writel_relaxed(0, tbu->status_reg);
+	spin_unlock_irqrestore(&smmu->atos_lock, *flags);
+}
+
+/*
+ * Zero means failure.
+ */
+static phys_addr_t qsmmuv500_iova_to_phys(
+		struct iommu_domain *domain, dma_addr_t iova, u32 sid)
+{
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+	struct arm_smmu_device *smmu = smmu_domain->smmu;
+	struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
+	struct qsmmuv500_tbu_device *tbu;
+	int ret;
+	phys_addr_t phys = 0;
+	u64 val, fsr;
+	unsigned long flags;
+	void __iomem *cb_base;
+	u32 sctlr_orig, sctlr;
+	int needs_redo = 0;
+
+	cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
+	tbu = qsmmuv500_find_tbu(smmu, sid);
+	if (!tbu)
+		return 0;
+
+	ret = arm_smmu_power_on(tbu->pwr);
+	if (ret)
+		return 0;
+
+	/*
+	 * Disable client transactions & wait for existing operations to
+	 * complete.
+	 */
+	ret = qsmmuv500_tbu_halt(tbu);
+	if (ret)
+		goto out_power_off;
+
+	/* Only one concurrent atos operation */
+	ret = qsmmuv500_ecats_lock(smmu_domain, tbu, &flags);
+	if (ret)
+		goto out_resume;
+
+	/*
+	 * We can be called from an interrupt handler with FSR already set
+	 * so terminate the faulting transaction prior to starting ecats.
+	 * No new racing faults can occur since we in the halted state.
+	 * ECATS can trigger the fault interrupt, so disable it temporarily
+	 * and check for an interrupt manually.
+	 */
+	fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR);
+	if (fsr & FSR_FAULT) {
+		writel_relaxed(fsr, cb_base + ARM_SMMU_CB_FSR);
+		writel_relaxed(RESUME_TERMINATE, cb_base + ARM_SMMU_CB_RESUME);
+	}
+	sctlr_orig = readl_relaxed(cb_base + ARM_SMMU_CB_SCTLR);
+	sctlr = sctlr_orig & ~(SCTLR_CFCFG | SCTLR_CFIE);
+	writel_relaxed(sctlr, cb_base + ARM_SMMU_CB_SCTLR);
+
+redo:
+	/* Set address and stream-id */
+	val = readq_relaxed(tbu->base + DEBUG_SID_HALT_REG);
+	val |= sid & DEBUG_SID_HALT_SID_MASK;
+	writeq_relaxed(val, tbu->base + DEBUG_SID_HALT_REG);
+	writeq_relaxed(iova, tbu->base + DEBUG_VA_ADDR_REG);
+
+	/*
+	 * Write-back Read and Write-Allocate
+	 * Priviledged, nonsecure, data transaction
+	 * Read operation.
+	 */
+	val = 0xF << DEBUG_TXN_AXCACHE_SHIFT;
+	val |= 0x3 << DEBUG_TXN_AXPROT_SHIFT;
+	val |= DEBUG_TXN_TRIGGER;
+	writeq_relaxed(val, tbu->base + DEBUG_TXN_TRIGG_REG);
+
+	ret = 0;
+	if (readl_poll_timeout_atomic(tbu->base + DEBUG_SR_HALT_ACK_REG,
+				val, !(val & DEBUG_SR_ECATS_RUNNING_VAL),
+				0, TBU_DBG_TIMEOUT_US)) {
+		dev_err(tbu->dev, "ECATS translation timed out!\n");
+	}
+
+	fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR);
+	if (fsr & FSR_FAULT) {
+		dev_err(tbu->dev, "ECATS generated a fault interrupt! FSR = %llx\n",
+			val);
+		ret = -EINVAL;
+
+		writel_relaxed(val, cb_base + ARM_SMMU_CB_FSR);
+		/*
+		 * Clear pending interrupts
+		 * Barrier required to ensure that the FSR is cleared
+		 * before resuming SMMU operation
+		 */
+		wmb();
+		writel_relaxed(RESUME_TERMINATE, cb_base + ARM_SMMU_CB_RESUME);
+	}
+
+	val = readq_relaxed(tbu->base + DEBUG_PAR_REG);
+	if (val & DEBUG_PAR_FAULT_VAL) {
+		dev_err(tbu->dev, "ECATS translation failed! PAR = %llx\n",
+			val);
+		ret = -EINVAL;
+	}
+
+	phys = (val >> DEBUG_PAR_PA_SHIFT) & DEBUG_PAR_PA_MASK;
+	if (ret < 0)
+		phys = 0;
+
+	/* Reset hardware */
+	writeq_relaxed(0, tbu->base + DEBUG_TXN_TRIGG_REG);
+	writeq_relaxed(0, tbu->base + DEBUG_VA_ADDR_REG);
+
+	/*
+	 * After a failed translation, the next successful translation will
+	 * incorrectly be reported as a failure.
+	 */
+	if (!phys && needs_redo++ < 2)
+		goto redo;
+
+	writel_relaxed(sctlr_orig, cb_base + ARM_SMMU_CB_SCTLR);
+	qsmmuv500_ecats_unlock(smmu_domain, tbu, &flags);
+
+out_resume:
+	qsmmuv500_tbu_resume(tbu);
+
+out_power_off:
+	arm_smmu_power_off(tbu->pwr);
+
+	return phys;
+}
+
+static phys_addr_t qsmmuv500_iova_to_phys_hard(
+		struct iommu_domain *domain, dma_addr_t iova)
+{
+	u16 sid;
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+	struct iommu_fwspec *fwspec;
+
+	/* Select a sid */
+	fwspec = smmu_domain->dev->iommu_fwspec;
+	sid = (u16)fwspec->ids[0];
+
+	return qsmmuv500_iova_to_phys(domain, iova, sid);
+}
+
 static int qsmmuv500_tbu_register(struct device *dev, void *data)
 {
 	struct arm_smmu_device *smmu = data;
@@ -4168,16 +4347,26 @@
 
 static int qsmmuv500_arch_init(struct arm_smmu_device *smmu)
 {
+	struct resource *res;
 	struct device *dev = smmu->dev;
-	struct list_head *list;
+	struct qsmmuv500_archdata *data;
+	struct platform_device *pdev;
 	int ret;
 
-	list = devm_kzalloc(dev, sizeof(*list), GFP_KERNEL);
-	if (!list)
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
 		return -ENOMEM;
 
-	INIT_LIST_HEAD(list);
-	smmu->archdata = list;
+	INIT_LIST_HEAD(&data->tbus);
+
+	pdev = container_of(dev, struct platform_device, dev);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tcu-base");
+	data->tcu_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(data->tcu_base))
+		return PTR_ERR(data->tcu_base);
+
+	data->version = readl_relaxed(data->tcu_base + TCU_HW_VERSION_HLOS1);
+	smmu->archdata = data;
 
 	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
 	if (ret)
@@ -4194,6 +4383,7 @@
 struct arm_smmu_arch_ops qsmmuv500_arch_ops = {
 	.init = qsmmuv500_arch_init,
 	.device_reset = qsmmuv500_device_reset,
+	.iova_to_phys_hard = qsmmuv500_iova_to_phys_hard,
 };
 
 static const struct of_device_id qsmmuv500_tbu_of_match[] = {
@@ -4206,6 +4396,8 @@
 	struct resource *res;
 	struct device *dev = &pdev->dev;
 	struct qsmmuv500_tbu_device *tbu;
+	const __be32 *cell;
+	int len;
 
 	tbu = devm_kzalloc(dev, sizeof(*tbu), GFP_KERNEL);
 	if (!tbu)
@@ -4225,6 +4417,13 @@
 	if (IS_ERR(tbu->status_reg))
 		return PTR_ERR(tbu->status_reg);
 
+	cell = of_get_property(dev->of_node, "qcom,stream-id-range", &len);
+	if (!cell || len < 8)
+		return -EINVAL;
+
+	tbu->sid_start = of_read_number(cell, 1);
+	tbu->num_sids = of_read_number(cell + 1, 1);
+
 	tbu->pwr = arm_smmu_init_power_resources(pdev);
 	if (IS_ERR(tbu->pwr))
 		return PTR_ERR(tbu->pwr);
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 34be95e..b9e50c1 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -915,7 +915,7 @@
 				 * which we used for the IOMMU lookup. Strictly speaking
 				 * we could do this for all PCI devices; we only need to
 				 * get the BDF# from the scope table for ACPI matches. */
-				if (pdev->is_virtfn)
+				if (pdev && pdev->is_virtfn)
 					goto got_pdev;
 
 				*bus = drhd->devices[i].bus;
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index 01e553c..b045e3b 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -1077,6 +1077,8 @@
 			pr_err("trigger lmh mitigation failed, rc=%d\n", rc);
 			return rc;
 		}
+		/* Wait for LMH mitigation to take effect */
+		udelay(500);
 	}
 
 	if (led->trigger_chgr) {
diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c
index c31d2e1..3060cfa 100644
--- a/drivers/leds/leds-qpnp-wled.c
+++ b/drivers/leds/leds-qpnp-wled.c
@@ -33,6 +33,7 @@
 
 /* ctrl registers */
 #define QPNP_WLED_FAULT_STATUS(b)	(b + 0x08)
+#define QPNP_WLED_INT_RT_STS(b)		(b + 0x10)
 #define QPNP_WLED_EN_REG(b)		(b + 0x46)
 #define QPNP_WLED_FDBK_OP_REG(b)	(b + 0x48)
 #define QPNP_WLED_VREF_REG(b)		(b + 0x49)
@@ -44,6 +45,7 @@
 #define QPNP_WLED_SOFTSTART_RAMP_DLY(b) (b + 0x53)
 #define QPNP_WLED_VLOOP_COMP_RES_REG(b)	(b + 0x55)
 #define QPNP_WLED_VLOOP_COMP_GM_REG(b)	(b + 0x56)
+#define QPNP_WLED_EN_PSM_REG(b)		(b + 0x5A)
 #define QPNP_WLED_PSM_CTRL_REG(b)	(b + 0x5B)
 #define QPNP_WLED_LCD_AUTO_PFM_REG(b)	(b + 0x5C)
 #define QPNP_WLED_SC_PRO_REG(b)		(b + 0x5E)
@@ -82,12 +84,13 @@
 #define QPNP_WLED_VREF_PSM_MIN_MV			400
 #define QPNP_WLED_VREF_PSM_MAX_MV			750
 #define QPNP_WLED_VREF_PSM_DFLT_AMOLED_MV		450
-#define QPNP_WLED_PSM_CTRL_OVERWRITE			0x80
+#define QPNP_WLED_PSM_OVERWRITE_BIT			BIT(7)
 #define QPNP_WLED_LCD_AUTO_PFM_DFLT_THRESH		1
 #define QPNP_WLED_LCD_AUTO_PFM_THRESH_MAX		0xF
 #define QPNP_WLED_LCD_AUTO_PFM_EN_SHIFT			7
 #define QPNP_WLED_LCD_AUTO_PFM_EN_BIT			BIT(7)
 #define QPNP_WLED_LCD_AUTO_PFM_THRESH_MASK		GENMASK(3, 0)
+#define QPNP_WLED_EN_PSM_BIT				BIT(7)
 
 #define QPNP_WLED_ILIM_MASK		GENMASK(2, 0)
 #define QPNP_WLED_ILIM_OVERWRITE	BIT(7)
@@ -117,6 +120,9 @@
 		QPNP_WLED_TEST4_EN_CLAMP_BIT |		\
 		QPNP_WLED_TEST4_EN_SOFT_START_BIT)
 #define QPNP_WLED_TEST4_EN_IIND_UP	0x1
+#define QPNP_WLED_ILIM_FAULT_BIT	BIT(0)
+#define QPNP_WLED_OVP_FAULT_BIT		BIT(1)
+#define QPNP_WLED_SC_FAULT_BIT		BIT(2)
 
 /* sink registers */
 #define QPNP_WLED_CURR_SINK_REG(b)	(b + 0x46)
@@ -335,6 +341,7 @@
  *  @ lcd_auto_pfm_thresh - the threshold for lcd auto pfm mode
  *  @ loop_auto_gm_en - select if auto gm is enabled
  *  @ lcd_auto_pfm_en - select if auto pfm is enabled in lcd mode
+ *  @ lcd_psm_ctrl - select if psm needs to be controlled in lcd mode
  *  @ avdd_mode_spmi - enable avdd programming via spmi
  *  @ en_9b_dim_res - enable or disable 9bit dimming
  *  @ en_phase_stag - enable or disable phase staggering
@@ -380,6 +387,7 @@
 	u8			lcd_auto_pfm_thresh;
 	bool			loop_auto_gm_en;
 	bool			lcd_auto_pfm_en;
+	bool			lcd_psm_ctrl;
 	bool			avdd_mode_spmi;
 	bool			en_9b_dim_res;
 	bool			en_phase_stag;
@@ -549,6 +557,30 @@
 	return 0;
 }
 
+static int qpnp_wled_psm_config(struct qpnp_wled *wled, bool enable)
+{
+	int rc;
+
+	if (!wled->lcd_psm_ctrl)
+		return 0;
+
+	rc = qpnp_wled_masked_write_reg(wled,
+			QPNP_WLED_EN_PSM_REG(wled->ctrl_base),
+			QPNP_WLED_EN_PSM_BIT,
+			enable ? QPNP_WLED_EN_PSM_BIT : 0);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_wled_masked_write_reg(wled,
+			QPNP_WLED_PSM_CTRL_REG(wled->ctrl_base),
+			QPNP_WLED_PSM_OVERWRITE_BIT,
+			enable ? QPNP_WLED_PSM_OVERWRITE_BIT : 0);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
 static int qpnp_wled_module_en(struct qpnp_wled *wled,
 				u16 base_addr, bool state)
 {
@@ -561,21 +593,31 @@
 	if (rc < 0)
 		return rc;
 
-	if (wled->ovp_irq > 0) {
-		if (state && wled->ovp_irq_disabled) {
-			/*
-			 * Wait for at least 10ms before enabling OVP fault
-			 * interrupt after enabling the module so that soft
-			 * start is completed. Keep OVP interrupt disabled
-			 * when the module is disabled.
-			 */
-			usleep_range(10000, 11000);
+	/*
+	 * Wait for at least 10ms before enabling OVP fault interrupt after
+	 * enabling the module so that soft start is completed. Also, this
+	 * delay can be used to control PSM during enable when required. Keep
+	 * OVP interrupt disabled when the module is disabled.
+	 */
+	if (state) {
+		usleep_range(10000, 11000);
+		rc = qpnp_wled_psm_config(wled, false);
+		if (rc < 0)
+			return rc;
+
+		if (wled->ovp_irq > 0 && wled->ovp_irq_disabled) {
 			enable_irq(wled->ovp_irq);
 			wled->ovp_irq_disabled = false;
-		} else if (!state && !wled->ovp_irq_disabled) {
+		}
+	} else {
+		if (wled->ovp_irq > 0 && !wled->ovp_irq_disabled) {
 			disable_irq(wled->ovp_irq);
 			wled->ovp_irq_disabled = true;
 		}
+
+		rc = qpnp_wled_psm_config(wled, true);
+		if (rc < 0)
+			return rc;
 	}
 
 	return 0;
@@ -990,7 +1032,7 @@
 		reg &= QPNP_WLED_VREF_PSM_MASK;
 		reg |= ((wled->vref_psm_mv - QPNP_WLED_VREF_PSM_MIN_MV)/
 			QPNP_WLED_VREF_PSM_STEP_MV);
-		reg |= QPNP_WLED_PSM_CTRL_OVERWRITE;
+		reg |= QPNP_WLED_PSM_OVERWRITE_BIT;
 		rc = qpnp_wled_write_reg(wled,
 				QPNP_WLED_PSM_CTRL_REG(wled->ctrl_base), reg);
 		if (rc)
@@ -1053,16 +1095,25 @@
 {
 	struct qpnp_wled *wled = _wled;
 	int rc;
-	u8 val;
+	u8 fault_sts, int_sts;
 
 	rc = qpnp_wled_read_reg(wled,
-			QPNP_WLED_FAULT_STATUS(wled->ctrl_base), &val);
+			QPNP_WLED_INT_RT_STS(wled->ctrl_base), &int_sts);
+	if (rc < 0) {
+		pr_err("Error in reading WLED_INT_RT_STS rc=%d\n", rc);
+		return IRQ_HANDLED;
+	}
+
+	rc = qpnp_wled_read_reg(wled,
+			QPNP_WLED_FAULT_STATUS(wled->ctrl_base), &fault_sts);
 	if (rc < 0) {
 		pr_err("Error in reading WLED_FAULT_STATUS rc=%d\n", rc);
 		return IRQ_HANDLED;
 	}
 
-	pr_err("WLED OVP fault detected, fault_status= %x\n", val);
+	if (fault_sts & (QPNP_WLED_OVP_FAULT_BIT | QPNP_WLED_ILIM_FAULT_BIT))
+		pr_err("WLED OVP fault detected, int_sts=%x fault_sts= %x\n",
+			int_sts, fault_sts);
 	return IRQ_HANDLED;
 }
 
@@ -1677,6 +1728,8 @@
 				wled->ovp_irq, rc);
 			return rc;
 		}
+		disable_irq(wled->ovp_irq);
+		wled->ovp_irq_disabled = true;
 	}
 
 	if (wled->sc_irq >= 0) {
@@ -2063,6 +2116,8 @@
 	wled->en_ext_pfet_sc_pro = of_property_read_bool(pdev->dev.of_node,
 					"qcom,en-ext-pfet-sc-pro");
 
+	wled->lcd_psm_ctrl = of_property_read_bool(pdev->dev.of_node,
+				"qcom,lcd-psm-ctrl");
 	return 0;
 }
 
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 85a6be8..817dfa3 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -897,9 +897,10 @@
 			}
 		}
 
-		if (led->mpp_cfg->pwm_mode != MANUAL_MODE)
+		if (led->mpp_cfg->pwm_mode != MANUAL_MODE) {
 			pwm_enable(led->mpp_cfg->pwm_cfg->pwm_dev);
-		else {
+			led->mpp_cfg->pwm_cfg->pwm_enabled = 1;
+		} else {
 			if (led->cdev.brightness < LED_MPP_CURRENT_MIN)
 				led->cdev.brightness = LED_MPP_CURRENT_MIN;
 			else {
@@ -950,6 +951,7 @@
 			led->mpp_cfg->pwm_mode =
 				led->mpp_cfg->pwm_cfg->default_mode;
 			pwm_disable(led->mpp_cfg->pwm_cfg->pwm_dev);
+			led->mpp_cfg->pwm_cfg->pwm_enabled = 0;
 		}
 		rc = qpnp_led_masked_write(led,
 					LED_MPP_MODE_CTRL(led->base),
@@ -1606,7 +1608,7 @@
 			dev_err(&led->pdev->dev, "pwm enable failed\n");
 			return rc;
 		}
-
+		led->kpdbl_cfg->pwm_cfg->pwm_enabled = 1;
 		set_bit(led->kpdbl_cfg->row_id, kpdbl_leds_in_use);
 
 		/* is_kpdbl_master_turn_on will be set to true when GPLED1
@@ -1642,6 +1644,7 @@
 						"pwm enable failed\n");
 					return rc;
 				}
+				led->kpdbl_cfg->pwm_cfg->pwm_enabled = 1;
 			} else {
 				if (kpdbl_master) {
 					pwm_disable(kpdbl_master);
@@ -1660,6 +1663,7 @@
 			is_kpdbl_master_turn_on = false;
 		} else {
 			pwm_disable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
+			led->kpdbl_cfg->pwm_cfg->pwm_enabled = 0;
 			clear_bit(led->kpdbl_cfg->row_id, kpdbl_leds_in_use);
 			if (bitmap_weight(kpdbl_leds_in_use,
 				NUM_KPDBL_LEDS) == 1 && kpdbl_master &&
@@ -1727,20 +1731,17 @@
 				"Failed to write led enable reg\n");
 			return rc;
 		}
-
+		if (!led->rgb_cfg->pwm_cfg->pwm_enabled) {
+			pwm_enable(led->rgb_cfg->pwm_cfg->pwm_dev);
+			led->rgb_cfg->pwm_cfg->pwm_enabled = 1;
+		}
+	} else {
+		led->rgb_cfg->pwm_cfg->mode =
+			led->rgb_cfg->pwm_cfg->default_mode;
 		if (led->rgb_cfg->pwm_cfg->pwm_enabled) {
 			pwm_disable(led->rgb_cfg->pwm_cfg->pwm_dev);
 			led->rgb_cfg->pwm_cfg->pwm_enabled = 0;
 		}
-
-		rc = pwm_enable(led->rgb_cfg->pwm_cfg->pwm_dev);
-		if (!rc)
-			led->rgb_cfg->pwm_cfg->pwm_enabled = 1;
-	} else {
-		led->rgb_cfg->pwm_cfg->mode =
-			led->rgb_cfg->pwm_cfg->default_mode;
-		pwm_disable(led->rgb_cfg->pwm_cfg->pwm_dev);
-		led->rgb_cfg->pwm_cfg->pwm_enabled = 0;
 		rc = qpnp_led_masked_write(led,
 			RGB_LED_EN_CTL(led->base),
 			led->rgb_cfg->enable, RGB_LED_DISABLE);
@@ -2183,11 +2184,17 @@
 	previous_pwm_us = pwm_cfg->pwm_period_us;
 
 	pwm_cfg->pwm_period_us = pwm_us;
-	pwm_free(pwm_cfg->pwm_dev);
+	if (pwm_cfg->pwm_enabled) {
+		pwm_disable(pwm_cfg->pwm_dev);
+		pwm_cfg->pwm_enabled = 0;
+	}
 	ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
 	if (ret) {
 		pwm_cfg->pwm_period_us = previous_pwm_us;
-		pwm_free(pwm_cfg->pwm_dev);
+		if (pwm_cfg->pwm_enabled) {
+			pwm_disable(pwm_cfg->pwm_dev);
+			pwm_cfg->pwm_enabled = 0;
+		}
 		qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
 		qpnp_led_set(&led->cdev, led->cdev.brightness);
 		dev_err(&led->pdev->dev,
@@ -2237,12 +2244,18 @@
 
 	previous_pause_lo = pwm_cfg->lut_params.lut_pause_lo;
 
-	pwm_free(pwm_cfg->pwm_dev);
+	if (pwm_cfg->pwm_enabled) {
+		pwm_disable(pwm_cfg->pwm_dev);
+		pwm_cfg->pwm_enabled = 0;
+	}
 	pwm_cfg->lut_params.lut_pause_lo = pause_lo;
 	ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
 	if (ret) {
 		pwm_cfg->lut_params.lut_pause_lo = previous_pause_lo;
-		pwm_free(pwm_cfg->pwm_dev);
+		if (pwm_cfg->pwm_enabled) {
+			pwm_disable(pwm_cfg->pwm_dev);
+			pwm_cfg->pwm_enabled = 0;
+		}
 		qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
 		qpnp_led_set(&led->cdev, led->cdev.brightness);
 		dev_err(&led->pdev->dev,
@@ -2292,12 +2305,18 @@
 
 	previous_pause_hi = pwm_cfg->lut_params.lut_pause_hi;
 
-	pwm_free(pwm_cfg->pwm_dev);
+	if (pwm_cfg->pwm_enabled) {
+		pwm_disable(pwm_cfg->pwm_dev);
+		pwm_cfg->pwm_enabled = 0;
+	}
 	pwm_cfg->lut_params.lut_pause_hi = pause_hi;
 	ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
 	if (ret) {
 		pwm_cfg->lut_params.lut_pause_hi = previous_pause_hi;
-		pwm_free(pwm_cfg->pwm_dev);
+		if (pwm_cfg->pwm_enabled) {
+			pwm_disable(pwm_cfg->pwm_dev);
+			pwm_cfg->pwm_enabled = 0;
+		}
 		qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
 		qpnp_led_set(&led->cdev, led->cdev.brightness);
 		dev_err(&led->pdev->dev,
@@ -2348,12 +2367,18 @@
 	previous_start_idx = pwm_cfg->duty_cycles->start_idx;
 	pwm_cfg->duty_cycles->start_idx = start_idx;
 	pwm_cfg->lut_params.start_idx = pwm_cfg->duty_cycles->start_idx;
-	pwm_free(pwm_cfg->pwm_dev);
+	if (pwm_cfg->pwm_enabled) {
+		pwm_disable(pwm_cfg->pwm_dev);
+		pwm_cfg->pwm_enabled = 0;
+	}
 	ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
 	if (ret) {
 		pwm_cfg->duty_cycles->start_idx = previous_start_idx;
 		pwm_cfg->lut_params.start_idx = pwm_cfg->duty_cycles->start_idx;
-		pwm_free(pwm_cfg->pwm_dev);
+		if (pwm_cfg->pwm_enabled) {
+			pwm_disable(pwm_cfg->pwm_dev);
+			pwm_cfg->pwm_enabled = 0;
+		}
 		qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
 		qpnp_led_set(&led->cdev, led->cdev.brightness);
 		dev_err(&led->pdev->dev,
@@ -2403,12 +2428,18 @@
 
 	previous_ramp_step_ms = pwm_cfg->lut_params.ramp_step_ms;
 
-	pwm_free(pwm_cfg->pwm_dev);
+	if (pwm_cfg->pwm_enabled) {
+		pwm_disable(pwm_cfg->pwm_dev);
+		pwm_cfg->pwm_enabled = 0;
+	}
 	pwm_cfg->lut_params.ramp_step_ms = ramp_step_ms;
 	ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
 	if (ret) {
 		pwm_cfg->lut_params.ramp_step_ms = previous_ramp_step_ms;
-		pwm_free(pwm_cfg->pwm_dev);
+		if (pwm_cfg->pwm_enabled) {
+			pwm_disable(pwm_cfg->pwm_dev);
+			pwm_cfg->pwm_enabled = 0;
+		}
 		qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
 		qpnp_led_set(&led->cdev, led->cdev.brightness);
 		dev_err(&led->pdev->dev,
@@ -2458,12 +2489,18 @@
 
 	previous_lut_flags = pwm_cfg->lut_params.flags;
 
-	pwm_free(pwm_cfg->pwm_dev);
+	if (pwm_cfg->pwm_enabled) {
+		pwm_disable(pwm_cfg->pwm_dev);
+		pwm_cfg->pwm_enabled = 0;
+	}
 	pwm_cfg->lut_params.flags = lut_flags;
 	ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
 	if (ret) {
 		pwm_cfg->lut_params.flags = previous_lut_flags;
-		pwm_free(pwm_cfg->pwm_dev);
+		if (pwm_cfg->pwm_enabled) {
+			pwm_disable(pwm_cfg->pwm_dev);
+			pwm_cfg->pwm_enabled = 0;
+		}
 		qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
 		qpnp_led_set(&led->cdev, led->cdev.brightness);
 		dev_err(&led->pdev->dev,
@@ -2543,7 +2580,11 @@
 	pwm_cfg->old_duty_pcts = previous_duty_pcts;
 	pwm_cfg->lut_params.idx_len = pwm_cfg->duty_cycles->num_duty_pcts;
 
-	pwm_free(pwm_cfg->pwm_dev);
+	if (pwm_cfg->pwm_enabled) {
+		pwm_disable(pwm_cfg->pwm_dev);
+		pwm_cfg->pwm_enabled = 0;
+	}
+
 	ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
 	if (ret)
 		goto restore;
@@ -2558,7 +2599,10 @@
 	pwm_cfg->old_duty_pcts = pwm_cfg->duty_cycles->duty_pcts;
 	pwm_cfg->duty_cycles->duty_pcts = previous_duty_pcts;
 	pwm_cfg->lut_params.idx_len = pwm_cfg->duty_cycles->num_duty_pcts;
-	pwm_free(pwm_cfg->pwm_dev);
+	if (pwm_cfg->pwm_enabled) {
+		pwm_disable(pwm_cfg->pwm_dev);
+		pwm_cfg->pwm_enabled = 0;
+	}
 	qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
 	qpnp_led_set(&led->cdev, led->cdev.brightness);
 	return ret;
@@ -2588,7 +2632,10 @@
 				led->kpdbl_cfg->pwm_mode =
 						pwm_cfg->default_mode;
 		}
-		pwm_free(pwm_cfg->pwm_dev);
+		if (pwm_cfg->pwm_enabled) {
+			pwm_disable(pwm_cfg->pwm_dev);
+			pwm_cfg->pwm_enabled = 0;
+		}
 		qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
 		if (led->id == QPNP_ID_RGB_RED || led->id == QPNP_ID_RGB_GREEN
 				|| led->id == QPNP_ID_RGB_BLUE) {
@@ -3541,8 +3588,11 @@
 	}
 
 	rc = qpnp_get_config_pwm(led->kpdbl_cfg->pwm_cfg, led->pdev,  node);
-	if (rc < 0)
+	if (rc < 0) {
+		if (led->kpdbl_cfg->pwm_cfg->pwm_dev)
+			pwm_put(led->kpdbl_cfg->pwm_cfg->pwm_dev);
 		return rc;
+	}
 
 	rc = of_property_read_u32(node, "qcom,row-id", &val);
 	if (!rc)
@@ -3605,8 +3655,11 @@
 	}
 
 	rc = qpnp_get_config_pwm(led->rgb_cfg->pwm_cfg, led->pdev, node);
-	if (rc < 0)
+	if (rc < 0) {
+		if (led->rgb_cfg->pwm_cfg->pwm_dev)
+			pwm_put(led->rgb_cfg->pwm_cfg->pwm_dev);
 		return rc;
+	}
 
 	return 0;
 }
@@ -3729,8 +3782,11 @@
 	}
 
 	rc = qpnp_get_config_pwm(led->mpp_cfg->pwm_cfg, led->pdev, node);
-	if (rc < 0)
+	if (rc < 0) {
+		if (led->mpp_cfg->pwm_cfg && led->mpp_cfg->pwm_cfg->pwm_dev)
+			pwm_put(led->mpp_cfg->pwm_cfg->pwm_dev);
 		goto err_config_mpp;
+	}
 
 	return 0;
 
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index c041db6..0db8a6d 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -151,4 +151,11 @@
 	  Support for communication with the hardened-RPM blocks in
 	  Qualcomm Technologies Inc (QTI) SoCs using TCS hardware mailbox.
 
+config MSM_QMP
+	bool "QTI Mailbox Protocol(QMP)"
+	depends on MSM_SMEM
+	help
+	  QMP is a lightweight communication protocol for sending messages to
+	  a remote processor. This protocol fits into the Generic Mailbox
+	  Framework. QMP uses a mailbox located in shared memory.
 endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 0a01d79..3c811d3 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -31,3 +31,5 @@
 obj-$(CONFIG_BCM_PDC_MBOX)	+= bcm-pdc-mailbox.o
 
 obj-$(CONFIG_QTI_RPMH_MBOX)	+= qti-tcs.o
+
+obj-$(CONFIG_MSM_QMP)	+= msm_qmp.o
diff --git a/drivers/mailbox/msm_qmp.c b/drivers/mailbox/msm_qmp.c
new file mode 100644
index 0000000..dd022d3
--- /dev/null
+++ b/drivers/mailbox/msm_qmp.c
@@ -0,0 +1,811 @@
+/* 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 <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/kthread.h>
+#include <linux/workqueue.h>
+#include <linux/mailbox/qmp.h>
+
+#define QMP_MAGIC	0x4d41494c	/* MAIL */
+#define QMP_VERSION	0x1
+#define QMP_FEATURES	0x0
+#define QMP_NUM_CHANS	0x1
+#define QMP_TOUT_MS	5000
+#define QMP_TX_TOUT_MS	2000
+
+#define QMP_MBOX_LINK_DOWN		0xFFFF0000
+#define QMP_MBOX_LINK_UP		0x0000FFFF
+#define QMP_MBOX_CH_DISCONNECTED	0xFFFF0000
+#define QMP_MBOX_CH_CONNECTED		0x0000FFFF
+
+#define MSG_RAM_ALIGN_BYTES 3
+
+/**
+ * enum qmp_local_state - definition of the local state machine
+ * @LINK_DISCONNECTED:		Init state, waiting for ucore to start
+ * @LINK_NEGOTIATION:		Set local link state to up, wait for ucore ack
+ * @LINK_CONNECTED:		Link state up, channel not connected
+ * @LOCAL_CONNECTING:		Channel opening locally, wait for ucore ack
+ * @LOCAL_CONNECTED:		Channel opened locally
+ * @CHANNEL_CONNECTED:		Channel fully opened
+ * @LOCAL_DISCONNECTING:	Channel closing locally, wait for ucore ack
+ */
+enum qmp_local_state {
+	LINK_DISCONNECTED,
+	LINK_NEGOTIATION,
+	LINK_CONNECTED,
+	LOCAL_CONNECTING,
+	LOCAL_CONNECTED,
+	CHANNEL_CONNECTED,
+	LOCAL_DISCONNECTING,
+};
+
+/**
+ * struct channel_desc - description of a core's link, channel and mailbox state
+ * @link_state		Current link state of core
+ * @link_state_ack	Ack for other core to use when link state changes
+ * @ch_state		Current channel state of core
+ * @ch_state_ack	Ack for other core to use when channel state changes
+ * @mailbox_size	Size of this core's mailbox
+ * @mailbox_offset	Location of core's mailbox from a base smem location
+ */
+struct channel_desc {
+	u32 link_state;
+	u32 link_state_ack;
+	u32 ch_state;
+	u32 ch_state_ack;
+	u32 mailbox_size;
+	u32 mailbox_offset;
+};
+
+/**
+ * struct mbox_desc - description of the protocol's mailbox state
+ * @magic	Magic number field to be set by ucore
+ * @version	Version field to be set by ucore
+ * @features	Features field to be set by ucore
+ * @ucore	Channel descriptor to hold state of ucore
+ * @mcore	Channel descriptor to hold state of mcore
+ * @reserved	Reserved in case of future use
+ *
+ * This structure resides in SMEM and contains the control information for the
+ * mailbox channel. Each core in the link will have one channel descriptor
+ */
+struct mbox_desc {
+	u32 magic;
+	u32 version;
+	u32 features;
+	struct channel_desc ucore;
+	struct channel_desc mcore;
+	u32 reserved;
+};
+
+/**
+ * struct qmp_core_version - local structure to hold version and features
+ * @version	Version field to indicate what version the ucore supports
+ * @features	Features field to indicate what features the ucore supports
+ */
+struct qmp_core_version {
+	u32 version;
+	u32 features;
+};
+
+/**
+ * struct qmp_device - local information for managing a single mailbox
+ * @dev:		The device that corresponds to this mailbox
+ * @mbox:		The mbox controller for this mailbox
+ * @name:		The name of this mailbox
+ * @local_state:	Current state of the mailbox protocol
+ * @link_complete:	Use to block until link negotiation with remote proc
+ *			is complete
+ * @ch_complete:	Use to block until the channel is fully opened
+ * @tx_sent:		True if tx is sent and remote proc has not sent ack
+ * @ch_in_use:		True if this mailbox's channel owned by a client
+ * @rx_buf:		buffer to pass to client, holds copied data from mailbox
+ * @version:		Version and features received during link negotiation
+ * @mcore_mbox_offset:	Offset of mcore mbox from the msgram start
+ * @mcore_mbox_size:	Size of the mcore mbox
+ * @desc:		Reference to the mailbox descriptor in SMEM
+ * @msgram:		Reference to the start of msgram
+ * @irq_mask:		Mask written to @tx_irq_reg to trigger irq
+ * @tx_irq_reg:		Reference to the register to send an irq to remote proc
+ * @rx_reset_reg:	Reference to the register to reset the rx irq, if
+ *			applicable
+ * @rx_irq_line:	The incoming interrupt line
+ * @tx_irq_count:	Number of tx interrupts triggered
+ * @rx_irq_count:	Number of rx interrupts received
+ * @kwork:		Work to be executed when an irq is received
+ * @kworker:		Handle to entitiy to process incoming data
+ * @task:		Handle to task context used to run @kworker
+ * @state_lock:		Serialize mailbox state changes
+ * @dwork:		Delayed work to detect timed out tx
+ * @tx_lock:		Serialize access for writes to mailbox
+ */
+struct qmp_device {
+	struct device *dev;
+	struct mbox_controller *mbox;
+	const char *name;
+	enum qmp_local_state local_state;
+	struct completion link_complete;
+	struct completion ch_complete;
+	bool tx_sent;
+	bool ch_in_use;
+	struct qmp_pkt rx_pkt;
+	struct qmp_core_version version;
+	u32 mcore_mbox_offset;
+	u32 mcore_mbox_size;
+	void __iomem *desc;
+	void __iomem *msgram;
+	u32 irq_mask;
+	void __iomem *tx_irq_reg;
+	void __iomem *rx_reset_reg;
+	u32 rx_irq_line;
+	u32 tx_irq_count;
+	u32 rx_irq_count;
+	struct kthread_work kwork;
+	struct kthread_worker kworker;
+	struct task_struct *task;
+	struct mutex state_lock;
+	struct delayed_work dwork;
+	spinlock_t tx_lock;
+};
+
+/**
+ * send_irq() - send an irq to a remote entity as an event signal.
+ * @mdev:	Which remote entity that should receive the irq.
+ */
+static void send_irq(struct qmp_device *mdev)
+{
+	/*
+	 * Any data associated with this event must be visable to the remote
+	 * before the interrupt is triggered
+	 */
+	wmb();
+	writel_relaxed(mdev->irq_mask, mdev->tx_irq_reg);
+	mdev->tx_irq_count++;
+}
+
+/**
+ * qmp_irq_handler() - handle irq from remote entitity.
+ * @irq:	irq number for the trggered interrupt.
+ * @priv:	private pointer to qmp mbox device.
+ */
+irqreturn_t qmp_irq_handler(int irq, void *priv)
+{
+	struct qmp_device *mdev = (struct qmp_device *)priv;
+
+	if (mdev->rx_reset_reg)
+		writel_relaxed(mdev->irq_mask, mdev->rx_reset_reg);
+
+	kthread_queue_work(&mdev->kworker, &mdev->kwork);
+	mdev->rx_irq_count++;
+
+	return IRQ_HANDLED;
+}
+
+static void memcpy32_toio(void *dest, void *src, size_t size)
+{
+	u32 *dest_local = (u32 *)dest;
+	u32 *src_local = (u32 *)src;
+
+	WARN_ON(size & MSG_RAM_ALIGN_BYTES);
+	size /= sizeof(u32);
+	while (size--)
+		iowrite32(*src_local++, dest_local++);
+}
+
+static void memcpy32_fromio(void *dest, void *src, size_t size)
+{
+	u32 *dest_local = (u32 *)dest;
+	u32 *src_local = (u32 *)src;
+
+	WARN_ON(size & MSG_RAM_ALIGN_BYTES);
+	size /= sizeof(u32);
+	while (size--)
+		*dest_local++ = ioread32(src_local++);
+}
+
+/**
+ * set_ucore_link_ack() - set the link ack in the ucore channel desc.
+ * @mdev:	the mailbox for the field that is being set.
+ * @state:	the value to set the ack field to.
+ */
+static void set_ucore_link_ack(struct qmp_device *mdev, u32 state)
+{
+	u32 offset;
+
+	offset = offsetof(struct mbox_desc, ucore);
+	offset += offsetof(struct channel_desc, link_state_ack);
+	iowrite32(state, mdev->desc + offset);
+}
+
+/**
+ * set_ucore_ch_ack() - set the channel ack in the ucore channel desc.
+ * @mdev:	the mailbox for the field that is being set.
+ * @state:	the value to set the ack field to.
+ */
+static void set_ucore_ch_ack(struct qmp_device *mdev, u32 state)
+{
+	u32 offset;
+
+	offset = offsetof(struct mbox_desc, ucore);
+	offset += offsetof(struct channel_desc, ch_state_ack);
+	iowrite32(state, mdev->desc + offset);
+}
+
+/**
+ * set_mcore_ch() - set the channel state in the mcore channel desc.
+ * @mdev:	the mailbox for the field that is being set.
+ * @state:	the value to set the channel field to.
+ */
+static void set_mcore_ch(struct qmp_device *mdev, u32 state)
+{
+	u32 offset;
+
+	offset = offsetof(struct mbox_desc, mcore);
+	offset += offsetof(struct channel_desc, ch_state);
+	iowrite32(state, mdev->desc + offset);
+}
+
+/**
+ * qmp_notify_timeout() - Notify client of tx timeout with -EIO
+ * @work:	Structure for work that was scheduled.
+ */
+static void qmp_notify_timeout(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct qmp_device *mdev = container_of(dwork, struct qmp_device, dwork);
+	struct mbox_chan *chan = &mdev->mbox->chans[0];
+	int err = -EIO;
+
+	pr_err("%s: qmp tx timeout for %s\n", __func__, mdev->name);
+	mbox_chan_txdone(chan, err);
+}
+
+/**
+ * qmp_startup() - Start qmp mailbox channel for communication. Waits for
+ *			remote subsystem to open channel if link is not
+ *			initated or until timeout.
+ * @chan:	mailbox channel that is being opened.
+ *
+ * Return: 0 on succes or standard Linux error code.
+ */
+static int qmp_startup(struct mbox_chan *chan)
+{
+	struct qmp_device *mdev = chan->con_priv;
+
+	if (!mdev)
+		return -EINVAL;
+
+	mutex_lock(&mdev->state_lock);
+	if (mdev->local_state == CHANNEL_CONNECTED) {
+		mutex_unlock(&mdev->state_lock);
+		return -EINVAL;
+	}
+	if (!completion_done(&mdev->link_complete)) {
+		mutex_unlock(&mdev->state_lock);
+		return -EAGAIN;
+	}
+
+	set_mcore_ch(mdev, QMP_MBOX_CH_CONNECTED);
+	mdev->local_state = LOCAL_CONNECTING;
+	mutex_unlock(&mdev->state_lock);
+
+	send_irq(mdev);
+	wait_for_completion_interruptible_timeout(&mdev->ch_complete,
+					msecs_to_jiffies(QMP_TOUT_MS));
+	return 0;
+}
+
+static inline void qmp_schedule_tx_timeout(struct qmp_device *mdev)
+{
+	schedule_delayed_work(&mdev->dwork, msecs_to_jiffies(QMP_TX_TOUT_MS));
+}
+
+/**
+ * qmp_send_data() - Copy the data to the channel's mailbox and notify
+ *				remote subsystem of new data. This function will
+ *				return an error if the previous message sent has
+ *				not been read. Cannot Sleep.
+ * @chan:	mailbox channel that data is to be sent over.
+ * @data:	Data to be sent to remote processor, should be in the format of
+ *		a qmp_pkt.
+ *
+ * Return: 0 on succes or standard Linux error code.
+ */
+static int qmp_send_data(struct mbox_chan *chan, void *data)
+{
+	struct qmp_device *mdev = chan->con_priv;
+	struct qmp_pkt *pkt = (struct qmp_pkt *)data;
+	void __iomem *addr;
+	unsigned long flags;
+
+	if (!mdev || !data || mdev->local_state != CHANNEL_CONNECTED)
+		return -EINVAL;
+
+	spin_lock_irqsave(&mdev->tx_lock, flags);
+	addr = mdev->msgram + mdev->mcore_mbox_offset;
+	if (ioread32(addr)) {
+		spin_unlock_irqrestore(&mdev->tx_lock, flags);
+		return -EBUSY;
+	}
+
+	if (pkt->size + sizeof(pkt->size) > mdev->mcore_mbox_size) {
+		spin_unlock_irqrestore(&mdev->tx_lock, flags);
+		return -EINVAL;
+	}
+	memcpy32_toio(addr + sizeof(pkt->size), pkt->data, pkt->size);
+	iowrite32(pkt->size, addr);
+	mdev->tx_sent = true;
+	send_irq(mdev);
+	qmp_schedule_tx_timeout(mdev);
+	spin_unlock_irqrestore(&mdev->tx_lock, flags);
+	return 0;
+}
+
+/**
+ * qmp_shutdown() - Disconnect this mailbox channel so the client does not
+ *				receive anymore data and can reliquish control
+ *				of the channel
+ * @chan:	mailbox channel to be shutdown.
+ */
+static void qmp_shutdown(struct mbox_chan *chan)
+{
+	struct qmp_device *mdev = chan->con_priv;
+
+	mutex_lock(&mdev->state_lock);
+	if (mdev->local_state != LINK_DISCONNECTED) {
+		mdev->local_state = LOCAL_DISCONNECTING;
+		set_mcore_ch(mdev, QMP_MBOX_CH_DISCONNECTED);
+		send_irq(mdev);
+	}
+	mdev->ch_in_use = false;
+	mutex_unlock(&mdev->state_lock);
+}
+
+/**
+ * qmp_last_tx_done() - qmp does not support polling operations, print
+ *				error of unexpected usage and return true to
+ *				resume operation.
+ * @chan:	Corresponding mailbox channel for requested last tx.
+ *
+ * Return: true
+ */
+static bool qmp_last_tx_done(struct mbox_chan *chan)
+{
+	pr_err("In %s, unexpected usage of last_tx_done\n", __func__);
+	return true;
+}
+
+/**
+ * qmp_recv_data() - received notification that data is available in the
+ *			mailbox. Copy data from mailbox and pass to client.
+ * @mdev:	mailbox device that received the notification.
+ * @mbox_of:	offset of mailbox from msgram start.
+ */
+static void qmp_recv_data(struct qmp_device *mdev, u32 mbox_of)
+{
+	void __iomem *addr;
+	struct qmp_pkt *pkt;
+
+	addr = mdev->msgram + mbox_of;
+	pkt = &mdev->rx_pkt;
+	pkt->size = ioread32(addr);
+
+	if (pkt->size > mdev->mcore_mbox_size)
+		pr_err("%s: Invalid mailbox packet\n", __func__);
+	else {
+		memcpy32_fromio(pkt->data, addr + sizeof(pkt->size), pkt->size);
+		mbox_chan_received_data(&mdev->mbox->chans[0], &pkt);
+	}
+	iowrite32(0, addr);
+	send_irq(mdev);
+}
+
+/**
+ * init_mcore_state() - initialize the mcore state of a mailbox.
+ * @mdev:	mailbox device to be initialized.
+ */
+static void init_mcore_state(struct qmp_device *mdev)
+{
+	struct channel_desc mcore;
+	u32 offset = offsetof(struct mbox_desc, mcore);
+
+	mcore.link_state = QMP_MBOX_LINK_UP;
+	mcore.link_state_ack = QMP_MBOX_LINK_DOWN;
+	mcore.ch_state = QMP_MBOX_CH_DISCONNECTED;
+	mcore.ch_state_ack = QMP_MBOX_CH_DISCONNECTED;
+	mcore.mailbox_size = mdev->mcore_mbox_size;
+	mcore.mailbox_offset = mdev->mcore_mbox_offset;
+	memcpy32_toio(mdev->desc + offset, &mcore, sizeof(mcore));
+}
+
+/**
+ * __qmp_rx_worker() - Handle incoming messages from remote processor.
+ * @mdev:	mailbox device that received notification.
+ */
+static void __qmp_rx_worker(struct qmp_device *mdev)
+{
+	u32 msg_len;
+	struct mbox_desc desc;
+
+	memcpy_fromio(&desc, mdev->desc, sizeof(desc));
+	if (desc.magic != QMP_MAGIC)
+		return;
+
+	mutex_lock(&mdev->state_lock);
+	switch (mdev->local_state) {
+	case LINK_DISCONNECTED:
+		mdev->version.version = desc.version;
+		mdev->version.features = desc.features;
+		set_ucore_link_ack(mdev, desc.ucore.link_state);
+		if (desc.mcore.mailbox_size) {
+			mdev->mcore_mbox_size = desc.mcore.mailbox_size;
+			mdev->mcore_mbox_offset = desc.mcore.mailbox_offset;
+		}
+		init_mcore_state(mdev);
+		mdev->local_state = LINK_NEGOTIATION;
+		mdev->rx_pkt.data = devm_kzalloc(mdev->dev,
+						 desc.ucore.mailbox_size,
+						 GFP_KERNEL);
+		if (!mdev->rx_pkt.data) {
+			pr_err("In %s: failed to allocate rx pkt\n", __func__);
+			break;
+		}
+		send_irq(mdev);
+		break;
+	case LINK_NEGOTIATION:
+		if (desc.mcore.link_state_ack != QMP_MBOX_LINK_UP ||
+				desc.mcore.link_state != QMP_MBOX_LINK_UP) {
+			pr_err("In %s: rx interrupt without negotiation ack\n",
+					__func__);
+			break;
+		}
+		mdev->local_state = LINK_CONNECTED;
+		complete_all(&mdev->link_complete);
+		break;
+	case LINK_CONNECTED:
+		if (desc.ucore.ch_state == desc.ucore.ch_state_ack) {
+			pr_err("In %s: rx interrupt without channel open\n",
+					__func__);
+			break;
+		}
+		set_ucore_ch_ack(mdev, desc.ucore.ch_state);
+		send_irq(mdev);
+		break;
+	case LOCAL_CONNECTING:
+		if (desc.mcore.ch_state_ack == QMP_MBOX_CH_CONNECTED &&
+				desc.mcore.ch_state == QMP_MBOX_CH_CONNECTED)
+			mdev->local_state = LOCAL_CONNECTED;
+
+		if (desc.ucore.ch_state != desc.ucore.ch_state_ack) {
+			set_ucore_ch_ack(mdev, desc.ucore.ch_state);
+			send_irq(mdev);
+		}
+		if (mdev->local_state == LOCAL_CONNECTED &&
+				desc.mcore.ch_state == QMP_MBOX_CH_CONNECTED &&
+				desc.ucore.ch_state == QMP_MBOX_CH_CONNECTED) {
+			mdev->local_state = CHANNEL_CONNECTED;
+			complete_all(&mdev->ch_complete);
+		}
+		break;
+	case LOCAL_CONNECTED:
+		if (desc.ucore.ch_state == desc.ucore.ch_state_ack) {
+			pr_err("In %s: rx interrupt without remote channel open\n",
+					__func__);
+			break;
+		}
+		set_ucore_ch_ack(mdev, desc.ucore.ch_state);
+		mdev->local_state = CHANNEL_CONNECTED;
+		send_irq(mdev);
+		complete_all(&mdev->ch_complete);
+		break;
+	case CHANNEL_CONNECTED:
+		if (desc.ucore.ch_state == QMP_MBOX_CH_DISCONNECTED) {
+			set_ucore_ch_ack(mdev, desc.ucore.ch_state);
+			mdev->local_state = LOCAL_CONNECTED;
+			send_irq(mdev);
+		}
+
+		msg_len = ioread32(mdev->msgram + desc.ucore.mailbox_offset);
+		if (msg_len)
+			qmp_recv_data(mdev, desc.ucore.mailbox_offset);
+
+		if (mdev->tx_sent) {
+			msg_len = ioread32(mdev->msgram +
+						mdev->mcore_mbox_offset);
+			if (msg_len == 0) {
+				mdev->tx_sent = false;
+				cancel_delayed_work(&mdev->dwork);
+				mbox_chan_txdone(&mdev->mbox->chans[0], 0);
+			}
+		}
+		break;
+	case LOCAL_DISCONNECTING:
+		if (desc.mcore.ch_state_ack == QMP_MBOX_CH_DISCONNECTED &&
+				desc.mcore.ch_state == desc.mcore.ch_state_ack)
+			mdev->local_state = LINK_CONNECTED;
+		reinit_completion(&mdev->ch_complete);
+		break;
+	default:
+		pr_err("In %s: Local Channel State corrupted\n", __func__);
+	}
+	mutex_unlock(&mdev->state_lock);
+}
+
+static void rx_worker(struct kthread_work *work)
+{
+	struct qmp_device *mdev;
+
+	mdev = container_of(work, struct qmp_device, kwork);
+	__qmp_rx_worker(mdev);
+}
+
+/**
+ * qmp_mbox_of_xlate() - Returns a mailbox channel to be used for this mailbox
+ *			device. Make sure the channel is not already in use.
+ * @mbox:	Mailbox device controlls the requested channel.
+ * @spec:	Device tree arguments to specify which channel is requested.
+ */
+static struct mbox_chan *qmp_mbox_of_xlate(struct mbox_controller *mbox,
+		const struct of_phandle_args *spec)
+{
+	struct qmp_device *mdev = dev_get_drvdata(mbox->dev);
+	unsigned int channel = spec->args[0];
+
+	if (!mdev || channel >= mbox->num_chans)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&mdev->state_lock);
+	if (mdev->ch_in_use) {
+		pr_err("%s, mbox channel already in use %s\n", __func__,
+								mdev->name);
+		mutex_unlock(&mdev->state_lock);
+		return ERR_PTR(-EBUSY);
+	}
+	mdev->ch_in_use = true;
+	mutex_unlock(&mdev->state_lock);
+	return &mbox->chans[0];
+}
+
+/**
+ * parse_devicetree() - Parse the device tree information for QMP, map io
+ *			memory and register for needed interrupts
+ * @pdev:	platform device for this driver.
+ * @mdev:	mailbox device to hold the device tree configuration.
+ *
+ * Return: 0 on succes or standard Linux error code.
+ */
+static int qmp_parse_devicetree(struct platform_device *pdev,
+					struct qmp_device *mdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	char *key;
+	int rc;
+	const char *subsys_name;
+	u32 rx_irq_line, tx_irq_mask;
+	u32 desc_of = 0;
+	u32 mbox_of = 0;
+	u32 mbox_size = 0;
+	struct resource *msgram_r, *tx_irq_reg_r;
+
+	key = "label";
+	subsys_name = of_get_property(node, key, NULL);
+	if (!subsys_name) {
+		pr_err("%s: missing key %s\n", __func__, key);
+		return -ENODEV;
+	}
+
+	key = "msgram";
+	msgram_r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+	if (!msgram_r) {
+		pr_err("%s: missing key %s\n", __func__, key);
+		return -ENODEV;
+	}
+
+	key = "irq-reg-base";
+	tx_irq_reg_r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+	if (!tx_irq_reg_r) {
+		pr_err("%s: missing key %s\n", __func__, key);
+		return -ENODEV;
+	}
+
+	key = "qcom,irq-mask";
+	rc = of_property_read_u32(node, key, &tx_irq_mask);
+	if (rc) {
+		pr_err("%s: missing key %s\n", __func__, key);
+		return -ENODEV;
+	}
+
+	key = "interrupts";
+	rx_irq_line = irq_of_parse_and_map(node, 0);
+	if (!rx_irq_line) {
+		pr_err("%s: missing key %s\n", __func__, key);
+		return -ENODEV;
+	}
+
+	key = "mbox-desc-offset";
+	rc = of_property_read_u32(node, key, &desc_of);
+	if (rc) {
+		pr_err("%s: missing key %s\n", __func__, key);
+		return -ENODEV;
+	}
+
+	key = "mbox-offset";
+	rc = of_property_read_u32(node, key, &mbox_of);
+	if (!rc)
+		mdev->mcore_mbox_offset = mbox_of;
+
+	key = "mbox-size";
+	rc = of_property_read_u32(node, key, &mbox_size);
+	if (!rc)
+		mdev->mcore_mbox_size = mbox_size;
+
+	mdev->name = subsys_name;
+	mdev->msgram = devm_ioremap_nocache(&pdev->dev, msgram_r->start,
+						resource_size(msgram_r));
+	if (!mdev->msgram)
+		return -ENOMEM;
+
+	mdev->desc = mdev->msgram + desc_of;
+	if (!mdev->desc)
+		return -ENOMEM;
+
+	mdev->irq_mask = tx_irq_mask;
+	mdev->tx_irq_reg = devm_ioremap_nocache(&pdev->dev, tx_irq_reg_r->start,
+						resource_size(tx_irq_reg_r));
+	if (!mdev->tx_irq_reg)
+		return -ENOMEM;
+
+	mdev->rx_irq_line = rx_irq_line;
+	return 0;
+}
+
+/**
+ * cleanup_workqueue() - Flush all work and stop the thread for this mailbox.
+ * @mdev:	mailbox device to cleanup.
+ */
+static void cleanup_workqueue(struct qmp_device *mdev)
+{
+	kthread_flush_worker(&mdev->kworker);
+	kthread_stop(mdev->task);
+	mdev->task = NULL;
+}
+
+static struct mbox_chan_ops qmp_mbox_ops = {
+	.startup = qmp_startup,
+	.shutdown = qmp_shutdown,
+	.send_data = qmp_send_data,
+	.last_tx_done = qmp_last_tx_done,
+};
+
+static const struct of_device_id qmp_mbox_match_table[] = {
+	{ .compatible = "qcom,qmp-mbox" },
+	{},
+};
+
+static int qmp_mbox_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct mbox_controller *mbox;
+	struct qmp_device *mdev;
+	struct mbox_chan *chans;
+	int ret = 0;
+
+	mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL);
+	if (!mdev)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, mdev);
+
+	ret = qmp_parse_devicetree(pdev, mdev);
+	if (ret)
+		return ret;
+
+	mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+
+	chans = devm_kzalloc(&pdev->dev, sizeof(*chans) * QMP_NUM_CHANS,
+								GFP_KERNEL);
+	if (!chans)
+		return -ENOMEM;
+
+	mbox->dev = &pdev->dev;
+	mbox->ops = &qmp_mbox_ops;
+	mbox->chans = chans;
+	mbox->chans[0].con_priv = mdev;
+	mbox->num_chans = QMP_NUM_CHANS;
+	mbox->txdone_irq = true;
+	mbox->txdone_poll = false;
+	mbox->of_xlate = qmp_mbox_of_xlate;
+
+	mdev->dev = &pdev->dev;
+	mdev->mbox = mbox;
+	spin_lock_init(&mdev->tx_lock);
+	mutex_init(&mdev->state_lock);
+	mdev->local_state = LINK_DISCONNECTED;
+	kthread_init_work(&mdev->kwork, rx_worker);
+	kthread_init_worker(&mdev->kworker);
+	mdev->task = kthread_run(kthread_worker_fn, &mdev->kworker, "qmp_%s",
+								mdev->name);
+	init_completion(&mdev->link_complete);
+	init_completion(&mdev->ch_complete);
+	mdev->tx_sent = false;
+	mdev->ch_in_use = false;
+	INIT_DELAYED_WORK(&mdev->dwork, qmp_notify_timeout);
+
+	ret = mbox_controller_register(mbox);
+	if (ret) {
+		cleanup_workqueue(mdev);
+		pr_err("%s: failed to register mbox controller %d\n", __func__,
+									ret);
+		return ret;
+	}
+
+	ret = devm_request_irq(&pdev->dev, mdev->rx_irq_line, qmp_irq_handler,
+		IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND | IRQF_SHARED,
+		node->name, mdev);
+	if (ret < 0) {
+		cleanup_workqueue(mdev);
+		mbox_controller_unregister(mdev->mbox);
+		pr_err("%s: request irq on %d failed: %d\n", __func__,
+							mdev->rx_irq_line, ret);
+		return ret;
+	}
+	ret = enable_irq_wake(mdev->rx_irq_line);
+	if (ret < 0)
+		pr_err("%s: enable_irq_wake on %d failed: %d\n", __func__,
+							mdev->rx_irq_line, ret);
+
+	qmp_irq_handler(0, mdev);
+	return 0;
+}
+
+static int qmp_mbox_remove(struct platform_device *pdev)
+{
+	struct qmp_device *mdev = platform_get_drvdata(pdev);
+
+	cleanup_workqueue(mdev);
+	mbox_controller_unregister(mdev->mbox);
+	return 0;
+}
+
+static struct platform_driver qmp_mbox_driver = {
+	.probe = qmp_mbox_probe,
+	.remove = qmp_mbox_remove,
+	.driver = {
+		.name = "qmp_mbox",
+		.owner = THIS_MODULE,
+		.of_match_table = qmp_mbox_match_table,
+	},
+};
+
+static int __init qmp_init(void)
+{
+	int rc = 0;
+
+	rc = platform_driver_register(&qmp_mbox_driver);
+	if (rc)
+		pr_err("%s: qmp_mbox_driver reg failed %d\n", __func__, rc);
+	return rc;
+}
+arch_initcall(qmp_init);
+
+MODULE_DESCRIPTION("MSM QTI Mailbox Protocol");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mailbox/qti-tcs.c b/drivers/mailbox/qti-tcs.c
index 5b114cb..1c73c5a2 100644
--- a/drivers/mailbox/qti-tcs.c
+++ b/drivers/mailbox/qti-tcs.c
@@ -121,6 +121,7 @@
 
 /* One per MBOX controller */
 struct tcs_drv {
+	const char *name;
 	void *base; /* start address of the RSC's registers */
 	void *reg_base; /* start address for DRV specific register */
 	int drv_id;
@@ -333,6 +334,7 @@
 	u32 irq_status, sts;
 	struct tcs_mbox *tcs;
 	struct tcs_response *resp;
+	struct tcs_cmd *cmd;
 	u32 irq_clear = 0;
 	u32 data;
 
@@ -352,28 +354,20 @@
 
 		cancel_delayed_work(&resp->dwork);
 
-		/* Clear the AMC mode for non-ACTIVE TCSes */
 		tcs = get_tcs_from_index(drv, m);
 		if (!tcs) {
 			pr_err("TCS-%d doesn't exist in DRV\n", m);
 			continue;
 		}
-		if (tcs->type != ACTIVE_TCS) {
-			data = read_tcs_reg(base, TCS_DRV_CONTROL, m, 0);
-			data &= ~TCS_AMC_MODE_ENABLE;
-			write_tcs_reg(base, TCS_DRV_CONTROL, m, 0, data);
-		} else {
-			/* Clear the enable bit for the commands */
-			write_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0, 0);
-		}
 
 		/* Check if all commands were completed */
 		resp->err = 0;
 		for (i = 0; i < resp->msg->num_payload; i++) {
+			cmd = &resp->msg->payload[i];
 			sts = read_tcs_reg(base, TCS_DRV_CMD_STATUS, m, i);
-			if (!(sts & CMD_STATUS_ISSUED) ||
-				(resp->msg->is_complete &&
-					!(sts & CMD_STATUS_COMPL)))
+			if ((!(sts & CMD_STATUS_ISSUED)) ||
+				((resp->msg->is_complete || cmd->complete) &&
+				(!(sts & CMD_STATUS_COMPL))))
 				resp->err = -EIO;
 		}
 
@@ -385,7 +379,18 @@
 			mbox_chan_received_data(resp->chan, resp->msg);
 		}
 
-		trace_rpmh_notify_irq(m, resp->msg->payload[0].addr, resp->err);
+		trace_rpmh_notify_irq(drv->name, m, resp->msg->payload[0].addr,
+						resp->err);
+
+		/* Clear the AMC mode for non-ACTIVE TCSes */
+		if (tcs->type != ACTIVE_TCS) {
+			data = read_tcs_reg(base, TCS_DRV_CONTROL, m, 0);
+			data &= ~TCS_AMC_MODE_ENABLE;
+			write_tcs_reg(base, TCS_DRV_CONTROL, m, 0, data);
+		} else {
+			/* Clear the enable bit for the commands */
+			write_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0, 0);
+		}
 
 		/* Notify the client that this request is completed. */
 		send_tcs_response(resp);
@@ -401,7 +406,9 @@
 static inline void mbox_notify_tx_done(struct mbox_chan *chan,
 				struct tcs_mbox_msg *msg, int m, int err)
 {
-	trace_rpmh_notify(m, msg->payload[0].addr, err);
+	struct tcs_drv *drv = container_of(chan->mbox, struct tcs_drv, mbox);
+
+	trace_rpmh_notify(drv->name, m, msg->payload[0].addr, err);
 	mbox_chan_txdone(chan, err);
 }
 
@@ -467,15 +474,16 @@
 	mbox_notify_tx_done(chan, msg, -1, err);
 }
 
-static void __tcs_buffer_write(void __iomem *base, int d, int m, int n,
+static void __tcs_buffer_write(struct tcs_drv *drv, int d, int m, int n,
 			struct tcs_mbox_msg *msg, bool trigger)
 {
-	u32 cmd_msgid = 0;
+	u32 msgid, cmd_msgid = 0;
 	u32 cmd_enable = 0;
 	u32 cmd_complete;
 	u32 enable = TCS_AMC_MODE_ENABLE;
 	struct tcs_cmd *cmd;
 	int i;
+	void __iomem *base = drv->reg_base;
 
 	/* We have homologous command set i.e pure read or write, not a mix */
 	cmd_msgid = CMD_MSGID_LEN;
@@ -489,11 +497,13 @@
 		cmd = &msg->payload[i];
 		cmd_enable |= BIT(n + i);
 		cmd_complete |= cmd->complete << (n + i);
-		write_tcs_reg(base, TCS_DRV_CMD_MSGID, m, n + i, cmd_msgid);
+		msgid = cmd_msgid;
+		msgid |= (cmd->complete) ? CMD_MSGID_RESP_REQ : 0;
+		write_tcs_reg(base, TCS_DRV_CMD_MSGID, m, n + i, msgid);
 		write_tcs_reg(base, TCS_DRV_CMD_ADDR, m, n + i, cmd->addr);
 		write_tcs_reg(base, TCS_DRV_CMD_DATA, m, n + i, cmd->data);
-		trace_rpmh_send_msg(base, m, n + i,
-				cmd_msgid, cmd->addr, cmd->data, cmd->complete);
+		trace_rpmh_send_msg(drv->name, m, n + i, msgid, cmd->addr,
+					cmd->data, cmd->complete, trigger);
 	}
 
 	/* Write the send-after-prev completion bits for the batch */
@@ -716,7 +726,7 @@
 	}
 
 	/* Write to the TCS or AMC */
-	__tcs_buffer_write(drv->reg_base, d, m, n, msg, trigger);
+	__tcs_buffer_write(drv, d, m, n, msg, trigger);
 
 	/* Schedule a timeout response, incase there is no actual response */
 	if (trigger)
@@ -727,6 +737,41 @@
 	return 0;
 }
 
+static void __tcs_buffer_invalidate(void __iomem *base, int m)
+{
+	write_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0, 0);
+}
+
+static int tcs_mbox_invalidate(struct mbox_chan *chan)
+{
+	struct tcs_drv *drv = container_of(chan->mbox, struct tcs_drv, mbox);
+	struct tcs_mbox *tcs;
+	int m, i;
+	int inv_types[] = { WAKE_TCS, SLEEP_TCS };
+	int type = 0;
+
+	do {
+		tcs = get_tcs_of_type(drv, inv_types[type]);
+		if (IS_ERR(tcs))
+			return PTR_ERR(tcs);
+
+		spin_lock(&tcs->tcs_lock);
+		for (i = 0; i < tcs->num_tcs; i++) {
+			m = i + tcs->tcs_offset;
+			spin_lock(&tcs->tcs_m_lock[i]);
+			while (!tcs_is_free(drv->reg_base, m))
+				cpu_relax();
+			__tcs_buffer_invalidate(drv->reg_base, m);
+			spin_unlock(&tcs->tcs_m_lock[i]);
+		}
+		/* Mark the TCS as free */
+		bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
+		spin_unlock(&tcs->tcs_lock);
+	} while (++type < ARRAY_SIZE(inv_types));
+
+	return 0;
+}
+
 /**
  * chan_tcs_write: Validate the incoming message and write to the
  * appropriate TCS block.
@@ -771,6 +816,13 @@
 		goto tx_fail;
 	}
 
+	/*
+	 * Since we are re-purposing the wake TCS, invalidate previous
+	 * contents to avoid confusion.
+	 */
+	if (msg->state == RPMH_AWAKE_STATE)
+		tcs_mbox_invalidate(chan);
+
 	/* Post the message to the TCS and trigger */
 	ret = tcs_mbox_write(chan, msg, true);
 
@@ -791,50 +843,16 @@
 	return 0;
 }
 
-static void __tcs_buffer_invalidate(void __iomem *base, int m)
-{
-	write_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0, 0);
-}
-
-static int tcs_mbox_invalidate(struct mbox_chan *chan)
-{
-	struct tcs_drv *drv = container_of(chan->mbox, struct tcs_drv, mbox);
-	struct tcs_mbox *tcs;
-	int m, i;
-	int inv_types[] = { WAKE_TCS, SLEEP_TCS };
-	int type = 0;
-
-	do {
-		tcs = get_tcs_of_type(drv, inv_types[type]);
-		if (IS_ERR(tcs))
-			return PTR_ERR(tcs);
-
-		spin_lock(&tcs->tcs_lock);
-		for (i = 0; i < tcs->num_tcs; i++) {
-			m = i + tcs->tcs_offset;
-			spin_lock(&tcs->tcs_m_lock[i]);
-			while (!tcs_is_free(drv->reg_base, m))
-				cpu_relax();
-			__tcs_buffer_invalidate(drv->reg_base, m);
-			spin_unlock(&tcs->tcs_m_lock[i]);
-		}
-		/* Mark the TCS as free */
-		bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
-		spin_unlock(&tcs->tcs_lock);
-	} while (++type < ARRAY_SIZE(inv_types));
-
-	return 0;
-}
-
-static void __tcs_write_hidden(void *base, int d, struct tcs_mbox_msg *msg)
+static void __tcs_write_hidden(struct tcs_drv *drv, int d,
+					struct tcs_mbox_msg *msg)
 {
 	int i;
-	void __iomem *addr = base + TCS_HIDDEN_CMD0_DRV_DATA;
+	void __iomem *addr = drv->base + TCS_HIDDEN_CMD0_DRV_DATA;
 
 	for (i = 0; i < msg->num_payload; i++) {
 		/* Only data is write capable */
 		writel_relaxed(cpu_to_le32(msg->payload[i].data), addr);
-		trace_rpmh_control_msg(addr, msg->payload[i].data);
+		trace_rpmh_control_msg(drv->name, msg->payload[i].data);
 		addr += TCS_HIDDEN_CMD_SHIFT;
 	}
 }
@@ -855,7 +873,7 @@
 	}
 
 	spin_lock(&tcs->tcs_lock);
-	__tcs_write_hidden(tcs->drv->base, drv->drv_id, msg);
+	__tcs_write_hidden(tcs->drv, drv->drv_id, msg);
 	spin_unlock(&tcs->tcs_lock);
 
 	return 0;
@@ -949,6 +967,7 @@
 	u32 config, max_tcs, ncpt;
 	int tcs_type_count[TCS_TYPE_NR] = { 0 };
 	struct resource *res;
+	u32 irq_mask;
 
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
@@ -1073,6 +1092,10 @@
 	drv->num_tcs = st;
 	drv->pdev = pdev;
 
+	drv->name = of_get_property(pdev->dev.of_node, "label", NULL);
+	if (!drv->name)
+		drv->name = dev_name(&pdev->dev);
+
 	ret = tcs_response_pool_init(drv);
 	if (ret)
 		return ret;
@@ -1088,9 +1111,14 @@
 	if (ret)
 		return ret;
 
-	/* Enable interrupts for AMC TCS */
-	write_tcs_reg(drv->reg_base, TCS_DRV_IRQ_ENABLE, 0, 0,
-					drv->tcs[ACTIVE_TCS].tcs_mask);
+	/*
+	 * Enable interrupts for AMC TCS,
+	 * if there are no AMC TCS, use wake TCS.
+	 */
+	irq_mask = (drv->tcs[ACTIVE_TCS].num_tcs) ?
+				drv->tcs[ACTIVE_TCS].tcs_mask :
+				drv->tcs[WAKE_TCS].tcs_mask;
+	write_tcs_reg(drv->reg_base, TCS_DRV_IRQ_ENABLE, 0, 0, irq_mask);
 
 	ret = mbox_controller_register(&drv->mbox);
 	if (ret)
diff --git a/drivers/media/platform/msm/camera/Makefile b/drivers/media/platform/msm/camera/Makefile
index faba819..c897669 100644
--- a/drivers/media/platform/msm/camera/Makefile
+++ b/drivers/media/platform/msm/camera/Makefile
@@ -1,5 +1,4 @@
-ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
-
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr/
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_utils/
-
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_core/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync/
diff --git a/drivers/media/platform/msm/camera/cam_core/Makefile b/drivers/media/platform/msm/camera/cam_core/Makefile
new file mode 100644
index 0000000..417de13
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/Makefile
@@ -0,0 +1,3 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_context.o cam_node.o cam_subdev.o
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.c b/drivers/media/platform/msm/camera/cam_core/cam_context.c
new file mode 100644
index 0000000..56b34f5
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.c
@@ -0,0 +1,361 @@
+/* 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 <linux/slab.h>
+#include <linux/uaccess.h>
+#include "cam_context.h"
+
+static int cam_context_handle_hw_event(void *context, uint32_t evt_id,
+	void *evt_data)
+{
+	int rc = 0;
+	struct cam_context *ctx = (struct cam_context *)context;
+
+	if (!ctx || !ctx->state_machine) {
+		pr_err("%s: Context is not ready.\n", __func__);
+		return -EINVAL;
+	}
+
+	if (ctx->state_machine[ctx->state].irq_ops)
+		rc = ctx->state_machine[ctx->state].irq_ops(ctx, evt_id,
+			evt_data);
+	else
+		pr_debug("%s: No function to handle event %d in dev %d, state %d\n",
+				__func__, evt_id, ctx->dev_hdl, ctx->state);
+	return rc;
+}
+
+int cam_context_handle_get_dev_info(struct cam_context *ctx,
+	struct cam_req_mgr_device_info *info)
+{
+	int rc;
+
+	if (!ctx->state_machine) {
+		pr_err("%s: Context is not ready.\n'", __func__);
+		return -EINVAL;
+	}
+
+	if (!info) {
+		pr_err("%s: Invalid get device info payload.\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->ctx_mutex);
+	if (ctx->state_machine[ctx->state].crm_ops.get_dev_info) {
+		rc = ctx->state_machine[ctx->state].crm_ops.get_dev_info(
+			ctx, info);
+	} else {
+		pr_err("%s: No get device info in dev %d, state %d\n",
+			__func__, ctx->dev_hdl, ctx->state);
+		rc = -EPROTO;
+	}
+	mutex_unlock(&ctx->ctx_mutex);
+
+	return rc;
+}
+
+int cam_context_handle_link(struct cam_context *ctx,
+	struct cam_req_mgr_core_dev_link_setup *link)
+{
+	int rc;
+
+	if (!ctx->state_machine) {
+		pr_err("%s: Context is not ready.\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!link) {
+		pr_err("%s: Invalid link payload.\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->ctx_mutex);
+	if (ctx->state_machine[ctx->state].crm_ops.link) {
+		rc = ctx->state_machine[ctx->state].crm_ops.link(ctx, link);
+	} else {
+		pr_err("%s: No crm link in dev %d, state %d\n", __func__,
+			ctx->dev_hdl, ctx->state);
+		rc = -EPROTO;
+	}
+	mutex_unlock(&ctx->ctx_mutex);
+
+	return rc;
+}
+
+int cam_context_handle_unlink(struct cam_context *ctx,
+	struct cam_req_mgr_core_dev_link_setup *unlink)
+{
+	int rc;
+
+	if (!ctx->state_machine) {
+		pr_err("%s: Context is not ready!\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!unlink) {
+		pr_err("%s: Invalid unlink payload.\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->ctx_mutex);
+	if (ctx->state_machine[ctx->state].crm_ops.unlink) {
+		rc = ctx->state_machine[ctx->state].crm_ops.unlink(
+			ctx, unlink);
+	} else {
+		pr_err("%s: No crm unlink in dev %d, state %d\n",
+			__func__, ctx->dev_hdl, ctx->state);
+		rc = -EPROTO;
+	}
+	mutex_unlock(&ctx->ctx_mutex);
+
+	return rc;
+}
+
+int cam_context_handle_apply_req(struct cam_context *ctx,
+	struct cam_req_mgr_apply_request *apply)
+{
+	int rc;
+
+	if (!ctx->state_machine) {
+		pr_err("%s: Context is not ready.\n'", __func__);
+		return -EINVAL;
+	}
+
+	if (!apply) {
+		pr_err("%s: Invalid apply request payload.\n'", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->ctx_mutex);
+	if (ctx->state_machine[ctx->state].crm_ops.apply_req) {
+		rc = ctx->state_machine[ctx->state].crm_ops.apply_req(ctx,
+			apply);
+	} else {
+		pr_err("%s: No crm apply req in dev %d, state %d\n",
+			__func__, ctx->dev_hdl, ctx->state);
+		rc = -EPROTO;
+	}
+	mutex_unlock(&ctx->ctx_mutex);
+
+	return rc;
+}
+
+
+int cam_context_handle_acquire_dev(struct cam_context *ctx,
+	struct cam_acquire_dev_cmd *cmd)
+{
+	int rc;
+
+	if (!ctx->state_machine) {
+		pr_err("%s: Context is not ready.\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!cmd) {
+		pr_err("%s: Invalid acquire device command payload.\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->ctx_mutex);
+	if (ctx->state_machine[ctx->state].ioctl_ops.acquire_dev) {
+		rc = ctx->state_machine[ctx->state].ioctl_ops.acquire_dev(
+			ctx, cmd);
+	} else {
+		pr_err("%s: No acquire device in dev %d, state %d\n",
+			__func__, cmd->dev_handle, ctx->state);
+		rc = -EPROTO;
+	}
+	mutex_unlock(&ctx->ctx_mutex);
+
+	return rc;
+}
+
+int cam_context_handle_release_dev(struct cam_context *ctx,
+	struct cam_release_dev_cmd *cmd)
+{
+	int rc;
+
+	if (!ctx->state_machine) {
+		pr_err("%s: Context is not ready.\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!cmd) {
+		pr_err("%s: Invalid release device command payload.\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->ctx_mutex);
+	if (ctx->state_machine[ctx->state].ioctl_ops.release_dev) {
+		rc = ctx->state_machine[ctx->state].ioctl_ops.release_dev(
+			ctx, cmd);
+	} else {
+		pr_err("%s: No release device in dev %d, state %d\n",
+			__func__, ctx->dev_hdl, ctx->state);
+		rc = -EPROTO;
+	}
+	mutex_unlock(&ctx->ctx_mutex);
+
+	return rc;
+}
+
+int cam_context_handle_config_dev(struct cam_context *ctx,
+	struct cam_config_dev_cmd *cmd)
+{
+	int rc;
+
+	if (!ctx->state_machine) {
+		pr_err("%s: context is not ready\n'", __func__);
+		return -EINVAL;
+	}
+
+	if (!cmd) {
+		pr_err("%s: Invalid config device command payload.\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->ctx_mutex);
+	if (ctx->state_machine[ctx->state].ioctl_ops.config_dev) {
+		rc = ctx->state_machine[ctx->state].ioctl_ops.config_dev(
+			ctx, cmd);
+	} else {
+		pr_err("%s: No config device in dev %d, state %d\n",
+			__func__, ctx->dev_hdl, ctx->state);
+		rc = -EPROTO;
+	}
+	mutex_unlock(&ctx->ctx_mutex);
+
+	return rc;
+}
+
+int cam_context_handle_start_dev(struct cam_context *ctx,
+	struct cam_start_stop_dev_cmd *cmd)
+{
+	int rc = 0;
+
+	if (!ctx->state_machine) {
+		pr_err("%s: Context is not ready.\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!cmd) {
+		pr_err("%s: Invalid start device command payload.\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->ctx_mutex);
+	if (ctx->state_machine[ctx->state].ioctl_ops.start_dev)
+		rc = ctx->state_machine[ctx->state].ioctl_ops.start_dev(
+			ctx, cmd);
+	else
+		/* start device can be optional for some driver */
+		pr_debug("%s: No start device in dev %d, state %d\n",
+			__func__, ctx->dev_hdl, ctx->state);
+
+	mutex_unlock(&ctx->ctx_mutex);
+
+	return rc;
+}
+
+int cam_context_handle_stop_dev(struct cam_context *ctx,
+	struct cam_start_stop_dev_cmd *cmd)
+{
+	int rc = 0;
+
+	if (!ctx->state_machine) {
+		pr_err("%s: Context is not ready.\n'", __func__);
+		return -EINVAL;
+	}
+
+	if (!cmd) {
+		pr_err("%s: Invalid stop device command payload.\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->ctx_mutex);
+	if (ctx->state_machine[ctx->state].ioctl_ops.stop_dev)
+		rc = ctx->state_machine[ctx->state].ioctl_ops.stop_dev(
+			ctx, cmd);
+	else
+		/* stop device can be optional for some driver */
+		pr_warn("%s: No stop device in dev %d, state %d\n",
+			__func__, ctx->dev_hdl, ctx->state);
+	mutex_unlock(&ctx->ctx_mutex);
+
+	return rc;
+}
+
+int cam_context_init(struct cam_context *ctx,
+	struct cam_req_mgr_kmd_ops *crm_node_intf,
+	struct cam_hw_mgr_intf *hw_mgr_intf,
+	struct cam_ctx_request *req_list,
+	uint32_t req_size)
+{
+	int i;
+
+	/* crm_node_intf is optinal */
+	if (!ctx || !hw_mgr_intf || !req_list) {
+		pr_err("%s: Invalid input parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	memset(ctx, 0, sizeof(*ctx));
+
+	INIT_LIST_HEAD(&ctx->list);
+	mutex_init(&ctx->ctx_mutex);
+	spin_lock_init(&ctx->lock);
+
+	ctx->ctx_crm_intf = NULL;
+	ctx->crm_ctx_intf = crm_node_intf;
+	ctx->hw_mgr_intf = hw_mgr_intf;
+	ctx->irq_cb_intf = cam_context_handle_hw_event;
+
+	INIT_LIST_HEAD(&ctx->active_req_list);
+	INIT_LIST_HEAD(&ctx->wait_req_list);
+	INIT_LIST_HEAD(&ctx->pending_req_list);
+	INIT_LIST_HEAD(&ctx->free_req_list);
+	ctx->req_list = req_list;
+	ctx->req_size = req_size;
+	for (i = 0; i < req_size; i++) {
+		INIT_LIST_HEAD(&ctx->req_list[i].list);
+		list_add_tail(&ctx->req_list[i].list, &ctx->free_req_list);
+	}
+	ctx->state = CAM_CTX_AVAILABLE;
+	ctx->state_machine = NULL;
+	ctx->ctx_priv = NULL;
+
+	return 0;
+}
+
+int cam_context_deinit(struct cam_context *ctx)
+{
+	if (!ctx)
+		return -EINVAL;
+
+	/**
+	 * This is called from platform device remove.
+	 * Everyting should be released at this moment.
+	 * so we just free the memory for the context
+	 */
+	if (ctx->state != CAM_CTX_AVAILABLE)
+		pr_err("%s: Device did not shutdown cleanly.\n", __func__);
+
+	memset(ctx, 0, sizeof(*ctx));
+
+	return 0;
+}
+
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.h b/drivers/media/platform/msm/camera/cam_core/cam_context.h
new file mode 100644
index 0000000..c7329cf
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.h
@@ -0,0 +1,302 @@
+/* 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.
+ */
+
+#ifndef _CAM_CONTEXT_H_
+#define _CAM_CONTEXT_H_
+
+#include <linux/spinlock.h>
+#include "cam_req_mgr_interface.h"
+#include "cam_hw_mgr_intf.h"
+
+/* Forward declarations */
+struct cam_context;
+
+/* max request number */
+#define CAM_CTX_REQ_MAX              20
+
+/**
+ * enum cam_ctx_state -  context top level states
+ *
+ */
+enum cam_context_state {
+	CAM_CTX_UNINIT               = 0,
+	CAM_CTX_AVAILABLE            = 1,
+	CAM_CTX_ACQUIRED             = 2,
+	CAM_CTX_READY                = 3,
+	CAM_CTX_ACTIVATED            = 4,
+	CAM_CTX_STATE_MAX            = 5,
+};
+
+/**
+ * struct cam_ctx_request - Common request structure for the context
+ *
+ * @list:                  Link list entry
+ * @status:                Request status
+ * @request_id:            Request id
+ * @req_priv:              Derived request object
+ *
+ */
+struct cam_ctx_request {
+	struct list_head   list;
+	uint32_t           status;
+	uint64_t           request_id;
+	void              *req_priv;
+};
+
+/**
+ * struct cam_ctx_ioctl_ops - Function table for handling IOCTL calls
+ *
+ * @acquire_dev:           Function pointer for acquire device
+ * @release_dev:           Function pointer for release device
+ * @config_dev:            Function pointer for config device
+ * @start_dev:             Function pointer for start device
+ * @stop_dev:              Function pointer for stop device
+ *
+ */
+struct cam_ctx_ioctl_ops {
+	int (*acquire_dev)(struct cam_context *ctx,
+			struct cam_acquire_dev_cmd *cmd);
+	int (*release_dev)(struct cam_context *ctx,
+			struct cam_release_dev_cmd *cmd);
+	int (*config_dev)(struct cam_context *ctx,
+			struct cam_config_dev_cmd *cmd);
+	int (*start_dev)(struct cam_context *ctx,
+			struct cam_start_stop_dev_cmd *cmd);
+	int (*stop_dev)(struct cam_context *ctx,
+			struct cam_start_stop_dev_cmd *cmd);
+};
+
+/**
+ * struct cam_ctx_crm_ops -  Function table for handling CRM to context calls
+ *
+ * @get_dev_info:          Get device informaiton
+ * @link:                  Link the context
+ * @unlink:                Unlink the context
+ * @apply_req:             Apply setting for the context
+ *
+ */
+struct cam_ctx_crm_ops {
+	int (*get_dev_info)(struct cam_context *ctx,
+			struct cam_req_mgr_device_info *);
+	int (*link)(struct cam_context *ctx,
+			struct cam_req_mgr_core_dev_link_setup *link);
+	int (*unlink)(struct cam_context *ctx,
+			struct cam_req_mgr_core_dev_link_setup *unlink);
+	int (*apply_req)(struct cam_context *ctx,
+			struct cam_req_mgr_apply_request *apply);
+};
+
+
+/**
+ * struct cam_ctx_ops - Collection of the interface funciton tables
+ *
+ * @ioctl_ops:             Ioctl funciton table
+ * @crm_ops:               CRM to context interface function table
+ * @irq_ops:               Hardware event handle function
+ *
+ */
+struct cam_ctx_ops {
+	struct cam_ctx_ioctl_ops     ioctl_ops;
+	struct cam_ctx_crm_ops       crm_ops;
+	cam_hw_event_cb_func         irq_ops;
+};
+
+/**
+ * struct cam_context - camera context object for the subdevice node
+ *
+ * @list:                  Link list entry
+ * @sessoin_hdl:           Session handle
+ * @dev_hdl:               Device handle
+ * @link_hdl:              Link handle
+ * @ctx_mutex:             Mutex for ioctl calls
+ * @lock:                  Spin lock
+ * @active_req_list:       Requests pending for done event
+ * @pending_req_list:      Requests pending for reg upd event
+ * @wait_req_list:         Requests waiting for apply
+ * @free_req_list:         Requests that are free
+ * @req_list:              Reference to the request storage
+ * @req_size:              Size of the request storage
+ * @hw_mgr_intf:           Context to HW interface
+ * @ctx_crm_intf:          Context to CRM interface
+ * @crm_ctx_intf:          CRM to context interface
+ * @irq_cb_intf:           HW to context callback interface
+ * @state:                 Current state for top level state machine
+ * @state_machine:         Top level state machine
+ * @ctx_priv:              Private context pointer
+ *
+ */
+struct cam_context {
+	struct list_head             list;
+	int32_t                      session_hdl;
+	int32_t                      dev_hdl;
+	int32_t                      link_hdl;
+
+	struct mutex                 ctx_mutex;
+	spinlock_t                   lock;
+
+	struct list_head             active_req_list;
+	struct list_head             pending_req_list;
+	struct list_head             wait_req_list;
+	struct list_head             free_req_list;
+	struct cam_ctx_request      *req_list;
+	uint32_t                     req_size;
+
+	struct cam_hw_mgr_intf      *hw_mgr_intf;
+	struct cam_req_mgr_crm_cb   *ctx_crm_intf;
+	struct cam_req_mgr_kmd_ops  *crm_ctx_intf;
+	cam_hw_event_cb_func         irq_cb_intf;
+
+	enum cam_context_state       state;
+	struct cam_ctx_ops          *state_machine;
+
+	void                        *ctx_priv;
+};
+
+/**
+ * cam_context_handle_get_dev_info()
+ *
+ * @brief:        Handle get device information command
+ *
+ * @ctx:                   Object pointer for cam_context
+ * @info:                  Device information returned
+ *
+ */
+int cam_context_handle_get_dev_info(struct cam_context *ctx,
+		struct cam_req_mgr_device_info *info);
+
+/**
+ * cam_context_handle_link()
+ *
+ * @brief:        Handle link command
+ *
+ * @ctx:                   Object pointer for cam_context
+ * @link:                  Link command payload
+ *
+ */
+int cam_context_handle_link(struct cam_context *ctx,
+		struct cam_req_mgr_core_dev_link_setup *link);
+
+/**
+ * cam_context_handle_unlink()
+ *
+ * @brief:        Handle unlink command
+ *
+ * @ctx:                   Object pointer for cam_context
+ * @unlink:                Unlink command payload
+ *
+ */
+int cam_context_handle_unlink(struct cam_context *ctx,
+		struct cam_req_mgr_core_dev_link_setup *unlink);
+
+/**
+ * cam_context_handle_apply_req()
+ *
+ * @brief:        Handle apply request command
+ *
+ * @ctx:                   Object pointer for cam_context
+ * @apply:                 Apply request command payload
+ *
+ */
+int cam_context_handle_apply_req(struct cam_context *ctx,
+		struct cam_req_mgr_apply_request *apply);
+
+
+/**
+ * cam_context_handle_acquire_dev()
+ *
+ * @brief:        Handle acquire device command
+ *
+ * @ctx:                   Object pointer for cam_context
+ * @cmd:                   Acquire device command payload
+ *
+ */
+int cam_context_handle_acquire_dev(struct cam_context *ctx,
+		struct cam_acquire_dev_cmd *cmd);
+
+/**
+ * cam_context_handle_release_dev()
+ *
+ * @brief:        Handle release device command
+ *
+ * @ctx:                   Object pointer for cam_context
+ * @cmd:                   Release device command payload
+ *
+ */
+int cam_context_handle_release_dev(struct cam_context *ctx,
+		struct cam_release_dev_cmd *cmd);
+
+/**
+ * cam_context_handle_config_dev()
+ *
+ * @brief:        Handle config device command
+ *
+ * @ctx:                   Object pointer for cam_context
+ * @cmd:                   Config device command payload
+ *
+ */
+int cam_context_handle_config_dev(struct cam_context *ctx,
+		struct cam_config_dev_cmd *cmd);
+
+/**
+ * cam_context_handle_start_dev()
+ *
+ * @brief:        Handle start device command
+ *
+ * @ctx:                   Object pointer for cam_context
+ * @cmd:                   Start device command payload
+ *
+ */
+int cam_context_handle_start_dev(struct cam_context *ctx,
+		struct cam_start_stop_dev_cmd *cmd);
+
+/**
+ * cam_context_handle_stop_dev()
+ *
+ * @brief:        Handle stop device command
+ *
+ * @ctx:                   Object pointer for cam_context
+ * @cmd:                   Stop device command payload
+ *
+ */
+int cam_context_handle_stop_dev(struct cam_context *ctx,
+		struct cam_start_stop_dev_cmd *cmd);
+
+/**
+ * cam_context_deinit()
+ *
+ * @brief:        Camera context deinitialize function
+ *
+ * @ctx:                   Object pointer for cam_context
+ *
+ */
+int cam_context_deinit(struct cam_context *ctx);
+
+/**
+ * cam_context_init()
+ *
+ * @brief:        Camera context initialize function
+ *
+ * @ctx:                   Object pointer for cam_context
+ * @crm_node_intf:         Function table for crm to context interface
+ * @hw_mgr_intf:           Function table for context to hw interface
+ * @req_list:              Requests storage
+ * @req_size:              Size of the request storage
+ *
+ */
+int cam_context_init(struct cam_context *ctx,
+		struct cam_req_mgr_kmd_ops *crm_node_intf,
+		struct cam_hw_mgr_intf *hw_mgr_intf,
+		struct cam_ctx_request *req_list,
+		uint32_t req_size);
+
+
+#endif  /* _CAM_CONTEXT_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_hw.h b/drivers/media/platform/msm/camera/cam_core/cam_hw.h
new file mode 100644
index 0000000..d01a84a
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_hw.h
@@ -0,0 +1,53 @@
+/* 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.
+ */
+
+#ifndef _CAM_HW_H_
+#define _CAM_HW_H_
+
+#include "cam_soc_util.h"
+
+/*
+ * This file declares Enums, Structures and APIs to be used as template
+ * when writing any HW driver in the camera subsystem.
+ */
+
+/* Hardware state enum */
+enum cam_hw_state {
+	CAM_HW_STATE_POWER_DOWN,
+	CAM_HW_STATE_POWER_UP,
+};
+
+/**
+ * struct cam_hw_info - Common hardware information
+ *
+ * @hw_mutex:              Hardware mutex
+ * @hw_lock:               Hardware spinlock
+ * @hw_complete:           Hardware Completion
+ * @open_count:            Count to track the HW enable from the client
+ * @hw_state:              Hardware state
+ * @soc_info:              Platform SOC properties for hardware
+ * @node_info:             Private HW data related to nodes
+ * @core_info:             Private HW data related to core logic
+ *
+ */
+struct cam_hw_info {
+	struct mutex                    hw_mutex;
+	spinlock_t                      hw_lock;
+	struct completion               hw_complete;
+	uint32_t                        open_count;
+	enum cam_hw_state               hw_state;
+	struct cam_hw_soc_info          soc_info;
+	void                           *node_info;
+	void                           *core_info;
+};
+
+#endif /* _CAM_HW_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_hw_intf.h b/drivers/media/platform/msm/camera/cam_core/cam_hw_intf.h
new file mode 100644
index 0000000..3a997ae
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_hw_intf.h
@@ -0,0 +1,80 @@
+/* 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.
+ */
+
+#ifndef _CAM_HW_INTF_H_
+#define _CAM_HW_INTF_H_
+
+#include <linux/types.h>
+
+/*
+ * This file declares Constants, Enums, Structures and APIs to be used as
+ * Interface between HW driver and HW Manager.
+ */
+
+/**
+ * struct cam_hw_ops - Hardware layer interface functions
+ *
+ * @get_hw_caps:           Function pointer for get hw caps
+ * @init:                  Function poniter for initialize hardware
+ * @deinit:                Function pointer for deinitialize hardware
+ * @reset:                 Function pointer for reset hardware
+ * @reserve:               Function pointer for reserve hardware
+ * @release:               Function pointer for release hardware
+ * @start:                 Function pointer for start hardware
+ * @stop:                  Function pointer for stop hardware
+ * @read:                  Function pointer for read hardware registers
+ * @write:                 Function pointer for Write hardware registers
+ * @process_cmd:           Function pointer for additional hardware controls
+ *
+ */
+struct cam_hw_ops {
+	int (*get_hw_caps)(void *hw_priv,
+		void *get_hw_cap_args, uint32_t arg_size);
+	int (*init)(void *hw_priv,
+		void *init_hw_args, uint32_t arg_size);
+	int (*deinit)(void *hw_priv,
+		void *init_hw_args, uint32_t arg_size);
+	int (*reset)(void *hw_priv,
+		void *reset_core_args, uint32_t arg_size);
+	int (*reserve)(void *hw_priv,
+		void *reserve_args, uint32_t arg_size);
+	int (*release)(void *hw_priv,
+		void *release_args, uint32_t arg_size);
+	int (*start)(void *hw_priv,
+		void *start_args, uint32_t arg_size);
+	int (*stop)(void *hw_priv,
+		void *stop_args, uint32_t arg_size);
+	int (*read)(void *hw_priv,
+		void *read_args, uint32_t arg_size);
+	int (*write)(void *hw_priv,
+		void *write_args, uint32_t arg_size);
+	int (*process_cmd)(void *hw_priv,
+		uint32_t cmd_type, void *cmd_args, uint32_t arg_size);
+};
+
+/**
+ * struct cam_hw_intf - Common hardware node
+ *
+ * @hw_type:               Hardware type
+ * @hw_idx:                Hardware ID
+ * @hw_ops:                Hardware interface function table
+ * @hw_priv:               Private hardware node pointer
+ *
+ */
+struct cam_hw_intf {
+	uint32_t                     hw_type;
+	uint32_t                     hw_idx;
+	struct cam_hw_ops            hw_ops;
+	void                        *hw_priv;
+};
+
+#endif /* _CAM_HW_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
new file mode 100644
index 0000000..db605e7
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
@@ -0,0 +1,209 @@
+/* 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.
+ */
+
+#ifndef _CAM_HW_MGR_INTF_H_
+#define _CAM_HW_MGR_INTF_H_
+
+/*
+ * This file declares Constants, Enums, Structures and APIs to be used as
+ * Interface between HW Manager and Context.
+ */
+
+
+/* maximum context numbers */
+#define CAM_CTX_MAX                         8
+
+/* maximum buf done irqs */
+#define CAM_NUM_OUT_PER_COMP_IRQ_MAX        12
+
+/* hardware event callback function type */
+typedef int (*cam_hw_event_cb_func)(void *context, uint32_t evt_id,
+	void *evt_data);
+
+/**
+ * struct cam_hw_update_entry - Entry for hardware config
+ *
+ * @handle:                Memory handle for the configuration
+ * @offset:                Memory offset
+ * @len:                   Size of the configuration
+ * @flags:                 Flags for the config entry(eg. DMI)
+ *
+ */
+struct cam_hw_update_entry {
+	int                handle;
+	uint32_t           offset;
+	uint32_t           len;
+	uint32_t           flags;
+};
+
+/**
+ * struct cam_hw_fence_map_entry - Entry for the resource to sync id map
+ *
+ * @resrouce_handle:       Resource port id for the buffer
+ * @sync_id:               Synce id
+ *
+ */
+struct cam_hw_fence_map_entry {
+	uint32_t           resource_handle;
+	int32_t            sync_id;
+};
+
+/**
+ * struct cam_hw_done_event_data - Payload for hw done event
+ *
+ * @num_handles:           number of handles in the event
+ * @resrouce_handle:       list of the resource handle
+ * @timestamp:             time stamp
+ *
+ */
+struct cam_hw_done_event_data {
+	uint32_t           num_handles;
+	uint32_t           resource_handle[CAM_NUM_OUT_PER_COMP_IRQ_MAX];
+	struct timeval     timestamp;
+};
+
+/**
+ * struct cam_hw_acquire_args - Payload for acquire command
+ *
+ * @context_data:          Context data pointer for the callback function
+ * @event_cb:              Callback function array
+ * @num_acq:               Total number of acquire in the payload
+ * @acquire_info:          Acquired resource array pointer
+ * @ctxt_to_hw_map:        HW context (returned)
+ *
+ */
+struct cam_hw_acquire_args {
+	void                        *context_data;
+	cam_hw_event_cb_func         event_cb;
+	uint32_t                     num_acq;
+	uint64_t                     acquire_info;
+	void                        *ctxt_to_hw_map;
+};
+
+/**
+ * struct cam_hw_release_args - Payload for release command
+ *
+ * @ctxt_to_hw_map:        HW context from the acquire
+ *
+ */
+struct cam_hw_release_args {
+	void              *ctxt_to_hw_map;
+};
+
+/**
+ * struct cam_hw_start_args - Payload for start command
+ *
+ * @ctxt_to_hw_map:        HW context from the acquire
+ * @num_hw_update_entries: Number of Hardware configuration
+ * @hw_update_entries:     Hardware configuration list
+ *
+ */
+struct cam_hw_start_args {
+	void                        *ctxt_to_hw_map;
+	uint32_t                     num_hw_update_entries;
+	struct cam_hw_update_entry  *hw_update_entries;
+};
+
+/**
+ * struct cam_hw_stop_args - Payload for stop command
+ *
+ * @ctxt_to_hw_map:        HW context from the acquire
+ *
+ */
+struct cam_hw_stop_args {
+	void              *ctxt_to_hw_map;
+};
+
+/**
+ * struct cam_hw_prepare_update_args - Payload for prepare command
+ *
+ * @packet:                CSL packet from user mode driver
+ * @ctxt_to_hw_map:        HW context from the acquire
+ * @max_hw_update_entries: Maximum hardware update entries supported
+ * @hw_update_entries:     Actual hardware update configuration (returned)
+ * @num_hw_update_entries: Number of actual hardware update entries (returned)
+ * @max_out_map_entries:   Maximum output fence mapping supported
+ * @out_map_entries:       Actual output fence mapping list (returned)
+ * @num_out_map_entries:   Number of actual output fence mapping (returned)
+ * @max_in_map_entries:    Maximum input fence mapping supported
+ * @in_map_entries:        Actual input fence mapping list (returned)
+ * @num_in_map_entries:    Number of acutal input fence mapping (returned)
+ *
+ */
+struct cam_hw_prepare_update_args {
+	struct cam_packet              *packet;
+	void                           *ctxt_to_hw_map;
+	uint32_t                        max_hw_update_entries;
+	struct cam_hw_update_entry     *hw_update_entries;
+	uint32_t                        num_hw_update_entries;
+	uint32_t                        max_out_map_entries;
+	struct cam_hw_fence_map_entry  *out_map_entries;
+	uint32_t                        num_out_map_entries;
+	uint32_t                        max_in_map_entries;
+	struct cam_hw_fence_map_entry  *in_map_entries;
+	uint32_t                        num_in_map_entries;
+};
+
+/**
+ * struct cam_hw_config_args - Payload for config command
+ *
+ * @ctxt_to_hw_map:        HW context from the acquire
+ * @num_hw_update_entries: Number of hardware update entries
+ * @hw_update_entries:     Hardware update list
+ *
+ */
+struct cam_hw_config_args {
+	void                        *ctxt_to_hw_map;
+	uint32_t                     num_hw_update_entries;
+	struct cam_hw_update_entry  *hw_update_entries;
+};
+
+/**
+ * cam_hw_mgr_intf - HW manager interface
+ *
+ * @hw_mgr_priv:           HW manager object
+ * @hw_get_caps:           Function pointer for get hw caps
+ *                               args = cam_query_cap_cmd
+ * @hw_acquire:            Function poniter for acquire hw resources
+ *                               args = cam_hw_acquire_args
+ * @hw_release:            Function pointer for release hw device resource
+ *                               args = cam_hw_release_args
+ * @hw_start:              Function pointer for start hw devices
+ *                               args = cam_hw_start_args
+ * @hw_stop:               Function pointer for stop hw devices
+ *                               args = cam_hw_stop_args
+ * @hw_prepare_update:     Function pointer for prepare hw update for hw devices
+ *                               args = cam_hw_prepare_update_args
+ * @hw_config:             Function pointer for configure hw devices
+ *                               args = cam_hw_config_args
+ * @hw_read:               Function pointer for read hardware registers
+ * @hw_write:              Function pointer for Write hardware registers
+ * @hw_cmd:                Function pointer for any customized commands for the
+ *                         hardware manager
+ *
+ */
+struct cam_hw_mgr_intf {
+	void *hw_mgr_priv;
+
+	int (*hw_get_caps)(void *hw_priv, void *hw_caps_args);
+	int (*hw_acquire)(void *hw_priv, void *hw_acquire_args);
+	int (*hw_release)(void *hw_priv, void *hw_release_args);
+	int (*hw_start)(void *hw_priv, void *hw_start_args);
+	int (*hw_stop)(void *hw_priv, void *hw_stop_args);
+	int (*hw_prepare_update)(void *hw_priv, void *hw_prepare_update_args);
+	int (*hw_config)(void *hw_priv, void *hw_config_args);
+	int (*hw_read)(void *hw_priv, void *read_args);
+	int (*hw_write)(void *hw_priv, void *write_args);
+	int (*hw_cmd)(void *hw_priv, void *write_args);
+};
+
+#endif /* _CAM_HW_MGR_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.c b/drivers/media/platform/msm/camera/cam_core/cam_node.c
new file mode 100644
index 0000000..ef60822
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c
@@ -0,0 +1,413 @@
+/* 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 <linux/debugfs.h>
+#include <linux/videodev2.h>
+#include <linux/uaccess.h>
+
+#include "cam_node.h"
+
+static int __cam_node_handle_query_cap(struct cam_node *node,
+	struct cam_query_cap_cmd *query)
+{
+	int rc = -EFAULT;
+
+	if (!query)
+		return -EINVAL;
+
+	if (node->hw_mgr_intf.hw_get_caps) {
+		rc = node->hw_mgr_intf.hw_get_caps(
+			node->hw_mgr_intf.hw_mgr_priv, query);
+	}
+	return rc;
+}
+
+static int __cam_node_handle_acquire_dev(struct cam_node *node,
+	struct cam_acquire_dev_cmd *acquire)
+{
+	int rc = 0;
+	struct cam_context *ctx = NULL;
+
+	if (!acquire)
+		return -EINVAL;
+
+	mutex_lock(&node->list_mutex);
+	if (!list_empty(&node->free_ctx_list)) {
+		ctx = list_first_entry(&node->free_ctx_list,
+			struct cam_context, list);
+		list_del_init(&ctx->list);
+	}
+	mutex_unlock(&node->list_mutex);
+
+	if (!ctx) {
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	rc = cam_context_handle_acquire_dev(ctx, acquire);
+	if (rc) {
+		pr_err("%s: Acquire device failed\n", __func__);
+		goto free_ctx;
+	}
+
+	return 0;
+free_ctx:
+	mutex_lock(&node->list_mutex);
+	list_add_tail(&ctx->list, &node->free_ctx_list);
+	mutex_unlock(&node->list_mutex);
+err:
+	return rc;
+}
+
+static int __cam_node_handle_start_dev(struct cam_node *node,
+	struct cam_start_stop_dev_cmd *start)
+{
+	struct cam_context *ctx = NULL;
+
+	if (!start)
+		return -EINVAL;
+
+	if (start->dev_handle <= 0) {
+		pr_err("Invalid device handle for context\n");
+		return -EINVAL;
+	}
+
+	if (start->session_handle <= 0) {
+		pr_err("Invalid session handle for context\n");
+		return -EINVAL;
+	}
+
+	ctx = (struct cam_context *)cam_get_device_priv(start->dev_handle);
+	if (!ctx) {
+		pr_err("%s: Can not get context for handle %d\n",
+			__func__, start->dev_handle);
+		return -EINVAL;
+	}
+
+	return cam_context_handle_start_dev(ctx, start);
+}
+
+static int __cam_node_handle_stop_dev(struct cam_node *node,
+	struct cam_start_stop_dev_cmd *stop)
+{
+	struct cam_context *ctx = NULL;
+
+	if (!stop)
+		return -EINVAL;
+
+	if (stop->dev_handle <= 0) {
+		pr_err("Invalid device handle for context\n");
+		return -EINVAL;
+	}
+
+	if (stop->session_handle <= 0) {
+		pr_err("Invalid session handle for context\n");
+		return -EINVAL;
+	}
+
+	ctx = (struct cam_context *)cam_get_device_priv(stop->dev_handle);
+	if (!ctx) {
+		pr_err("%s: Can not get context for handle %d\n",
+			__func__, stop->dev_handle);
+		return -EINVAL;
+	}
+
+	return cam_context_handle_stop_dev(ctx, stop);
+}
+
+static int __cam_node_handle_config_dev(struct cam_node *node,
+	struct cam_config_dev_cmd *config)
+{
+	struct cam_context *ctx = NULL;
+
+	if (!config)
+		return -EINVAL;
+
+	if (config->dev_handle <= 0) {
+		pr_err("Invalid device handle for context\n");
+		return -EINVAL;
+	}
+
+	if (config->session_handle <= 0) {
+		pr_err("Invalid session handle for context\n");
+		return -EINVAL;
+	}
+
+	ctx = (struct cam_context *)cam_get_device_priv(config->dev_handle);
+	if (!ctx) {
+		pr_err("%s: Can not get context for handle %d\n",
+			__func__, config->dev_handle);
+		return -EINVAL;
+	}
+
+	return cam_context_handle_config_dev(ctx, config);
+}
+
+static int __cam_node_handle_release_dev(struct cam_node *node,
+	struct cam_release_dev_cmd *release)
+{
+	int rc = 0;
+	struct cam_context *ctx = NULL;
+
+	if (!release)
+		return -EINVAL;
+
+	if (release->dev_handle <= 0) {
+		pr_err("Invalid device handle for context\n");
+		return -EINVAL;
+	}
+
+	if (release->session_handle <= 0) {
+		pr_err("Invalid session handle for context\n");
+		return -EINVAL;
+	}
+
+	ctx = (struct cam_context *)cam_get_device_priv(release->dev_handle);
+	if (!ctx) {
+		pr_err("%s: Can not get context for handle %d\n",
+			__func__, release->dev_handle);
+		return -EINVAL;
+	}
+
+	rc = cam_context_handle_release_dev(ctx, release);
+	if (rc)
+		pr_err("%s: context release failed\n", __func__);
+
+	rc = cam_destroy_device_hdl(release->dev_handle);
+	if (rc)
+		pr_err("%s: destroy device handle is failed\n", __func__);
+
+	mutex_lock(&node->list_mutex);
+	list_add_tail(&ctx->list, &node->free_ctx_list);
+	mutex_unlock(&node->list_mutex);
+	return rc;
+}
+
+static int __cam_node_get_dev_info(struct cam_req_mgr_device_info *info)
+{
+	struct cam_context *ctx = NULL;
+
+	if (!info)
+		return -EINVAL;
+
+	ctx = (struct cam_context *) cam_get_device_priv(info->dev_hdl);
+	if (!ctx) {
+		pr_err("%s: Can not get context  for handle %d\n",
+			__func__, info->dev_hdl);
+		return -EINVAL;
+	}
+	return cam_context_handle_get_dev_info(ctx, info);
+}
+
+static int __cam_node_link_setup(struct cam_req_mgr_core_dev_link_setup *setup)
+{
+	int rc;
+	struct cam_context *ctx = NULL;
+
+	if (!setup)
+		return -EINVAL;
+
+	ctx = (struct cam_context *) cam_get_device_priv(setup->dev_hdl);
+	if (!ctx) {
+		pr_err("%s: Can not get context for handle %d\n",
+			__func__, setup->dev_hdl);
+		return -EINVAL;
+	}
+
+	if (setup->link_enable)
+		rc = cam_context_handle_link(ctx, setup);
+	else
+		rc = cam_context_handle_unlink(ctx, setup);
+
+	return rc;
+}
+
+static int __cam_node_apply_req(struct cam_req_mgr_apply_request *apply)
+{
+	struct cam_context *ctx = NULL;
+
+	if (!apply)
+		return -EINVAL;
+
+	ctx = (struct cam_context *) cam_get_device_priv(apply->dev_hdl);
+	if (!ctx) {
+		pr_err("%s: Can not get context for handle %d\n",
+			__func__, apply->dev_hdl);
+		return -EINVAL;
+	}
+
+	return cam_context_handle_apply_req(ctx, apply);
+}
+
+int cam_node_deinit(struct cam_node *node)
+{
+	if (node)
+		memset(node, 0, sizeof(*node));
+
+	pr_debug("%s: deinit complete!\n", __func__);
+	return 0;
+
+}
+
+int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf,
+	struct cam_context *ctx_list, uint32_t ctx_size, char *name)
+{
+	int rc = 0;
+	int i;
+
+	if (!node || !hw_mgr_intf ||
+		sizeof(node->hw_mgr_intf) != sizeof(*hw_mgr_intf)) {
+		return -EINVAL;
+	}
+
+	memset(node, 0, sizeof(*node));
+
+	strlcpy(node->name, name, sizeof(node->name));
+
+	memcpy(&node->hw_mgr_intf, hw_mgr_intf, sizeof(node->hw_mgr_intf));
+
+	node->crm_node_intf.apply_req = __cam_node_apply_req;
+	node->crm_node_intf.get_dev_info = __cam_node_get_dev_info;
+	node->crm_node_intf.link_setup = __cam_node_link_setup;
+
+	mutex_init(&node->list_mutex);
+	INIT_LIST_HEAD(&node->free_ctx_list);
+	node->ctx_list = ctx_list;
+	node->ctx_size = ctx_size;
+	for (i = 0; i < ctx_size; i++) {
+		if (!ctx_list[i].state_machine) {
+			pr_err("%s: camera context %d is not initialized!",
+				__func__, i);
+			rc = -1;
+			goto err;
+		}
+		INIT_LIST_HEAD(&ctx_list[i].list);
+		list_add_tail(&ctx_list[i].list, &node->free_ctx_list);
+	}
+
+	node->state = CAM_NODE_STATE_INIT;
+err:
+	pr_debug("%s: Exit. (rc = %d)\n", __func__, rc);
+	return rc;
+}
+
+int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd)
+{
+	int rc = 0;
+
+	if (!cmd)
+		return -EINVAL;
+
+	pr_debug("%s: handle cmd %d\n", __func__, cmd->op_code);
+
+	switch (cmd->op_code) {
+	case CAM_QUERY_CAP: {
+		struct cam_query_cap_cmd query;
+
+		if (copy_from_user(&query, (void __user *)cmd->handle,
+			sizeof(query))) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = __cam_node_handle_query_cap(node, &query);
+		if (rc) {
+			pr_err("%s: querycap is failed(rc = %d)\n",
+				__func__,  rc);
+			break;
+		}
+		if (copy_to_user((void __user *)cmd->handle, &query,
+			sizeof(query)))
+			rc = -EFAULT;
+		break;
+	}
+	case CAM_ACQUIRE_DEV: {
+		struct cam_acquire_dev_cmd acquire;
+
+		if (copy_from_user(&acquire, (void __user *)cmd->handle,
+			sizeof(acquire))) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = __cam_node_handle_acquire_dev(node, &acquire);
+		if (rc) {
+			pr_err("%s: acquire device failed(rc = %d)\n",
+				__func__, rc);
+			break;
+		}
+		if (copy_to_user((void __user *)cmd->handle, &acquire,
+			sizeof(acquire)))
+			rc = -EFAULT;
+		break;
+	}
+	case CAM_START_DEV: {
+		struct cam_start_stop_dev_cmd start;
+
+		if (copy_from_user(&start, (void __user *)cmd->handle,
+			sizeof(start)))
+			rc = -EFAULT;
+		else {
+			rc = __cam_node_handle_start_dev(node, &start);
+			if (rc)
+				pr_err("%s: start device failed(rc = %d)\n",
+					__func__, rc);
+		}
+		break;
+	}
+	case CAM_STOP_DEV: {
+		struct cam_start_stop_dev_cmd stop;
+
+		if (copy_from_user(&stop, (void __user *)cmd->handle,
+			sizeof(stop)))
+			rc = -EFAULT;
+		else {
+			rc = __cam_node_handle_stop_dev(node, &stop);
+			if (rc)
+				pr_err("%s: stop device failed(rc = %d)\n",
+					__func__, rc);
+		}
+		break;
+	}
+	case CAM_CONFIG_DEV: {
+		struct cam_config_dev_cmd config;
+
+		if (copy_from_user(&config, (void __user *)cmd->handle,
+			sizeof(config)))
+			rc = -EFAULT;
+		else {
+			rc = __cam_node_handle_config_dev(node, &config);
+			if (rc)
+				pr_err("%s: config device failed(rc = %d)\n",
+					__func__, rc);
+		}
+		break;
+	}
+	case CAM_RELEASE_DEV: {
+		struct cam_release_dev_cmd release;
+
+		if (copy_from_user(&release, (void __user *)cmd->handle,
+			sizeof(release)))
+			rc = -EFAULT;
+		else {
+			rc = __cam_node_handle_release_dev(node, &release);
+			if (rc)
+				pr_err("%s: release device failed(rc = %d)\n",
+					__func__, rc);
+		}
+		break;
+	}
+	default:
+		pr_err("Unknown op code %d\n", cmd->op_code);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.h b/drivers/media/platform/msm/camera/cam_core/cam_node.h
new file mode 100644
index 0000000..6e4a641
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_node.h
@@ -0,0 +1,90 @@
+/* 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.
+ */
+
+#ifndef _CAM_NODE_H_
+#define _CAM_NODE_H_
+
+#include "cam_context.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_req_mgr_interface.h"
+
+#define CAM_NODE_NAME_LENGTH_MAX        256
+
+#define CAM_NODE_STATE_UNINIT           0
+#define CAM_NODE_STATE_INIT             1
+
+/**
+ * struct cam_node - Singleton Node for camera HW devices
+ *
+ * @name:                  Name for struct cam_node
+ * @state:                 Node state:
+ *                            0 = uninitialized, 1 = initialized
+ * @list_mutex:            Mutex for the context pool
+ * @free_ctx_list:         Free context pool list
+ * @ctx_list:              Context list
+ * @ctx_size:              Context list size
+ * @hw_mgr_intf:           Interface for cam_node to HW
+ * @crm_node_intf:         Interface for the CRM to cam_node
+ *
+ */
+struct cam_node {
+	char                         name[CAM_NODE_NAME_LENGTH_MAX];
+	uint32_t                     state;
+
+	/* context pool */
+	struct mutex                 list_mutex;
+	struct list_head             free_ctx_list;
+	struct cam_context          *ctx_list;
+	uint32_t                     ctx_size;
+
+	/* interfaces */
+	struct cam_hw_mgr_intf       hw_mgr_intf;
+	struct cam_req_mgr_kmd_ops   crm_node_intf;
+};
+
+/**
+ * cam_node_handle_ioctl()
+ *
+ * @brief:       Handle ioctl commands
+ *
+ * @node:                  Node handle
+ * @cmd:                   IOCTL command
+ *
+ */
+int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd);
+
+/**
+ * cam_node_deinit()
+ *
+ * @brief:       Deinitialization function for the Node interface
+ *
+ * @node:                  Node handle
+ *
+ */
+int cam_node_deinit(struct cam_node *node);
+
+/**
+ * cam_node_init()
+ *
+ * @brief:       Initialization function for the Node interface.
+ *
+ * @node:                  Cam_node pointer
+ * @hw_mgr_intf:           HW manager interface blob
+ * @ctx_list:              List of cam_contexts to be added
+ * @ctx_size:              Size of the cam_context
+ * @name:                  Name for the node
+ *
+ */
+int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf,
+	struct cam_context *ctx_list, uint32_t ctx_size, char *name);
+
+#endif /* _CAM_NODE_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_subdev.c b/drivers/media/platform/msm/camera/cam_core/cam_subdev.c
new file mode 100644
index 0000000..03b18cf
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_subdev.c
@@ -0,0 +1,143 @@
+/* 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 "cam_subdev.h"
+#include "cam_node.h"
+
+/**
+ * cam_subdev_subscribe_event()
+ *
+ * @brief: function to subscribe to v4l2 events
+ *
+ * @sd:                    Pointer to struct v4l2_subdev.
+ * @fh:                    Pointer to struct v4l2_fh.
+ * @sub:                   Pointer to struct v4l2_event_subscription.
+ */
+static int cam_subdev_subscribe_event(struct v4l2_subdev *sd,
+	struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub)
+{
+	return v4l2_event_subscribe(fh, sub, CAM_SUBDEVICE_EVENT_MAX, NULL);
+}
+
+/**
+ * cam_subdev_unsubscribe_event()
+ *
+ * @brief: function to unsubscribe from v4l2 events
+ *
+ * @sd:                    Pointer to struct v4l2_subdev.
+ * @fh:                    Pointer to struct v4l2_fh.
+ * @sub:                   Pointer to struct v4l2_event_subscription.
+ */
+static int cam_subdev_unsubscribe_event(struct v4l2_subdev *sd,
+	struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub)
+{
+	return v4l2_event_unsubscribe(fh, sub);
+}
+
+static long cam_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd,
+	void *arg)
+{
+	long rc;
+	struct cam_node *node =
+		(struct cam_node *) v4l2_get_subdevdata(sd);
+
+	if (!node || node->state == CAM_NODE_STATE_UNINIT) {
+		rc = -EINVAL;
+		goto end;
+	}
+
+	switch (cmd) {
+	case VIDIOC_CAM_CONTROL:
+		rc = cam_node_handle_ioctl(node,
+			(struct cam_control *) arg);
+		break;
+	default:
+		pr_err("Invalid command %d for %s!\n", cmd,
+			node->name);
+		rc = -EINVAL;
+	}
+end:
+	return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long cam_subdev_compat_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, unsigned long arg)
+{
+	return cam_subdev_ioctl(sd, cmd, compat_ptr(arg));
+}
+#endif
+
+const struct v4l2_subdev_core_ops cam_subdev_core_ops = {
+	.ioctl = cam_subdev_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = cam_subdev_compat_ioctl,
+#endif
+	.subscribe_event = cam_subdev_subscribe_event,
+	.unsubscribe_event = cam_subdev_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_ops cam_subdev_ops = {
+	.core = &cam_subdev_core_ops,
+};
+
+int cam_subdev_remove(struct cam_subdev *sd)
+{
+	if (!sd)
+		return -EINVAL;
+
+	cam_unregister_subdev(sd);
+	cam_node_deinit((struct cam_node *)sd->token);
+	kfree(sd->token);
+
+	return 0;
+}
+
+int cam_subdev_probe(struct cam_subdev *sd, struct platform_device *pdev,
+	char *name, uint32_t dev_type)
+{
+	int rc;
+	struct cam_node *node = NULL;
+
+	if (!sd || !pdev || !name) {
+		rc = -EINVAL;
+		goto err;
+	}
+
+	node = kzalloc(sizeof(*node), GFP_KERNEL);
+	if (!node) {
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	/* Setup camera v4l2 subdevice */
+	sd->pdev = pdev;
+	sd->name = name;
+	sd->ops = &cam_subdev_ops;
+	sd->token = node;
+	sd->sd_flags =
+		V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+	sd->ent_function = dev_type;
+	rc = cam_register_subdev(sd);
+	if (rc) {
+		pr_err("%s: cam_register_subdev() failed for dev: %s!\n",
+			__func__, sd->name);
+		goto err;
+	}
+	platform_set_drvdata(sd->pdev, sd);
+	return rc;
+err:
+	kfree(node);
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_dev_mgr_util.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_dev_mgr_util.h
deleted file mode 100644
index 69970b5..0000000
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_dev_mgr_util.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* 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.
- */
-
-#ifndef _CAM_DEV_MGR_UTIL_H_
-#define _CAM_DEV_MGR_UTIL_H_
-
-#define CAM_SUBDEVICE_EVENT_MAX 30
-
-#include <linux/types.h>
-#include <media/v4l2-fh.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-ioctl.h>
-
-/**
- * struct cam_subdev - describes a camera sub-device
- *
- * @sd: struct v4l2_subdev
- * @ops: struct v4l2_subdev_ops
- * @internal_ops: struct v4l2_subdev_internal_ops
- * @name: Name of the sub-device. Please notice that the name must be unique.
- * @sd_flags: subdev flags. Can be:
- *   %V4L2_SUBDEV_FL_HAS_DEVNODE - Set this flag if this subdev needs a
- *   device node;
- *   %V4L2_SUBDEV_FL_HAS_EVENTS -  Set this flag if this subdev generates
- *   events.
- * @token: pointer to cookie of the client driver
- * @ent_function: media entity function type. Can be:
- *   %CAM_IFE_DEVICE_TYPE - identifies as IFE device;
- *   %CAM_ICP_DEVICE_TYPE - identifies as ICP device.
- * Each instance of a subdev driver should create this struct, either
- * stand-alone or embedded in a larger struct.
- *
- * This structure should be initialized/registered by cam_register_subdev
- */
-struct cam_subdev {
-	struct v4l2_subdev sd;
-	const struct v4l2_subdev_ops *ops;
-	const struct v4l2_subdev_internal_ops *internal_ops;
-	char *name;
-	u32 sd_flags;
-	void *token;
-	u32 ent_function;
-};
-
-/**
- * cam_register_subdev()
- *
- * @brief:  Registration function for camera subdevice
- *
- * @sd: pointer to struct cam_subdev.
- */
-int cam_register_subdev(struct cam_subdev *sd);
-
-/**
- * cam_unregister_subdev()
- *
- * @brief:  Unregistration function for camera subdevice
- *
- * @sd: pointer to struct cam_subdev.
- */
-int cam_unregister_subdev(struct cam_subdev *sd);
-
-/**
- * cam_send_event()
- *
- * @brief: Inline function to sent event to user space
- *
- * @csd: pointer to struct cam_subdev.
- * @ev: pointer to struct v4l2_event.
- */
-static inline int cam_send_event(struct cam_subdev *csd,
-	const struct v4l2_event *ev)
-{
-	if (!csd || !ev)
-		return -EINVAL;
-
-	v4l2_event_queue(csd->sd.devnode, ev);
-
-	return 0;
-}
-
-/**
- * cam_get_subdev_data()
- *
- * @brief: Inline function to retrieve the private data
- *
- * @csd: pointer to struct cam_subdev.
- */
-static inline void *cam_get_subdev_data(struct cam_subdev *csd)
-{
-	if (!csd)
-		return ERR_PTR(-EINVAL);
-
-	return v4l2_get_subdevdata(&csd->sd);
-}
-
-/**
- * cam_sd_subscribe_event()
- *
- * @brief: Inline function to subscribe to v4l2 events
- *
- * @sd: pointer to struct v4l2_subdev.
- * @fh: pointer to struct v4l2_fh.
- * @sub: pointer to struct v4l2_event_subscription.
- */
-static inline int cam_sd_subscribe_event(struct v4l2_subdev *sd,
-	struct v4l2_fh *fh,
-	struct v4l2_event_subscription *sub)
-{
-	return v4l2_event_subscribe(fh, sub, CAM_SUBDEVICE_EVENT_MAX, NULL);
-}
-
-/**
- * cam_sd_unsubscribe_event()
- *
- * @brief: Inline function to unsubscribe from v4l2 events
- *
- * @sd: pointer to struct v4l2_subdev.
- * @fh: pointer to struct v4l2_fh.
- * @sub: pointer to struct v4l2_event_subscription.
- */
-static inline int cam_sd_unsubscribe_event(struct v4l2_subdev *sd,
-	struct v4l2_fh *fh,
-	struct v4l2_event_subscription *sub)
-{
-	return v4l2_event_unsubscribe(fh, sub);
-}
-#endif /* _CAM_DEV_MGR_UTIL_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
index 2dba2c8..f3af1bd 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
@@ -23,7 +23,7 @@
 #include "cam_req_mgr_dev.h"
 #include "cam_req_mgr_util.h"
 #include "cam_req_mgr_core.h"
-#include "cam_dev_mgr_util.h"
+#include "cam_subdev.h"
 
 #define CAM_REQ_MGR_EVENT_MAX 30
 
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_subdev.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_subdev.h
new file mode 100644
index 0000000..78f2223
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_subdev.h
@@ -0,0 +1,106 @@
+/* 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.
+ */
+
+#ifndef _CAM_SUBDEV_H_
+#define _CAM_SUBDEV_H_
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+
+#define CAM_SUBDEVICE_EVENT_MAX 30
+
+/**
+ * struct cam_subdev - describes a camera sub-device
+ *
+ * @pdev:                  Pointer to the platform device
+ * @sd:                    V4l2 subdevice
+ * @ops:                   V4l2 subdecie operations
+ * @internal_ops:          V4l2 subdevice internal operations
+ * @name:                  Name of the sub-device. Please notice that the name
+ *                             must be unique.
+ * @sd_flags:              Subdev flags. Can be:
+ *                             %V4L2_SUBDEV_FL_HAS_DEVNODE - Set this flag if
+ *                                 this subdev needs a device node.
+ *                             %V4L2_SUBDEV_FL_HAS_EVENTS -  Set this flag if
+ *                                 this subdev generates events.
+ * @token:                 Pointer to cookie of the client driver
+ * @ent_function:          Media entity function type. Can be:
+ *                             %CAM_IFE_DEVICE_TYPE - identifies as IFE device.
+ *                             %CAM_ICP_DEVICE_TYPE - identifies as ICP device.
+ *
+ * Each instance of a subdev driver should create this struct, either
+ * stand-alone or embedded in a larger struct. This structure should be
+ * initialized/registered by cam_register_subdev
+ *
+ */
+struct cam_subdev {
+	struct platform_device                *pdev;
+	struct v4l2_subdev                     sd;
+	const struct v4l2_subdev_ops          *ops;
+	const struct v4l2_subdev_internal_ops *internal_ops;
+	char                                  *name;
+	u32                                    sd_flags;
+	void                                  *token;
+	u32                                    ent_function;
+};
+
+/**
+ * cam_subdev_probe()
+ *
+ * @brief:      Camera Subdevice node probe function for v4l2 setup
+ *
+ * @sd:                    Camera subdevice object
+ * @name:                  Name of the subdevice node
+ * @dev_type:              Subdevice node type
+ *
+ */
+int cam_subdev_probe(struct cam_subdev *sd, struct platform_device *pdev,
+	char *name, uint32_t dev_type);
+
+/**
+ * cam_subdev_remove()
+ *
+ * @brief:      Called when subdevice node is unloaded
+ *
+ * @sd:                    Camera subdevice node object
+ *
+ */
+int cam_subdev_remove(struct cam_subdev *sd);
+
+/**
+ * cam_register_subdev()
+ *
+ * @brief:   This is the common utility function to be called by each camera
+ *           subdevice node when it tries to register itself to the camera
+ *           request manager
+ *
+ * @sd:                    Pointer to struct cam_subdev.
+ */
+int cam_register_subdev(struct cam_subdev *sd);
+
+/**
+ * cam_unregister_subdev()
+ *
+ * @brief:    This is the common utility function to be called by each camera
+ *            subdevice node when it tries to unregister itself from the
+ *            camera request manger
+ *
+ * @sd:                    Pointer to struct cam_subdev.
+ */
+int cam_unregister_subdev(struct cam_subdev *sd);
+
+#endif /* _CAM_SUBDEV_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sync/Makefile b/drivers/media/platform/msm/camera/cam_sync/Makefile
new file mode 100644
index 0000000..e3012cb
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sync/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync.o cam_sync_util.o
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
new file mode 100644
index 0000000..a736148
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
@@ -0,0 +1,1024 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "CAM-SYNC %s:%d " fmt, __func__, __LINE__
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/irqflags.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include "cam_sync_util.h"
+
+struct sync_device *sync_dev;
+
+int cam_sync_create(int32_t *sync_obj, const char *name)
+{
+	int rc;
+	long idx;
+
+	do {
+		idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS);
+			if (idx >= CAM_SYNC_MAX_OBJS)
+				return -ENOMEM;
+	} while (!spin_trylock_bh(&sync_dev->row_spinlocks[idx]));
+
+	rc = cam_sync_init_object(sync_dev->sync_table, idx, name);
+	if (rc) {
+		pr_err("Error: Unable to init row at idx = %ld\n", idx);
+		spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
+		return -EINVAL;
+	}
+
+	set_bit(idx, sync_dev->bitmap);
+	*sync_obj = idx;
+	spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
+
+	return rc;
+}
+
+int cam_sync_register_callback(sync_callback cb_func,
+	void *userdata, int32_t sync_obj)
+{
+	struct sync_callback_info *sync_cb;
+	struct sync_callback_info *cb_info;
+	struct sync_callback_info *temp_cb;
+	struct sync_table_row *row = NULL;
+
+	if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0 || !cb_func)
+		return -EINVAL;
+
+	spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
+	row = sync_dev->sync_table + sync_obj;
+
+	if (row->state == CAM_SYNC_STATE_INVALID) {
+		pr_err("Error: accessing an uninitialized sync obj %d\n",
+			sync_obj);
+		spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+		return -EINVAL;
+	}
+
+	sync_cb = kzalloc(sizeof(*sync_cb), GFP_ATOMIC);
+	if (!sync_cb) {
+		spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+		return -ENOMEM;
+	}
+
+	/* Trigger callback if sync object is already in SIGNALED state */
+	if (row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS ||
+		row->state == CAM_SYNC_STATE_SIGNALED_ERROR) {
+		sync_cb->callback_func = cb_func;
+		sync_cb->cb_data = userdata;
+		sync_cb->sync_obj = sync_obj;
+		INIT_WORK(&sync_cb->cb_dispatch_work,
+			cam_sync_util_cb_dispatch);
+
+		sync_cb->status = row->state;
+		queue_work(sync_dev->work_queue,
+			&sync_cb->cb_dispatch_work);
+
+		spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+		return 0;
+	}
+
+	/* Don't register if callback was registered earlier */
+	list_for_each_entry_safe(cb_info, temp_cb, &row->callback_list, list) {
+		if (cb_info->callback_func == cb_func &&
+			cb_info->cb_data == userdata) {
+			kfree(sync_cb);
+			spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+			return -EALREADY;
+		}
+	}
+
+	sync_cb->callback_func = cb_func;
+	sync_cb->cb_data = userdata;
+	sync_cb->sync_obj = sync_obj;
+	INIT_WORK(&sync_cb->cb_dispatch_work, cam_sync_util_cb_dispatch);
+	list_add_tail(&sync_cb->list, &row->callback_list);
+	spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+
+	return 0;
+}
+
+int cam_sync_deregister_callback(sync_callback cb_func,
+	void *userdata, int32_t sync_obj)
+{
+	struct sync_table_row *row = NULL;
+	struct sync_callback_info *sync_cb, *temp;
+
+	if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
+		return -EINVAL;
+
+	spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
+	row = sync_dev->sync_table + sync_obj;
+
+	if (row->state == CAM_SYNC_STATE_INVALID) {
+		pr_err("Error: accessing an uninitialized sync obj = %d\n",
+			sync_obj);
+		spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+		return -EINVAL;
+	}
+
+	list_for_each_entry_safe(sync_cb, temp, &row->callback_list, list) {
+		if (sync_cb->callback_func == cb_func &&
+			sync_cb->cb_data == userdata) {
+			list_del_init(&sync_cb->list);
+			kfree(sync_cb);
+		}
+	}
+
+	spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+	return 0;
+}
+
+int cam_sync_signal(int32_t sync_obj, uint32_t status)
+{
+	int rc;
+	struct sync_table_row *row = NULL;
+	struct sync_table_row *parent_row = NULL;
+	struct sync_callback_info *sync_cb;
+	struct sync_user_payload *payload_info;
+	struct sync_parent_info *parent_info;
+	struct list_head sync_list;
+	struct cam_signalable_info *list_info = NULL;
+	struct cam_signalable_info *temp_list_info = NULL;
+
+	/* Objects to be signaled will be added into this list */
+	INIT_LIST_HEAD(&sync_list);
+
+	if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
+		return -EINVAL;
+
+	row = sync_dev->sync_table + sync_obj;
+	if (row->state == CAM_SYNC_STATE_INVALID) {
+		pr_err("Error: accessing an uninitialized sync obj = %d\n",
+			sync_obj);
+		return -EINVAL;
+	}
+
+	spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
+	if (row->type == CAM_SYNC_TYPE_GROUP) {
+		spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+		pr_err("Error: Signaling a GROUP sync object = %d\n",
+			sync_obj);
+		return -EINVAL;
+	}
+
+	if (row->state != CAM_SYNC_STATE_ACTIVE) {
+		spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+		pr_err("Error: Sync object already signaled sync_obj = %d",
+			sync_obj);
+		return -EALREADY;
+	}
+
+	if (status != CAM_SYNC_STATE_SIGNALED_SUCCESS &&
+		status != CAM_SYNC_STATE_SIGNALED_ERROR) {
+		spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+		pr_err("Error: signaling with undefined status = %d\n",
+			status);
+		return -EINVAL;
+	}
+
+	row->state = status;
+	rc = cam_sync_util_add_to_signalable_list(sync_obj, status, &sync_list);
+	if (rc < 0) {
+		spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+		return rc;
+	}
+
+	/*
+	 * Now iterate over all parents of this object and if they too need to
+	 * be signaled add them to the list
+	 */
+	list_for_each_entry(parent_info,
+		&row->parents_list,
+		list) {
+		parent_row = sync_dev->sync_table + parent_info->sync_id;
+		spin_lock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]);
+		parent_row->remaining--;
+
+		parent_row->state = cam_sync_util_get_state(
+			parent_row->state,
+			status);
+
+		if (!parent_row->remaining) {
+			rc = cam_sync_util_add_to_signalable_list
+				(parent_info->sync_id,
+					parent_row->state,
+					&sync_list);
+			if (rc < 0) {
+				spin_unlock_bh(
+					&sync_dev->row_spinlocks[
+						parent_info->sync_id]);
+				return rc;
+			}
+		}
+		spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]);
+	}
+
+	/*
+	 * Now dispatch the various sync objects collected so far, in our
+	 * list
+	 */
+	list_for_each_entry_safe(list_info,
+		temp_list_info,
+		&sync_list,
+		list) {
+		struct sync_table_row *signalable_row = NULL;
+		struct sync_callback_info *temp_sync_cb;
+		struct sync_user_payload *temp_payload_info;
+
+		signalable_row = sync_dev->sync_table + list_info->sync_obj;
+		/* Dispatch kernel callbacks if any were registered earlier */
+		list_for_each_entry_safe(sync_cb,
+		temp_sync_cb, &signalable_row->callback_list, list) {
+			sync_cb->status = list_info->status;
+			queue_work(sync_dev->work_queue,
+				&sync_cb->cb_dispatch_work);
+			list_del_init(&sync_cb->list);
+		}
+
+		/* Dispatch user payloads if any were registered earlier */
+		list_for_each_entry_safe(payload_info, temp_payload_info,
+		&signalable_row->user_payload_list, list) {
+			spin_lock_bh(&sync_dev->cam_sync_eventq_lock);
+			if (!sync_dev->cam_sync_eventq) {
+				spin_unlock_bh(
+				&sync_dev->cam_sync_eventq_lock);
+				break;
+			}
+			spin_unlock_bh(&sync_dev->cam_sync_eventq_lock);
+			cam_sync_util_send_v4l2_event(
+				CAM_SYNC_V4L_EVENT_ID_CB_TRIG,
+				list_info->sync_obj,
+				list_info->status,
+				payload_info->payload_data,
+				CAM_SYNC_PAYLOAD_WORDS * sizeof(__u64));
+
+			list_del_init(&payload_info->list);
+			/*
+			 * We can free the list node here because
+			 * sending V4L event will make a deep copy
+			 * anyway
+			 */
+			kfree(payload_info);
+		}
+
+		/*
+		 * This needs to be done because we want to unblock anyone
+		 * who might be blocked and waiting on this sync object
+		 */
+		complete_all(&signalable_row->signaled);
+
+		list_del_init(&list_info->list);
+		kfree(list_info);
+	}
+
+	spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+
+	return rc;
+}
+
+int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj)
+{
+	int rc;
+	long idx = 0;
+
+	rc = cam_sync_util_validate_merge(sync_obj,
+		num_objs);
+	if (rc < 0) {
+		pr_err("Validation failed, Merge not allowed");
+		return -EINVAL;
+	}
+
+	rc = cam_sync_util_find_and_set_empty_row(sync_dev, &idx);
+	if (rc < 0) {
+		pr_err("Error: Unable to find empty row, table full");
+		return -EINVAL;
+	}
+
+	if (idx <= 0 || idx >= CAM_SYNC_MAX_OBJS) {
+		pr_err("Error: Invalid empty row index returned = %ld", idx);
+		return -EINVAL;
+	}
+
+	rc = cam_sync_init_group_object(sync_dev->sync_table,
+		idx, sync_obj,
+		num_objs);
+
+	if (rc < 0) {
+		pr_err("Error: Unable to init row at idx = %ld\n", idx);
+		return -EINVAL;
+	}
+
+	*merged_obj = idx;
+
+	return 0;
+}
+
+int cam_sync_destroy(int32_t sync_obj)
+{
+	struct sync_table_row *row = NULL;
+
+	if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
+		return -EINVAL;
+
+	row = sync_dev->sync_table + sync_obj;
+	if (row->state == CAM_SYNC_STATE_INVALID) {
+		pr_err("Error: accessing an uninitialized sync obj: idx = %d\n",
+			sync_obj);
+		return -EINVAL;
+	}
+
+	cam_sync_deinit_object(sync_dev->sync_table, sync_obj);
+	return 0;
+}
+
+int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms)
+{
+	unsigned long timeleft;
+	int rc = -EINVAL;
+	struct sync_table_row *row = NULL;
+
+	if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
+		return -EINVAL;
+
+	row = sync_dev->sync_table + sync_obj;
+
+	if (row->state == CAM_SYNC_STATE_INVALID) {
+		pr_err("Error: accessing an uninitialized sync obj = %d\n",
+			sync_obj);
+		return -EINVAL;
+	}
+
+	timeleft = wait_for_completion_timeout(&row->signaled,
+		msecs_to_jiffies(timeout_ms));
+
+	if (!timeleft) {
+		pr_err("Error: cam_sync_wait() timed out for sync obj = %d\n",
+			sync_obj);
+		rc = -ETIMEDOUT;
+	} else {
+		switch (row->state) {
+		case CAM_SYNC_STATE_INVALID:
+		case CAM_SYNC_STATE_ACTIVE:
+		case CAM_SYNC_STATE_SIGNALED_ERROR:
+			pr_err("Error: Wait on invalid state = %d, obj = %d\n",
+				row->state, sync_obj);
+			rc = -EINVAL;
+			break;
+		case CAM_SYNC_STATE_SIGNALED_SUCCESS:
+			rc = 0;
+			break;
+		default:
+			rc = -EINVAL;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int cam_sync_handle_create(struct cam_private_ioctl_arg *k_ioctl)
+{
+	struct cam_sync_info sync_create;
+	int result;
+
+	if (k_ioctl->size != sizeof(struct cam_sync_info))
+		return -EINVAL;
+
+	if (!k_ioctl->ioctl_ptr)
+		return -EINVAL;
+
+	if (copy_from_user(&sync_create,
+		(void *)k_ioctl->ioctl_ptr,
+		k_ioctl->size))
+		return -EFAULT;
+
+	result = cam_sync_create(&sync_create.sync_obj,
+		sync_create.name);
+
+	if (!result)
+		if (copy_to_user((void *)k_ioctl->ioctl_ptr,
+			&sync_create,
+			k_ioctl->size))
+			return -EFAULT;
+
+	return result;
+}
+
+static int cam_sync_handle_signal(struct cam_private_ioctl_arg *k_ioctl)
+{
+	struct cam_sync_signal sync_signal;
+
+	if (k_ioctl->size != sizeof(struct cam_sync_signal))
+		return -EINVAL;
+
+	if (!k_ioctl->ioctl_ptr)
+		return -EINVAL;
+
+	if (copy_from_user(&sync_signal,
+		(void *)k_ioctl->ioctl_ptr,
+		k_ioctl->size))
+		return -EFAULT;
+
+	return cam_sync_signal(sync_signal.sync_obj,
+		sync_signal.sync_state);
+}
+
+static int cam_sync_handle_merge(struct cam_private_ioctl_arg *k_ioctl)
+{
+	struct cam_sync_merge sync_merge;
+	uint32_t *sync_objs;
+	uint32_t num_objs;
+	uint32_t size;
+	int result;
+
+	if (k_ioctl->size != sizeof(struct cam_sync_merge))
+		return -EINVAL;
+
+	if (!k_ioctl->ioctl_ptr)
+		return -EINVAL;
+
+	if (copy_from_user(&sync_merge,
+		(void *)k_ioctl->ioctl_ptr,
+		k_ioctl->size))
+		return -EFAULT;
+
+	if (sync_merge.num_objs >= CAM_SYNC_MAX_OBJS)
+		return -EINVAL;
+
+	size = sizeof(uint32_t) * sync_merge.num_objs;
+	sync_objs = kzalloc(size, GFP_ATOMIC);
+
+	if (!sync_objs)
+		return -ENOMEM;
+
+	if (copy_from_user(sync_objs,
+	(void *)sync_merge.sync_objs,
+	sizeof(uint32_t) * sync_merge.num_objs)) {
+		kfree(sync_objs);
+		return -EFAULT;
+	}
+
+	num_objs = sync_merge.num_objs;
+
+	result = cam_sync_merge(sync_objs,
+		num_objs,
+		&sync_merge.merged);
+
+	if (!result)
+		if (copy_to_user((void *)k_ioctl->ioctl_ptr,
+			&sync_merge,
+			k_ioctl->size)) {
+			kfree(sync_objs);
+			return -EFAULT;
+	}
+
+	kfree(sync_objs);
+
+	return result;
+}
+
+static int cam_sync_handle_wait(struct cam_private_ioctl_arg *k_ioctl)
+{
+	struct cam_sync_wait sync_wait;
+
+	if (k_ioctl->size != sizeof(struct cam_sync_wait))
+		return -EINVAL;
+
+	if (!k_ioctl->ioctl_ptr)
+		return -EINVAL;
+
+	if (copy_from_user(&sync_wait,
+		(void *)k_ioctl->ioctl_ptr,
+		k_ioctl->size))
+		return -EFAULT;
+
+	k_ioctl->result = cam_sync_wait(sync_wait.sync_obj,
+		sync_wait.timeout_ms);
+
+	return 0;
+}
+
+static int cam_sync_handle_destroy(struct cam_private_ioctl_arg *k_ioctl)
+{
+	struct cam_sync_info sync_create;
+
+	if (k_ioctl->size != sizeof(struct cam_sync_info))
+		return -EINVAL;
+
+	if (!k_ioctl->ioctl_ptr)
+		return -EINVAL;
+
+	if (copy_from_user(&sync_create,
+		(void *)k_ioctl->ioctl_ptr,
+		k_ioctl->size))
+		return -EFAULT;
+
+	return cam_sync_destroy(sync_create.sync_obj);
+}
+
+static int cam_sync_handle_register_user_payload(
+	struct cam_private_ioctl_arg *k_ioctl)
+{
+	struct cam_sync_userpayload_info userpayload_info;
+	struct sync_user_payload *user_payload_kernel;
+	struct sync_user_payload *user_payload_iter;
+	struct sync_user_payload *temp_upayload_kernel;
+	uint32_t sync_obj;
+	struct sync_table_row *row = NULL;
+
+	if (k_ioctl->size != sizeof(struct cam_sync_userpayload_info))
+		return -EINVAL;
+
+	if (!k_ioctl->ioctl_ptr)
+		return -EINVAL;
+
+	if (copy_from_user(&userpayload_info,
+		(void *)k_ioctl->ioctl_ptr,
+		k_ioctl->size))
+		return -EFAULT;
+
+	sync_obj = userpayload_info.sync_obj;
+	if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
+		return -EINVAL;
+
+	user_payload_kernel = kzalloc(sizeof(*user_payload_kernel), GFP_KERNEL);
+	if (!user_payload_kernel)
+		return -ENOMEM;
+
+	memcpy(user_payload_kernel->payload_data,
+		userpayload_info.payload,
+		CAM_SYNC_PAYLOAD_WORDS * sizeof(__u64));
+
+	spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
+	row =  sync_dev->sync_table + sync_obj;
+
+	if (row->state == CAM_SYNC_STATE_INVALID) {
+		pr_err("Error: accessing an uninitialized sync obj = %d\n",
+			sync_obj);
+		spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+		kfree(user_payload_kernel);
+		return -EINVAL;
+	}
+
+	if (row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS ||
+		row->state == CAM_SYNC_STATE_SIGNALED_ERROR) {
+
+		cam_sync_util_send_v4l2_event(CAM_SYNC_V4L_EVENT_ID_CB_TRIG,
+			sync_obj,
+			row->state,
+			user_payload_kernel->payload_data,
+			CAM_SYNC_USER_PAYLOAD_SIZE * sizeof(__u64));
+
+		spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+		kfree(user_payload_kernel);
+		return 0;
+	}
+
+	list_for_each_entry_safe(user_payload_iter,
+		temp_upayload_kernel,
+		&row->user_payload_list,
+		list) {
+		if (user_payload_iter->payload_data[0] ==
+				user_payload_kernel->payload_data[0] &&
+			user_payload_iter->payload_data[1] ==
+				user_payload_kernel->payload_data[1]) {
+
+			spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+			kfree(user_payload_kernel);
+			return -EALREADY;
+		}
+	}
+
+	list_add_tail(&user_payload_kernel->list, &row->user_payload_list);
+	spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+	return 0;
+}
+
+static int cam_sync_handle_deregister_user_payload(
+	struct cam_private_ioctl_arg *k_ioctl)
+{
+	struct cam_sync_userpayload_info userpayload_info;
+	struct sync_user_payload *user_payload_kernel, *temp;
+	uint32_t sync_obj;
+	struct sync_table_row *row = NULL;
+
+	if (k_ioctl->size != sizeof(struct cam_sync_userpayload_info)) {
+		CDBG("Incorrect ioctl size\n");
+		return -EINVAL;
+	}
+
+	if (!k_ioctl->ioctl_ptr) {
+		CDBG("Invalid embedded ioctl ptr\n");
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&userpayload_info,
+		(void *)k_ioctl->ioctl_ptr,
+		k_ioctl->size))
+		return -EFAULT;
+
+	sync_obj = userpayload_info.sync_obj;
+	if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
+		return -EINVAL;
+
+	spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
+	row =  sync_dev->sync_table + sync_obj;
+
+	if (row->state == CAM_SYNC_STATE_INVALID) {
+		pr_err("Error: accessing an uninitialized sync obj = %d\n",
+			sync_obj);
+		spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+		return -EINVAL;
+	}
+
+	list_for_each_entry_safe(user_payload_kernel, temp,
+				&row->user_payload_list, list) {
+		if (user_payload_kernel->payload_data[0] ==
+				userpayload_info.payload[0] &&
+				user_payload_kernel->payload_data[1] ==
+				userpayload_info.payload[1]) {
+			list_del_init(&user_payload_kernel->list);
+			kfree(user_payload_kernel);
+		}
+	}
+
+	spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+	return 0;
+}
+
+static long cam_sync_dev_ioctl(struct file *filep, void *fh,
+		bool valid_prio, unsigned int cmd, void *arg)
+{
+	int32_t rc;
+	struct sync_device *sync_dev = video_drvdata(filep);
+	struct cam_private_ioctl_arg k_ioctl;
+
+	if (!sync_dev) {
+		pr_err("%s sync_dev NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!arg)
+		return -EINVAL;
+
+	if (cmd != CAM_PRIVATE_IOCTL_CMD)
+		return -ENOIOCTLCMD;
+
+	k_ioctl = *(struct cam_private_ioctl_arg *)arg;
+
+	switch (k_ioctl.id) {
+	case CAM_SYNC_CREATE:
+		rc = cam_sync_handle_create(&k_ioctl);
+		break;
+	case CAM_SYNC_DESTROY:
+		rc = cam_sync_handle_destroy(&k_ioctl);
+		break;
+	case CAM_SYNC_REGISTER_PAYLOAD:
+		rc = cam_sync_handle_register_user_payload(
+			&k_ioctl);
+		break;
+	case CAM_SYNC_DEREGISTER_PAYLOAD:
+		rc = cam_sync_handle_deregister_user_payload(
+			&k_ioctl);
+		break;
+	case CAM_SYNC_SIGNAL:
+		rc = cam_sync_handle_signal(&k_ioctl);
+		break;
+	case CAM_SYNC_MERGE:
+		rc = cam_sync_handle_merge(&k_ioctl);
+		break;
+	case CAM_SYNC_WAIT:
+		rc = cam_sync_handle_wait(&k_ioctl);
+		((struct cam_private_ioctl_arg *)arg)->result =
+			k_ioctl.result;
+		break;
+	default:
+		rc = -ENOIOCTLCMD;
+	}
+
+	return rc;
+}
+
+static unsigned int cam_sync_poll(struct file *f,
+	struct poll_table_struct *pll_table)
+{
+	int rc = 0;
+	struct v4l2_fh *eventq = f->private_data;
+
+	if (!eventq)
+		return -EINVAL;
+
+	poll_wait(f, &eventq->wait, pll_table);
+
+	if (v4l2_event_pending(eventq))
+		rc = POLLPRI;
+
+	return rc;
+}
+
+static int cam_sync_open(struct file *filep)
+{
+	int rc;
+	struct sync_device *sync_dev = video_drvdata(filep);
+
+	if (!sync_dev) {
+		pr_err("%s Sync device NULL\n", __func__);
+		return -ENODEV;
+	}
+
+	mutex_lock(&sync_dev->table_lock);
+	if (sync_dev->open_cnt >= 1) {
+		mutex_unlock(&sync_dev->table_lock);
+		return -EALREADY;
+	}
+
+	rc = v4l2_fh_open(filep);
+	if (!rc) {
+		sync_dev->open_cnt++;
+		spin_lock_bh(&sync_dev->cam_sync_eventq_lock);
+		sync_dev->cam_sync_eventq = filep->private_data;
+		spin_unlock_bh(&sync_dev->cam_sync_eventq_lock);
+	} else {
+		pr_err("v4l2_fh_open failed : %d\n", rc);
+	}
+	mutex_unlock(&sync_dev->table_lock);
+
+	return rc;
+}
+
+static int cam_sync_close(struct file *filep)
+{
+	int rc = 0;
+	int i;
+	struct sync_device *sync_dev = video_drvdata(filep);
+
+	if (!sync_dev) {
+		pr_err("%s Sync device NULL\n", __func__);
+		rc = -ENODEV;
+		return rc;
+	}
+	mutex_lock(&sync_dev->table_lock);
+	sync_dev->open_cnt--;
+	if (!sync_dev->open_cnt) {
+		for (i = 1; i < CAM_SYNC_MAX_OBJS; i++) {
+			struct sync_table_row *row =
+			sync_dev->sync_table + i;
+			if (row->state == CAM_SYNC_STATE_INVALID)
+				continue;
+
+			/* Signal all remaining objects as ERR,but we don't care
+			 * about the return status here apart from logging it
+			 */
+			rc = cam_sync_signal(i, CAM_SYNC_STATE_SIGNALED_ERROR);
+			if (rc < 0)
+				pr_err("Cleanup signal failed: idx = %d\n", i);
+
+			rc = cam_sync_destroy(i);
+			if (rc < 0)
+				pr_err("Cleanup destroy failed: idx = %d\n", i);
+		}
+	}
+	mutex_unlock(&sync_dev->table_lock);
+	spin_lock_bh(&sync_dev->cam_sync_eventq_lock);
+	sync_dev->cam_sync_eventq = NULL;
+	spin_unlock_bh(&sync_dev->cam_sync_eventq_lock);
+	v4l2_fh_release(filep);
+
+	return rc;
+}
+
+int cam_sync_subscribe_event(struct v4l2_fh *fh,
+		const struct v4l2_event_subscription *sub)
+{
+	return v4l2_event_subscribe(fh, sub, CAM_SYNC_MAX_V4L2_EVENTS, NULL);
+}
+
+int cam_sync_unsubscribe_event(struct v4l2_fh *fh,
+		const struct v4l2_event_subscription *sub)
+{
+	return v4l2_event_unsubscribe(fh, sub);
+}
+
+static const struct v4l2_ioctl_ops g_cam_sync_ioctl_ops = {
+	.vidioc_subscribe_event = cam_sync_subscribe_event,
+	.vidioc_unsubscribe_event = cam_sync_unsubscribe_event,
+	.vidioc_default = cam_sync_dev_ioctl,
+};
+
+static struct v4l2_file_operations cam_sync_v4l2_fops = {
+	.owner = THIS_MODULE,
+	.open  = cam_sync_open,
+	.release = cam_sync_close,
+	.poll = cam_sync_poll,
+	.unlocked_ioctl   = video_ioctl2,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = video_ioctl2,
+#endif
+};
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+static int cam_sync_media_controller_init(struct sync_device *sync_dev,
+	struct platform_device *pdev)
+{
+	int rc;
+
+	sync_dev->v4l2_dev.mdev = kzalloc(sizeof(struct media_device),
+		GFP_KERNEL);
+	if (!sync_dev->v4l2_dev.mdev)
+		return -ENOMEM;
+
+	media_device_init(sync_dev->v4l2_dev.mdev);
+	strlcpy(sync_dev->v4l2_dev.mdev->model, CAM_SYNC_DEVICE_NAME,
+			sizeof(sync_dev->v4l2_dev.mdev->model));
+	sync_dev->v4l2_dev.mdev->dev = &(pdev->dev);
+
+	rc = media_device_register(sync_dev->v4l2_dev.mdev);
+	if (rc < 0)
+		goto register_fail;
+
+	rc = media_entity_pads_init(&sync_dev->vdev->entity, 0, NULL);
+	if (rc < 0)
+		goto entity_fail;
+
+	return 0;
+
+entity_fail:
+	media_device_unregister(sync_dev->v4l2_dev.mdev);
+register_fail:
+	media_device_cleanup(sync_dev->v4l2_dev.mdev);
+	return rc;
+}
+
+static void cam_sync_media_controller_cleanup(struct sync_device *sync_dev)
+{
+	media_entity_cleanup(&sync_dev->vdev->entity);
+	media_device_unregister(sync_dev->v4l2_dev.mdev);
+	media_device_cleanup(sync_dev->v4l2_dev.mdev);
+	kfree(sync_dev->v4l2_dev.mdev);
+}
+
+static void cam_sync_init_entity(struct sync_device *sync_dev)
+{
+	sync_dev->vdev->entity.function = CAM_SYNC_DEVICE_TYPE;
+	sync_dev->vdev->entity.name =
+				video_device_node_name(sync_dev->vdev);
+}
+#else
+static int cam_sync_media_controller_init(struct sync_device *sync_dev,
+	struct platform_device *pdev)
+{
+	return 0;
+}
+
+static void cam_sync_media_controller_cleanup(struct sync_device *sync_dev)
+{
+}
+
+static void cam_sync_init_entity(struct sync_device *sync_dev)
+{
+}
+#endif
+
+static int cam_sync_probe(struct platform_device *pdev)
+{
+	int rc;
+	int idx;
+
+	sync_dev = kzalloc(sizeof(*sync_dev), GFP_KERNEL);
+	if (!sync_dev)
+		return -ENOMEM;
+
+	mutex_init(&sync_dev->table_lock);
+	spin_lock_init(&sync_dev->cam_sync_eventq_lock);
+
+	for (idx = 0; idx < CAM_SYNC_MAX_OBJS; idx++)
+		spin_lock_init(&sync_dev->row_spinlocks[idx]);
+
+	sync_dev->vdev = video_device_alloc();
+	if (!sync_dev->vdev) {
+		rc = -ENOMEM;
+		goto vdev_fail;
+	}
+
+	rc = cam_sync_media_controller_init(sync_dev, pdev);
+	if (rc < 0)
+		goto mcinit_fail;
+
+	sync_dev->vdev->v4l2_dev = &sync_dev->v4l2_dev;
+
+	rc = v4l2_device_register(&(pdev->dev), sync_dev->vdev->v4l2_dev);
+	if (rc < 0)
+		goto register_fail;
+
+	strlcpy(sync_dev->vdev->name, CAM_SYNC_NAME,
+				sizeof(sync_dev->vdev->name));
+	sync_dev->vdev->release  = video_device_release;
+	sync_dev->vdev->fops     = &cam_sync_v4l2_fops;
+	sync_dev->vdev->ioctl_ops = &g_cam_sync_ioctl_ops;
+	sync_dev->vdev->minor     = -1;
+	sync_dev->vdev->vfl_type  = VFL_TYPE_GRABBER;
+	rc = video_register_device(sync_dev->vdev,
+		VFL_TYPE_GRABBER, -1);
+	if (rc < 0)
+		goto v4l2_fail;
+
+	cam_sync_init_entity(sync_dev);
+	video_set_drvdata(sync_dev->vdev, sync_dev);
+	memset(&sync_dev->sync_table, 0, sizeof(sync_dev->sync_table));
+	memset(&sync_dev->bitmap, 0, sizeof(sync_dev->bitmap));
+	bitmap_zero(sync_dev->bitmap, CAM_SYNC_MAX_OBJS);
+
+	/*
+	 * We treat zero as invalid handle, so we will keep the 0th bit set
+	 * always
+	 */
+	set_bit(0, sync_dev->bitmap);
+
+	sync_dev->work_queue = alloc_workqueue(CAM_SYNC_WORKQUEUE_NAME,
+		WQ_HIGHPRI | WQ_UNBOUND, 0);
+
+	if (!sync_dev->work_queue) {
+		pr_err("Error: high priority work queue creation failed!\n");
+		rc = -ENOMEM;
+		goto v4l2_fail;
+	}
+
+	return rc;
+
+v4l2_fail:
+	v4l2_device_unregister(sync_dev->vdev->v4l2_dev);
+register_fail:
+	cam_sync_media_controller_cleanup(sync_dev);
+mcinit_fail:
+	video_device_release(sync_dev->vdev);
+vdev_fail:
+	mutex_destroy(&sync_dev->table_lock);
+	kfree(sync_dev);
+	return rc;
+}
+
+static int cam_sync_remove(struct platform_device *pdev)
+{
+	v4l2_device_unregister(sync_dev->vdev->v4l2_dev);
+	cam_sync_media_controller_cleanup(sync_dev);
+	video_device_release(sync_dev->vdev);
+	kfree(sync_dev);
+	sync_dev = NULL;
+
+	return 0;
+}
+
+static struct platform_device cam_sync_device = {
+	.name = "cam_sync",
+	.id = -1,
+};
+
+static struct platform_driver cam_sync_driver = {
+	.probe = cam_sync_probe,
+	.remove = cam_sync_remove,
+	.driver = {
+		.name = "cam_sync",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init cam_sync_init(void)
+{
+	int rc;
+
+	rc = platform_device_register(&cam_sync_device);
+	if (rc)
+		return -ENODEV;
+
+	return platform_driver_register(&cam_sync_driver);
+}
+
+static void __exit cam_sync_exit(void)
+{
+	int idx;
+
+	for (idx = 0; idx < CAM_SYNC_MAX_OBJS; idx++)
+		spin_lock_init(&sync_dev->row_spinlocks[idx]);
+	platform_driver_unregister(&cam_sync_driver);
+	platform_device_unregister(&cam_sync_device);
+	kfree(sync_dev);
+}
+
+module_init(cam_sync_init);
+module_exit(cam_sync_exit);
+MODULE_DESCRIPTION("Camera sync driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_api.h b/drivers/media/platform/msm/camera/cam_sync/cam_sync_api.h
new file mode 100644
index 0000000..9646887
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_api.h
@@ -0,0 +1,128 @@
+/* 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.
+ */
+
+#ifndef __CAM_SYNC_API_H__
+#define __CAM_SYNC_API_H__
+
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/completion.h>
+#include <linux/videodev2.h>
+#include <uapi/media/cam_sync.h>
+
+#define SYNC_DEBUG_NAME_LEN 63
+typedef void (*sync_callback)(int32_t sync_obj, int status, void *data);
+
+/* Kernel APIs */
+
+/**
+ * @brief: Creates a sync object
+ *
+ *  The newly created sync obj is assigned to sync_obj.
+ *  sync object.
+ *
+ * @param sync_obj   : Pointer to int referencing the sync object.
+ * @param name : Optional parameter associating a name with the sync object for
+ * debug purposes. Only first SYNC_DEBUG_NAME_LEN bytes are accepted,
+ * rest will be ignored.
+ *
+ * @return Status of operation. Zero in case of success.
+ * -EINVAL will be returned if sync_obj is an invalid pointer.
+ * -ENOMEM will be returned if the kernel can't allocate space for
+ * sync object.
+ */
+int cam_sync_create(int32_t *sync_obj, const char *name);
+
+/**
+ * @brief: Registers a callback with a sync object
+ *
+ * @param cb_func:  Pointer to callback to be registered
+ * @param userdata: Opaque pointer which will be passed back with callback.
+ * @param sync_obj: int referencing the sync object.
+ *
+ * @return Status of operation. Zero in case of success.
+ * -EINVAL will be returned if userdata is invalid.
+ * -ENOMEM will be returned if cb_func is invalid.
+ *
+ */
+int cam_sync_register_callback(sync_callback cb_func,
+	void *userdata, int32_t sync_obj);
+
+/**
+ * @brief: De-registers a callback with a sync object
+ *
+ * @param cb_func:  Pointer to callback to be de-registered
+ * @param userdata: Opaque pointer which will be passed back with callback.
+ * @param sync_obj: int referencing the sync object.
+ *
+ * @return Status of operation. Zero in case of success.
+ * -EINVAL will be returned if userdata is invalid.
+ * -ENOMEM will be returned if cb_func is invalid.
+ */
+int cam_sync_deregister_callback(sync_callback cb_func,
+	void *userdata, int32_t sync_obj);
+
+/**
+ * @brief: Signals a sync object with the status argument.
+ *
+ * This function will signal the sync object referenced by the sync_obj
+ * parameter and when doing so, will trigger callbacks in both user space and
+ * kernel. Callbacks will triggered asynchronously and their order of execution
+ * is not guaranteed. The status parameter will indicate whether the entity
+ * performing the signaling wants to convey an error case or a success case.
+ *
+ * @param sync_obj: int referencing the sync object.
+ * @param status: Status of the signaling. Can be either SYNC_SIGNAL_ERROR or
+ * SYNC_SIGNAL_SUCCESS.
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_signal(int32_t sync_obj, uint32_t status);
+
+/**
+ * @brief: Merges multiple sync objects
+ *
+ * This function will merge multiple sync objects into a sync group.
+ *
+ * @param sync_obj: pointer to a block of ints to be merged
+ * @param num_objs: Number of ints in the block
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj);
+
+/**
+ * @brief: Destroys a sync object
+ *
+ * @param sync_obj: int referencing the sync object to be destroyed
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_destroy(int32_t sync_obj);
+
+/**
+ * @brief: Waits for a sync object synchronously
+ *
+ * Does a wait on the sync object identified by sync_obj for a maximum
+ * of timeout_ms milliseconds. Must not be called from interrupt context as
+ * this API can sleep. Should be called from process context only.
+ *
+ * @param sync_obj: int referencing the sync object to be waited upon
+ * @timeout_ms sync_obj: Timeout in ms.
+ *
+ * @return 0 upon success, -EINVAL if sync object is in bad state or arguments
+ * are invalid, -ETIMEDOUT if wait times out.
+ */
+int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms);
+
+
+#endif /* __CAM_SYNC_API_H__ */
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h b/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h
new file mode 100644
index 0000000..ba9bef4
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h
@@ -0,0 +1,186 @@
+/* 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.
+ */
+
+#ifndef __CAM_SYNC_PRIVATE_H__
+#define __CAM_SYNC_PRIVATE_H__
+
+#include <linux/bitmap.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+
+#ifdef CONFIG_CAM_SYNC_DBG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+#define CAM_SYNC_OBJ_NAME_LEN           64
+#define CAM_SYNC_MAX_OBJS               1024
+#define CAM_SYNC_MAX_V4L2_EVENTS        50
+#define CAM_SYNC_DEBUG_FILENAME         "cam_debug"
+#define CAM_SYNC_DEBUG_BASEDIR          "cam"
+#define CAM_SYNC_DEBUG_BUF_SIZE         32
+#define CAM_SYNC_PAYLOAD_WORDS          2
+#define CAM_SYNC_NAME                   "cam_sync"
+#define CAM_SYNC_WORKQUEUE_NAME         "HIPRIO_SYNC_WORK_QUEUE"
+
+#define CAM_SYNC_TYPE_INDV              0
+#define CAM_SYNC_TYPE_GROUP             1
+
+/**
+ * enum sync_type - Enum to indicate the type of sync object,
+ * i.e. individual or group.
+ *
+ * @SYNC_TYPE_INDV  : Object is an individual sync object
+ * @SYNC_TYPE_GROUP : Object is a group sync object
+ */
+enum sync_type {
+	SYNC_TYPE_INDV,
+	SYNC_TYPE_GROUP
+};
+
+/**
+ * struct sync_parent_info - Single node of information about a parent
+ * of a sync object, usually part of the parents linked list
+ *
+ * @sync_id  : Sync object id of parent
+ * @list     : List member used to append this node to a linked list
+ */
+struct sync_parent_info {
+	int32_t sync_id;
+	struct list_head list;
+};
+
+/**
+ * struct sync_parent_info - Single node of information about a child
+ * of a sync object, usually part of the children linked list
+ *
+ * @sync_id  : Sync object id of child
+ * @list     : List member used to append this node to a linked list
+ */
+struct sync_child_info {
+	int32_t sync_id;
+	struct list_head list;
+};
+
+
+/**
+ * struct sync_callback_info - Single node of information about a kernel
+ * callback registered on a sync object
+ *
+ * @callback_func    : Callback function, registered by client driver
+ * @cb_data          : Callback data, registered by client driver
+ * @status........   : Status with which callback will be invoked in client
+ * @sync_obj         : Sync id of the object for which callback is registered
+ * @cb_dispatch_work : Work representing the call dispatch
+ * @list             : List member used to append this node to a linked list
+ */
+struct sync_callback_info {
+	sync_callback callback_func;
+	void *cb_data;
+	int status;
+	int32_t sync_obj;
+	struct work_struct cb_dispatch_work;
+	struct list_head list;
+};
+
+/**
+ * struct sync_user_payload - Single node of information about a user space
+ * payload registered from user space
+ *
+ * @payload_data    : Payload data, opaque to kernel
+ * @list            : List member used to append this node to a linked list
+ */
+struct sync_user_payload {
+	uint64_t payload_data[CAM_SYNC_PAYLOAD_WORDS];
+	struct list_head list;
+};
+
+/**
+ * struct sync_table_row - Single row of information about a sync object, used
+ * for internal book keeping in the sync driver
+ *
+ * @name              : Optional string representation of the sync object
+ * @type              : Type of the sync object (individual or group)
+ * @sync_id           : Integer id representing this sync object
+ * @parents_list      : Linked list of parents of this sync object
+ * @children_list     : Linked list of children of this sync object
+ * @state             : State (INVALID, ACTIVE, SIGNALED_SUCCESS or
+ *                      SIGNALED_ERROR)
+ * @remaining         : Count of remaining children that not been signaled
+ * @signaled          : Completion variable on which block calls will wait
+ * @callback_list     : Linked list of kernel callbacks registered
+ * @user_payload_list : LInked list of user space payloads registered
+ */
+struct sync_table_row {
+	char name[CAM_SYNC_OBJ_NAME_LEN];
+	enum sync_type type;
+	int32_t sync_id;
+	/* List of parents, which are merged objects */
+	struct list_head parents_list;
+	/* List of children, which constitute the merged object */
+	struct list_head children_list;
+	uint32_t state;
+	uint32_t remaining;
+	struct completion signaled;
+	struct list_head callback_list;
+	struct list_head user_payload_list;
+};
+
+/**
+ * struct cam_signalable_info - Information for a single sync object that is
+ * ready to be signaled
+ *
+ * @sync_obj : Sync object id of signalable object
+ * @status   : Status with which to signal
+ * @list     : List member used to append this node to a linked list
+ */
+struct cam_signalable_info {
+	int32_t sync_obj;
+	uint32_t status;
+	struct list_head list;
+};
+
+/**
+ * struct sync_device - Internal struct to book keep sync driver details
+ *
+ * @vdev            : Video device
+ * @v4l2_dev        : V4L2 device
+ * @sync_table      : Table of all sync objects
+ * @row_spinlocks   : Spinlock array, one for each row in the table
+ * @table_lock      : Mutex used to lock the table
+ * @open_cnt        : Count of file open calls made on the sync driver
+ * @work_queue      : Work queue used for dispatching kernel callbacks
+ * @cam_sync_eventq : Event queue used to dispatch user payloads to user space
+ * @bitmap          : Bitmap representation of all sync objects
+ */
+struct sync_device {
+	struct video_device *vdev;
+	struct v4l2_device v4l2_dev;
+	struct sync_table_row sync_table[CAM_SYNC_MAX_OBJS];
+	spinlock_t row_spinlocks[CAM_SYNC_MAX_OBJS];
+	struct mutex table_lock;
+	int open_cnt;
+	struct workqueue_struct *work_queue;
+	struct v4l2_fh *cam_sync_eventq;
+	spinlock_t cam_sync_eventq_lock;
+	DECLARE_BITMAP(bitmap, CAM_SYNC_MAX_OBJS);
+};
+
+
+#endif /* __CAM_SYNC_PRIVATE_H__ */
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
new file mode 100644
index 0000000..4f5bf87
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
@@ -0,0 +1,296 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "CAM-SYNC-UTIL %s:%d " fmt, __func__, __LINE__
+
+#include "cam_sync_util.h"
+
+int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev,
+	long *idx)
+{
+	int rc = 0;
+
+	mutex_lock(&sync_dev->table_lock);
+
+	*idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS);
+
+	if (*idx < CAM_SYNC_MAX_OBJS)
+		set_bit(*idx, sync_dev->bitmap);
+	else
+		rc = -1;
+
+	mutex_unlock(&sync_dev->table_lock);
+
+	return rc;
+}
+
+int cam_sync_init_object(struct sync_table_row *table,
+	uint32_t idx,
+	const char *name)
+{
+	struct sync_table_row *row = table + idx;
+
+	if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS)
+		return -EINVAL;
+
+	if (name)
+		strlcpy(row->name, name, SYNC_DEBUG_NAME_LEN);
+	INIT_LIST_HEAD(&row->parents_list);
+	INIT_LIST_HEAD(&row->children_list);
+	row->type = CAM_SYNC_TYPE_INDV;
+	row->sync_id = idx;
+	row->state = CAM_SYNC_STATE_ACTIVE;
+	row->remaining = 0;
+	init_completion(&row->signaled);
+	INIT_LIST_HEAD(&row->callback_list);
+	INIT_LIST_HEAD(&row->user_payload_list);
+
+	return 0;
+}
+
+int cam_sync_init_group_object(struct sync_table_row *table,
+	uint32_t idx,
+	uint32_t *sync_objs,
+	uint32_t num_objs)
+{
+	int i;
+	struct sync_child_info *child_info;
+	struct sync_parent_info *parent_info;
+	struct sync_table_row *row = table + idx;
+	struct sync_table_row *child_row = NULL;
+
+	spin_lock_bh(&sync_dev->row_spinlocks[idx]);
+	INIT_LIST_HEAD(&row->parents_list);
+
+	INIT_LIST_HEAD(&row->children_list);
+
+	/*
+	 * While traversing parents and children, we allocate in a loop and in
+	 * case allocation fails, we call the clean up function which frees up
+	 * all memory allocation thus far
+	 */
+	for (i = 0; i < num_objs; i++) {
+		child_info = kzalloc(sizeof(*child_info), GFP_ATOMIC);
+
+		if (!child_info) {
+			cam_sync_util_cleanup_children_list(
+				&row->children_list);
+			spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
+			return -ENOMEM;
+		}
+
+		child_info->sync_id = sync_objs[i];
+		list_add_tail(&child_info->list, &row->children_list);
+	}
+
+	for (i = 0; i < num_objs; i++) {
+		/* This gets us the row corresponding to the sync object */
+		child_row = table + sync_objs[i];
+		spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
+		parent_info = kzalloc(sizeof(*parent_info), GFP_ATOMIC);
+		if (!parent_info) {
+			cam_sync_util_cleanup_parents_list(
+				&child_row->parents_list);
+			cam_sync_util_cleanup_children_list(
+				&row->children_list);
+			spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
+			spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
+			return -ENOMEM;
+		}
+		parent_info->sync_id = idx;
+		list_add_tail(&parent_info->list, &child_row->parents_list);
+		spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
+	}
+
+	row->type = CAM_SYNC_TYPE_GROUP;
+	row->sync_id = idx;
+	row->state = CAM_SYNC_STATE_ACTIVE;
+	row->remaining = num_objs;
+	init_completion(&row->signaled);
+	INIT_LIST_HEAD(&row->callback_list);
+	INIT_LIST_HEAD(&row->user_payload_list);
+
+	spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
+	return 0;
+}
+
+int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx)
+{
+	struct sync_table_row *row = table + idx;
+	struct sync_child_info *child_info, *temp_child;
+	struct sync_callback_info *sync_cb, *temp_cb;
+	struct sync_parent_info *parent_info, *temp_parent;
+	struct sync_user_payload *upayload_info, *temp_upayload;
+
+	if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS)
+		return -EINVAL;
+
+	spin_lock_bh(&sync_dev->row_spinlocks[idx]);
+	clear_bit(idx, sync_dev->bitmap);
+	list_for_each_entry_safe(child_info, temp_child,
+				&row->children_list, list) {
+		list_del_init(&child_info->list);
+		kfree(child_info);
+	}
+
+	list_for_each_entry_safe(parent_info, temp_parent,
+				&row->parents_list, list) {
+		list_del_init(&parent_info->list);
+		kfree(parent_info);
+	}
+
+	list_for_each_entry_safe(upayload_info, temp_upayload,
+				&row->user_payload_list, list) {
+		list_del_init(&upayload_info->list);
+		kfree(upayload_info);
+	}
+
+	list_for_each_entry_safe(sync_cb, temp_cb,
+				&row->callback_list, list) {
+		list_del_init(&sync_cb->list);
+		kfree(sync_cb);
+	}
+
+	row->state = CAM_SYNC_STATE_INVALID;
+	memset(row, 0, sizeof(*row));
+	spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
+
+	return 0;
+}
+
+void cam_sync_util_cb_dispatch(struct work_struct *cb_dispatch_work)
+{
+	struct sync_callback_info *cb_info = container_of(cb_dispatch_work,
+		struct sync_callback_info,
+		cb_dispatch_work);
+
+	cb_info->callback_func(cb_info->sync_obj,
+		cb_info->status,
+		cb_info->cb_data);
+
+	kfree(cb_info);
+}
+
+void cam_sync_util_send_v4l2_event(uint32_t id,
+	uint32_t sync_obj,
+	int status,
+	void *payload,
+	int len)
+{
+	struct v4l2_event event;
+	__u64 *payload_data = NULL;
+	struct cam_sync_ev_header *ev_header = NULL;
+
+	event.id = id;
+	event.type = CAM_SYNC_V4L_EVENT;
+
+	ev_header = CAM_SYNC_GET_HEADER_PTR(event);
+	ev_header->sync_obj = sync_obj;
+	ev_header->status = status;
+
+	payload_data = CAM_SYNC_GET_PAYLOAD_PTR(event, __u64);
+	memcpy(payload_data, payload, len);
+
+	v4l2_event_queue(sync_dev->vdev, &event);
+}
+
+int cam_sync_util_validate_merge(uint32_t *sync_obj, uint32_t num_objs)
+{
+	int i;
+	struct sync_table_row *row = NULL;
+
+	for (i = 0; i < num_objs; i++) {
+		row = sync_dev->sync_table + sync_obj[i];
+		spin_lock_bh(&sync_dev->row_spinlocks[sync_obj[i]]);
+		if (row->type == CAM_SYNC_TYPE_GROUP ||
+			row->state == CAM_SYNC_STATE_INVALID) {
+			pr_err("Group obj %d can't be merged or obj UNINIT\n",
+				sync_obj[i]);
+			spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj[i]]);
+			return -EINVAL;
+		}
+		spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj[i]]);
+	}
+	return 0;
+}
+
+int cam_sync_util_add_to_signalable_list(int32_t sync_obj,
+	uint32_t status,
+	struct list_head *sync_list)
+{
+	struct cam_signalable_info *signalable_info = NULL;
+
+	signalable_info = kzalloc(sizeof(*signalable_info), GFP_ATOMIC);
+	if (!signalable_info)
+		return -ENOMEM;
+
+	signalable_info->sync_obj = sync_obj;
+	signalable_info->status = status;
+
+	list_add_tail(&signalable_info->list, sync_list);
+
+	return 0;
+}
+
+int cam_sync_util_get_state(int current_state,
+	int new_state)
+{
+	int result = CAM_SYNC_STATE_SIGNALED_ERROR;
+
+	if (new_state != CAM_SYNC_STATE_SIGNALED_SUCCESS &&
+		new_state != CAM_SYNC_STATE_SIGNALED_ERROR)
+		return CAM_SYNC_STATE_SIGNALED_ERROR;
+
+	switch (current_state) {
+	case CAM_SYNC_STATE_INVALID:
+		result =  CAM_SYNC_STATE_SIGNALED_ERROR;
+		break;
+
+	case CAM_SYNC_STATE_ACTIVE:
+	case CAM_SYNC_STATE_SIGNALED_SUCCESS:
+		if (new_state == CAM_SYNC_STATE_SIGNALED_ERROR)
+			result = CAM_SYNC_STATE_SIGNALED_ERROR;
+		else if (new_state == CAM_SYNC_STATE_SIGNALED_SUCCESS)
+			result = CAM_SYNC_STATE_SIGNALED_SUCCESS;
+		break;
+
+	case CAM_SYNC_STATE_SIGNALED_ERROR:
+		result = CAM_SYNC_STATE_SIGNALED_ERROR;
+		break;
+	}
+
+	return result;
+}
+
+void cam_sync_util_cleanup_children_list(struct list_head *list_to_clean)
+{
+	struct sync_child_info *child_info = NULL;
+	struct sync_child_info *temp_child_info = NULL;
+
+	list_for_each_entry_safe(child_info,
+			temp_child_info, list_to_clean, list) {
+		list_del_init(&child_info->list);
+		kfree(child_info);
+	}
+}
+
+void cam_sync_util_cleanup_parents_list(struct list_head *list_to_clean)
+{
+	struct sync_parent_info *parent_info = NULL;
+	struct sync_parent_info *temp_parent_info = NULL;
+
+	list_for_each_entry_safe(parent_info,
+			temp_parent_info, list_to_clean, list) {
+		list_del_init(&parent_info->list);
+		kfree(parent_info);
+	}
+}
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h
new file mode 100644
index 0000000..9dedd14
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h
@@ -0,0 +1,156 @@
+/* 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.
+ */
+
+#ifndef __CAM_SYNC_UTIL_H__
+#define __CAM_SYNC_UTIL_H__
+
+
+#include <cam_sync_api.h>
+#include "cam_sync_private.h"
+
+extern struct sync_device *sync_dev;
+
+/**
+ * @brief: Finds an empty row in the sync table and sets its corresponding bit
+ * in the bit array
+ *
+ * @param sync_dev : Pointer to the sync device instance
+ * @param idx      : Pointer to an long containing the index found in the bit
+ *                   array
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev,
+	long *idx);
+
+/**
+ * @brief: Function to initialize an empty row in the sync table. This should be
+ *         called only for individual sync objects.
+ *
+ * @param table : Pointer to the sync objects table
+ * @param idx   : Index of row to initialize
+ * @param name  : Optional string representation of the sync object. Should be
+ *                63 characters or less
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_init_object(struct sync_table_row *table,
+	uint32_t idx,
+	const char *name);
+
+/**
+ * @brief: Function to uninitialize a row in the sync table
+ *
+ * @param table : Pointer to the sync objects table
+ * @param idx   : Index of row to initialize
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx);
+
+/**
+ * @brief: Function to initialize a row in the sync table when the object is a
+ *         group object, also known as a merged sync object
+ *
+ * @param table     : Pointer to the sync objects table
+ * @param idx       : Index of row to initialize
+ * @param sync_objs : Array of sync objects which will merged
+ *                    or grouped together
+ * @param num_objs  : Number of sync objects in the array
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_init_group_object(struct sync_table_row *table,
+	uint32_t idx,
+	uint32_t *sync_objs,
+	uint32_t num_objs);
+
+int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx);
+
+/**
+ * @brief: Function to dispatch a kernel callback for a sync callback
+ *
+ * @param cb_dispatch_work : Pointer to the work_struct that needs to be
+ *                           dispatched
+ *
+ * @return None
+ */
+void cam_sync_util_cb_dispatch(struct work_struct *cb_dispatch_work);
+
+/**
+ * @brief: Function to send V4L event to user space
+ * @param id       : V4L event id to send
+ * @param sync_obj : Sync obj for which event needs to be sent
+ * @param status   : Status of the event
+ * @payload        : Payload that needs to be sent to user space
+ * @len            : Length of the payload
+ *
+ * @return None
+ */
+void cam_sync_util_send_v4l2_event(uint32_t id,
+	uint32_t sync_obj,
+	int status,
+	void *payload,
+	int len);
+
+/**
+ * @brief: Function to validate sync merge arguments
+ *
+ * @param sync_obj : Array of sync objects to merge
+ * @param num_objs : Number of sync objects in the array
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_util_validate_merge(uint32_t *sync_obj, uint32_t num_objs);
+
+/**
+ * @brief: Function which adds sync object information to the signalable list
+ *
+ * @param sync_obj : Sync object to add
+ * @param status   : Status of above sync object
+ * @param list     : Linked list where the information should be added to
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_util_add_to_signalable_list(int32_t sync_obj,
+	uint32_t status,
+	struct list_head *sync_list);
+
+/**
+ * @brief: Function which gets the next state of the sync object based on the
+ *         current state and the new state
+ *
+ * @param current_state : Current state of the sync object
+ * @param new_state     : New state of the sync object
+ *
+ * @return Next state of the sync object
+ */
+int cam_sync_util_get_state(int current_state,
+	int new_state);
+
+/**
+ * @brief: Function to clean up the children of a sync object
+ * @param list_to_clean : List to clean up
+ *
+ * @return None
+ */
+void cam_sync_util_cleanup_children_list(struct list_head *list_to_clean);
+
+/**
+ * @brief: Function to clean up the parents of a sync object
+ * @param list_to_clean : List to clean up
+ *
+ * @return None
+ */
+void cam_sync_util_cleanup_parents_list(struct list_head *list_to_clean);
+
+#endif /* __CAM_SYNC_UTIL_H__ */
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
index d396d4f..683386c 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
@@ -59,7 +59,7 @@
 	int rc = 0;
 	long clk_rate_round;
 
-	if (!clk || !clk_name || !clk_rate)
+	if (!clk || !clk_name)
 		return -EINVAL;
 
 	CDBG("enable %s, clk %pK rate %d\n",
@@ -231,8 +231,8 @@
 		return rc;
 	}
 
-	rc = of_property_read_string_index(of_node, "src-clock-name",
-				i, &src_clk_str);
+	rc = of_property_read_string_index(of_node, "src-clock-name", 0,
+		&src_clk_str);
 	if (rc) {
 		CDBG("No src_clk_str found\n");
 		soc_info->src_clk_idx = -1;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index 643e8a0..9a28700 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -112,7 +112,10 @@
 		return -EINVAL;
 	}
 
-	if (bus->bus_hdl < 1) {
+	if (!bus->bus_hdl) {
+		SDEROT_DBG("bus scaling not enabled\n");
+		return 0;
+	} else if (bus->bus_hdl < 0) {
 		SDEROT_ERR("invalid bus handle %d\n", bus->bus_hdl);
 		return -EINVAL;
 	}
@@ -2004,7 +2007,7 @@
 	devm_kfree(&mgr->pdev->dev, req);
 }
 
-static void sde_rotator_cancel_all_requests(struct sde_rot_mgr *mgr,
+void sde_rotator_cancel_all_requests(struct sde_rot_mgr *mgr,
 	struct sde_rot_file_private *private)
 {
 	struct sde_rot_entry_container *req, *req_next;
@@ -2501,8 +2504,7 @@
 	mgr->data_bus.bus_scale_pdata = msm_bus_cl_get_pdata(dev);
 	if (IS_ERR_OR_NULL(mgr->data_bus.bus_scale_pdata)) {
 		ret = PTR_ERR(mgr->data_bus.bus_scale_pdata);
-		if (!ret) {
-			ret = -EINVAL;
+		if (ret) {
 			SDEROT_ERR("msm_bus_cl_get_pdata failed. ret=%d\n",
 					ret);
 			mgr->data_bus.bus_scale_pdata = NULL;
@@ -2638,8 +2640,8 @@
 static int sde_rotator_bus_scale_register(struct sde_rot_mgr *mgr)
 {
 	if (!mgr->data_bus.bus_scale_pdata) {
-		SDEROT_ERR("Scale table is NULL\n");
-		return -EINVAL;
+		SDEROT_DBG("Bus scaling is not enabled\n");
+		return 0;
 	}
 
 	mgr->data_bus.bus_hdl =
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
index 0818917..980e4af 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
@@ -686,6 +686,14 @@
 int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable);
 
 /*
+ * sde_rotator_cancel_all_requests - cancel all outstanding requests
+ * @mgr: Pointer to rotator manager
+ * @private: Pointer to rotator manager per file context
+ */
+void sde_rotator_cancel_all_requests(struct sde_rot_mgr *mgr,
+	struct sde_rot_file_private *private);
+
+/*
  * sde_rot_mgr_lock - serialization lock prior to rotator manager calls
  * @mgr: Pointer to rotator manager
  */
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
index 86e04d6..e56c70a 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
@@ -996,11 +996,14 @@
 {
 	struct sde_rotator_debug_base *dbg = file->private_data;
 
-	if (dbg && dbg->buf) {
+	if (dbg) {
+		mutex_lock(&dbg->buflock);
 		kfree(dbg->buf);
 		dbg->buf_len = 0;
 		dbg->buf = NULL;
+		mutex_unlock(&dbg->buflock);
 	}
+
 	return 0;
 }
 
@@ -1032,8 +1035,10 @@
 	if (cnt > (dbg->max_offset - off))
 		cnt = dbg->max_offset - off;
 
+	mutex_lock(&dbg->buflock);
 	dbg->off = off;
 	dbg->cnt = cnt;
+	mutex_unlock(&dbg->buflock);
 
 	SDEROT_DBG("offset=%x cnt=%x\n", off, cnt);
 
@@ -1053,7 +1058,10 @@
 	if (*ppos)
 		return 0;	/* the end */
 
+	mutex_lock(&dbg->buflock);
 	len = snprintf(buf, sizeof(buf), "0x%08zx %zx\n", dbg->off, dbg->cnt);
+	mutex_unlock(&dbg->buflock);
+
 	if (len < 0 || len >= sizeof(buf))
 		return 0;
 
@@ -1092,6 +1100,8 @@
 	if (off >= dbg->max_offset)
 		return -EFAULT;
 
+	mutex_lock(&dbg->buflock);
+
 	/* Enable Clock for register access */
 	sde_rotator_clk_ctrl(dbg->mgr, true);
 
@@ -1100,6 +1110,8 @@
 	/* Disable Clock after register access */
 	sde_rotator_clk_ctrl(dbg->mgr, false);
 
+	mutex_unlock(&dbg->buflock);
+
 	SDEROT_DBG("addr=%zx data=%x\n", off, data);
 
 	return count;
@@ -1110,12 +1122,14 @@
 {
 	struct sde_rotator_debug_base *dbg = file->private_data;
 	size_t len;
+	int rc = 0;
 
 	if (!dbg) {
 		SDEROT_ERR("invalid handle\n");
 		return -ENODEV;
 	}
 
+	mutex_lock(&dbg->buflock);
 	if (!dbg->buf) {
 		char dump_buf[64];
 		char *ptr;
@@ -1127,7 +1141,8 @@
 
 		if (!dbg->buf) {
 			SDEROT_ERR("not enough memory to hold reg dump\n");
-			return -ENOMEM;
+			rc = -ENOMEM;
+			goto debug_read_error;
 		}
 
 		ptr = dbg->base + dbg->off;
@@ -1157,18 +1172,26 @@
 		dbg->buf_len = tot;
 	}
 
-	if (*ppos >= dbg->buf_len)
-		return 0; /* done reading */
+	if (*ppos >= dbg->buf_len) {
+		rc = 0; /* done reading */
+		goto debug_read_error;
+	}
 
 	len = min(count, dbg->buf_len - (size_t) *ppos);
 	if (copy_to_user(user_buf, dbg->buf + *ppos, len)) {
 		SDEROT_ERR("failed to copy to user\n");
-		return -EFAULT;
+		rc = -EFAULT;
+		goto debug_read_error;
 	}
 
 	*ppos += len; /* increase offset */
 
+	mutex_unlock(&dbg->buflock);
 	return len;
+
+debug_read_error:
+	mutex_unlock(&dbg->buflock);
+	return rc;
 }
 
 static const struct file_operations sde_rotator_off_fops = {
@@ -1202,6 +1225,9 @@
 	if (!dbg)
 		return -ENOMEM;
 
+	mutex_init(&dbg->buflock);
+	mutex_lock(&dbg->buflock);
+
 	if (name)
 		strlcpy(dbg->name, name, sizeof(dbg->name));
 	dbg->base = io_data->base;
@@ -1223,6 +1249,7 @@
 			dbg->base += rot_dev->mdata->regdump ?
 				rot_dev->mdata->regdump[0].offset : 0;
 	}
+	mutex_unlock(&dbg->buflock);
 
 	strlcpy(dbgname + prefix_len, "off", sizeof(dbgname) - prefix_len);
 	ent_off = debugfs_create_file(dbgname, 0644, debugfs_root, dbg,
@@ -1240,7 +1267,9 @@
 		goto reg_fail;
 	}
 
+	mutex_lock(&dbg->buflock);
 	dbg->mgr = rot_dev->mgr;
+	mutex_unlock(&dbg->buflock);
 
 	return 0;
 reg_fail:
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h
index c2c6f97..c6d0151 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.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
@@ -53,6 +53,7 @@
 	char *buf;
 	size_t buf_len;
 	struct sde_rot_mgr *mgr;
+	struct mutex buflock;
 };
 
 #if defined(CONFIG_DEBUG_FS)
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index 47f4cb0..c061446 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -450,11 +450,15 @@
 			list_empty(&ctx->pending_list),
 			msecs_to_jiffies(rot_dev->streamoff_timeout));
 	mutex_lock(q->lock);
-	if (!ret)
+	if (!ret) {
 		SDEDEV_ERR(rot_dev->dev,
 				"timeout to stream off s:%d t:%d p:%d\n",
 				ctx->session_id, q->type,
 				!list_empty(&ctx->pending_list));
+		sde_rot_mgr_lock(rot_dev->mgr);
+		sde_rotator_cancel_all_requests(rot_dev->mgr, ctx->private);
+		sde_rot_mgr_unlock(rot_dev->mgr);
+	}
 
 	sde_rotator_return_all_buffers(q, VB2_BUF_STATE_ERROR);
 
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 27e2d28..9071361 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -48,7 +48,7 @@
 #define XIN_WRITEBACK		1
 
 /* wait for at most 2 vsync for lowest refresh rate (24hz) */
-#define KOFF_TIMEOUT		(42 * 32)
+#define KOFF_TIMEOUT		(84)
 
 /* default stream buffer headroom in lines */
 #define DEFAULT_SBUF_HEADROOM	20
@@ -1860,6 +1860,7 @@
 	u32 danger_lut = 0;	/* applicable for realtime client only */
 	u32 safe_lut = 0;	/* applicable for realtime client only */
 	u32 flags = 0;
+	u32 rststs = 0;
 	struct sde_rotation_item *item;
 	int ret;
 
@@ -1931,10 +1932,46 @@
 
 	SDEROT_EVTLOG(ctx->start_ctrl, ctx->sys_cache_mode, ctx->op_mode);
 
+	/*
+	 * if Rotator HW is reset, but missing PM event notification, we
+	 * need to init the SW timestamp automatically.
+	 */
+	rststs = SDE_ROTREG_READ(rot->mdss_base, REGDMA_RESET_STATUS_REG);
+	if (!rot->reset_hw_ts && rststs) {
+		u32 l_ts, h_ts, swts;
+
+		swts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG);
+		h_ts = atomic_read(&rot->timestamp[ROT_QUEUE_HIGH_PRIORITY]);
+		l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]);
+		SDEROT_EVTLOG(0xbad0, rststs, swts, h_ts, l_ts);
+
+		if (ctx->q_id == ROT_QUEUE_HIGH_PRIORITY)
+			h_ts = (h_ts - 1) & SDE_REGDMA_SWTS_MASK;
+		else
+			l_ts = (l_ts - 1) & SDE_REGDMA_SWTS_MASK;
+
+		/* construct the combined timstamp */
+		swts = (h_ts & SDE_REGDMA_SWTS_MASK) |
+			((l_ts & SDE_REGDMA_SWTS_MASK) <<
+			 SDE_REGDMA_SWTS_SHIFT);
+
+		SDEROT_DBG("swts:0x%x, h_ts:0x%x, l_ts;0x%x\n",
+				swts, h_ts, l_ts);
+		SDEROT_EVTLOG(0x900d, swts, h_ts, l_ts);
+		rot->last_hw_ts = swts;
+
+		SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG,
+				rot->last_hw_ts);
+		SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_RESET_STATUS_REG, 0);
+		/* ensure write is issued to the rotator HW */
+		wmb();
+	}
+
 	if (rot->reset_hw_ts) {
 		SDEROT_EVTLOG(rot->last_hw_ts);
 		SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG,
 				rot->last_hw_ts);
+		SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_RESET_STATUS_REG, 0);
 		/* ensure write is issued to the rotator HW */
 		wmb();
 		rot->reset_hw_ts = false;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
index dc97bdf..aa762dd 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
@@ -291,5 +291,6 @@
 #define REGDMA_INT_LOW_MASK             0x00000700
 #define REGDMA_INT_ERR_MASK             0x000F0000
 #define REGDMA_TIMESTAMP_REG            ROT_SSPP_TPG_PATTERN_GEN_INIT_VAL
+#define REGDMA_RESET_STATUS_REG         ROT_SSPP_TPG_RGB_MAPPING
 
 #endif /*_SDE_ROTATOR_R3_HWIO_H */
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
index 4f6386b..e209192 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
@@ -471,11 +471,18 @@
 
 	sde_smmu = (struct sde_smmu_client *)token;
 
-	/* trigger rotator panic and dump */
-	SDEROT_ERR("trigger rotator panic and dump, iova=0x%08lx\n", iova);
+	/* trigger rotator dump */
+	SDEROT_ERR("trigger rotator dump, iova=0x%08lx, flags=0x%x\n",
+			iova, flags);
+	SDEROT_ERR("SMMU device:%s", sde_smmu->dev->kobj.name);
 
-	sde_rot_dump_panic();
+	/* generate dump, but no panic */
+	sde_rot_evtlog_tout_handler(false, __func__, "rot", "vbif_dbg_bus");
 
+	/*
+	 * return -ENOSYS to allow smmu driver to dump out useful
+	 * debug info.
+	 */
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 16c2aae..87a4ac8 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -33,7 +33,6 @@
 	[ilog2(HAL_H264_PROFILE_CONSTRAINED_HIGH)] =
 		HFI_H264_PROFILE_CONSTRAINED_HIGH,
 	[ilog2(HAL_VPX_PROFILE_VERSION_1)] = HFI_VPX_PROFILE_VERSION_1,
-	[ilog2(HAL_MVC_PROFILE_STEREO_HIGH)] = HFI_H264_PROFILE_STEREO_HIGH,
 };
 
 static int entropy_mode[] = {
@@ -68,13 +67,10 @@
 	[ilog2(HAL_COLOR_FORMAT_BGR565)] = HFI_COLOR_FORMAT_BGR565,
 	[ilog2(HAL_COLOR_FORMAT_RGB888)] = HFI_COLOR_FORMAT_RGB888,
 	[ilog2(HAL_COLOR_FORMAT_BGR888)] = HFI_COLOR_FORMAT_BGR888,
-	[ilog2(HAL_COLOR_FORMAT_RGBA8888)] = HFI_COLOR_FORMAT_RGBA8888,
 	/* UBWC Color formats*/
 	[ilog2(HAL_COLOR_FORMAT_NV12_UBWC)] =  HFI_COLOR_FORMAT_NV12_UBWC,
 	[ilog2(HAL_COLOR_FORMAT_NV12_TP10_UBWC)] =
 			HFI_COLOR_FORMAT_YUV420_TP10_UBWC,
-	[ilog2(HAL_COLOR_FORMAT_RGBA8888_UBWC)] =
-			HFI_COLOR_FORMAT_RGBA8888_UBWC,
 };
 
 static int nal_type[] = {
@@ -126,26 +122,6 @@
 	}
 }
 
-u32 get_hfi_layout(enum hal_buffer_layout_type hal_buf_layout)
-{
-	u32 hfi_layout;
-
-	switch (hal_buf_layout) {
-	case HAL_BUFFER_LAYOUT_TOP_BOTTOM:
-		hfi_layout = HFI_MVC_BUFFER_LAYOUT_TOP_BOTTOM;
-		break;
-	case HAL_BUFFER_LAYOUT_SEQ:
-		hfi_layout = HFI_MVC_BUFFER_LAYOUT_SEQ;
-		break;
-	default:
-		dprintk(VIDC_ERR, "Invalid buffer layout: %#x\n",
-			hal_buf_layout);
-		hfi_layout = HFI_MVC_BUFFER_LAYOUT_SEQ;
-		break;
-	}
-	return hfi_layout;
-}
-
 enum hal_domain vidc_get_hal_domain(u32 hfi_domain)
 {
 	enum hal_domain hal_domain = 0;
@@ -192,9 +168,6 @@
 	case HFI_VIDEO_CODEC_VP9:
 		hal_codec = HAL_VIDEO_CODEC_VP9;
 		break;
-	case HFI_VIDEO_CODEC_HEVC_HYBRID:
-		hal_codec = HAL_VIDEO_CODEC_HEVC_HYBRID;
-		break;
 	default:
 		dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
 			__func__, hfi_codec);
@@ -233,7 +206,6 @@
 	u32 hfi_codec = 0;
 
 	switch (hal_codec) {
-	case HAL_VIDEO_CODEC_MVC:
 	case HAL_VIDEO_CODEC_H264:
 		hfi_codec = HFI_VIDEO_CODEC_H264;
 		break;
@@ -252,9 +224,6 @@
 	case HAL_VIDEO_CODEC_VP9:
 		hfi_codec = HFI_VIDEO_CODEC_VP9;
 		break;
-	case HAL_VIDEO_CODEC_HEVC_HYBRID:
-		hfi_codec = HFI_VIDEO_CODEC_HEVC_HYBRID;
-		break;
 	default:
 		dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
 			__func__, hal_codec);
@@ -555,12 +524,6 @@
 	case HAL_EXTRADATA_INTERLACE_VIDEO:
 		ret = HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA;
 		break;
-	case HAL_EXTRADATA_VC1_FRAMEDISP:
-		ret = HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA;
-		break;
-	case HAL_EXTRADATA_VC1_SEQDISP:
-		ret = HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA;
-		break;
 	case HAL_EXTRADATA_TIMESTAMP:
 		ret = HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA;
 		break;
@@ -673,9 +636,6 @@
 	case HAL_LTR_MODE_MANUAL:
 		ltrmode = HFI_LTR_MODE_MANUAL;
 		break;
-	case HAL_LTR_MODE_PERIODIC:
-		ltrmode = HFI_LTR_MODE_PERIODIC;
-		break;
 	default:
 		dprintk(VIDC_ERR, "Invalid ltr mode: %#x\n",
 			ltr_mode_type);
@@ -939,31 +899,10 @@
 		struct hfi_cmd_session_get_property_packet *pkt,
 		struct hal_session *session, enum hal_property ptype)
 {
-	int rc = 0;
-
-	if (!pkt || !session) {
-		dprintk(VIDC_ERR, "%s Invalid parameters\n", __func__);
-		return -EINVAL;
-	}
-	pkt->size = sizeof(struct hfi_cmd_session_get_property_packet);
-	pkt->packet_type = HFI_CMD_SESSION_GET_PROPERTY;
-	pkt->session_id = hash32_ptr(session);
-	pkt->num_properties = 1;
-	switch (ptype) {
-	case HAL_CONFIG_VDEC_ENTROPY:
-		pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VDEC_ENTROPY;
-		break;
-	case HAL_PARAM_PROFILE_LEVEL_CURRENT:
-		pkt->rg_property_data[0] =
-			HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
-		break;
-	default:
-		dprintk(VIDC_ERR, "%s cmd:%#x not supported\n", __func__,
+	/* Currently no get property is supported */
+	dprintk(VIDC_ERR, "%s cmd:%#x not supported\n", __func__,
 			ptype);
-		rc = -EINVAL;
-		break;
-	}
-	return rc;
+	return -EINVAL;
 }
 
 int create_pkt_cmd_session_set_property(
@@ -1028,8 +967,6 @@
 		break;
 	case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO:
 		break;
-	case HAL_PARAM_EXTRA_DATA_HEADER_CONFIG:
-		break;
 	case HAL_PARAM_FRAME_SIZE:
 	{
 		struct hfi_frame_size *hfi;
@@ -1142,14 +1079,6 @@
 		pkt->size += sizeof(u32) * 2;
 		break;
 	}
-	case HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
-	{
-		create_pkt_enable(pkt->rg_property_data,
-			HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER,
-			((struct hal_enable *)pdata)->enable);
-		pkt->size += sizeof(u32) * 2;
-		break;
-	}
 	case HAL_PARAM_VDEC_MULTI_STREAM:
 	{
 		struct hfi_multi_stream *hfi;
@@ -1199,10 +1128,6 @@
 			HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME;
 		pkt->size += sizeof(u32);
 		break;
-	case HAL_PARAM_VENC_MPEG4_SHORT_HEADER:
-		break;
-	case HAL_PARAM_VENC_MPEG4_AC_PREDICTION:
-		break;
 	case HAL_CONFIG_VENC_TARGET_BITRATE:
 	{
 		struct hfi_bitrate *hfi;
@@ -1590,14 +1515,6 @@
 		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
 		break;
 	}
-	case HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC:
-	{
-		create_pkt_enable(pkt->rg_property_data,
-			HFI_PROPERTY_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC,
-			((struct hal_enable *)pdata)->enable);
-		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
-		break;
-	}
 	case HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY:
 	{
 		create_pkt_enable(pkt->rg_property_data,
@@ -1606,21 +1523,6 @@
 		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
 		break;
 	}
-	case HAL_PARAM_MVC_BUFFER_LAYOUT:
-	{
-		struct hfi_mvc_buffer_layout_descp_type *hfi;
-		struct hal_mvc_buffer_layout *layout_info = pdata;
-
-		pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_MVC_BUFFER_LAYOUT;
-		hfi = (struct hfi_mvc_buffer_layout_descp_type *)
-			&pkt->rg_property_data[1];
-		hfi->layout_type = get_hfi_layout(layout_info->layout_type);
-		hfi->bright_view_first = layout_info->bright_view_first;
-		hfi->ngap = layout_info->ngap;
-		pkt->size += sizeof(u32) +
-			sizeof(struct hfi_mvc_buffer_layout_descp_type);
-		break;
-	}
 	case HAL_PARAM_VENC_LTRMODE:
 	{
 		struct hfi_ltr_mode *hfi;
@@ -1731,14 +1633,6 @@
 		pkt->size += sizeof(u32) * 2;
 		break;
 	}
-	case HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS:
-	{
-		pkt->rg_property_data[0] =
-			HFI_PROPERTY_PARAM_VENC_HIER_B_MAX_NUM_ENH_LAYER;
-		pkt->rg_property_data[1] = *(u32 *)pdata;
-		pkt->size += sizeof(u32) * 2;
-		break;
-	}
 	case HAL_PARAM_VENC_HIER_P_HYBRID_MODE:
 	{
 		pkt->rg_property_data[0] =
@@ -1937,7 +1831,6 @@
 	case HAL_PARAM_VDEC_MB_QUANTIZATION:
 	case HAL_PARAM_VDEC_NUM_CONCEALED_MB:
 	case HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING:
-	case HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING:
 	case HAL_CONFIG_BUFFER_COUNT_ACTUAL:
 	case HAL_CONFIG_VDEC_MULTI_STREAM:
 	case HAL_PARAM_VENC_MULTI_SLICE_INFO:
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index abc6cc8..7c99e90 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -26,13 +26,6 @@
 #define MAX_OPERATING_FRAME_RATE (300 << 16)
 #define OPERATING_FRAME_RATE_STEP (1 << 16)
 
-static const char *const mpeg_video_vidc_divx_format[] = {
-	"DIVX Format 3",
-	"DIVX Format 4",
-	"DIVX Format 5",
-	"DIVX Format 6",
-	NULL
-};
 static const char *const mpeg_video_stream_format[] = {
 	"NAL Format Start Codes",
 	"NAL Format One NAL Per Buffer",
@@ -57,29 +50,6 @@
 	"Turbo"
 };
 
-static const char *const h263_level[] = {
-	"1.0",
-	"2.0",
-	"3.0",
-	"4.0",
-	"4.5",
-	"5.0",
-	"6.0",
-	"7.0",
-};
-
-static const char *const h263_profile[] = {
-	"Baseline",
-	"H320 Coding",
-	"Backward Compatible",
-	"ISWV2",
-	"ISWV3",
-	"High Compression",
-	"Internet",
-	"Interlace",
-	"High Latency",
-};
-
 static const char *const vp8_profile_level[] = {
 	"Unused",
 	"0.0",
@@ -108,11 +78,6 @@
 	"CABAC Entropy Mode",
 };
 
-static const char *const mpeg_vidc_video_h264_mvc_layout[] = {
-	"Frame packing arrangement sequential",
-	"Frame packing arrangement top-bottom",
-};
-
 static const char *const mpeg_vidc_video_dpb_color_format[] = {
 	"DPB Color Format None",
 	"DPB Color Format UBWC",
@@ -462,37 +427,6 @@
 	return frame_size;
 }
 
-static int is_ctrl_valid_for_codec(struct msm_vidc_inst *inst,
-					struct v4l2_ctrl *ctrl)
-{
-	int rc = 0;
-
-	switch (ctrl->id) {
-	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
-		if (inst->fmts[OUTPUT_PORT].fourcc == V4L2_PIX_FMT_H264_MVC &&
-			ctrl->val != V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH) {
-			dprintk(VIDC_ERR,
-					"Profile %#x not supported for MVC\n",
-					ctrl->val);
-			rc = -ENOTSUPP;
-			break;
-		}
-		break;
-	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
-		if (inst->fmts[OUTPUT_PORT].fourcc == V4L2_PIX_FMT_H264_MVC &&
-			ctrl->val >= V4L2_MPEG_VIDEO_H264_LEVEL_5_2) {
-			dprintk(VIDC_ERR, "Level %#x not supported for MVC\n",
-					ctrl->val);
-			rc = -ENOTSUPP;
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-	return rc;
-}
-
 struct msm_vidc_format vdec_formats[] = {
 	{
 		.name = "YCbCr Semiplanar 4:2:0",
@@ -516,14 +450,6 @@
 		.type = CAPTURE_PORT,
 	},
 	{
-		.name = "Mpeg4",
-		.description = "Mpeg4 compressed format",
-		.fourcc = V4L2_PIX_FMT_MPEG4,
-		.get_frame_size = get_frame_size_compressed,
-		.type = OUTPUT_PORT,
-		.defer_outputs = false,
-	},
-	{
 		.name = "Mpeg2",
 		.description = "Mpeg2 compressed format",
 		.fourcc = V4L2_PIX_FMT_MPEG2,
@@ -532,30 +458,6 @@
 		.defer_outputs = false,
 	},
 	{
-		.name = "H263",
-		.description = "H263 compressed format",
-		.fourcc = V4L2_PIX_FMT_H263,
-		.get_frame_size = get_frame_size_compressed,
-		.type = OUTPUT_PORT,
-		.defer_outputs = false,
-	},
-	{
-		.name = "VC1",
-		.description = "VC-1 compressed format",
-		.fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
-		.get_frame_size = get_frame_size_compressed,
-		.type = OUTPUT_PORT,
-		.defer_outputs = false,
-	},
-	{
-		.name = "VC1 SP",
-		.description = "VC-1 compressed format G",
-		.fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
-		.get_frame_size = get_frame_size_compressed,
-		.type = OUTPUT_PORT,
-		.defer_outputs = false,
-	},
-	{
 		.name = "H264",
 		.description = "H264 compressed format",
 		.fourcc = V4L2_PIX_FMT_H264,
@@ -564,14 +466,6 @@
 		.defer_outputs = false,
 	},
 	{
-		.name = "H264_MVC",
-		.description = "H264_MVC compressed format",
-		.fourcc = V4L2_PIX_FMT_H264_MVC,
-		.get_frame_size = get_frame_size_compressed,
-		.type = OUTPUT_PORT,
-		.defer_outputs = false,
-	},
-	{
 		.name = "HEVC",
 		.description = "HEVC compressed format",
 		.fourcc = V4L2_PIX_FMT_HEVC,
@@ -826,10 +720,6 @@
 	}
 	hdev = inst->core->device;
 
-	rc = is_ctrl_valid_for_codec(inst, ctrl);
-	if (rc)
-		return rc;
-
 	/* Small helper macro for quickly getting a control and err checking */
 #define TRY_GET_CTRL(__ctrl_id) ({ \
 		struct v4l2_ctrl *__temp; \
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 64937aa..13cc1b2 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -37,11 +37,6 @@
 #define MAX_HYBRID_HIER_P_LAYERS 6
 
 #define L_MODE V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
-#define CODING V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY
-#define BITSTREAM_RESTRICT_ENABLED \
-	V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_ENABLED
-#define BITSTREAM_RESTRICT_DISABLED \
-	V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_DISABLED
 #define MIN_TIME_RESOLUTION 1
 #define MAX_TIME_RESOLUTION 0xFFFFFF
 #define DEFAULT_TIME_RESOLUTION 0x7530
@@ -774,72 +769,6 @@
 		.qmenu = NULL,
 	},
 	{
-		.id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE,
-		.name = "I-Frame X coordinate search range",
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.minimum = 4,
-		.maximum = 128,
-		.default_value = 4,
-		.step = 1,
-		.menu_skip_mask = 0,
-		.qmenu = NULL,
-	},
-	{
-		.id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE,
-		.name = "I-Frame Y coordinate search range",
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.minimum = 4,
-		.maximum = 128,
-		.default_value = 4,
-		.step = 1,
-		.menu_skip_mask = 0,
-		.qmenu = NULL,
-	},
-	{
-		.id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE,
-		.name = "P-Frame X coordinate search range",
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.minimum = 4,
-		.maximum = 128,
-		.default_value = 4,
-		.step = 1,
-		.menu_skip_mask = 0,
-		.qmenu = NULL,
-	},
-	{
-		.id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE,
-		.name = "P-Frame Y coordinate search range",
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.minimum = 4,
-		.maximum = 128,
-		.default_value = 4,
-		.step = 1,
-		.menu_skip_mask = 0,
-		.qmenu = NULL,
-	},
-	{
-		.id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE,
-		.name = "B-Frame X coordinate search range",
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.minimum = 4,
-		.maximum = 128,
-		.default_value = 4,
-		.step = 1,
-		.menu_skip_mask = 0,
-		.qmenu = NULL,
-	},
-	{
-		.id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE,
-		.name = "B-Frame Y coordinate search range",
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.minimum = 4,
-		.maximum = 128,
-		.default_value = 4,
-		.step = 1,
-		.menu_skip_mask = 0,
-		.qmenu = NULL,
-	},
-	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS,
 		.name = "Set Hier B num layers",
 		.type = V4L2_CTRL_TYPE_INTEGER,
@@ -1258,7 +1187,7 @@
 	struct hal_ltr_use use_ltr;
 	struct hal_ltr_mark mark_ltr;
 	struct hal_hybrid_hierp hyb_hierp;
-	u32 hier_p_layers = 0, hier_b_layers = 0;
+	u32 hier_p_layers = 0;
 	int max_hierp_layers;
 	int baselayerid = 0;
 	struct hal_video_signal_info signal_info = {0};
@@ -1475,28 +1404,6 @@
 			temp_ctrl->val);
 		pdata = &h264_entropy_control;
 		break;
-	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
-		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL);
-
-		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
-		profile_level.profile = msm_comm_v4l2_to_hal(ctrl->id,
-						ctrl->val);
-		profile_level.level = msm_comm_v4l2_to_hal(
-				V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
-				temp_ctrl->val);
-		pdata = &profile_level;
-		break;
-	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
-		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE);
-
-		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
-		profile_level.level = msm_comm_v4l2_to_hal(ctrl->id,
-							ctrl->val);
-		profile_level.profile = msm_comm_v4l2_to_hal(
-				V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
-				temp_ctrl->val);
-		pdata = &profile_level;
-		break;
 	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
 		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
 
@@ -1715,6 +1622,8 @@
 			enable.enable = 0;
 			break;
 		case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME:
+			enable.enable = 1;
+			break;
 		default:
 			rc = -ENOTSUPP;
 			break;
@@ -1835,16 +1744,6 @@
 		enable.enable = ctrl->val;
 		pdata = &enable;
 		break;
-	case V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS:
-		if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_HEVC) {
-			dprintk(VIDC_ERR, "Hier B supported for HEVC only\n");
-			rc = -ENOTSUPP;
-			break;
-		}
-		property_id = HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS;
-		hier_b_layers = ctrl->val;
-		pdata = &hier_b_layers;
-		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE:
 		property_id = HAL_PARAM_VENC_HIER_P_HYBRID_MODE;
 		hyb_hierp.layers = ctrl->val;
@@ -2081,7 +1980,6 @@
 	struct v4l2_ext_control *control;
 	struct hfi_device *hdev;
 	struct hal_ltr_mode ltr_mode;
-	struct hal_vc1e_perf_cfg_type search_range = { {0} };
 	u32 property_id = 0, layer_id = MSM_VIDC_ALL_LAYER_ID;
 	void *pdata = NULL;
 	struct msm_vidc_capability *cap = NULL;
@@ -2136,36 +2034,6 @@
 			property_id = HAL_PARAM_VENC_LTRMODE;
 			pdata = &ltr_mode;
 			break;
-		case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE:
-			search_range.i_frame.x_subsampled = control[i].value;
-			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
-			pdata = &search_range;
-			break;
-		case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE:
-			search_range.i_frame.y_subsampled = control[i].value;
-			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
-			pdata = &search_range;
-			break;
-		case V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE:
-			search_range.p_frame.x_subsampled = control[i].value;
-			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
-			pdata = &search_range;
-			break;
-		case V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE:
-			search_range.p_frame.y_subsampled = control[i].value;
-			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
-			pdata = &search_range;
-			break;
-		case V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE:
-			search_range.b_frame.x_subsampled = control[i].value;
-			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
-			pdata = &search_range;
-			break;
-		case V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE:
-			search_range.b_frame.y_subsampled = control[i].value;
-			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
-			pdata = &search_range;
-			break;
 		case V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_WIDTH:
 			sar.aspect_width = control[i].value;
 			property_id = HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 270fc31..114a702 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1820,14 +1820,12 @@
 
 	switch (ctrl->id) {
 
-	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
 	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
 	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
 	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
 		ctrl->val = inst->profile;
 	break;
 
-	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
 	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
 	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
 		ctrl->val = inst->level;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 74e68e4..5e49f42 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -52,8 +52,6 @@
 	"Extradata none",
 	"Extradata MB Quantization",
 	"Extradata Interlace Video",
-	"Extradata VC1 Framedisp",
-	"Extradata VC1 Seqdisp",
 	"Extradata timestamp",
 	"Extradata S3D Frame Packing",
 	"Extradata Frame Rate",
@@ -715,22 +713,13 @@
 	case V4L2_PIX_FMT_H264_MVC:
 		codec = HAL_VIDEO_CODEC_MVC;
 		break;
-	case V4L2_PIX_FMT_H263:
-		codec = HAL_VIDEO_CODEC_H263;
-		break;
+
 	case V4L2_PIX_FMT_MPEG1:
 		codec = HAL_VIDEO_CODEC_MPEG1;
 		break;
 	case V4L2_PIX_FMT_MPEG2:
 		codec = HAL_VIDEO_CODEC_MPEG2;
 		break;
-	case V4L2_PIX_FMT_MPEG4:
-		codec = HAL_VIDEO_CODEC_MPEG4;
-		break;
-	case V4L2_PIX_FMT_VC1_ANNEX_G:
-	case V4L2_PIX_FMT_VC1_ANNEX_L:
-		codec = HAL_VIDEO_CODEC_VC1;
-		break;
 	case V4L2_PIX_FMT_VP8:
 		codec = HAL_VIDEO_CODEC_VP8;
 		break;
@@ -766,9 +755,6 @@
 	case V4L2_PIX_FMT_NV12_TP10_UBWC:
 		format = HAL_COLOR_FORMAT_NV12_TP10_UBWC;
 		break;
-	case V4L2_PIX_FMT_RGB32:
-		format = HAL_COLOR_FORMAT_RGBA8888;
-		break;
 	default:
 		format = HAL_UNUSED_COLOR;
 		break;
@@ -2434,55 +2420,6 @@
 	put_inst(inst);
 }
 
-static void handle_seq_hdr_done(enum hal_command_response cmd, void *data)
-{
-	struct msm_vidc_cb_data_done *response = data;
-	struct msm_vidc_inst *inst;
-	struct vb2_buffer *vb;
-	struct vidc_hal_fbd *fill_buf_done;
-	struct vb2_v4l2_buffer *vbuf;
-
-	if (!response) {
-		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
-		return;
-	}
-
-	inst = get_inst(get_vidc_core(response->device_id),
-			response->session_id);
-	if (!inst) {
-		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
-		return;
-	}
-
-	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
-	vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
-				fill_buf_done->packet_buffer1);
-	if (!vb) {
-		dprintk(VIDC_ERR,
-				"Failed to find video buffer for seq_hdr_done: %pa\n",
-				&fill_buf_done->packet_buffer1);
-		goto err_seq_hdr_done;
-	}
-	vbuf = to_vb2_v4l2_buffer(vb);
-	vb->timestamp = 0;
-
-	vb->planes[0].bytesused = fill_buf_done->filled_len1;
-	vb->planes[0].data_offset = fill_buf_done->offset1;
-
-	vbuf->flags = V4L2_QCOM_BUF_FLAG_CODECCONFIG;
-
-	dprintk(VIDC_DBG, "Filled length = %d; offset = %d; flags %x\n",
-				vb->planes[0].bytesused,
-				vb->planes[0].data_offset,
-				vbuf->flags);
-	mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
-	vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
-	mutex_unlock(&inst->bufq[CAPTURE_PORT].lock);
-
-err_seq_hdr_done:
-	put_inst(inst);
-}
-
 void handle_cmd_response(enum hal_command_response cmd, void *data)
 {
 	dprintk(VIDC_DBG, "Command response = %d\n", cmd);
@@ -2527,9 +2464,6 @@
 	case HAL_SESSION_FLUSH_DONE:
 		handle_session_flush(cmd, data);
 		break;
-	case HAL_SESSION_GET_SEQ_HDR_DONE:
-		handle_seq_hdr_done(cmd, data);
-		break;
 	case HAL_SYS_WATCHDOG_TIMEOUT:
 	case HAL_SYS_ERROR:
 		handle_sys_error(cmd, data);
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 74e360e..eb36b33 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -539,7 +539,8 @@
 
 	*pb_tx_req_is_set = (queue->qhdr_tx_req == 1) ? 1 : 0;
 
-	if (msm_vidc_debug & VIDC_PKT) {
+	if ((msm_vidc_debug & VIDC_PKT) &&
+		!(queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q)) {
 		dprintk(VIDC_PKT, "%s: %pK\n", __func__, qinfo);
 		__dump_packet(packet, VIDC_PKT);
 	}
@@ -3176,14 +3177,12 @@
 		case HAL_SESSION_RESUME_DONE:
 		case HAL_SESSION_SET_PROP_DONE:
 		case HAL_SESSION_GET_PROP_DONE:
-		case HAL_SESSION_PARSE_SEQ_HDR_DONE:
 		case HAL_SESSION_RELEASE_BUFFER_DONE:
 		case HAL_SESSION_RELEASE_RESOURCE_DONE:
 		case HAL_SESSION_PROPERTY_INFO:
 			session_id = &info->response.cmd.session_id;
 			break;
 		case HAL_SESSION_ERROR:
-		case HAL_SESSION_GET_SEQ_HDR_DONE:
 		case HAL_SESSION_ETB_DONE:
 		case HAL_SESSION_FTB_DONE:
 			session_id = &info->response.data.session_id;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 7caff53..2a833dc 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -73,8 +73,6 @@
 #define HFI_EXTRADATA_NONE					0x00000000
 #define HFI_EXTRADATA_MB_QUANTIZATION		0x00000001
 #define HFI_EXTRADATA_INTERLACE_VIDEO		0x00000002
-#define HFI_EXTRADATA_VC1_FRAMEDISP			0x00000003
-#define HFI_EXTRADATA_VC1_SEQDISP			0x00000004
 #define HFI_EXTRADATA_TIMESTAMP				0x00000005
 #define HFI_EXTRADATA_S3D_FRAME_PACKING		0x00000006
 #define HFI_EXTRADATA_FRAME_RATE			0x00000007
@@ -132,8 +130,6 @@
 	(HFI_PROPERTY_PARAM_OX_START + 0x001)
 #define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO	\
 	(HFI_PROPERTY_PARAM_OX_START + 0x002)
-#define HFI_PROPERTY_PARAM_EXTRA_DATA_HEADER_CONFIG		\
-	(HFI_PROPERTY_PARAM_OX_START + 0x005)
 #define HFI_PROPERTY_PARAM_INDEX_EXTRADATA             \
 	(HFI_PROPERTY_PARAM_OX_START + 0x006)
 #define HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA	\
@@ -175,10 +171,6 @@
 	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00C)
 #define HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE   \
 	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00D)
-#define HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA		\
-	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x011)
-#define HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA		\
-	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x012)
 #define HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA			\
 	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x013)
 #define HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA	\
@@ -206,8 +198,6 @@
 
 #define HFI_PROPERTY_CONFIG_VDEC_OX_START				\
 	(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x4000)
-#define HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER	\
-	(HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x001)
 #define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING	\
 	(HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x002)
 #define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP			\
@@ -279,14 +269,6 @@
 	u32 picture_type;
 };
 
-struct hfi_extra_data_header_config {
-	u32 type;
-	u32 buffer_type;
-	u32 version;
-	u32 port_index;
-	u32 client_extra_data_id;
-};
-
 struct hfi_mb_error_map {
 	u32 error_map_size;
 	u8 rg_error_map[1];
@@ -720,35 +702,6 @@
 	u8 rg_mb_qp[1];
 };
 
-struct hfi_extradata_vc1_pswnd {
-	u32 ps_wnd_h_offset;
-	u32 ps_wnd_v_offset;
-	u32 ps_wnd_width;
-	u32 ps_wnd_height;
-};
-
-struct hfi_extradata_vc1_framedisp_payload {
-	u32 res_pic;
-	u32 ref;
-	u32 range_map_present;
-	u32 range_map_y;
-	u32 range_map_uv;
-	u32 num_pan_scan_wnds;
-	struct hfi_extradata_vc1_pswnd rg_ps_wnd[1];
-};
-
-struct hfi_extradata_vc1_seqdisp_payload {
-	u32 prog_seg_frm;
-	u32 uv_sampling_fmt;
-	u32 color_fmt_flag;
-	u32 color_primaries;
-	u32 transfer_char;
-	u32 mat_coeff;
-	u32 aspect_ratio;
-	u32 aspect_horiz;
-	u32 aspect_vert;
-};
-
 struct hfi_extradata_timestamp_payload {
 	u32 time_stamp_low;
 	u32 time_stamp_high;
@@ -836,10 +789,6 @@
 	u32 aspect_width;
 	u32 aspect_height;
 };
-struct hfi_extradata_panscan_wndw_payload {
-	u32 num_window;
-	struct hfi_extradata_vc1_pswnd wnd[1];
-};
 
 struct hfi_extradata_frame_type_payload {
 	u32 frame_rate;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index d60a0d1..8aa0bbb 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -98,8 +98,6 @@
 	HAL_EXTRADATA_NONE,
 	HAL_EXTRADATA_MB_QUANTIZATION,
 	HAL_EXTRADATA_INTERLACE_VIDEO,
-	HAL_EXTRADATA_VC1_FRAMEDISP,
-	HAL_EXTRADATA_VC1_SEQDISP,
 	HAL_EXTRADATA_TIMESTAMP,
 	HAL_EXTRADATA_S3D_FRAME_PACKING,
 	HAL_EXTRADATA_FRAME_RATE,
@@ -134,7 +132,6 @@
 	HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT,
 	HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO,
 	HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO,
-	HAL_PARAM_EXTRA_DATA_HEADER_CONFIG,
 	HAL_PARAM_INDEX_EXTRADATA,
 	HAL_PARAM_FRAME_SIZE,
 	HAL_CONFIG_REALTIME,
@@ -144,22 +141,16 @@
 	HAL_PARAM_VDEC_OUTPUT_ORDER,
 	HAL_PARAM_VDEC_PICTURE_TYPE_DECODE,
 	HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO,
-	HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER,
 	HAL_PARAM_VDEC_MULTI_STREAM,
 	HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT,
-	HAL_PARAM_DIVX_FORMAT,
 	HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING,
 	HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER,
 	HAL_CONFIG_VDEC_MB_ERROR_MAP,
 	HAL_CONFIG_VENC_REQUEST_IFRAME,
-	HAL_PARAM_VENC_MPEG4_SHORT_HEADER,
-	HAL_PARAM_VENC_MPEG4_AC_PREDICTION,
 	HAL_CONFIG_VENC_TARGET_BITRATE,
 	HAL_PARAM_PROFILE_LEVEL_CURRENT,
 	HAL_PARAM_VENC_H264_ENTROPY_CONTROL,
 	HAL_PARAM_VENC_RATE_CONTROL,
-	HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION,
-	HAL_PARAM_VENC_MPEG4_HEADER_EXTENSION,
 	HAL_PARAM_VENC_H264_DEBLOCK_CONTROL,
 	HAL_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF,
 	HAL_PARAM_VENC_SESSION_QP_RANGE,
@@ -190,7 +181,6 @@
 	HAL_PARAM_VDEC_NUM_CONCEALED_MB,
 	HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING,
 	HAL_PARAM_VENC_SLICE_DELIVERY_MODE,
-	HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING,
 	HAL_CONFIG_BUFFER_COUNT_ACTUAL,
 	HAL_CONFIG_VDEC_MULTI_STREAM,
 	HAL_PARAM_VENC_MULTI_SLICE_INFO,
@@ -204,12 +194,10 @@
 	HAL_PARAM_VENC_MAX_NUM_B_FRAMES,
 	HAL_PARAM_BUFFER_ALLOC_MODE,
 	HAL_PARAM_VDEC_FRAME_ASSEMBLY,
-	HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC,
 	HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY,
 	HAL_PARAM_VDEC_CONCEAL_COLOR,
 	HAL_PARAM_VDEC_SCS_THRESHOLD,
 	HAL_PARAM_GET_BUFFER_REQUIREMENTS,
-	HAL_PARAM_MVC_BUFFER_LAYOUT,
 	HAL_PARAM_VENC_LTRMODE,
 	HAL_CONFIG_VENC_MARKLTRFRAME,
 	HAL_CONFIG_VENC_USELTRFRAME,
@@ -221,7 +209,6 @@
 	HAL_PARAM_VPE_COLOR_SPACE_CONVERSION,
 	HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE,
 	HAL_CONFIG_VENC_PERF_MODE,
-	HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS,
 	HAL_PARAM_VDEC_NON_SECURE_OUTPUT2,
 	HAL_PARAM_VENC_HIER_P_HYBRID_MODE,
 	HAL_PARAM_VENC_MBI_STATISTICS_MODE,
@@ -232,7 +219,6 @@
 	HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO,
 	HAL_CONFIG_VDEC_ENTROPY,
 	HAL_PARAM_VENC_BITRATE_TYPE,
-	HAL_PARAM_VENC_H264_PIC_ORDER_CNT,
 	HAL_PARAM_VENC_LOW_LATENCY,
 	HAL_CONFIG_VENC_BLUR_RESOLUTION,
 	HAL_PARAM_VENC_H264_TRANSFORM_8x8,
@@ -289,31 +275,6 @@
 	HAL_UNUSED_CODEC = 0x10000000,
 };
 
-enum hal_h263_profile {
-	HAL_H263_PROFILE_BASELINE           = 0x00000001,
-	HAL_H263_PROFILE_H320CODING         = 0x00000002,
-	HAL_H263_PROFILE_BACKWARDCOMPATIBLE = 0x00000004,
-	HAL_H263_PROFILE_ISWV2              = 0x00000008,
-	HAL_H263_PROFILE_ISWV3              = 0x00000010,
-	HAL_H263_PROFILE_HIGHCOMPRESSION    = 0x00000020,
-	HAL_H263_PROFILE_INTERNET           = 0x00000040,
-	HAL_H263_PROFILE_INTERLACE          = 0x00000080,
-	HAL_H263_PROFILE_HIGHLATENCY        = 0x00000100,
-	HAL_UNUSED_H263_PROFILE = 0x10000000,
-};
-
-enum hal_h263_level {
-	HAL_H263_LEVEL_10 = 0x00000001,
-	HAL_H263_LEVEL_20 = 0x00000002,
-	HAL_H263_LEVEL_30 = 0x00000004,
-	HAL_H263_LEVEL_40 = 0x00000008,
-	HAL_H263_LEVEL_45 = 0x00000010,
-	HAL_H263_LEVEL_50 = 0x00000020,
-	HAL_H263_LEVEL_60 = 0x00000040,
-	HAL_H263_LEVEL_70 = 0x00000080,
-	HAL_UNUSED_H263_LEVEL = 0x10000000,
-};
-
 enum hal_mpeg2_profile {
 	HAL_MPEG2_PROFILE_SIMPLE  = 0x00000001,
 	HAL_MPEG2_PROFILE_MAIN    = 0x00000002,
@@ -332,44 +293,6 @@
 	HAL_UNUSED_MEPG2_LEVEL = 0x10000000,
 };
 
-enum hal_mpeg4_profile {
-	HAL_MPEG4_PROFILE_SIMPLE           = 0x00000001,
-	HAL_MPEG4_PROFILE_ADVANCEDSIMPLE   = 0x00000002,
-	HAL_MPEG4_PROFILE_CORE             = 0x00000004,
-	HAL_MPEG4_PROFILE_MAIN             = 0x00000008,
-	HAL_MPEG4_PROFILE_NBIT             = 0x00000010,
-	HAL_MPEG4_PROFILE_SCALABLETEXTURE  = 0x00000020,
-	HAL_MPEG4_PROFILE_SIMPLEFACE       = 0x00000040,
-	HAL_MPEG4_PROFILE_SIMPLEFBA        = 0x00000080,
-	HAL_MPEG4_PROFILE_BASICANIMATED    = 0x00000100,
-	HAL_MPEG4_PROFILE_HYBRID           = 0x00000200,
-	HAL_MPEG4_PROFILE_ADVANCEDREALTIME = 0x00000400,
-	HAL_MPEG4_PROFILE_CORESCALABLE     = 0x00000800,
-	HAL_MPEG4_PROFILE_ADVANCEDCODING   = 0x00001000,
-	HAL_MPEG4_PROFILE_ADVANCEDCORE     = 0x00002000,
-	HAL_MPEG4_PROFILE_ADVANCEDSCALABLE = 0x00004000,
-	HAL_MPEG4_PROFILE_SIMPLESCALABLE   = 0x00008000,
-	HAL_UNUSED_MPEG4_PROFILE = 0x10000000,
-};
-
-enum hal_mpeg4_level {
-	HAL_MPEG4_LEVEL_0  = 0x00000001,
-	HAL_MPEG4_LEVEL_0b = 0x00000002,
-	HAL_MPEG4_LEVEL_1  = 0x00000004,
-	HAL_MPEG4_LEVEL_2  = 0x00000008,
-	HAL_MPEG4_LEVEL_3  = 0x00000010,
-	HAL_MPEG4_LEVEL_4  = 0x00000020,
-	HAL_MPEG4_LEVEL_4a = 0x00000040,
-	HAL_MPEG4_LEVEL_5  = 0x00000080,
-	HAL_MPEG4_LEVEL_VENDOR_START_UNUSED = 0x7F000000,
-	HAL_MPEG4_LEVEL_6  = 0x7F000001,
-	HAL_MPEG4_LEVEL_7  = 0x7F000002,
-	HAL_MPEG4_LEVEL_8  = 0x7F000003,
-	HAL_MPEG4_LEVEL_9  = 0x7F000004,
-	HAL_MPEG4_LEVEL_3b = 0x7F000005,
-	HAL_UNUSED_MPEG4_LEVEL = 0x10000000,
-};
-
 enum hal_h264_profile {
 	HAL_H264_PROFILE_BASELINE = 0x00000001,
 	HAL_H264_PROFILE_MAIN     = 0x00000002,
@@ -457,66 +380,6 @@
 	HAL_VPX_PROFILE_UNUSED = 0x10000000,
 };
 
-enum hal_vc1_profile {
-	HAL_VC1_PROFILE_SIMPLE   = 0x00000001,
-	HAL_VC1_PROFILE_MAIN     = 0x00000002,
-	HAL_VC1_PROFILE_ADVANCED = 0x00000004,
-	HAL_UNUSED_VC1_PROFILE = 0x10000000,
-};
-
-enum hal_vc1_level {
-	HAL_VC1_LEVEL_LOW    = 0x00000001,
-	HAL_VC1_LEVEL_MEDIUM = 0x00000002,
-	HAL_VC1_LEVEL_HIGH   = 0x00000004,
-	HAL_VC1_LEVEL_0      = 0x00000008,
-	HAL_VC1_LEVEL_1      = 0x00000010,
-	HAL_VC1_LEVEL_2      = 0x00000020,
-	HAL_VC1_LEVEL_3      = 0x00000040,
-	HAL_VC1_LEVEL_4      = 0x00000080,
-	HAL_UNUSED_VC1_LEVEL = 0x10000000,
-};
-
-enum hal_divx_format {
-	HAL_DIVX_FORMAT_4,
-	HAL_DIVX_FORMAT_5,
-	HAL_DIVX_FORMAT_6,
-	HAL_UNUSED_DIVX_FORMAT = 0x10000000,
-};
-
-enum hal_divx_profile {
-	HAL_DIVX_PROFILE_QMOBILE  = 0x00000001,
-	HAL_DIVX_PROFILE_MOBILE   = 0x00000002,
-	HAL_DIVX_PROFILE_MT       = 0x00000004,
-	HAL_DIVX_PROFILE_HT       = 0x00000008,
-	HAL_DIVX_PROFILE_HD       = 0x00000010,
-	HAL_UNUSED_DIVX_PROFILE = 0x10000000,
-};
-
-enum hal_mvc_profile {
-	HAL_MVC_PROFILE_STEREO_HIGH  = 0x00001000,
-	HAL_UNUSED_MVC_PROFILE = 0x10000000,
-};
-
-enum hal_mvc_level {
-	HAL_MVC_LEVEL_1  = 0x00000001,
-	HAL_MVC_LEVEL_1b = 0x00000002,
-	HAL_MVC_LEVEL_11 = 0x00000004,
-	HAL_MVC_LEVEL_12 = 0x00000008,
-	HAL_MVC_LEVEL_13 = 0x00000010,
-	HAL_MVC_LEVEL_2  = 0x00000020,
-	HAL_MVC_LEVEL_21 = 0x00000040,
-	HAL_MVC_LEVEL_22 = 0x00000080,
-	HAL_MVC_LEVEL_3  = 0x00000100,
-	HAL_MVC_LEVEL_31 = 0x00000200,
-	HAL_MVC_LEVEL_32 = 0x00000400,
-	HAL_MVC_LEVEL_4  = 0x00000800,
-	HAL_MVC_LEVEL_41 = 0x00001000,
-	HAL_MVC_LEVEL_42 = 0x00002000,
-	HAL_MVC_LEVEL_5  = 0x00004000,
-	HAL_MVC_LEVEL_51 = 0x00008000,
-	HAL_UNUSED_MVC_LEVEL = 0x10000000,
-};
-
 struct hal_frame_rate {
 	enum hal_buffer buffer_type;
 	u32 frame_rate;
@@ -585,14 +448,6 @@
 	struct hal_uncompressed_plane_constraints rg_plane_format[1];
 };
 
-struct hal_extra_data_header_config {
-	u32 type;
-	enum hal_buffer buffer_type;
-	u32 version;
-	u32 port_index;
-	u32 client_extradata_id;
-};
-
 struct hal_frame_size {
 	enum hal_buffer buffer_type;
 	u32 width;
@@ -718,14 +573,6 @@
 	HAL_UNUSED_RC = 0x10000000,
 };
 
-struct hal_mpeg4_time_resolution {
-	u32 time_increment_resolution;
-};
-
-struct hal_mpeg4_header_extension {
-	u32 header_extension;
-};
-
 enum hal_h264_db_mode {
 	HAL_H264_DB_MODE_DISABLE,
 	HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY,
@@ -946,12 +793,6 @@
 	HAL_UNUSED_BUFFER_LAYOUT = 0x10000000,
 };
 
-struct hal_mvc_buffer_layout {
-	enum hal_buffer_layout_type layout_type;
-	u32 bright_view_first;
-	u32 ngap;
-};
-
 struct hal_aspect_ratio {
 	u32 aspect_width;
 	u32 aspect_height;
@@ -985,13 +826,6 @@
 	u32 enable;
 };
 
-struct hal_vc1e_perf_cfg_type {
-	struct {
-		u32 x_subsampled;
-		u32 y_subsampled;
-	} i_frame, p_frame, b_frame;
-};
-
 struct hal_vpe_color_space_conversion {
 	u32 csc_matrix[HAL_MAX_MATRIX_COEFFS];
 	u32 csc_bias[HAL_MAX_BIAS_COEFFS];
@@ -1105,7 +939,6 @@
 enum ltr_mode {
 	HAL_LTR_MODE_DISABLE,
 	HAL_LTR_MODE_MANUAL,
-	HAL_LTR_MODE_PERIODIC,
 };
 
 struct hal_ltr_mode {
@@ -1149,7 +982,6 @@
 	struct hal_uncompressed_plane_constraints plane_constraints;
 	struct hal_uncompressed_plane_actual_constraints_info
 						plane_constraints_info;
-	struct hal_extra_data_header_config extra_data_header_config;
 	struct hal_frame_size frame_size;
 	struct hal_enable enable;
 	struct hal_buffer_count_actual buffer_count_actual;
@@ -1162,8 +994,6 @@
 	struct hal_bitrate bitrate;
 	struct hal_profile_level profile_level;
 	struct hal_profile_level_supported profile_level_supported;
-	struct hal_mpeg4_time_resolution mpeg4_time_resolution;
-	struct hal_mpeg4_header_extension mpeg4_header_extension;
 	struct hal_h264_db_control h264_db_control;
 	struct hal_temporal_spatial_tradeoff temporal_spatial_tradeoff;
 	struct hal_quantization quantization;
@@ -1227,8 +1057,6 @@
 	HAL_SESSION_RESUME_DONE,
 	HAL_SESSION_SET_PROP_DONE,
 	HAL_SESSION_GET_PROP_DONE,
-	HAL_SESSION_PARSE_SEQ_HDR_DONE,
-	HAL_SESSION_GET_SEQ_HDR_DONE,
 	HAL_SESSION_RELEASE_BUFFER_DONE,
 	HAL_SESSION_RELEASE_RESOURCE_DONE,
 	HAL_SESSION_PROPERTY_INFO,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index dc64ad2..0d73410 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -81,7 +81,6 @@
 #define HFI_VIDEO_CODEC_VP8				0x00001000
 #define HFI_VIDEO_CODEC_HEVC				0x00002000
 #define HFI_VIDEO_CODEC_VP9				0x00004000
-#define HFI_VIDEO_CODEC_HEVC_HYBRID			0x80000000
 
 #define HFI_PROFILE_UNKNOWN					0x00000000
 #define HFI_H264_PROFILE_BASELINE			0x00000001
@@ -214,8 +213,6 @@
 	(HFI_PROPERTY_PARAM_COMMON_START + 0x00C)
 #define  HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED            \
 	(HFI_PROPERTY_PARAM_COMMON_START + 0x00E)
-#define HFI_PROPERTY_PARAM_MVC_BUFFER_LAYOUT \
-	(HFI_PROPERTY_PARAM_COMMON_START + 0x00F)
 #define  HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED	    \
 	(HFI_PROPERTY_PARAM_COMMON_START + 0x010)
 
@@ -281,8 +278,6 @@
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01E)
 #define  HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES \
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x020)
-#define HFI_PROPERTY_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC \
-	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x021)
 #define HFI_PROPERTY_PARAM_VENC_LOW_LATENCY_MODE	\
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x022)
 #define HFI_PROPERTY_PARAM_VENC_PRESERVE_TEXT_QUALITY \
@@ -549,7 +544,6 @@
 
 #define HFI_LTR_MODE_DISABLE	0x0
 #define HFI_LTR_MODE_MANUAL		0x1
-#define HFI_LTR_MODE_PERIODIC	0x2
 
 struct hfi_ltr_mode {
 	u32 ltr_mode;
@@ -744,7 +738,6 @@
 	u32 close_gop;
 	u32 h264_constrain_intra_pred;
 	u32 h264_transform_8x8_flag;
-	u32 mpeg4_qpel_enable;
 	u32 multi_refp_en;
 	u32 qmatrix_en;
 	u8 vpp_info_packet_mode;
@@ -786,15 +779,6 @@
 	u32 type;
 };
 
-#define HFI_MVC_BUFFER_LAYOUT_TOP_BOTTOM  (0)
-#define HFI_MVC_BUFFER_LAYOUT_SIDEBYSIDE  (1)
-#define HFI_MVC_BUFFER_LAYOUT_SEQ         (2)
-struct hfi_mvc_buffer_layout_descp_type {
-	u32    layout_type;
-	u32    bright_view_first;
-	u32    ngap;
-};
-
 
 #define HFI_CMD_SYS_COMMON_START			\
 (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + HFI_CMD_START_OFFSET \
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 5818986..1d1928a 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1363,6 +1363,10 @@
 		case V4L2_PIX_FMT_JPGL:		descr = "JPEG Lite"; break;
 		case V4L2_PIX_FMT_SE401:	descr = "GSPCA SE401"; break;
 		case V4L2_PIX_FMT_S5C_UYVY_JPG:	descr = "S5C73MX interleaved UYVY/JPEG"; break;
+		case V4L2_PIX_FMT_HEVC:
+			descr = "HEVC"; break;
+		case V4L2_PIX_FMT_VP9:
+			descr = "VP9"; break;
 		default:
 			WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat);
 			if (fmt->description[0])
diff --git a/drivers/mfd/msm-cdc-pinctrl.c b/drivers/mfd/msm-cdc-pinctrl.c
index 3ffd202..9622256 100644
--- a/drivers/mfd/msm-cdc-pinctrl.c
+++ b/drivers/mfd/msm-cdc-pinctrl.c
@@ -180,13 +180,15 @@
 		ret = PTR_ERR(gpio_data->pinctrl_sleep);
 		goto err_lookup_state;
 	}
-
-	/* Set pinctrl state to aud_sleep by default */
-	ret = pinctrl_select_state(gpio_data->pinctrl,
-				   gpio_data->pinctrl_sleep);
-	if (ret)
-		dev_err(&pdev->dev, "%s: set cdc gpio sleep state fail: %d\n",
-			__func__, ret);
+	/* skip setting to sleep state for LPI_TLMM GPIOs */
+	if (!of_property_read_bool(pdev->dev.of_node, "qcom,lpi-gpios")) {
+		/* Set pinctrl state to aud_sleep by default */
+		ret = pinctrl_select_state(gpio_data->pinctrl,
+					   gpio_data->pinctrl_sleep);
+		if (ret)
+			dev_err(&pdev->dev, "%s: set cdc gpio sleep state fail: %d\n",
+				__func__, ret);
+	}
 
 	gpio_data->gpio = of_get_named_gpio(pdev->dev.of_node,
 					    "qcom,cdc-rst-n-gpio", 0);
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index f0126dd..d143536 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -505,6 +505,7 @@
 
 	mutex_init(&wcd9xxx->io_lock);
 	mutex_init(&wcd9xxx->xfer_lock);
+	mutex_init(&wcd9xxx->reset_lock);
 
 	ret = wcd9xxx_bringup(wcd9xxx->dev);
 	if (ret) {
@@ -583,6 +584,7 @@
 err_bring_up:
 	mutex_destroy(&wcd9xxx->io_lock);
 	mutex_destroy(&wcd9xxx->xfer_lock);
+	mutex_destroy(&wcd9xxx->reset_lock);
 	return ret;
 }
 
@@ -595,6 +597,7 @@
 	wcd9xxx_core_res_deinit(&wcd9xxx->core_res);
 	mutex_destroy(&wcd9xxx->io_lock);
 	mutex_destroy(&wcd9xxx->xfer_lock);
+	mutex_destroy(&wcd9xxx->reset_lock);
 	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
 		slim_remove_device(wcd9xxx->slim_slave);
 }
@@ -1215,11 +1218,19 @@
 {
 	struct wcd9xxx *wcd9xxx;
 	struct wcd9xxx_pdata *pdata;
+	const struct slim_device_id *device_id;
 	int ret = 0;
 	int intf_type;
 
 	intf_type = wcd9xxx_get_intf_type();
 
+	wcd9xxx = devm_kzalloc(&slim->dev, sizeof(struct wcd9xxx),
+				GFP_KERNEL);
+	if (!wcd9xxx) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
 	if (!slim) {
 		ret = -EINVAL;
 		goto err;
@@ -1228,7 +1239,8 @@
 	if (intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
 		dev_dbg(&slim->dev, "%s:Codec is detected in I2C mode\n",
 			__func__);
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err;
 	}
 	if (slim->dev.of_node) {
 		dev_info(&slim->dev, "Platform data from device tree\n");
@@ -1262,21 +1274,22 @@
 		goto err;
 	}
 
-	wcd9xxx = devm_kzalloc(&slim->dev, sizeof(struct wcd9xxx),
-				GFP_KERNEL);
-	if (!wcd9xxx) {
-		ret = -ENOMEM;
-		goto err;
-	}
 	if (!slim->ctrl) {
 		dev_err(&slim->dev, "%s: Error, no SLIMBUS control data\n",
 			__func__);
 		ret = -EINVAL;
 		goto err_codec;
 	}
-	wcd9xxx->type = slim_get_device_id(slim)->driver_data;
+	device_id = slim_get_device_id(slim);
+	if (!device_id) {
+		dev_err(&slim->dev, "%s: Error, no device id\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	wcd9xxx->type = device_id->driver_data;
 	dev_info(&slim->dev, "%s: probing for wcd type: %d, name: %s\n",
-		 __func__, wcd9xxx->type, slim_get_device_id(slim)->name);
+		 __func__, wcd9xxx->type, device_id->name);
 
 	/* wcd9xxx members init */
 	wcd9xxx->multi_reg_write = wcd9xxx_slim_multi_reg_write;
@@ -1417,6 +1430,7 @@
 err_codec:
 	slim_set_clientdata(slim, NULL);
 err:
+	devm_kfree(&slim->dev, wcd9xxx);
 	return ret;
 }
 static int wcd9xxx_slim_remove(struct slim_device *pdev)
@@ -1470,9 +1484,11 @@
 	if (wcd9xxx->dev_up)
 		return 0;
 
+	mutex_lock(&wcd9xxx->reset_lock);
 	ret = wcd9xxx_reset(wcd9xxx->dev);
 	if (ret)
 		dev_err(wcd9xxx->dev, "%s: Resetting Codec failed\n", __func__);
+	mutex_unlock(&wcd9xxx->reset_lock);
 
 	return ret;
 }
@@ -1480,6 +1496,7 @@
 static int wcd9xxx_slim_device_up(struct slim_device *sldev)
 {
 	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+	int ret = 0;
 
 	if (!wcd9xxx) {
 		pr_err("%s: wcd9xxx is NULL\n", __func__);
@@ -1491,7 +1508,12 @@
 		return 0;
 
 	wcd9xxx->dev_up = true;
-	return wcd9xxx_device_up(wcd9xxx);
+
+	mutex_lock(&wcd9xxx->reset_lock);
+	ret = wcd9xxx_device_up(wcd9xxx);
+	mutex_unlock(&wcd9xxx->reset_lock);
+
+	return ret;
 }
 
 static int wcd9xxx_slim_device_down(struct slim_device *sldev)
@@ -1509,10 +1531,14 @@
 		return 0;
 
 	wcd9xxx->dev_up = false;
-	wcd9xxx_irq_exit(&wcd9xxx->core_res);
+
+	mutex_lock(&wcd9xxx->reset_lock);
 	if (wcd9xxx->dev_down)
 		wcd9xxx->dev_down(wcd9xxx);
+	wcd9xxx_irq_exit(&wcd9xxx->core_res);
 	wcd9xxx_reset_low(wcd9xxx->dev);
+	mutex_unlock(&wcd9xxx->reset_lock);
+
 	return 0;
 }
 
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 1a50f37..30ad689e 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -307,6 +307,7 @@
 		goto err_disable_irq;
 	}
 
+	memset(status, 0, sizeof(status));
 	ret = regmap_bulk_read(wcd9xxx_res->wcd_core_regmap,
 		wcd9xxx_res->intr_reg[WCD9XXX_INTR_STATUS_BASE],
 		status, num_irq_regs);
@@ -704,20 +705,27 @@
 
 static int wcd9xxx_irq_probe(struct platform_device *pdev)
 {
-	int irq;
+	int irq, dir_apps_irq = -EINVAL;
 	struct wcd9xxx_irq_drv_data *data;
 	struct device_node *node = pdev->dev.of_node;
 	int ret = -EINVAL;
 
 	irq = of_get_named_gpio(node, "qcom,gpio-connect", 0);
-	if (!gpio_is_valid(irq)) {
+	if (!gpio_is_valid(irq))
+		dir_apps_irq = platform_get_irq_byname(pdev, "wcd_irq");
+
+	if (!gpio_is_valid(irq) && dir_apps_irq < 0) {
 		dev_err(&pdev->dev, "TLMM connect gpio not found\n");
 		return -EPROBE_DEFER;
 	}
-	irq = gpio_to_irq(irq);
-	if (irq < 0) {
-		dev_err(&pdev->dev, "Unable to configure irq\n");
-		return irq;
+	if (dir_apps_irq > 0) {
+		irq = dir_apps_irq;
+	} else {
+		irq = gpio_to_irq(irq);
+		if (irq < 0) {
+			dev_err(&pdev->dev, "Unable to configure irq\n");
+			return irq;
+		}
 	}
 	dev_dbg(&pdev->dev, "%s: virq = %d\n", __func__, irq);
 	data = wcd9xxx_irq_add_domain(node, node->parent);
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index d3a926c..8bf1404 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -62,6 +62,10 @@
 		goto err;
 	}
 
+	if (!rx_num || rx_num > wcd9xxx->num_rx_port) {
+		pr_err("%s: invalid rx num %d\n", __func__, rx_num);
+		return -EINVAL;
+	}
 	if (wcd9xxx->rx_chs) {
 		wcd9xxx->num_rx_port = rx_num;
 		for (i = 0; i < rx_num; i++) {
@@ -84,6 +88,10 @@
 			wcd9xxx->num_rx_port);
 	}
 
+	if (!tx_num || tx_num > wcd9xxx->num_tx_port) {
+		pr_err("%s: invalid tx num %d\n", __func__, tx_num);
+		return -EINVAL;
+	}
 	if (wcd9xxx->tx_chs) {
 		wcd9xxx->num_tx_port = tx_num;
 		for (i = 0; i < tx_num; i++) {
diff --git a/drivers/mfd/wcd9xxx-utils.c b/drivers/mfd/wcd9xxx-utils.c
index 007b99d..8d3d4ad 100644
--- a/drivers/mfd/wcd9xxx-utils.c
+++ b/drivers/mfd/wcd9xxx-utils.c
@@ -669,7 +669,7 @@
 		return -EINVAL;
 	}
 
-	value = msm_cdc_get_gpio_state(wcd9xxx->wcd_rst_np);
+	value = msm_cdc_pinctrl_get_state(wcd9xxx->wcd_rst_np);
 	if (value > 0) {
 		wcd9xxx->avoid_cdc_rstlow = 1;
 		return 0;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 9c9d130..d593315 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -780,6 +780,15 @@
 	help
 	  Memory time statistics exported to /sys/kernel/memory_state_time
 
+config QPNP_MISC
+	tristate "QPNP Misc Peripheral"
+	depends on MFD_SPMI_PMIC
+	help
+	  Say 'y' here to include support for the QTI QPNP MISC
+	  peripheral. The MISC peripheral holds the USB ID interrupt
+	  and the driver provides an API to check if this interrupt
+	  is available on the current PMIC chip.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 19f9e1d..dd12e9a 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -53,6 +53,7 @@
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
 obj-$(CONFIG_CXL_BASE)		+= cxl/
 obj-$(CONFIG_PANEL)             += panel.o
+obj-$(CONFIG_QPNP_MISC) 	+= qpnp-misc.o
 obj-y				+= qcom/
 obj-$(CONFIG_MEMORY_STATE_TIME)	+= memory_state_time.o
 
diff --git a/drivers/misc/qcom/qdsp6v2/aac_in.c b/drivers/misc/qcom/qdsp6v2/aac_in.c
index b74aa59..c0828dc 100644
--- a/drivers/misc/qcom/qdsp6v2/aac_in.c
+++ b/drivers/misc/qcom/qdsp6v2/aac_in.c
@@ -34,6 +34,8 @@
 
 #define AAC_FORMAT_ADTS 65535
 
+#define MAX_SAMPLE_RATE_384K 384000
+
 static long aac_in_ioctl_shared(struct file *file, unsigned int cmd, void *arg)
 {
 	struct q6audio_in  *audio = file->private_data;
@@ -233,6 +235,13 @@
 			break;
 		}
 
+		if (cfg->sample_rate > MAX_SAMPLE_RATE_384K) {
+			pr_err("%s: ERROR: invalid sample rate = %u",
+				__func__, cfg->sample_rate);
+			rc = -EINVAL;
+			break;
+		}
+
 		min_bitrate = ((cfg->sample_rate)*(cfg->channels))/2;
 		/* This calculation should be based on AAC mode. But we cannot
 		 * get AAC mode in this setconfig. min_bitrate's logical max
diff --git a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
index c1d792b..b97a584 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
@@ -29,6 +29,8 @@
 	struct audio_client             *ac;
 	struct msm_hwacc_effects_config  config;
 
+	struct mutex			lock;
+
 	atomic_t			in_count;
 	atomic_t			out_count;
 
@@ -231,8 +233,11 @@
 		uint32_t idx = 0;
 		uint32_t size = 0;
 
+		mutex_lock(&effects->lock);
+
 		if (!effects->started) {
 			rc = -EFAULT;
+			mutex_unlock(&effects->lock);
 			goto ioctl_fail;
 		}
 
@@ -242,11 +247,13 @@
 		if (!rc) {
 			pr_err("%s: write wait_event_timeout\n", __func__);
 			rc = -EFAULT;
+			 mutex_unlock(&effects->lock);
 			goto ioctl_fail;
 		}
 		if (!atomic_read(&effects->out_count)) {
 			pr_err("%s: pcm stopped out_count 0\n", __func__);
 			rc = -EFAULT;
+			mutex_unlock(&effects->lock);
 			goto ioctl_fail;
 		}
 
@@ -256,6 +263,7 @@
 				copy_from_user(bufptr, (void *)arg,
 					effects->config.buf_cfg.output_len)) {
 				rc = -EFAULT;
+				mutex_unlock(&effects->lock);
 				goto ioctl_fail;
 			}
 			rc = q6asm_write(effects->ac,
@@ -263,6 +271,7 @@
 					 0, 0, NO_TIMESTAMP);
 			if (rc < 0) {
 				rc = -EFAULT;
+				mutex_unlock(&effects->lock);
 				goto ioctl_fail;
 			}
 			atomic_dec(&effects->out_count);
@@ -270,6 +279,7 @@
 			pr_err("%s: AUDIO_EFFECTS_WRITE: Buffer dropped\n",
 				__func__);
 		}
+		mutex_unlock(&effects->lock);
 		break;
 	}
 	case AUDIO_EFFECTS_READ: {
@@ -469,6 +479,7 @@
 		break;
 	}
 	case AUDIO_EFFECTS_SET_BUF_LEN: {
+		mutex_lock(&effects->lock);
 		if (copy_from_user(&effects->config.buf_cfg, (void *)arg,
 				   sizeof(effects->config.buf_cfg))) {
 			pr_err("%s: copy from user for AUDIO_EFFECTS_SET_BUF_LEN failed\n",
@@ -478,6 +489,7 @@
 		pr_debug("%s: write buf len: %d, read buf len: %d\n",
 			 __func__, effects->config.buf_cfg.output_len,
 			 effects->config.buf_cfg.input_len);
+		mutex_unlock(&effects->lock);
 		break;
 	}
 	case AUDIO_EFFECTS_GET_BUF_AVAIL: {
@@ -725,6 +737,7 @@
 	}
 	q6asm_audio_client_free(effects->ac);
 
+	mutex_destroy(&effects->lock);
 	kfree(effects);
 
 	pr_debug("%s: close session success\n", __func__);
@@ -752,6 +765,7 @@
 
 	init_waitqueue_head(&effects->read_wait);
 	init_waitqueue_head(&effects->write_wait);
+	mutex_init(&effects->lock);
 
 	effects->opened = 0;
 	effects->started = 0;
diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
index 73746ee..06e0dc3 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
@@ -122,7 +122,10 @@
 	list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
 		if (addr >= region_elt->vaddr &&
 			addr < region_elt->vaddr + region_elt->len &&
-			addr + len <= region_elt->vaddr + region_elt->len) {
+			addr + len <= region_elt->vaddr + region_elt->len &&
+			addr + len > addr) {
+			/* to avoid integer addition overflow */
+
 			/* offset since we could pass vaddr inside a registered
 			 * ion buffer
 			 */
diff --git a/drivers/misc/qpnp-misc.c b/drivers/misc/qpnp-misc.c
new file mode 100644
index 0000000..3c11de0
--- /dev/null
+++ b/drivers/misc/qpnp-misc.c
@@ -0,0 +1,352 @@
+/* Copyright (c) 2013-2014,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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/qpnp/qpnp-misc.h>
+
+#define QPNP_MISC_DEV_NAME "qcom,qpnp-misc"
+
+#define REG_DIG_MAJOR_REV	0x01
+#define REG_SUBTYPE		0x05
+#define REG_PWM_SEL		0x49
+#define REG_GP_DRIVER_EN	0x4C
+
+#define PWM_SEL_MAX		0x03
+#define GP_DRIVER_EN_BIT	BIT(0)
+
+static DEFINE_MUTEX(qpnp_misc_dev_list_mutex);
+static LIST_HEAD(qpnp_misc_dev_list);
+
+struct qpnp_misc_version {
+	u8	subtype;
+	u8	dig_major_rev;
+};
+
+/**
+ * struct qpnp_misc_dev - holds controller device specific information
+ * @list:			Doubly-linked list parameter linking to other
+ *				qpnp_misc devices.
+ * @mutex:			Mutex lock that is used to ensure mutual
+ *				exclusion between probing and accessing misc
+ *				driver information
+ * @dev:			Device pointer to the misc device
+ * @regmap:			Regmap pointer to the misc device
+ * @version:			struct that holds the subtype and dig_major_rev
+ *				of the chip.
+ */
+struct qpnp_misc_dev {
+	struct list_head		list;
+	struct mutex			mutex;
+	struct device			*dev;
+	struct regmap			*regmap;
+	struct qpnp_misc_version	version;
+
+	u32				base;
+	u8				pwm_sel;
+	bool				enable_gp_driver;
+};
+
+static const struct of_device_id qpnp_misc_match_table[] = {
+	{ .compatible = QPNP_MISC_DEV_NAME },
+	{}
+};
+
+enum qpnp_misc_version_name {
+	INVALID,
+	PM8941,
+	PM8226,
+	PMA8084,
+	PMDCALIFORNIUM,
+};
+
+static struct qpnp_misc_version irq_support_version[] = {
+	{0x00, 0x00}, /* INVALID */
+	{0x01, 0x02}, /* PM8941 */
+	{0x07, 0x00}, /* PM8226 */
+	{0x09, 0x00}, /* PMA8084 */
+	{0x16, 0x00}, /* PMDCALIFORNIUM */
+};
+
+static int qpnp_write_byte(struct qpnp_misc_dev *mdev, u16 addr, u8 val)
+{
+	int rc;
+
+	rc = regmap_write(mdev->regmap, mdev->base + addr, val);
+	if (rc)
+		pr_err("regmap write failed rc=%d\n", rc);
+
+	return rc;
+}
+
+static int qpnp_read_byte(struct qpnp_misc_dev *mdev, u16 addr, u8 *val)
+{
+	unsigned int temp;
+	int rc;
+
+	rc = regmap_read(mdev->regmap, mdev->base + addr, &temp);
+	if (rc) {
+		pr_err("regmap read failed rc=%d\n", rc);
+		return rc;
+	}
+
+	*val = (u8)temp;
+	return rc;
+}
+
+static int get_qpnp_misc_version_name(struct qpnp_misc_dev *dev)
+{
+	int i;
+
+	for (i = 1; i < ARRAY_SIZE(irq_support_version); i++)
+		if (dev->version.subtype == irq_support_version[i].subtype &&
+		    dev->version.dig_major_rev >=
+					irq_support_version[i].dig_major_rev)
+			return i;
+
+	return INVALID;
+}
+
+static bool __misc_irqs_available(struct qpnp_misc_dev *dev)
+{
+	int version_name = get_qpnp_misc_version_name(dev);
+
+	if (version_name == INVALID)
+		return 0;
+	return 1;
+}
+
+int qpnp_misc_read_reg(struct device_node *node, u16 addr, u8 *val)
+{
+	struct qpnp_misc_dev *mdev = NULL;
+	struct qpnp_misc_dev *mdev_found = NULL;
+	int rc;
+	u8 temp;
+
+	if (IS_ERR_OR_NULL(node)) {
+		pr_err("Invalid device node pointer\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&qpnp_misc_dev_list_mutex);
+	list_for_each_entry(mdev, &qpnp_misc_dev_list, list) {
+		if (mdev->dev->of_node == node) {
+			mdev_found = mdev;
+			break;
+		}
+	}
+	mutex_unlock(&qpnp_misc_dev_list_mutex);
+
+	if (!mdev_found) {
+		/*
+		 * No MISC device was found. This API should only
+		 * be called by drivers which have specified the
+		 * misc phandle in their device tree node.
+		 */
+		pr_err("no probed misc device found\n");
+		return -EPROBE_DEFER;
+	}
+
+	rc = qpnp_read_byte(mdev, addr, &temp);
+	if (rc < 0) {
+		dev_err(mdev->dev, "Failed to read addr %x, rc=%d\n", addr, rc);
+		return rc;
+	}
+
+	*val = temp;
+	return 0;
+}
+
+int qpnp_misc_irqs_available(struct device *consumer_dev)
+{
+	struct device_node *misc_node = NULL;
+	struct qpnp_misc_dev *mdev = NULL;
+	struct qpnp_misc_dev *mdev_found = NULL;
+
+	if (IS_ERR_OR_NULL(consumer_dev)) {
+		pr_err("Invalid consumer device pointer\n");
+		return -EINVAL;
+	}
+
+	misc_node = of_parse_phandle(consumer_dev->of_node, "qcom,misc-ref", 0);
+	if (!misc_node) {
+		pr_debug("Could not find qcom,misc-ref property in %s\n",
+			consumer_dev->of_node->full_name);
+		return 0;
+	}
+
+	mutex_lock(&qpnp_misc_dev_list_mutex);
+	list_for_each_entry(mdev, &qpnp_misc_dev_list, list) {
+		if (mdev->dev->of_node == misc_node) {
+			mdev_found = mdev;
+			break;
+		}
+	}
+	mutex_unlock(&qpnp_misc_dev_list_mutex);
+
+	if (!mdev_found) {
+		/*
+		 * No MISC device was found. This API should only
+		 * be called by drivers which have specified the
+		 * misc phandle in their device tree node.
+		 */
+		pr_err("no probed misc device found\n");
+		return -EPROBE_DEFER;
+	}
+
+	return __misc_irqs_available(mdev_found);
+}
+
+static int qpnp_misc_dt_init(struct qpnp_misc_dev *mdev)
+{
+	struct device_node *node = mdev->dev->of_node;
+	u32 val;
+	int rc;
+
+	rc = of_property_read_u32(node, "reg", &mdev->base);
+	if (rc < 0 || !mdev->base) {
+		dev_err(mdev->dev, "Base address not defined or invalid\n");
+		return -EINVAL;
+	}
+
+	if (!of_property_read_u32(node, "qcom,pwm-sel", &val)) {
+		if (val > PWM_SEL_MAX) {
+			dev_err(mdev->dev, "Invalid value for pwm-sel\n");
+			return -EINVAL;
+		}
+		mdev->pwm_sel = (u8)val;
+	}
+	mdev->enable_gp_driver = of_property_read_bool(node,
+						"qcom,enable-gp-driver");
+
+	WARN((mdev->pwm_sel > 0 && !mdev->enable_gp_driver),
+			"Setting PWM source without enabling gp driver\n");
+	WARN((mdev->pwm_sel == 0 && mdev->enable_gp_driver),
+			"Enabling gp driver without setting PWM source\n");
+
+	return 0;
+}
+
+static int qpnp_misc_config(struct qpnp_misc_dev *mdev)
+{
+	int rc, version_name;
+
+	version_name = get_qpnp_misc_version_name(mdev);
+
+	switch (version_name) {
+	case PMDCALIFORNIUM:
+		if (mdev->pwm_sel > 0 && mdev->enable_gp_driver) {
+			rc = qpnp_write_byte(mdev, REG_PWM_SEL, mdev->pwm_sel);
+			if (rc < 0) {
+				dev_err(mdev->dev,
+					"Failed to write PWM_SEL reg\n");
+				return rc;
+			}
+
+			rc = qpnp_write_byte(mdev, REG_GP_DRIVER_EN,
+					GP_DRIVER_EN_BIT);
+			if (rc < 0) {
+				dev_err(mdev->dev,
+					"Failed to write GP_DRIVER_EN reg\n");
+				return rc;
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int qpnp_misc_probe(struct platform_device *pdev)
+{
+	struct qpnp_misc_dev *mdev = ERR_PTR(-EINVAL);
+	int rc;
+
+	mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL);
+	if (!mdev)
+		return -ENOMEM;
+
+	mdev->dev = &pdev->dev;
+	mdev->regmap = dev_get_regmap(mdev->dev->parent, NULL);
+	if (!mdev->regmap) {
+		dev_err(mdev->dev, "Parent regmap is unavailable\n");
+		return -ENXIO;
+	}
+
+	rc = qpnp_misc_dt_init(mdev);
+	if (rc < 0) {
+		dev_err(mdev->dev,
+			"Error reading device tree properties, rc=%d\n", rc);
+		return rc;
+	}
+
+
+	rc = qpnp_read_byte(mdev, REG_SUBTYPE, &mdev->version.subtype);
+	if (rc < 0) {
+		dev_err(mdev->dev, "Failed to read subtype, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_read_byte(mdev, REG_DIG_MAJOR_REV,
+			&mdev->version.dig_major_rev);
+	if (rc < 0) {
+		dev_err(mdev->dev, "Failed to read dig_major_rev, rc=%d\n", rc);
+		return rc;
+	}
+
+	mutex_lock(&qpnp_misc_dev_list_mutex);
+	list_add_tail(&mdev->list, &qpnp_misc_dev_list);
+	mutex_unlock(&qpnp_misc_dev_list_mutex);
+
+	rc = qpnp_misc_config(mdev);
+	if (rc < 0) {
+		dev_err(mdev->dev,
+			"Error configuring module registers, rc=%d\n", rc);
+		return rc;
+	}
+
+	dev_info(mdev->dev, "probe successful\n");
+	return 0;
+}
+
+static struct platform_driver qpnp_misc_driver = {
+	.probe	= qpnp_misc_probe,
+	.driver	= {
+		.name		= QPNP_MISC_DEV_NAME,
+		.owner		= THIS_MODULE,
+		.of_match_table	= qpnp_misc_match_table,
+	},
+};
+
+static int __init qpnp_misc_init(void)
+{
+	return platform_driver_register(&qpnp_misc_driver);
+}
+
+static void __exit qpnp_misc_exit(void)
+{
+	return platform_driver_unregister(&qpnp_misc_driver);
+}
+
+subsys_initcall(qpnp_misc_init);
+module_exit(qpnp_misc_exit);
+
+MODULE_DESCRIPTION(QPNP_MISC_DEV_NAME);
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" QPNP_MISC_DEV_NAME);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 817fcf8..ace47ae 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2324,10 +2324,7 @@
 			err = mmc_blk_reset(md, card->host, type);
 			if (!err)
 				break;
-			if (err == -ENODEV ||
-				mmc_packed_cmd(mq_rq->cmd_type))
-				goto cmd_abort;
-			/* Fall through */
+			goto cmd_abort;
 		}
 		case MMC_BLK_ECC_ERR:
 			if (brq->data.blocks > 1) {
@@ -2843,6 +2840,13 @@
 		  MMC_QUIRK_LONG_READ_TIME),
 
 	/*
+	 * Some Samsung MMC cards need longer data read timeout than
+	 * indicated in CSD.
+	 */
+	MMC_FIXUP("Q7XSAB", CID_MANFID_SAMSUNG, 0x100, add_quirk_mmc,
+		  MMC_QUIRK_LONG_READ_TIME),
+
+	/*
 	 * On these Samsung MoviNAND parts, performing secure erase or
 	 * secure trim can result in unrecoverable corruption due to a
 	 * firmware bug.
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index daad32f..36d9d69 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -37,3 +37,13 @@
 	  about re-trying SD init requests. This can be a useful
 	  work-around for buggy controllers and hardware. Enable
 	  if you are experiencing issues with SD detection.
+
+config MMC_CLKGATE
+	bool "MMC host clock gating"
+	help
+	  This will attempt to aggressively gate the clock to the MMC card.
+	  This is done to save power due to gating off the logic and bus
+	  noise when the MMC card is not in use. Your host driver has to
+	  support handling this in order for it to be of any use.
+
+	  If unsure, say N.
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 40ddc3e..e19d912 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -226,6 +226,8 @@
 
 		if (mrq->done)
 			mrq->done(mrq);
+
+		mmc_host_clk_release(host);
 	}
 }
 
@@ -340,6 +342,7 @@
 			mrq->stop->mrq = mrq;
 		}
 	}
+	mmc_host_clk_hold(host);
 	led_trigger_event(host->led, LED_FULL);
 	__mmc_start_request(host, mrq);
 
@@ -634,8 +637,11 @@
 static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
 		 bool is_first_req)
 {
-	if (host->ops->pre_req)
+	if (host->ops->pre_req) {
+		mmc_host_clk_hold(host);
 		host->ops->pre_req(host, mrq, is_first_req);
+		mmc_host_clk_release(host);
+	}
 }
 
 /**
@@ -650,8 +656,11 @@
 static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
 			 int err)
 {
-	if (host->ops->post_req)
+	if (host->ops->post_req) {
+		mmc_host_clk_hold(host);
 		host->ops->post_req(host, mrq, err);
+		mmc_host_clk_release(host);
+	}
 }
 
 /**
@@ -949,9 +958,9 @@
 		unsigned int timeout_us, limit_us;
 
 		timeout_us = data->timeout_ns / 1000;
-		if (card->host->ios.clock)
+		if (mmc_host_clk_rate(card->host))
 			timeout_us += data->timeout_clks * 1000 /
-				(card->host->ios.clock / 1000);
+				(mmc_host_clk_rate(card->host) / 1000);
 
 		if (data->flags & MMC_DATA_WRITE)
 			/*
@@ -1080,6 +1089,9 @@
 	if (pm)
 		pm_runtime_get_sync(mmc_dev(host));
 
+	if (host->ops->enable && !stop && host->claim_cnt == 1)
+		host->ops->enable(host);
+
 	return stop;
 }
 EXPORT_SYMBOL(__mmc_claim_host);
@@ -1097,6 +1109,9 @@
 
 	WARN_ON(!host->claimed);
 
+	if (host->ops->disable && host->claim_cnt == 1)
+		host->ops->disable(host);
+
 	spin_lock_irqsave(&host->lock, flags);
 	if (--host->claim_cnt) {
 		/* Release for nested claim */
@@ -1149,6 +1164,8 @@
 		 ios->power_mode, ios->chip_select, ios->vdd,
 		 1 << ios->bus_width, ios->timing);
 
+	if (ios->clock > 0)
+		mmc_set_ungated(host);
 	host->ops->set_ios(host, ios);
 }
 
@@ -1157,15 +1174,17 @@
  */
 void mmc_set_chip_select(struct mmc_host *host, int mode)
 {
+	mmc_host_clk_hold(host);
 	host->ios.chip_select = mode;
 	mmc_set_ios(host);
+	mmc_host_clk_release(host);
 }
 
 /*
  * Sets the host clock to the highest possible frequency that
  * is below "hz".
  */
-void mmc_set_clock(struct mmc_host *host, unsigned int hz)
+static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
 {
 	WARN_ON(hz && hz < host->f_min);
 
@@ -1176,6 +1195,68 @@
 	mmc_set_ios(host);
 }
 
+void mmc_set_clock(struct mmc_host *host, unsigned int hz)
+{
+	mmc_host_clk_hold(host);
+	__mmc_set_clock(host, hz);
+	mmc_host_clk_release(host);
+}
+
+#ifdef CONFIG_MMC_CLKGATE
+/*
+ * This gates the clock by setting it to 0 Hz.
+ */
+void mmc_gate_clock(struct mmc_host *host)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->clk_lock, flags);
+	host->clk_old = host->ios.clock;
+	host->ios.clock = 0;
+	host->clk_gated = true;
+	spin_unlock_irqrestore(&host->clk_lock, flags);
+	mmc_set_ios(host);
+}
+
+/*
+ * This restores the clock from gating by using the cached
+ * clock value.
+ */
+void mmc_ungate_clock(struct mmc_host *host)
+{
+	/*
+	 * We should previously have gated the clock, so the clock shall
+	 * be 0 here! The clock may however be 0 during initialization,
+	 * when some request operations are performed before setting
+	 * the frequency. When ungate is requested in that situation
+	 * we just ignore the call.
+	 */
+	if (host->clk_old) {
+		BUG_ON(host->ios.clock);
+		/* This call will also set host->clk_gated to false */
+		__mmc_set_clock(host, host->clk_old);
+	}
+}
+
+void mmc_set_ungated(struct mmc_host *host)
+{
+	unsigned long flags;
+
+	/*
+	 * We've been given a new frequency while the clock is gated,
+	 * so make sure we regard this as ungating it.
+	 */
+	spin_lock_irqsave(&host->clk_lock, flags);
+	host->clk_gated = false;
+	spin_unlock_irqrestore(&host->clk_lock, flags);
+}
+
+#else
+void mmc_set_ungated(struct mmc_host *host)
+{
+}
+#endif
+
 int mmc_execute_tuning(struct mmc_card *card)
 {
 	struct mmc_host *host = card->host;
@@ -1190,7 +1271,9 @@
 	else
 		opcode = MMC_SEND_TUNING_BLOCK;
 
+	mmc_host_clk_hold(host);
 	err = host->ops->execute_tuning(host, opcode);
+	mmc_host_clk_release(host);
 
 	if (err)
 		pr_err("%s: tuning execution failed: %d\n",
@@ -1206,8 +1289,10 @@
  */
 void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
 {
+	mmc_host_clk_hold(host);
 	host->ios.bus_mode = mode;
 	mmc_set_ios(host);
+	mmc_host_clk_release(host);
 }
 
 /*
@@ -1215,8 +1300,10 @@
  */
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
 {
+	mmc_host_clk_hold(host);
 	host->ios.bus_width = width;
 	mmc_set_ios(host);
+	mmc_host_clk_release(host);
 }
 
 /*
@@ -1671,8 +1758,11 @@
 	int old_signal_voltage = host->ios.signal_voltage;
 
 	host->ios.signal_voltage = signal_voltage;
-	if (host->ops->start_signal_voltage_switch)
+	if (host->ops->start_signal_voltage_switch) {
+		mmc_host_clk_hold(host);
 		err = host->ops->start_signal_voltage_switch(host, &host->ios);
+		mmc_host_clk_release(host);
+	}
 
 	if (err)
 		host->ios.signal_voltage = old_signal_voltage;
@@ -1706,17 +1796,20 @@
 		pr_warn("%s: cannot verify signal voltage switch\n",
 			mmc_hostname(host));
 
+	mmc_host_clk_hold(host);
+
 	cmd.opcode = SD_SWITCH_VOLTAGE;
 	cmd.arg = 0;
 	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 
 	err = mmc_wait_for_cmd(host, &cmd, 0);
 	if (err)
-		return err;
+		goto err_command;
 
-	if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
-		return -EIO;
-
+	if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) {
+		err = -EIO;
+		goto err_command;
+	}
 	/*
 	 * The card should drive cmd and dat[0:3] low immediately
 	 * after the response of cmd11, but wait 1 ms to be sure
@@ -1765,6 +1858,9 @@
 		mmc_power_cycle(host, ocr);
 	}
 
+err_command:
+	mmc_host_clk_release(host);
+
 	return err;
 }
 
@@ -1773,8 +1869,10 @@
  */
 void mmc_set_timing(struct mmc_host *host, unsigned int timing)
 {
+	mmc_host_clk_hold(host);
 	host->ios.timing = timing;
 	mmc_set_ios(host);
+	mmc_host_clk_release(host);
 }
 
 /*
@@ -1782,8 +1880,10 @@
  */
 void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
 {
+	mmc_host_clk_hold(host);
 	host->ios.drv_type = drv_type;
 	mmc_set_ios(host);
+	mmc_host_clk_release(host);
 }
 
 int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
@@ -1791,6 +1891,7 @@
 {
 	struct mmc_host *host = card->host;
 	int host_drv_type = SD_DRIVER_TYPE_B;
+	int drive_strength;
 
 	*drv_type = 0;
 
@@ -1813,10 +1914,14 @@
 	 * information and let the hardware specific code
 	 * return what is possible given the options
 	 */
-	return host->ops->select_drive_strength(card, max_dtr,
-						host_drv_type,
-						card_drv_type,
-						drv_type);
+	mmc_host_clk_hold(host);
+	drive_strength = host->ops->select_drive_strength(card, max_dtr,
+							  host_drv_type,
+							  card_drv_type,
+							  drv_type);
+	mmc_host_clk_release(host);
+
+	return drive_strength;
 }
 
 /*
@@ -1835,6 +1940,8 @@
 	if (host->ios.power_mode == MMC_POWER_ON)
 		return;
 
+	mmc_host_clk_hold(host);
+
 	mmc_pwrseq_pre_power_on(host);
 
 	host->ios.vdd = fls(ocr) - 1;
@@ -1868,6 +1975,8 @@
 	 * time required to reach a stable voltage.
 	 */
 	mmc_delay(10);
+
+	mmc_host_clk_release(host);
 }
 
 void mmc_power_off(struct mmc_host *host)
@@ -1875,6 +1984,8 @@
 	if (host->ios.power_mode == MMC_POWER_OFF)
 		return;
 
+	mmc_host_clk_hold(host);
+
 	mmc_pwrseq_power_off(host);
 
 	host->ios.clock = 0;
@@ -1890,6 +2001,8 @@
 	 * can be successfully turned on again.
 	 */
 	mmc_delay(1);
+
+	mmc_host_clk_release(host);
 }
 
 void mmc_power_cycle(struct mmc_host *host, u32 ocr)
@@ -2103,7 +2216,7 @@
 		 */
 		timeout_clks <<= 1;
 		timeout_us += (timeout_clks * 1000) /
-			      (card->host->ios.clock / 1000);
+			      (mmc_host_clk_rate(card->host) / 1000);
 
 		erase_timeout = timeout_us / 1000;
 
@@ -2626,7 +2739,9 @@
 {
 	if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
 		return;
+	mmc_host_clk_hold(host);
 	host->ops->hw_reset(host);
+	mmc_host_clk_release(host);
 }
 
 int mmc_hw_reset(struct mmc_host *host)
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 0fa86a2..c975c7a 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -40,6 +40,9 @@
 
 void mmc_set_chip_select(struct mmc_host *host, int mode);
 void mmc_set_clock(struct mmc_host *host, unsigned int hz);
+void mmc_gate_clock(struct mmc_host *host);
+void mmc_ungate_clock(struct mmc_host *host);
+void mmc_set_ungated(struct mmc_host *host);
 void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
 u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index c8451ce..bf0f6ce 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -256,6 +256,11 @@
 			&mmc_clock_fops))
 		goto err_node;
 
+#ifdef CONFIG_MMC_CLKGATE
+	if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
+				root, &host->clk_delay))
+		goto err_node;
+#endif
 #ifdef CONFIG_FAIL_MMC_REQUEST
 	if (fail_request)
 		setup_fault_attr(&fail_default_attr, fail_request);
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 348b58b..f18105f 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -58,6 +58,246 @@
 	class_unregister(&mmc_host_class);
 }
 
+#ifdef CONFIG_MMC_CLKGATE
+static ssize_t clkgate_delay_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+	return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay);
+}
+
+static ssize_t clkgate_delay_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+	unsigned long flags, value;
+
+	if (kstrtoul(buf, 0, &value))
+		return -EINVAL;
+
+	spin_lock_irqsave(&host->clk_lock, flags);
+	host->clkgate_delay = value;
+	spin_unlock_irqrestore(&host->clk_lock, flags);
+	return count;
+}
+
+/*
+ * Enabling clock gating will make the core call out to the host
+ * once up and once down when it performs a request or card operation
+ * intermingled in any fashion. The driver will see this through
+ * set_ios() operations with ios.clock field set to 0 to gate (disable)
+ * the block clock, and to the old frequency to enable it again.
+ */
+static void mmc_host_clk_gate_delayed(struct mmc_host *host)
+{
+	unsigned long tick_ns;
+	unsigned long freq = host->ios.clock;
+	unsigned long flags;
+
+	if (!freq) {
+		pr_debug("%s: frequency set to 0 in disable function, "
+			 "this means the clock is already disabled.\n",
+			 mmc_hostname(host));
+		return;
+	}
+	/*
+	 * New requests may have appeared while we were scheduling,
+	 * then there is no reason to delay the check before
+	 * clk_disable().
+	 */
+	spin_lock_irqsave(&host->clk_lock, flags);
+
+	/*
+	 * Delay n bus cycles (at least 8 from MMC spec) before attempting
+	 * to disable the MCI block clock. The reference count may have
+	 * gone up again after this delay due to rescheduling!
+	 */
+	if (!host->clk_requests) {
+		spin_unlock_irqrestore(&host->clk_lock, flags);
+		tick_ns = DIV_ROUND_UP(1000000000, freq);
+		ndelay(host->clk_delay * tick_ns);
+	} else {
+		/* New users appeared while waiting for this work */
+		spin_unlock_irqrestore(&host->clk_lock, flags);
+		return;
+	}
+	mutex_lock(&host->clk_gate_mutex);
+	spin_lock_irqsave(&host->clk_lock, flags);
+	if (!host->clk_requests) {
+		spin_unlock_irqrestore(&host->clk_lock, flags);
+		/* This will set host->ios.clock to 0 */
+		mmc_gate_clock(host);
+		spin_lock_irqsave(&host->clk_lock, flags);
+		pr_debug("%s: gated MCI clock\n", mmc_hostname(host));
+	}
+	spin_unlock_irqrestore(&host->clk_lock, flags);
+	mutex_unlock(&host->clk_gate_mutex);
+}
+
+/*
+ * Internal work. Work to disable the clock at some later point.
+ */
+static void mmc_host_clk_gate_work(struct work_struct *work)
+{
+	struct mmc_host *host = container_of(work, struct mmc_host,
+					      clk_gate_work.work);
+
+	mmc_host_clk_gate_delayed(host);
+}
+
+/**
+ *	mmc_host_clk_hold - ungate hardware MCI clocks
+ *	@host: host to ungate.
+ *
+ *	Makes sure the host ios.clock is restored to a non-zero value
+ *	past this call.	Increase clock reference count and ungate clock
+ *	if we're the first user.
+ */
+void mmc_host_clk_hold(struct mmc_host *host)
+{
+	unsigned long flags;
+
+	/* cancel any clock gating work scheduled by mmc_host_clk_release() */
+	cancel_delayed_work_sync(&host->clk_gate_work);
+	mutex_lock(&host->clk_gate_mutex);
+	spin_lock_irqsave(&host->clk_lock, flags);
+	if (host->clk_gated) {
+		spin_unlock_irqrestore(&host->clk_lock, flags);
+		mmc_ungate_clock(host);
+		spin_lock_irqsave(&host->clk_lock, flags);
+		pr_debug("%s: ungated MCI clock\n", mmc_hostname(host));
+	}
+	host->clk_requests++;
+	spin_unlock_irqrestore(&host->clk_lock, flags);
+	mutex_unlock(&host->clk_gate_mutex);
+}
+
+/**
+ *	mmc_host_may_gate_card - check if this card may be gated
+ *	@card: card to check.
+ */
+static bool mmc_host_may_gate_card(struct mmc_card *card)
+{
+	/* If there is no card we may gate it */
+	if (!card)
+		return true;
+	/*
+	 * Don't gate SDIO cards! These need to be clocked at all times
+	 * since they may be independent systems generating interrupts
+	 * and other events. The clock requests counter from the core will
+	 * go down to zero since the core does not need it, but we will not
+	 * gate the clock, because there is somebody out there that may still
+	 * be using it.
+	 */
+	return !(card->quirks & MMC_QUIRK_BROKEN_CLK_GATING);
+}
+
+/**
+ *	mmc_host_clk_release - gate off hardware MCI clocks
+ *	@host: host to gate.
+ *
+ *	Calls the host driver with ios.clock set to zero as often as possible
+ *	in order to gate off hardware MCI clocks. Decrease clock reference
+ *	count and schedule disabling of clock.
+ */
+void mmc_host_clk_release(struct mmc_host *host)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->clk_lock, flags);
+	host->clk_requests--;
+	if (mmc_host_may_gate_card(host->card) &&
+	    !host->clk_requests)
+		schedule_delayed_work(&host->clk_gate_work,
+				      msecs_to_jiffies(host->clkgate_delay));
+	spin_unlock_irqrestore(&host->clk_lock, flags);
+}
+
+/**
+ *	mmc_host_clk_rate - get current clock frequency setting
+ *	@host: host to get the clock frequency for.
+ *
+ *	Returns current clock frequency regardless of gating.
+ */
+unsigned int mmc_host_clk_rate(struct mmc_host *host)
+{
+	unsigned long freq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->clk_lock, flags);
+	if (host->clk_gated)
+		freq = host->clk_old;
+	else
+		freq = host->ios.clock;
+	spin_unlock_irqrestore(&host->clk_lock, flags);
+	return freq;
+}
+
+/**
+ *	mmc_host_clk_init - set up clock gating code
+ *	@host: host with potential clock to control
+ */
+static inline void mmc_host_clk_init(struct mmc_host *host)
+{
+	host->clk_requests = 0;
+	/* Hold MCI clock for 8 cycles by default */
+	host->clk_delay = 8;
+	/*
+	 * Default clock gating delay is 0ms to avoid wasting power.
+	 * This value can be tuned by writing into sysfs entry.
+	 */
+	host->clkgate_delay = 0;
+	host->clk_gated = false;
+	INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
+	spin_lock_init(&host->clk_lock);
+	mutex_init(&host->clk_gate_mutex);
+}
+
+/**
+ *	mmc_host_clk_exit - shut down clock gating code
+ *	@host: host with potential clock to control
+ */
+static inline void mmc_host_clk_exit(struct mmc_host *host)
+{
+	/*
+	 * Wait for any outstanding gate and then make sure we're
+	 * ungated before exiting.
+	 */
+	if (cancel_delayed_work_sync(&host->clk_gate_work))
+		mmc_host_clk_gate_delayed(host);
+	if (host->clk_gated)
+		mmc_host_clk_hold(host);
+	/* There should be only one user now */
+	WARN_ON(host->clk_requests > 1);
+}
+
+static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
+{
+	host->clkgate_delay_attr.show = clkgate_delay_show;
+	host->clkgate_delay_attr.store = clkgate_delay_store;
+	sysfs_attr_init(&host->clkgate_delay_attr.attr);
+	host->clkgate_delay_attr.attr.name = "clkgate_delay";
+	host->clkgate_delay_attr.attr.mode = S_IRUGO | S_IWUSR;
+	if (device_create_file(&host->class_dev, &host->clkgate_delay_attr))
+		pr_err("%s: Failed to create clkgate_delay sysfs entry\n",
+				mmc_hostname(host));
+}
+#else
+
+static inline void mmc_host_clk_init(struct mmc_host *host)
+{
+}
+
+static inline void mmc_host_clk_exit(struct mmc_host *host)
+{
+}
+
+static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
+{
+}
+
+#endif
+
 void mmc_retune_enable(struct mmc_host *host)
 {
 	host->can_retune = 1;
@@ -382,6 +622,8 @@
 		return NULL;
 	}
 
+	mmc_host_clk_init(host);
+
 	spin_lock_init(&host->lock);
 	init_waitqueue_head(&host->wq);
 	INIT_DELAYED_WORK(&host->detect, mmc_rescan);
@@ -427,6 +669,7 @@
 #ifdef CONFIG_DEBUG_FS
 	mmc_add_host_debugfs(host);
 #endif
+	mmc_host_clk_sysfs_init(host);
 
 #ifdef CONFIG_BLOCK
 	mmc_latency_hist_sysfs_init(host);
@@ -466,6 +709,8 @@
 	device_del(&host->class_dev);
 
 	led_trigger_unregister_simple(host->led);
+
+	mmc_host_clk_exit(host);
 }
 
 EXPORT_SYMBOL(mmc_remove_host);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 5aa3f09..56e6355 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -2096,11 +2096,13 @@
 
 	if ((host->caps & MMC_CAP_HW_RESET) && host->ops->hw_reset &&
 	     mmc_can_reset(card)) {
+		mmc_host_clk_hold(host);
 		/* If the card accept RST_n signal, send it. */
 		mmc_set_clock(host, host->f_init);
 		host->ops->hw_reset(host);
 		/* Set initial state and call mmc_set_ios */
 		mmc_set_initial_state(host);
+		mmc_host_clk_release(host);
 	} else {
 		/* Do a brute force power cycle */
 		mmc_power_cycle(host, card->ocr);
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
index ca9cade..4e65ea5 100644
--- a/drivers/mmc/core/quirks.c
+++ b/drivers/mmc/core/quirks.c
@@ -35,7 +35,25 @@
 #define SDIO_DEVICE_ID_MARVELL_8797_F0	0x9128
 #endif
 
+/*
+ * This hook just adds a quirk for all sdio devices
+ */
+static void add_quirk_for_sdio_devices(struct mmc_card *card, int data)
+{
+	if (mmc_card_sdio(card))
+		card->quirks |= data;
+}
+
 static const struct mmc_fixup mmc_fixup_methods[] = {
+	/* by default sdio devices are considered CLK_GATING broken */
+	/* good cards will be whitelisted as they are tested */
+	SDIO_FIXUP(SDIO_ANY_ID, SDIO_ANY_ID,
+		   add_quirk_for_sdio_devices,
+		   MMC_QUIRK_BROKEN_CLK_GATING),
+
+	SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+		   remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
 	SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
 		   add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
 
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index a0aa64e..60542b2 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -838,7 +838,9 @@
 	if (!host->ops->get_ro)
 		return -1;
 
+	mmc_host_clk_hold(host);
 	ro = host->ops->get_ro(host);
+	mmc_host_clk_release(host);
 
 	return ro;
 }
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index b5ec3c8..8e10bdc 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -976,10 +976,13 @@
 	}
 
 	if (!err && host->sdio_irqs) {
-		if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD))
+		if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
 			wake_up_process(host->sdio_irq_thread);
-		else if (host->caps & MMC_CAP_SDIO_IRQ)
+		} else if (host->caps & MMC_CAP_SDIO_IRQ) {
+			mmc_host_clk_hold(host);
 			host->ops->enable_sdio_irq(host, 1);
+			mmc_host_clk_release(host);
+		}
 	}
 
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 91bbbfb..09cc67d 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -168,15 +168,21 @@
 		}
 
 		set_current_state(TASK_INTERRUPTIBLE);
-		if (host->caps & MMC_CAP_SDIO_IRQ)
+		if (host->caps & MMC_CAP_SDIO_IRQ) {
+			mmc_host_clk_hold(host);
 			host->ops->enable_sdio_irq(host, 1);
+			mmc_host_clk_release(host);
+		}
 		if (!kthread_should_stop())
 			schedule_timeout(period);
 		set_current_state(TASK_RUNNING);
 	} while (!kthread_should_stop());
 
-	if (host->caps & MMC_CAP_SDIO_IRQ)
+	if (host->caps & MMC_CAP_SDIO_IRQ) {
+		mmc_host_clk_hold(host);
 		host->ops->enable_sdio_irq(host, 0);
+		mmc_host_clk_release(host);
+	}
 
 	pr_debug("%s: IRQ thread exiting with code %d\n",
 		 mmc_hostname(host), ret);
@@ -202,7 +208,9 @@
 				return err;
 			}
 		} else if (host->caps & MMC_CAP_SDIO_IRQ) {
+			mmc_host_clk_hold(host);
 			host->ops->enable_sdio_irq(host, 1);
+			mmc_host_clk_release(host);
 		}
 	}
 
@@ -221,7 +229,9 @@
 			atomic_set(&host->sdio_irq_thread_abort, 1);
 			kthread_stop(host->sdio_irq_thread);
 		} else if (host->caps & MMC_CAP_SDIO_IRQ) {
+			mmc_host_clk_hold(host);
 			host->ops->enable_sdio_irq(host, 0);
+			mmc_host_clk_release(host);
 		}
 	}
 
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 5274f50..defb66e 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -396,18 +396,26 @@
 	  If unsure, say N.
 
 config MMC_SDHCI_MSM
-	tristate "Qualcomm SDHCI Controller Support"
-	depends on ARCH_QCOM || (ARM && COMPILE_TEST)
+	tristate "Qualcomm Technologies, Inc. SDHCI Controller Support"
+	depends on ARCH_QCOM || ARCH_MSM || (ARM && COMPILE_TEST)
 	depends on MMC_SDHCI_PLTFM
 	help
 	  This selects the Secure Digital Host Controller Interface (SDHCI)
-	  support present in Qualcomm SOCs. The controller supports
-	  SD/MMC/SDIO devices.
+	  support present in Qualcomm Technologies, Inc. SOCs. The controller
+	  supports SD/MMC/SDIO devices.
 
 	  If you have a controller with this interface, say Y or M here.
 
 	  If unsure, say N.
 
+config MMC_MSM
+	tristate "Qualcomm SDCC Controller Support"
+	depends on MMC && (ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50)
+	help
+	  This provides support for the SD/MMC cell found in the
+	  MSM and QSD SOCs from Qualcomm. The controller also has
+	  support for SDIO devices.
+
 config MMC_MXC
 	tristate "Freescale i.MX21/27/31 or MPC512x Multimedia Card support"
 	depends on ARCH_MXC || PPC_MPC512x
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index e2bdaaf..ef56624 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -71,8 +71,8 @@
 obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)	+= sdhci-of-esdhc.o
 obj-$(CONFIG_MMC_SDHCI_OF_HLWD)		+= sdhci-of-hlwd.o
 obj-$(CONFIG_MMC_SDHCI_BCM_KONA)	+= sdhci-bcm-kona.o
-obj-$(CONFIG_MMC_SDHCI_IPROC)		+= sdhci-iproc.o
 obj-$(CONFIG_MMC_SDHCI_MSM)		+= sdhci-msm.o
+obj-$(CONFIG_MMC_SDHCI_IPROC)		+= sdhci-iproc.o
 obj-$(CONFIG_MMC_SDHCI_ST)		+= sdhci-st.o
 obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32)	+= sdhci-pic32.o
 obj-$(CONFIG_MMC_SDHCI_BRCMSTB)		+= sdhci-brcmstb.o
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 90ed2e1..1861af0 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1,7 +1,8 @@
 /*
- * drivers/mmc/host/sdhci-msm.c - Qualcomm SDHCI Platform driver
+ * drivers/mmc/host/sdhci-msm.c - Qualcomm Technologies, Inc. MSM SDHCI Platform
+ * driver source file
  *
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,106 +16,218 @@
  */
 
 #include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/gfp.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+#include <linux/io.h>
 #include <linux/delay.h>
-#include <linux/mmc/mmc.h>
+#include <linux/scatterlist.h>
 #include <linux/slab.h>
+#include <linux/mmc/mmc.h>
 
 #include "sdhci-pltfm.h"
 
-#define CORE_MCI_VERSION		0x50
-#define CORE_VERSION_MAJOR_SHIFT	28
-#define CORE_VERSION_MAJOR_MASK		(0xf << CORE_VERSION_MAJOR_SHIFT)
-#define CORE_VERSION_MINOR_MASK		0xff
-
+#define SDHCI_VER_100		0x2B
 #define CORE_HC_MODE		0x78
 #define HC_MODE_EN		0x1
-#define CORE_POWER		0x0
-#define CORE_SW_RST		BIT(7)
 
-#define CORE_PWRCTL_STATUS	0xdc
-#define CORE_PWRCTL_MASK	0xe0
-#define CORE_PWRCTL_CLEAR	0xe4
-#define CORE_PWRCTL_CTL		0xe8
-#define CORE_PWRCTL_BUS_OFF	BIT(0)
-#define CORE_PWRCTL_BUS_ON	BIT(1)
-#define CORE_PWRCTL_IO_LOW	BIT(2)
-#define CORE_PWRCTL_IO_HIGH	BIT(3)
-#define CORE_PWRCTL_BUS_SUCCESS BIT(0)
-#define CORE_PWRCTL_IO_SUCCESS	BIT(2)
-#define REQ_BUS_OFF		BIT(0)
-#define REQ_BUS_ON		BIT(1)
-#define REQ_IO_LOW		BIT(2)
-#define REQ_IO_HIGH		BIT(3)
-#define INT_MASK		0xf
+#define CORE_POWER		0x0
+#define CORE_SW_RST		(1 << 7)
+
+#define CORE_PWRCTL_STATUS	0xDC
+#define CORE_PWRCTL_MASK	0xE0
+#define CORE_PWRCTL_CLEAR	0xE4
+#define CORE_PWRCTL_CTL		0xE8
+
+#define CORE_PWRCTL_BUS_OFF	0x01
+#define CORE_PWRCTL_BUS_ON	(1 << 1)
+#define CORE_PWRCTL_IO_LOW	(1 << 2)
+#define CORE_PWRCTL_IO_HIGH	(1 << 3)
+
+#define CORE_PWRCTL_BUS_SUCCESS	0x01
+#define CORE_PWRCTL_BUS_FAIL	(1 << 1)
+#define CORE_PWRCTL_IO_SUCCESS	(1 << 2)
+#define CORE_PWRCTL_IO_FAIL	(1 << 3)
+
+#define INT_MASK		0xF
 #define MAX_PHASES		16
-#define CORE_DLL_LOCK		BIT(7)
-#define CORE_DLL_EN		BIT(16)
-#define CORE_CDR_EN		BIT(17)
-#define CORE_CK_OUT_EN		BIT(18)
-#define CORE_CDR_EXT_EN		BIT(19)
-#define CORE_DLL_PDN		BIT(29)
-#define CORE_DLL_RST		BIT(30)
+
+#define CORE_DLL_LOCK		(1 << 7)
+#define CORE_DLL_EN		(1 << 16)
+#define CORE_CDR_EN		(1 << 17)
+#define CORE_CK_OUT_EN		(1 << 18)
+#define CORE_CDR_EXT_EN		(1 << 19)
+#define CORE_DLL_PDN		(1 << 29)
+#define CORE_DLL_RST		(1 << 30)
 #define CORE_DLL_CONFIG		0x100
+#define CORE_DLL_TEST_CTL	0x104
 #define CORE_DLL_STATUS		0x108
 
-#define CORE_VENDOR_SPEC	0x10c
-#define CORE_CLK_PWRSAVE	BIT(1)
+#define CORE_VENDOR_SPEC	0x10C
+#define CORE_CLK_PWRSAVE	(1 << 1)
+#define CORE_IO_PAD_PWR_SWITCH	(1 << 16)
 
-#define CORE_VENDOR_SPEC_CAPABILITIES0	0x11c
+/* 8KB descriptors */
+#define SDHCI_MSM_MAX_SEGMENTS  (1 << 13)
+#define SDHCI_MSM_MMC_CLK_GATE_DELAY	200 /* msecs */
 
-#define CDR_SELEXT_SHIFT	20
-#define CDR_SELEXT_MASK		(0xf << CDR_SELEXT_SHIFT)
-#define CMUX_SHIFT_PHASE_SHIFT	24
-#define CMUX_SHIFT_PHASE_MASK	(7 << CMUX_SHIFT_PHASE_SHIFT)
-
-struct sdhci_msm_host {
-	struct platform_device *pdev;
-	void __iomem *core_mem;	/* MSM SDCC mapped address */
-	int pwr_irq;		/* power irq */
-	struct clk *clk;	/* main SD/MMC bus clock */
-	struct clk *pclk;	/* SDHC peripheral bus clock */
-	struct clk *bus_clk;	/* SDHC bus voter clock */
-	struct mmc_host *mmc;
+static const u32 tuning_block_64[] = {
+	0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
+	0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
+	0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
+	0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
 };
 
-/* Platform specific tuning */
-static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll)
+static const u32 tuning_block_128[] = {
+	0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
+	0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
+	0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
+	0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
+	0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
+	0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
+	0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
+	0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
+};
+
+/* This structure keeps information per regulator */
+struct sdhci_msm_reg_data {
+	/* voltage regulator handle */
+	struct regulator *reg;
+	/* regulator name */
+	const char *name;
+	/* voltage level to be set */
+	u32 low_vol_level;
+	u32 high_vol_level;
+	/* Load values for low power and high power mode */
+	u32 lpm_uA;
+	u32 hpm_uA;
+
+	/* is this regulator enabled? */
+	bool is_enabled;
+	/* is this regulator needs to be always on? */
+	bool is_always_on;
+	/* is low power mode setting required for this regulator? */
+	bool lpm_sup;
+	bool set_voltage_sup;
+};
+
+/*
+ * This structure keeps information for all the
+ * regulators required for a SDCC slot.
+ */
+struct sdhci_msm_slot_reg_data {
+	/* keeps VDD/VCC regulator info */
+	struct sdhci_msm_reg_data *vdd_data;
+	 /* keeps VDD IO regulator info */
+	struct sdhci_msm_reg_data *vdd_io_data;
+};
+
+struct sdhci_msm_gpio {
+	u32 no;
+	const char *name;
+	bool is_enabled;
+};
+
+struct sdhci_msm_gpio_data {
+	struct sdhci_msm_gpio *gpio;
+	u8 size;
+};
+
+struct sdhci_msm_pin_data {
+	/*
+	 * = 1 if controller pins are using gpios
+	 * = 0 if controller has dedicated MSM pads
+	 */
+	bool cfg_sts;
+	struct sdhci_msm_gpio_data *gpio_data;
+};
+
+struct sdhci_msm_pltfm_data {
+	/* Supported UHS-I Modes */
+	u32 caps;
+
+	/* More capabilities */
+	u32 caps2;
+
+	unsigned long mmc_bus_width;
+	u32 max_clk;
+	struct sdhci_msm_slot_reg_data *vreg_data;
+	bool nonremovable;
+	struct sdhci_msm_pin_data *pin_data;
+};
+
+struct sdhci_msm_host {
+	void __iomem *core_mem;    /* MSM SDCC mapped address */
+	struct clk	 *clk;     /* main SD/MMC bus clock */
+	struct clk	 *pclk;    /* SDHC peripheral bus clock */
+	struct clk	 *bus_clk; /* SDHC bus voter clock */
+	atomic_t clks_on; /* Set if clocks are enabled */
+	struct sdhci_msm_pltfm_data *pdata;
+	struct mmc_host  *mmc;
+	struct sdhci_pltfm_data sdhci_msm_pdata;
+	wait_queue_head_t pwr_irq_wait;
+};
+
+enum vdd_io_level {
+	/* set vdd_io_data->low_vol_level */
+	VDD_IO_LOW,
+	/* set vdd_io_data->high_vol_level */
+	VDD_IO_HIGH,
+	/*
+	 * set whatever there in voltage_level (third argument) of
+	 * sdhci_msm_set_vdd_io_vol() function.
+	 */
+	VDD_IO_SET_LEVEL,
+};
+
+/* MSM platform specific tuning */
+static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host,
+						u8 poll)
 {
+	int rc = 0;
 	u32 wait_cnt = 50;
-	u8 ck_out_en;
+	u8 ck_out_en = 0;
 	struct mmc_host *mmc = host->mmc;
 
-	/* Poll for CK_OUT_EN bit.  max. poll time = 50us */
+	/* poll for CK_OUT_EN bit.  max. poll time = 50us */
 	ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
 			CORE_CK_OUT_EN);
 
 	while (ck_out_en != poll) {
 		if (--wait_cnt == 0) {
-			dev_err(mmc_dev(mmc), "%s: CK_OUT_EN bit is not %d\n",
-			       mmc_hostname(mmc), poll);
-			return -ETIMEDOUT;
+			pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
+				mmc_hostname(mmc), __func__, poll);
+			rc = -ETIMEDOUT;
+			goto out;
 		}
 		udelay(1);
 
-		ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
-				CORE_CK_OUT_EN);
+		ck_out_en = !!(readl_relaxed(host->ioaddr +
+				CORE_DLL_CONFIG) & CORE_CK_OUT_EN);
 	}
-
-	return 0;
+out:
+	return rc;
 }
 
 static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
 {
-	int rc;
-	static const u8 grey_coded_phase_table[] = {
-		0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
-		0xc, 0xd, 0xf, 0xe, 0xa, 0xb, 0x9, 0x8
-	};
+	int rc = 0;
+	u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
+					0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
+					0x8};
 	unsigned long flags;
 	u32 config;
 	struct mmc_host *mmc = host->mmc;
 
+	pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
 	spin_lock_irqsave(&host->lock, flags);
 
 	config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
@@ -131,10 +244,10 @@
 	 * Write the selected DLL clock output phase (0 ... 15)
 	 * to CDR_SELEXT bit field of DLL_CONFIG register.
 	 */
-	config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
-	config &= ~CDR_SELEXT_MASK;
-	config |= grey_coded_phase_table[phase] << CDR_SELEXT_SHIFT;
-	writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+	writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+			& ~(0xF << 20))
+			| (grey_coded_phase_table[phase] << 20)),
+			host->ioaddr + CORE_DLL_CONFIG);
 
 	/* Set CK_OUT_EN bit of DLL_CONFIG register to 1. */
 	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
@@ -152,10 +265,11 @@
 	goto out;
 
 err_out:
-	dev_err(mmc_dev(mmc), "%s: Failed to set DLL phase: %d\n",
-	       mmc_hostname(mmc), phase);
+	pr_err("%s: %s: Failed to set DLL phase: %d\n",
+		mmc_hostname(mmc), __func__, phase);
 out:
 	spin_unlock_irqrestore(&host->lock, flags);
+	pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
 	return rc;
 }
 
@@ -170,19 +284,20 @@
  */
 
 static int msm_find_most_appropriate_phase(struct sdhci_host *host,
-					   u8 *phase_table, u8 total_phases)
+				u8 *phase_table, u8 total_phases)
 {
 	int ret;
 	u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
-	u8 phases_per_row[MAX_PHASES] = { 0 };
+	u8 phases_per_row[MAX_PHASES] = {0};
 	int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
 	int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
 	bool phase_0_found = false, phase_15_found = false;
 	struct mmc_host *mmc = host->mmc;
 
+	pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
 	if (!total_phases || (total_phases > MAX_PHASES)) {
-		dev_err(mmc_dev(mmc), "%s: Invalid argument: total_phases=%d\n",
-		       mmc_hostname(mmc), total_phases);
+		pr_err("%s: %s: invalid argument: total_phases=%d\n",
+			mmc_hostname(mmc), __func__, total_phases);
 		return -EINVAL;
 	}
 
@@ -240,7 +355,7 @@
 		i = phases_15;
 		for (cnt = 0; cnt < phases_0; cnt++) {
 			ranges[phase_15_raw_index][i] =
-			    ranges[phase_0_raw_index][cnt];
+				ranges[phase_0_raw_index][cnt];
 			if (++i >= MAX_PHASES)
 				break;
 		}
@@ -256,24 +371,25 @@
 		}
 	}
 
-	i = (curr_max * 3) / 4;
+	i = ((curr_max * 3) / 4);
 	if (i)
 		i--;
 
-	ret = ranges[selected_row_index][i];
+	ret = (int)ranges[selected_row_index][i];
 
 	if (ret >= MAX_PHASES) {
 		ret = -EINVAL;
-		dev_err(mmc_dev(mmc), "%s: Invalid phase selected=%d\n",
-		       mmc_hostname(mmc), ret);
+		pr_err("%s: %s: invalid phase selected=%d\n",
+			mmc_hostname(mmc), __func__, ret);
 	}
 
+	pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
 	return ret;
 }
 
 static inline void msm_cm_dll_set_freq(struct sdhci_host *host)
 {
-	u32 mclk_freq = 0, config;
+	u32 mclk_freq = 0;
 
 	/* Program the MCLK value to MCLK_FREQ bit field */
 	if (host->clock <= 112000000)
@@ -293,28 +409,31 @@
 	else if (host->clock <= 200000000)
 		mclk_freq = 7;
 
-	config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
-	config &= ~CMUX_SHIFT_PHASE_MASK;
-	config |= mclk_freq << CMUX_SHIFT_PHASE_SHIFT;
-	writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+	writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+			& ~(7 << 24)) | (mclk_freq << 24)),
+			host->ioaddr + CORE_DLL_CONFIG);
 }
 
-/* Initialize the DLL (Programmable Delay Line) */
+/* Initialize the DLL (Programmable Delay Line ) */
 static int msm_init_cm_dll(struct sdhci_host *host)
 {
 	struct mmc_host *mmc = host->mmc;
-	int wait_cnt = 50;
+	int rc = 0;
 	unsigned long flags;
+	u32 wait_cnt;
 
+	pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
 	spin_lock_irqsave(&host->lock, flags);
 
 	/*
 	 * Make sure that clock is always enabled when DLL
 	 * tuning is in progress. Keeping PWRSAVE ON may
-	 * turn off the clock.
+	 * turn off the clock. So let's disable the PWRSAVE
+	 * here and re-enable it once tuning is completed.
 	 */
 	writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
-			& ~CORE_CLK_PWRSAVE), host->ioaddr + CORE_VENDOR_SPEC);
+			& ~CORE_CLK_PWRSAVE),
+			host->ioaddr + CORE_VENDOR_SPEC);
 
 	/* Write 1 to DLL_RST bit of DLL_CONFIG register */
 	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
@@ -341,69 +460,107 @@
 	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
 			| CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG);
 
+	wait_cnt = 50;
 	/* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */
 	while (!(readl_relaxed(host->ioaddr + CORE_DLL_STATUS) &
-		 CORE_DLL_LOCK)) {
+		CORE_DLL_LOCK)) {
 		/* max. wait for 50us sec for LOCK bit to be set */
 		if (--wait_cnt == 0) {
-			dev_err(mmc_dev(mmc), "%s: DLL failed to LOCK\n",
-			       mmc_hostname(mmc));
-			spin_unlock_irqrestore(&host->lock, flags);
-			return -ETIMEDOUT;
+			pr_err("%s: %s: DLL failed to LOCK\n",
+				mmc_hostname(mmc), __func__);
+			rc = -ETIMEDOUT;
+			goto out;
 		}
+		/* wait for 1us before polling again */
 		udelay(1);
 	}
 
+out:
+	/* re-enable PWRSAVE */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) |
+			CORE_CLK_PWRSAVE),
+			host->ioaddr + CORE_VENDOR_SPEC);
 	spin_unlock_irqrestore(&host->lock, flags);
-	return 0;
+	pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
+	return rc;
 }
 
-static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
+int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
 {
-	int tuning_seq_cnt = 3;
-	u8 phase, tuned_phases[16], tuned_phase_cnt = 0;
+	unsigned long flags;
+	u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
+	const u32 *tuning_block_pattern = tuning_block_64;
+	int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
 	int rc;
 	struct mmc_host *mmc = host->mmc;
-	struct mmc_ios ios = host->mmc->ios;
 
-	/*
-	 * Tuning is required for SDR104, HS200 and HS400 cards and
-	 * if clock frequency is greater than 100MHz in these modes.
-	 */
-	if (host->clock <= 100 * 1000 * 1000 ||
-	    !((ios.timing == MMC_TIMING_MMC_HS200) ||
-	      (ios.timing == MMC_TIMING_UHS_SDR104)))
-		return 0;
+	pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
+	/* Tuning is only required for SDR104 modes */
+	spin_lock_irqsave(&host->lock, flags);
 
-retry:
-	/* First of all reset the tuning block */
+	if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
+		(mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
+		tuning_block_pattern = tuning_block_128;
+		size = sizeof(tuning_block_128);
+	}
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	/* first of all reset the tuning block */
 	rc = msm_init_cm_dll(host);
 	if (rc)
-		return rc;
+		goto out;
+
+	data_buf = kmalloc(size, GFP_KERNEL);
+	if (!data_buf) {
+		rc = -ENOMEM;
+		goto out;
+	}
 
 	phase = 0;
 	do {
-		/* Set the phase in delay line hw block */
+		struct mmc_command cmd = {0};
+		struct mmc_data data = {0};
+		struct mmc_request mrq = {
+			.cmd = &cmd,
+			.data = &data
+		};
+		struct scatterlist sg;
+
+		/* set the phase in delay line hw block */
 		rc = msm_config_cm_dll_phase(host, phase);
 		if (rc)
-			return rc;
+			goto kfree;
 
-		rc = mmc_send_tuning(mmc, opcode, NULL);
-		if (!rc) {
-			/* Tuning is successful at this tuning point */
+		cmd.opcode = opcode;
+		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+		data.blksz = size;
+		data.blocks = 1;
+		data.flags = MMC_DATA_READ;
+		data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
+
+		data.sg = &sg;
+		data.sg_len = 1;
+		sg_init_one(&sg, data_buf, size);
+		memset(data_buf, 0, size);
+		mmc_wait_for_req(mmc, &mrq);
+
+		if (!cmd.error && !data.error &&
+			!memcmp(data_buf, tuning_block_pattern, size)) {
+			/* tuning is successful at this tuning point */
 			tuned_phases[tuned_phase_cnt++] = phase;
-			dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
-				 mmc_hostname(mmc), phase);
+			pr_debug("%s: %s: found good phase = %d\n",
+				mmc_hostname(mmc), __func__, phase);
 		}
-	} while (++phase < ARRAY_SIZE(tuned_phases));
+	} while (++phase < 16);
 
 	if (tuned_phase_cnt) {
 		rc = msm_find_most_appropriate_phase(host, tuned_phases,
-						     tuned_phase_cnt);
+							tuned_phase_cnt);
 		if (rc < 0)
-			return rc;
+			goto kfree;
 		else
-			phase = rc;
+			phase = (u8)rc;
 
 		/*
 		 * Finally set the selected phase in delay
@@ -411,121 +568,737 @@
 		 */
 		rc = msm_config_cm_dll_phase(host, phase);
 		if (rc)
-			return rc;
-		dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
-			 mmc_hostname(mmc), phase);
+			goto kfree;
+		pr_debug("%s: %s: finally setting the tuning phase to %d\n",
+				mmc_hostname(mmc), __func__, phase);
 	} else {
-		if (--tuning_seq_cnt)
-			goto retry;
-		/* Tuning failed */
-		dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n",
-		       mmc_hostname(mmc));
-		rc = -EIO;
+		/* tuning failed */
+		pr_err("%s: %s: no tuning point found\n",
+			mmc_hostname(mmc), __func__);
+		rc = -EAGAIN;
 	}
 
+kfree:
+	kfree(data_buf);
+out:
+	pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
 	return rc;
 }
 
-static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
-					unsigned int uhs)
+static int sdhci_msm_setup_gpio(struct sdhci_msm_pltfm_data *pdata, bool enable)
 {
-	struct mmc_host *mmc = host->mmc;
-	u16 ctrl_2;
+	struct sdhci_msm_gpio_data *curr;
+	int i, ret = 0;
 
-	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-	/* Select Bus Speed Mode for host */
-	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
-	switch (uhs) {
-	case MMC_TIMING_UHS_SDR12:
-		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
-		break;
-	case MMC_TIMING_UHS_SDR25:
-		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
-		break;
-	case MMC_TIMING_UHS_SDR50:
-		ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
-		break;
-	case MMC_TIMING_MMC_HS200:
-	case MMC_TIMING_UHS_SDR104:
-		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
-		break;
-	case MMC_TIMING_UHS_DDR50:
-	case MMC_TIMING_MMC_DDR52:
-		ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
-		break;
+	curr = pdata->pin_data->gpio_data;
+	for (i = 0; i < curr->size; i++) {
+		if (!gpio_is_valid(curr->gpio[i].no)) {
+			ret = -EINVAL;
+			pr_err("%s: Invalid gpio = %d\n", __func__,
+					curr->gpio[i].no);
+			goto free_gpios;
+		}
+		if (enable) {
+			ret = gpio_request(curr->gpio[i].no,
+						curr->gpio[i].name);
+			if (ret) {
+				pr_err("%s: gpio_request(%d, %s) failed %d\n",
+					__func__, curr->gpio[i].no,
+					curr->gpio[i].name, ret);
+				goto free_gpios;
+			}
+			curr->gpio[i].is_enabled = true;
+		} else {
+			gpio_free(curr->gpio[i].no);
+			curr->gpio[i].is_enabled = false;
+		}
 	}
+	return ret;
 
-	/*
-	 * When clock frequency is less than 100MHz, the feedback clock must be
-	 * provided and DLL must not be used so that tuning can be skipped. To
-	 * provide feedback clock, the mode selection can be any value less
-	 * than 3'b011 in bits [2:0] of HOST CONTROL2 register.
-	 */
-	if (host->clock <= 100000000 &&
-	    (uhs == MMC_TIMING_MMC_HS400 ||
-	     uhs == MMC_TIMING_MMC_HS200 ||
-	     uhs == MMC_TIMING_UHS_SDR104))
-		ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
-
-	dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n",
-		mmc_hostname(host->mmc), host->clock, uhs, ctrl_2);
-	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+free_gpios:
+	for (i--; i >= 0; i--) {
+		gpio_free(curr->gpio[i].no);
+		curr->gpio[i].is_enabled = false;
+	}
+	return ret;
 }
 
-static void sdhci_msm_voltage_switch(struct sdhci_host *host)
+static int sdhci_msm_setup_pins(struct sdhci_msm_pltfm_data *pdata, bool enable)
 {
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
-	u32 irq_status, irq_ack = 0;
+	int ret = 0;
 
-	irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
-	irq_status &= INT_MASK;
+	if (!pdata->pin_data || (pdata->pin_data->cfg_sts == enable))
+		return 0;
 
-	writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR);
+	ret = sdhci_msm_setup_gpio(pdata, enable);
+	if (!ret)
+		pdata->pin_data->cfg_sts = enable;
 
-	if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
-		irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
-	if (irq_status & (CORE_PWRCTL_IO_LOW | CORE_PWRCTL_IO_HIGH))
-		irq_ack |= CORE_PWRCTL_IO_SUCCESS;
+	return ret;
+}
+
+#define MAX_PROP_SIZE 32
+static int sdhci_msm_dt_parse_vreg_info(struct device *dev,
+		struct sdhci_msm_reg_data **vreg_data, const char *vreg_name)
+{
+	int len, ret = 0;
+	const __be32 *prop;
+	char prop_name[MAX_PROP_SIZE];
+	struct sdhci_msm_reg_data *vreg;
+	struct device_node *np = dev->of_node;
+
+	snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
+	if (!of_parse_phandle(np, prop_name, 0)) {
+		dev_err(dev, "No vreg data found for %s\n", vreg_name);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+	if (!vreg) {
+		dev_err(dev, "No memory for vreg: %s\n", vreg_name);
+		ret = -ENOMEM;
+		return ret;
+	}
+
+	vreg->name = vreg_name;
+
+	snprintf(prop_name, MAX_PROP_SIZE,
+			"qcom,%s-always-on", vreg_name);
+	if (of_get_property(np, prop_name, NULL))
+		vreg->is_always_on = true;
+
+	snprintf(prop_name, MAX_PROP_SIZE,
+			"qcom,%s-lpm-sup", vreg_name);
+	if (of_get_property(np, prop_name, NULL))
+		vreg->lpm_sup = true;
+
+	snprintf(prop_name, MAX_PROP_SIZE,
+			"qcom,%s-voltage-level", vreg_name);
+	prop = of_get_property(np, prop_name, &len);
+	if (!prop || (len != (2 * sizeof(__be32)))) {
+		dev_warn(dev, "%s %s property\n",
+			prop ? "invalid format" : "no", prop_name);
+	} else {
+		vreg->low_vol_level = be32_to_cpup(&prop[0]);
+		vreg->high_vol_level = be32_to_cpup(&prop[1]);
+	}
+
+	snprintf(prop_name, MAX_PROP_SIZE,
+			"qcom,%s-current-level", vreg_name);
+	prop = of_get_property(np, prop_name, &len);
+	if (!prop || (len != (2 * sizeof(__be32)))) {
+		dev_warn(dev, "%s %s property\n",
+			prop ? "invalid format" : "no", prop_name);
+	} else {
+		vreg->lpm_uA = be32_to_cpup(&prop[0]);
+		vreg->hpm_uA = be32_to_cpup(&prop[1]);
+	}
+
+	*vreg_data = vreg;
+	dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
+		vreg->name, vreg->is_always_on ? "always_on," : "",
+		vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
+		vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
+
+	return ret;
+}
+
+#define GPIO_NAME_MAX_LEN 32
+static int sdhci_msm_dt_parse_gpio_info(struct device *dev,
+		struct sdhci_msm_pltfm_data *pdata)
+{
+	int ret = 0, cnt, i;
+	struct sdhci_msm_pin_data *pin_data;
+	struct device_node *np = dev->of_node;
+
+	pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
+	if (!pin_data) {
+		dev_err(dev, "No memory for pin_data\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cnt = of_gpio_count(np);
+	if (cnt > 0) {
+		pin_data->gpio_data = devm_kzalloc(dev,
+				sizeof(struct sdhci_msm_gpio_data), GFP_KERNEL);
+		if (!pin_data->gpio_data) {
+			dev_err(dev, "No memory for gpio_data\n");
+			ret = -ENOMEM;
+			goto out;
+		}
+		pin_data->gpio_data->size = cnt;
+		pin_data->gpio_data->gpio = devm_kzalloc(dev, cnt *
+				sizeof(struct sdhci_msm_gpio), GFP_KERNEL);
+
+		if (!pin_data->gpio_data->gpio) {
+			dev_err(dev, "No memory for gpio\n");
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		for (i = 0; i < cnt; i++) {
+			const char *name = NULL;
+			char result[GPIO_NAME_MAX_LEN];
+			pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
+			of_property_read_string_index(np,
+					"qcom,gpio-names", i, &name);
+
+			snprintf(result, GPIO_NAME_MAX_LEN, "%s-%s",
+					dev_name(dev), name ? name : "?");
+			pin_data->gpio_data->gpio[i].name = result;
+			dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
+					pin_data->gpio_data->gpio[i].name,
+					pin_data->gpio_data->gpio[i].no);
+			pdata->pin_data = pin_data;
+		}
+	}
+
+out:
+	if (ret)
+		dev_err(dev, "%s failed with err %d\n", __func__, ret);
+	return ret;
+}
+
+/* Parse platform data */
+static struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev)
+{
+	struct sdhci_msm_pltfm_data *pdata = NULL;
+	struct device_node *np = dev->of_node;
+	u32 bus_width = 0;
+	int len, i;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(dev, "failed to allocate memory for platform data\n");
+		goto out;
+	}
+
+	of_property_read_u32(np, "qcom,bus-width", &bus_width);
+	if (bus_width == 8)
+		pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
+	else if (bus_width == 4)
+		pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
+	else {
+		dev_notice(dev, "invalid bus-width, default to 1-bit mode\n");
+		pdata->mmc_bus_width = 0;
+	}
+
+	pdata->vreg_data = devm_kzalloc(dev, sizeof(struct
+						    sdhci_msm_slot_reg_data),
+					GFP_KERNEL);
+	if (!pdata->vreg_data) {
+		dev_err(dev, "failed to allocate memory for vreg data\n");
+		goto out;
+	}
+
+	if (sdhci_msm_dt_parse_vreg_info(dev, &pdata->vreg_data->vdd_data,
+					 "vdd")) {
+		dev_err(dev, "failed parsing vdd data\n");
+		goto out;
+	}
+	if (sdhci_msm_dt_parse_vreg_info(dev,
+					 &pdata->vreg_data->vdd_io_data,
+					 "vdd-io")) {
+		dev_err(dev, "failed parsing vdd-io data\n");
+		goto out;
+	}
+
+	if (sdhci_msm_dt_parse_gpio_info(dev, pdata)) {
+		dev_err(dev, "failed parsing gpio data\n");
+		goto out;
+	}
+
+	of_property_read_u32(np, "qcom,max-clk-rate", &pdata->max_clk);
+
+	len = of_property_count_strings(np, "qcom,bus-speed-mode");
+
+	for (i = 0; i < len; i++) {
+		const char *name = NULL;
+
+		of_property_read_string_index(np,
+			"qcom,bus-speed-mode", i, &name);
+		if (!name)
+			continue;
+
+		if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
+			pdata->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
+		else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
+			pdata->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
+		else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
+			pdata->caps |= MMC_CAP_1_8V_DDR
+						| MMC_CAP_UHS_DDR50;
+		else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
+			pdata->caps |= MMC_CAP_1_2V_DDR
+						| MMC_CAP_UHS_DDR50;
+	}
+
+	if (of_get_property(np, "qcom,nonremovable", NULL))
+		pdata->nonremovable = true;
+
+	return pdata;
+out:
+	return NULL;
+}
+
+/* Regulator utility functions */
+static int sdhci_msm_vreg_init_reg(struct device *dev,
+					struct sdhci_msm_reg_data *vreg)
+{
+	int ret = 0;
+
+	/* check if regulator is already initialized? */
+	if (vreg->reg)
+		goto out;
+
+	/* Get the regulator handle */
+	vreg->reg = devm_regulator_get(dev, vreg->name);
+	if (IS_ERR(vreg->reg)) {
+		ret = PTR_ERR(vreg->reg);
+		pr_err("%s: devm_regulator_get(%s) failed. ret=%d\n",
+			__func__, vreg->name, ret);
+		goto out;
+	}
+
+	/* sanity check */
+	if (!vreg->high_vol_level || !vreg->hpm_uA) {
+		pr_err("%s: %s invalid constraints specified\n",
+		       __func__, vreg->name);
+		ret = -EINVAL;
+	}
+
+out:
+	return ret;
+}
+
+static void sdhci_msm_vreg_deinit_reg(struct sdhci_msm_reg_data *vreg)
+{
+	if (vreg->reg)
+		devm_regulator_put(vreg->reg);
+}
+
+static int sdhci_msm_vreg_set_optimum_mode(struct sdhci_msm_reg_data
+						  *vreg, int uA_load)
+{
+	int ret = 0;
+	
+	/*
+	 * regulators that do not support regulator_set_voltage also
+	 * do not support regulator_set_optimum_mode
+	 */
+	if (vreg->set_voltage_sup) {
+		ret = regulator_set_load(vreg->reg, uA_load);
+		if (ret < 0)
+			pr_err("%s: regulator_set_load(reg=%s,uA_load=%d) failed. ret=%d\n",
+			       __func__, vreg->name, uA_load, ret);
+		else
+			/*
+			 * regulator_set_load() can return non zero
+			 * value even for success case.
+			 */
+			ret = 0;
+	}
+	return ret;
+}
+
+static int sdhci_msm_vreg_set_voltage(struct sdhci_msm_reg_data *vreg,
+					int min_uV, int max_uV)
+{
+	int ret = 0;
+
+	ret = regulator_set_voltage(vreg->reg, min_uV, max_uV);
+	if (ret) {
+		pr_err("%s: regulator_set_voltage(%s)failed. min_uV=%d,max_uV=%d,ret=%d\n",
+			       __func__, vreg->name, min_uV, max_uV, ret);
+		}
+
+	return ret;
+}
+
+static int sdhci_msm_vreg_enable(struct sdhci_msm_reg_data *vreg)
+{
+	int ret = 0;
+
+	/* Put regulator in HPM (high power mode) */
+	ret = sdhci_msm_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
+	if (ret < 0)
+		return ret;
+
+	if (!vreg->is_enabled) {
+		/* Set voltage level */
+		ret = sdhci_msm_vreg_set_voltage(vreg, vreg->high_vol_level,
+						vreg->high_vol_level);
+		if (ret)
+			return ret;
+	}
+	ret = regulator_enable(vreg->reg);
+	if (ret) {
+		pr_err("%s: regulator_enable(%s) failed. ret=%d\n",
+				__func__, vreg->name, ret);
+		return ret;
+	}
+	vreg->is_enabled = true;
+	return ret;
+}
+
+static int sdhci_msm_vreg_disable(struct sdhci_msm_reg_data *vreg)
+{
+	int ret = 0;
+
+	/* Never disable regulator marked as always_on */
+	if (vreg->is_enabled && !vreg->is_always_on) {
+		ret = regulator_disable(vreg->reg);
+		if (ret) {
+			pr_err("%s: regulator_disable(%s) failed. ret=%d\n",
+				__func__, vreg->name, ret);
+			goto out;
+		}
+		vreg->is_enabled = false;
+
+		ret = sdhci_msm_vreg_set_optimum_mode(vreg, 0);
+		if (ret < 0)
+			goto out;
+
+		/* Set min. voltage level to 0 */
+		ret = sdhci_msm_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
+		if (ret)
+			goto out;
+	} else if (vreg->is_enabled && vreg->is_always_on) {
+		if (vreg->lpm_sup) {
+			/* Put always_on regulator in LPM (low power mode) */
+			ret = sdhci_msm_vreg_set_optimum_mode(vreg,
+							      vreg->lpm_uA);
+			if (ret < 0)
+				goto out;
+		}
+	}
+out:
+	return ret;
+}
+
+static int sdhci_msm_setup_vreg(struct sdhci_msm_pltfm_data *pdata,
+			bool enable, bool is_init)
+{
+	int ret = 0, i;
+	struct sdhci_msm_slot_reg_data *curr_slot;
+	struct sdhci_msm_reg_data *vreg_table[2];
+
+	curr_slot = pdata->vreg_data;
+	if (!curr_slot) {
+		pr_debug("%s: vreg info unavailable,assuming the slot is powered by always on domain\n",
+			 __func__);
+		goto out;
+	}
+
+	vreg_table[0] = curr_slot->vdd_data;
+	vreg_table[1] = curr_slot->vdd_io_data;
+
+	for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
+		if (vreg_table[i]) {
+			if (enable)
+				ret = sdhci_msm_vreg_enable(vreg_table[i]);
+			else
+				ret = sdhci_msm_vreg_disable(vreg_table[i]);
+			if (ret)
+				goto out;
+		}
+	}
+out:
+	return ret;
+}
+
+/*
+ * Reset vreg by ensuring it is off during probe. A call
+ * to enable vreg is needed to balance disable vreg
+ */
+static int sdhci_msm_vreg_reset(struct sdhci_msm_pltfm_data *pdata)
+{
+	int ret;
+
+	ret = sdhci_msm_setup_vreg(pdata, 1, true);
+	if (ret)
+		return ret;
+	ret = sdhci_msm_setup_vreg(pdata, 0, true);
+	return ret;
+}
+
+/* This init function should be called only once for each SDHC slot */
+static int sdhci_msm_vreg_init(struct device *dev,
+				struct sdhci_msm_pltfm_data *pdata,
+				bool is_init)
+{
+	int ret = 0;
+	struct sdhci_msm_slot_reg_data *curr_slot;
+	struct sdhci_msm_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
+
+	curr_slot = pdata->vreg_data;
+	if (!curr_slot)
+		goto out;
+
+	curr_vdd_reg = curr_slot->vdd_data;
+	curr_vdd_io_reg = curr_slot->vdd_io_data;
+
+	if (!is_init)
+		/* Deregister all regulators from regulator framework */
+		goto vdd_io_reg_deinit;
 
 	/*
-	 * The driver has to acknowledge the interrupt, switch voltages and
-	 * report back if it succeded or not to this register. The voltage
-	 * switches are handled by the sdhci core, so just report success.
+	 * Get the regulator handle from voltage regulator framework
+	 * and then try to set the voltage level for the regulator
 	 */
-	writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
+	if (curr_vdd_reg) {
+		ret = sdhci_msm_vreg_init_reg(dev, curr_vdd_reg);
+		if (ret)
+			goto out;
+	}
+	if (curr_vdd_io_reg) {
+		ret = sdhci_msm_vreg_init_reg(dev, curr_vdd_io_reg);
+		if (ret)
+			goto vdd_reg_deinit;
+	}
+	ret = sdhci_msm_vreg_reset(pdata);
+	if (ret)
+		dev_err(dev, "vreg reset failed (%d)\n", ret);
+	goto out;
+
+vdd_io_reg_deinit:
+	if (curr_vdd_io_reg)
+		sdhci_msm_vreg_deinit_reg(curr_vdd_io_reg);
+vdd_reg_deinit:
+	if (curr_vdd_reg)
+		sdhci_msm_vreg_deinit_reg(curr_vdd_reg);
+out:
+	return ret;
+}
+
+
+static int sdhci_msm_set_vdd_io_vol(struct sdhci_msm_pltfm_data *pdata,
+			enum vdd_io_level level,
+			unsigned int voltage_level)
+{
+	int ret = 0;
+	int set_level;
+	struct sdhci_msm_reg_data *vdd_io_reg;
+
+	if (!pdata->vreg_data)
+		return ret;
+
+	vdd_io_reg = pdata->vreg_data->vdd_io_data;
+	if (vdd_io_reg && vdd_io_reg->is_enabled) {
+		switch (level) {
+		case VDD_IO_LOW:
+			set_level = vdd_io_reg->low_vol_level;
+			break;
+		case VDD_IO_HIGH:
+			set_level = vdd_io_reg->high_vol_level;
+			break;
+		case VDD_IO_SET_LEVEL:
+			set_level = voltage_level;
+			break;
+		default:
+			pr_err("%s: invalid argument level = %d",
+					__func__, level);
+			ret = -EINVAL;
+			return ret;
+		}
+		ret = sdhci_msm_vreg_set_voltage(vdd_io_reg, set_level,
+				set_level);
+	}
+	return ret;
 }
 
 static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
 {
 	struct sdhci_host *host = (struct sdhci_host *)data;
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	u8 irq_status = 0;
+	u8 irq_ack = 0;
+	int ret = 0;
 
-	sdhci_msm_voltage_switch(host);
+	irq_status = readb_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
+	pr_debug("%s: Received IRQ(%d), status=0x%x\n",
+		mmc_hostname(msm_host->mmc), irq, irq_status);
 
+	/* Clear the interrupt */
+	writeb_relaxed(irq_status, (msm_host->core_mem + CORE_PWRCTL_CLEAR));
+	/*
+	 * SDHC has core_mem and hc_mem device memory and these memory
+	 * addresses do not fall within 1KB region. Hence, any update to
+	 * core_mem address space would require an mb() to ensure this gets
+	 * completed before its next update to registers within hc_mem.
+	 */
+	mb();
+
+	/* Handle BUS ON/OFF*/
+	if (irq_status & CORE_PWRCTL_BUS_ON) {
+		ret = sdhci_msm_setup_vreg(msm_host->pdata, true, false);
+		if (!ret)
+			ret = sdhci_msm_setup_pins(msm_host->pdata, true);
+		if (ret)
+			irq_ack |= CORE_PWRCTL_BUS_FAIL;
+		else
+			irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
+	}
+	if (irq_status & CORE_PWRCTL_BUS_OFF) {
+		ret = sdhci_msm_setup_vreg(msm_host->pdata, false, false);
+		if (!ret)
+			ret = sdhci_msm_setup_pins(msm_host->pdata, false);
+		if (ret)
+			irq_ack |= CORE_PWRCTL_BUS_FAIL;
+		else
+			irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
+	}
+	/* Handle IO LOW/HIGH */
+	if (irq_status & CORE_PWRCTL_IO_LOW) {
+		/* Switch voltage Low */
+		ret = sdhci_msm_set_vdd_io_vol(msm_host->pdata, VDD_IO_LOW, 0);
+		if (ret)
+			irq_ack |= CORE_PWRCTL_IO_FAIL;
+		else
+			irq_ack |= CORE_PWRCTL_IO_SUCCESS;
+	}
+	if (irq_status & CORE_PWRCTL_IO_HIGH) {
+		/* Switch voltage High */
+		ret = sdhci_msm_set_vdd_io_vol(msm_host->pdata, VDD_IO_HIGH, 0);
+		if (ret)
+			irq_ack |= CORE_PWRCTL_IO_FAIL;
+		else
+			irq_ack |= CORE_PWRCTL_IO_SUCCESS;
+	}
+
+	/* ACK status to the core */
+	writeb_relaxed(irq_ack, (msm_host->core_mem + CORE_PWRCTL_CTL));
+	/*
+	 * SDHC has core_mem and hc_mem device memory and these memory
+	 * addresses do not fall within 1KB region. Hence, any update to
+	 * core_mem address space would require an mb() to ensure this gets
+	 * completed before its next update to registers within hc_mem.
+	 */
+	mb();
+
+	if (irq_status & CORE_PWRCTL_IO_HIGH)
+		writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) &
+				~CORE_IO_PAD_PWR_SWITCH),
+				host->ioaddr + CORE_VENDOR_SPEC);
+	if (irq_status & CORE_PWRCTL_IO_LOW)
+		writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) |
+				CORE_IO_PAD_PWR_SWITCH),
+				host->ioaddr + CORE_VENDOR_SPEC);
+	mb();
+
+	pr_debug("%s: Handled IRQ(%d), ret=%d, ack=0x%x\n",
+		mmc_hostname(msm_host->mmc), irq, ret, irq_ack);
+	wake_up_interruptible(&msm_host->pwr_irq_wait);
 	return IRQ_HANDLED;
 }
 
-static const struct of_device_id sdhci_msm_dt_match[] = {
-	{ .compatible = "qcom,sdhci-msm-v4" },
-	{},
-};
+static void sdhci_msm_check_power_status(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	int ret = 0;
 
-MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
+	pr_debug("%s: %s: power status before waiting 0x%x\n",
+		mmc_hostname(host->mmc), __func__,
+		readb_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL));
 
-static const struct sdhci_ops sdhci_msm_ops = {
+	ret = wait_event_interruptible(msm_host->pwr_irq_wait,
+				       (readb_relaxed(msm_host->core_mem +
+						      CORE_PWRCTL_CTL)) != 0x0);
+	if (ret)
+		pr_warning("%s: %s: returned due to error %d\n",
+				mmc_hostname(host->mmc), __func__, ret);
+	pr_debug("%s: %s: ret %d power status after handling power IRQ 0x%x\n",
+		mmc_hostname(host->mmc), __func__, ret,
+		readb_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL));
+}
+
+static void sdhci_msm_toggle_cdr(struct sdhci_host *host, bool enable)
+{
+	if (enable)
+		writel_relaxed((readl_relaxed(host->ioaddr +
+					      CORE_DLL_CONFIG) | CORE_CDR_EN),
+			       host->ioaddr + CORE_DLL_CONFIG);
+	else
+		writel_relaxed((readl_relaxed(host->ioaddr +
+					      CORE_DLL_CONFIG) & ~CORE_CDR_EN),
+			       host->ioaddr + CORE_DLL_CONFIG);
+}
+
+static unsigned int sdhci_msm_max_segs(void)
+{
+	return SDHCI_MSM_MAX_SEGMENTS;
+}
+
+void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+	int rc;
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	unsigned long flags;
+
+	if (clock && !atomic_read(&msm_host->clks_on)) {
+		pr_debug("%s: request to enable clock at rate %u\n",
+				mmc_hostname(host->mmc), clock);
+		if (!IS_ERR_OR_NULL(msm_host->bus_clk)) {
+			rc = clk_prepare_enable(msm_host->bus_clk);
+			if (rc) {
+				pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
+					mmc_hostname(host->mmc), __func__, rc);
+				goto out;
+			}
+		}
+		if (!IS_ERR(msm_host->pclk)) {
+			rc = clk_prepare_enable(msm_host->pclk);
+			if (rc) {
+				pr_err("%s: %s: failed to enable the pclk with error %d\n",
+					mmc_hostname(host->mmc), __func__, rc);
+				goto disable_bus_clk;
+			}
+		}
+		rc = clk_prepare_enable(msm_host->clk);
+		if (rc) {
+			pr_err("%s: %s: failed to enable the host-clk with error %d\n",
+				mmc_hostname(host->mmc), __func__, rc);
+			goto disable_pclk;
+		}
+		mb();
+		atomic_set(&msm_host->clks_on, 1);
+
+	} else if (!clock && atomic_read(&msm_host->clks_on)) {
+		pr_debug("%s: request to disable clocks\n",
+				mmc_hostname(host->mmc));
+		sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+		mb();
+		clk_disable_unprepare(msm_host->clk);
+		if (!IS_ERR(msm_host->pclk))
+			clk_disable_unprepare(msm_host->pclk);
+		if (!IS_ERR_OR_NULL(msm_host->bus_clk))
+			clk_disable_unprepare(msm_host->bus_clk);
+		atomic_set(&msm_host->clks_on, 0);
+	}
+	spin_lock_irqsave(&host->lock, flags);
+	host->clock = clock;
+	spin_unlock_irqrestore(&host->lock, flags);
+	goto out;
+disable_pclk:
+	if (!IS_ERR_OR_NULL(msm_host->pclk))
+		clk_disable_unprepare(msm_host->pclk);
+disable_bus_clk:
+	if (!IS_ERR_OR_NULL(msm_host->bus_clk))
+		clk_disable_unprepare(msm_host->bus_clk);
+out:
+	return;
+}
+
+static struct sdhci_ops sdhci_msm_ops = {
+	.check_power_status = sdhci_msm_check_power_status,
 	.platform_execute_tuning = sdhci_msm_execute_tuning,
-	.reset = sdhci_reset,
-	.set_clock = sdhci_set_clock,
-	.set_bus_width = sdhci_set_bus_width,
-	.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
-	.voltage_switch = sdhci_msm_voltage_switch,
-};
-
-static const struct sdhci_pltfm_data sdhci_msm_pdata = {
-	.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
-		  SDHCI_QUIRK_NO_CARD_NO_RESET |
-		  SDHCI_QUIRK_SINGLE_POWER_WRITE,
-	.ops = &sdhci_msm_ops,
+	.toggle_cdr = sdhci_msm_toggle_cdr,
+	.get_max_segments = sdhci_msm_max_segs,
+	.set_clock = sdhci_msm_set_clock,
 };
 
 static int sdhci_msm_probe(struct platform_device *pdev)
@@ -533,30 +1306,47 @@
 	struct sdhci_host *host;
 	struct sdhci_pltfm_host *pltfm_host;
 	struct sdhci_msm_host *msm_host;
-	struct resource *core_memres;
-	int ret;
-	u16 host_version, core_minor;
-	u32 core_version, caps;
-	u8 core_major;
+	struct resource *core_memres = NULL;
+	int ret = 0, pwr_irq = 0, dead = 0;
+	u32 host_version;
 
-	host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, sizeof(*msm_host));
-	if (IS_ERR(host))
-		return PTR_ERR(host);
+	pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
+	msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
+				GFP_KERNEL);
+	if (!msm_host) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	init_waitqueue_head(&msm_host->pwr_irq_wait);
+
+	msm_host->sdhci_msm_pdata.ops = &sdhci_msm_ops;
+	host = sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata, 0);
+	if (IS_ERR(host)) {
+		ret = PTR_ERR(host);
+		goto out;
+	}
 
 	pltfm_host = sdhci_priv(host);
-	msm_host = sdhci_pltfm_priv(pltfm_host);
+	pltfm_host->priv = msm_host;
 	msm_host->mmc = host->mmc;
-	msm_host->pdev = pdev;
 
-	ret = mmc_of_parse(host->mmc);
-	if (ret)
+	/* Extract platform data */
+	if (pdev->dev.of_node) {
+		msm_host->pdata = sdhci_msm_populate_pdata(&pdev->dev);
+		if (!msm_host->pdata) {
+			dev_err(&pdev->dev, "DT parsing error\n");
+			goto pltfm_free;
+		}
+	} else {
+		dev_err(&pdev->dev, "No device tree node\n");
 		goto pltfm_free;
+	}
 
-	sdhci_get_of_property(pdev);
+	/* Setup Clocks */
 
 	/* Setup SDCC bus voter clock. */
-	msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus");
-	if (!IS_ERR(msm_host->bus_clk)) {
+	msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
+	if (!IS_ERR_OR_NULL(msm_host->bus_clk)) {
 		/* Vote for max. clk rate for max. performance */
 		ret = clk_set_rate(msm_host->bus_clk, INT_MAX);
 		if (ret)
@@ -567,113 +1357,146 @@
 	}
 
 	/* Setup main peripheral bus clock */
-	msm_host->pclk = devm_clk_get(&pdev->dev, "iface");
-	if (IS_ERR(msm_host->pclk)) {
-		ret = PTR_ERR(msm_host->pclk);
-		dev_err(&pdev->dev, "Peripheral clk setup failed (%d)\n", ret);
-		goto bus_clk_disable;
+	msm_host->pclk = devm_clk_get(&pdev->dev, "iface_clk");
+	if (!IS_ERR(msm_host->pclk)) {
+		ret = clk_prepare_enable(msm_host->pclk);
+		if (ret)
+			goto bus_clk_disable;
 	}
 
-	ret = clk_prepare_enable(msm_host->pclk);
-	if (ret)
-		goto bus_clk_disable;
-
 	/* Setup SDC MMC clock */
-	msm_host->clk = devm_clk_get(&pdev->dev, "core");
+	msm_host->clk = devm_clk_get(&pdev->dev, "core_clk");
 	if (IS_ERR(msm_host->clk)) {
 		ret = PTR_ERR(msm_host->clk);
-		dev_err(&pdev->dev, "SDC MMC clk setup failed (%d)\n", ret);
 		goto pclk_disable;
 	}
 
-	/* Vote for maximum clock rate for maximum performance */
-	ret = clk_set_rate(msm_host->clk, INT_MAX);
-	if (ret)
-		dev_warn(&pdev->dev, "core clock boost failed\n");
-
 	ret = clk_prepare_enable(msm_host->clk);
 	if (ret)
 		goto pclk_disable;
 
-	core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	msm_host->core_mem = devm_ioremap_resource(&pdev->dev, core_memres);
-
-	if (IS_ERR(msm_host->core_mem)) {
-		dev_err(&pdev->dev, "Failed to remap registers\n");
-		ret = PTR_ERR(msm_host->core_mem);
+	atomic_set(&msm_host->clks_on, 1);
+	/* Setup regulators */
+	ret = sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, true);
+	if (ret) {
+		dev_err(&pdev->dev, "Regulator setup failed (%d)\n", ret);
 		goto clk_disable;
 	}
 
 	/* Reset the core and Enable SDHC mode */
-	writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_POWER) |
-		       CORE_SW_RST, msm_host->core_mem + CORE_POWER);
+	core_memres = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "core_mem");
+	msm_host->core_mem = devm_ioremap(&pdev->dev, core_memres->start,
+					resource_size(core_memres));
 
-	/* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */
-	usleep_range(1000, 5000);
-	if (readl(msm_host->core_mem + CORE_POWER) & CORE_SW_RST) {
-		dev_err(&pdev->dev, "Stuck in reset\n");
-		ret = -ETIMEDOUT;
-		goto clk_disable;
+	if (!msm_host->core_mem) {
+		dev_err(&pdev->dev, "Failed to remap registers\n");
+		ret = -ENOMEM;
+		goto vreg_deinit;
 	}
 
+	/* Set SW_RST bit in POWER register (Offset 0x0) */
+	writel_relaxed(CORE_SW_RST, msm_host->core_mem + CORE_POWER);
 	/* Set HC_MODE_EN bit in HC_MODE register */
 	writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
 
-	host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
+	/*
+	 * Following are the deviations from SDHC spec v3.0 -
+	 * 1. Card detection is handled using separate GPIO.
+	 * 2. Bus power control is handled by interacting with PMIC.
+	 */
+	host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+	host->quirks |= SDHCI_QUIRK_SINGLE_POWER_WRITE;
+
+	host_version = readl_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
 	dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n",
 		host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
-			       SDHCI_VENDOR_VER_SHIFT));
-
-	core_version = readl_relaxed(msm_host->core_mem + CORE_MCI_VERSION);
-	core_major = (core_version & CORE_VERSION_MAJOR_MASK) >>
-		      CORE_VERSION_MAJOR_SHIFT;
-	core_minor = core_version & CORE_VERSION_MINOR_MASK;
-	dev_dbg(&pdev->dev, "MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n",
-		core_version, core_major, core_minor);
-
-	/*
-	 * Support for some capabilities is not advertised by newer
-	 * controller versions and must be explicitly enabled.
-	 */
-	if (core_major >= 1 && core_minor != 0x11 && core_minor != 0x12) {
-		caps = readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES);
-		caps |= SDHCI_CAN_VDD_300 | SDHCI_CAN_DO_8BIT;
-		writel_relaxed(caps, host->ioaddr +
-			       CORE_VENDOR_SPEC_CAPABILITIES0);
+		  SDHCI_VENDOR_VER_SHIFT));
+	if (((host_version & SDHCI_VENDOR_VER_MASK) >>
+		SDHCI_VENDOR_VER_SHIFT) == SDHCI_VER_100) {
+		/*
+		 * Add 40us delay in interrupt handler when
+		 * operating at initialization frequency(400KHz).
+		 */
+		host->quirks2 |= SDHCI_QUIRK2_SLOW_INT_CLR;
+		/*
+		 * Set Software Reset for DAT line in Software
+		 * Reset Register (Bit 2).
+		 */
+		host->quirks2 |= SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT;
 	}
 
-	/* Setup IRQ for handling power/voltage tasks with PMIC */
-	msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
-	if (msm_host->pwr_irq < 0) {
-		dev_err(&pdev->dev, "Get pwr_irq failed (%d)\n",
-			msm_host->pwr_irq);
-		ret = msm_host->pwr_irq;
-		goto clk_disable;
+	/* Setup PWRCTL irq */
+	pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
+	if (pwr_irq < 0) {
+		dev_err(&pdev->dev, "Failed to get pwr_irq by name (%d)\n",
+				pwr_irq);
+		goto vreg_deinit;
 	}
-
-	ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
+	ret = devm_request_threaded_irq(&pdev->dev, pwr_irq, NULL,
 					sdhci_msm_pwr_irq, IRQF_ONESHOT,
 					dev_name(&pdev->dev), host);
 	if (ret) {
-		dev_err(&pdev->dev, "Request IRQ failed (%d)\n", ret);
-		goto clk_disable;
+		dev_err(&pdev->dev, "Request threaded irq(%d) failed (%d)\n",
+				pwr_irq, ret);
+		goto vreg_deinit;
 	}
 
+	/* Enable pwr irq interrupts */
+	writel_relaxed(INT_MASK, (msm_host->core_mem + CORE_PWRCTL_MASK));
+
+#ifdef CONFIG_MMC_CLKGATE
+	/* Set clock gating delay to be used when CONFIG_MMC_CLKGATE is set */
+	msm_host->mmc->clkgate_delay = SDHCI_MSM_MMC_CLK_GATE_DELAY;
+#endif
+
+	/* Set host capabilities */
+	msm_host->mmc->caps |= msm_host->pdata->mmc_bus_width;
+	msm_host->mmc->caps |= msm_host->pdata->caps;
+	msm_host->mmc->caps |= MMC_CAP_HW_RESET;
+	msm_host->mmc->caps2 |= msm_host->pdata->caps2;
+	msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR;
+	msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
+
+	if (msm_host->pdata->nonremovable)
+		msm_host->mmc->caps |= MMC_CAP_NONREMOVABLE;
+
 	ret = sdhci_add_host(host);
-	if (ret)
-		goto clk_disable;
+	if (ret) {
+		dev_err(&pdev->dev, "Add host failed (%d)\n", ret);
+		goto vreg_deinit;
+	}
 
-	return 0;
+	 /* Set core clk rate, optionally override from dts */
+	if (msm_host->pdata->max_clk)
+		host->max_clk = msm_host->pdata->max_clk;
+	ret = clk_set_rate(msm_host->clk, host->max_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "MClk rate set failed (%d)\n", ret);
+		goto remove_host;
+	}
 
+	/* Successful initialization */
+	goto out;
+
+remove_host:
+	dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+	sdhci_remove_host(host, dead);
+vreg_deinit:
+	sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
 clk_disable:
-	clk_disable_unprepare(msm_host->clk);
+	if (!IS_ERR(msm_host->clk))
+		clk_disable_unprepare(msm_host->clk);
 pclk_disable:
-	clk_disable_unprepare(msm_host->pclk);
+	if (!IS_ERR(msm_host->pclk))
+		clk_disable_unprepare(msm_host->pclk);
 bus_clk_disable:
-	if (!IS_ERR(msm_host->bus_clk))
+	if (!IS_ERR_OR_NULL(msm_host->bus_clk))
 		clk_disable_unprepare(msm_host->bus_clk);
 pltfm_free:
 	sdhci_pltfm_free(pdev);
+out:
+	pr_debug("%s: Exit %s\n", dev_name(&pdev->dev), __func__);
 	return ret;
 }
 
@@ -681,29 +1504,37 @@
 {
 	struct sdhci_host *host = platform_get_drvdata(pdev);
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	struct sdhci_msm_pltfm_data *pdata = msm_host->pdata;
 	int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) ==
-		    0xffffffff);
+			0xffffffff);
 
+	pr_debug("%s: %s\n", dev_name(&pdev->dev), __func__);
 	sdhci_remove_host(host, dead);
-	clk_disable_unprepare(msm_host->clk);
-	clk_disable_unprepare(msm_host->pclk);
-	if (!IS_ERR(msm_host->bus_clk))
-		clk_disable_unprepare(msm_host->bus_clk);
 	sdhci_pltfm_free(pdev);
+	sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
+
+	if (pdata->pin_data)
+		sdhci_msm_setup_gpio(pdata, false);
 	return 0;
 }
 
+static const struct of_device_id sdhci_msm_dt_match[] = {
+	{.compatible = "qcom,sdhci-msm"},
+};
+MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
+
 static struct platform_driver sdhci_msm_driver = {
-	.probe = sdhci_msm_probe,
-	.remove = sdhci_msm_remove,
-	.driver = {
-		   .name = "sdhci_msm",
-		   .of_match_table = sdhci_msm_dt_match,
+	.probe		= sdhci_msm_probe,
+	.remove		= sdhci_msm_remove,
+	.driver		= {
+		.name	= "sdhci_msm",
+		.owner	= THIS_MODULE,
+		.of_match_table = sdhci_msm_dt_match,
 	},
 };
 
 module_platform_driver(sdhci_msm_driver);
 
-MODULE_DESCRIPTION("Qualcomm Secure Digital Host Controller Interface driver");
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Secure Digital Host Controller Interface driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index 410a55b..1cfd7f9 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -28,13 +28,9 @@
 #include "sdhci-pltfm.h"
 #include <linux/of.h>
 
-#define SDHCI_ARASAN_CLK_CTRL_OFFSET	0x2c
 #define SDHCI_ARASAN_VENDOR_REGISTER	0x78
 
 #define VENDOR_ENHANCED_STROBE		BIT(0)
-#define CLK_CTRL_TIMEOUT_SHIFT		16
-#define CLK_CTRL_TIMEOUT_MASK		(0xf << CLK_CTRL_TIMEOUT_SHIFT)
-#define CLK_CTRL_TIMEOUT_MIN_EXP	13
 
 #define PHY_CLK_TOO_SLOW_HZ		400000
 
@@ -163,15 +159,15 @@
 
 static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
 {
-	u32 div;
 	unsigned long freq;
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 
-	div = readl(host->ioaddr + SDHCI_ARASAN_CLK_CTRL_OFFSET);
-	div = (div & CLK_CTRL_TIMEOUT_MASK) >> CLK_CTRL_TIMEOUT_SHIFT;
+	/* SDHCI timeout clock is in kHz */
+	freq = DIV_ROUND_UP(clk_get_rate(pltfm_host->clk), 1000);
 
-	freq = clk_get_rate(pltfm_host->clk);
-	freq /= 1 << (CLK_CTRL_TIMEOUT_MIN_EXP + div);
+	/* or in MHz */
+	if (host->caps & SDHCI_TIMEOUT_CLK_UNIT)
+		freq = DIV_ROUND_UP(freq, 1000);
 
 	return freq;
 }
diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c
index a9b7fc0..387ae1c 100644
--- a/drivers/mmc/host/sdhci-of-at91.c
+++ b/drivers/mmc/host/sdhci-of-at91.c
@@ -85,11 +85,30 @@
 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 }
 
+/*
+ * In this specific implementation of the SDHCI controller, the power register
+ * needs to have a valid voltage set even when the power supply is managed by
+ * an external regulator.
+ */
+static void sdhci_at91_set_power(struct sdhci_host *host, unsigned char mode,
+		     unsigned short vdd)
+{
+	if (!IS_ERR(host->mmc->supply.vmmc)) {
+		struct mmc_host *mmc = host->mmc;
+
+		spin_unlock_irq(&host->lock);
+		mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+		spin_lock_irq(&host->lock);
+	}
+	sdhci_set_power_noreg(host, mode, vdd);
+}
+
 static const struct sdhci_ops sdhci_at91_sama5d2_ops = {
 	.set_clock		= sdhci_at91_set_clock,
 	.set_bus_width		= sdhci_set_bus_width,
 	.reset			= sdhci_reset,
 	.set_uhs_signaling	= sdhci_set_uhs_signaling,
+	.set_power		= sdhci_at91_set_power,
 };
 
 static const struct sdhci_pltfm_data soc_data_sama5d2 = {
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index 1d9e00a..b0b9ceb 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -412,6 +412,8 @@
 	if (mode == MMC_POWER_OFF)
 		return;
 
+	spin_unlock_irq(&host->lock);
+
 	/*
 	 * Bus power might not enable after D3 -> D0 transition due to the
 	 * present state not yet having propagated. Retry for up to 2ms.
@@ -424,6 +426,8 @@
 		reg |= SDHCI_POWER_ON;
 		sdhci_writeb(host, reg, SDHCI_POWER_CONTROL);
 	}
+
+	spin_lock_irq(&host->lock);
 }
 
 static const struct sdhci_ops sdhci_intel_byt_ops = {
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index 3280f20..33b4fa6 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -23,6 +23,7 @@
 
 struct sdhci_pltfm_host {
 	struct clk *clk;
+	void *priv; /* to handle quirks across io-accessor calls */
 
 	/* migrate from sdhci_of_host */
 	unsigned int clock;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ba637ff..e72d188 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -748,6 +748,17 @@
 	}
 }
 
+static void sdhci_set_blk_size_reg(struct sdhci_host *host, unsigned int blksz,
+				   unsigned int sdma_boundary)
+{
+	if (host->flags & SDHCI_USE_ADMA)
+		sdhci_writew(host, SDHCI_MAKE_BLKSZ(0, blksz),
+			     SDHCI_BLOCK_SIZE);
+	else
+		sdhci_writew(host, SDHCI_MAKE_BLKSZ(sdma_boundary, blksz),
+			     SDHCI_BLOCK_SIZE);
+}
+
 static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
 {
 	u8 ctrl;
@@ -880,8 +891,7 @@
 	sdhci_set_transfer_irqs(host);
 
 	/* Set the DMA boundary value and block size */
-	sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
-		data->blksz), SDHCI_BLOCK_SIZE);
+	sdhci_set_blk_size_reg(host, data->blksz, SDHCI_DEFAULT_BOUNDARY_ARG);
 	sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
 }
 
@@ -1350,7 +1360,8 @@
 
 	host->mmc->actual_clock = 0;
 
-	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+	if (host->clock)
+		sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
 
 	if (clock == 0)
 		return;
@@ -1371,7 +1382,9 @@
 			return;
 		}
 		timeout--;
-		mdelay(1);
+		spin_unlock_irq(&host->lock);
+		usleep_range(900, 1100);
+		spin_lock_irq(&host->lock);
 	}
 
 	clk |= SDHCI_CLOCK_CARD_EN;
@@ -1579,22 +1592,16 @@
 		return;
 	}
 
-	/*
-	 * Reset the chip on each power off.
-	 * Should clear out any weird states.
-	 */
-	if (ios->power_mode == MMC_POWER_OFF) {
-		sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
-		sdhci_reinit(host);
-	}
-
 	if (host->version >= SDHCI_SPEC_300 &&
 		(ios->power_mode == MMC_POWER_UP) &&
 		!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
 		sdhci_enable_preset_value(host, false);
 
+	spin_lock_irqsave(&host->lock, flags);
 	if (!ios->clock || ios->clock != host->clock) {
+		spin_unlock_irqrestore(&host->lock, flags);
 		host->ops->set_clock(host, ios->clock);
+		spin_lock_irqsave(&host->lock, flags);
 		host->clock = ios->clock;
 
 		if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK &&
@@ -1609,11 +1616,13 @@
 			host->mmc->max_busy_timeout /= host->timeout_clk;
 		}
 	}
+	spin_unlock_irqrestore(&host->lock, flags);
 
 	if (host->ops->set_power)
 		host->ops->set_power(host, ios->power_mode, ios->vdd);
 	else
-		sdhci_set_power(host, ios->power_mode, ios->vdd);
+		if (ios->power_mode & (MMC_POWER_UP | MMC_POWER_ON))
+			sdhci_set_power(host, ios->power_mode, ios->vdd);
 
 	if (host->ops->platform_send_init_74_clocks)
 		host->ops->platform_send_init_74_clocks(host, ios->power_mode);
@@ -1712,6 +1721,7 @@
 	} else
 		sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
+	spin_unlock_irqrestore(&host->lock, flags);
 	/*
 	 * Some (ENE) controllers go apeshit on some ios operation,
 	 * signalling timeout and CRC errors even on CMD0. Resetting
@@ -1720,8 +1730,19 @@
 	if (host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
 		sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
+	/*
+	 * Reset the chip on each power off.
+	 * Should clear out any weird states.
+	 */
+	if (ios->power_mode == MMC_POWER_OFF) {
+		sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
+		sdhci_reinit(host);
+		sdhci_set_power(host, ios->power_mode, ios->vdd);
+	}
+	if (!ios->clock)
+		sdhci_set_clock(host, ios->clock);
+
 	mmiowb();
-	spin_unlock_irqrestore(&host->lock, flags);
 }
 
 static int sdhci_get_cd(struct mmc_host *mmc)
@@ -2054,14 +2075,11 @@
 		 */
 		if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) {
 			if (mmc->ios.bus_width == MMC_BUS_WIDTH_8)
-				sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128),
-					     SDHCI_BLOCK_SIZE);
+				sdhci_set_blk_size_reg(host, 128, 7);
 			else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4)
-				sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
-					     SDHCI_BLOCK_SIZE);
+				sdhci_set_blk_size_reg(host, 64, 7);
 		} else {
-			sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
-				     SDHCI_BLOCK_SIZE);
+			sdhci_set_blk_size_reg(host, 64, 7);
 		}
 
 		/*
@@ -2360,6 +2378,9 @@
 		sdhci_do_reset(host, SDHCI_RESET_DATA);
 
 		host->pending_reset = false;
+	} else {
+		if (host->quirks2 & SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT)
+			sdhci_reset(host, SDHCI_RESET_DATA);
 	}
 
 	if (!sdhci_has_requests(host))
@@ -2706,11 +2727,19 @@
 			result = IRQ_WAKE_THREAD;
 		}
 
-		if (intmask & SDHCI_INT_CMD_MASK)
+		if (intmask & SDHCI_INT_CMD_MASK) {
+			if ((host->quirks2 & SDHCI_QUIRK2_SLOW_INT_CLR) &&
+				(host->clock <= 400000))
+				udelay(40);
 			sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
+		}
 
-		if (intmask & SDHCI_INT_DATA_MASK)
+		if (intmask & SDHCI_INT_DATA_MASK) {
+			if ((host->quirks2 & SDHCI_QUIRK2_SLOW_INT_CLR) &&
+			    (host->clock <= 400000))
+				udelay(40);
 			sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
+		}
 
 		if (intmask & SDHCI_INT_BUS_POWER)
 			pr_err("%s: Card is consuming too much power!\n",
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 2570455..b56b3c1 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -425,6 +425,17 @@
 #define SDHCI_QUIRK2_ACMD23_BROKEN			(1<<14)
 /* Broken Clock divider zero in controller */
 #define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN		(1<<15)
+/*
+ * Read Transfer Active/ Write Transfer Active may be not
+ * de-asserted after end of transaction. Issue reset for DAT line.
+ */
+#define SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT                 (1<<17)
+/*
+ * Slow interrupt clearance at 400KHz may cause
+ * host controller driver interrupt handler to
+ * be called twice.
+*/
+#define SDHCI_QUIRK2_SLOW_INT_CLR			(1<<18)
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
@@ -558,7 +569,10 @@
 	void	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
 	void	(*hw_reset)(struct sdhci_host *host);
 	void    (*adma_workaround)(struct sdhci_host *host, u32 intmask);
+	unsigned int	(*get_max_segments)(void);
 	void    (*card_event)(struct sdhci_host *host);
+	void	(*toggle_cdr)(struct sdhci_host *host, bool enable);
+	void	(*check_power_status)(struct sdhci_host *host);
 	void	(*voltage_switch)(struct sdhci_host *host);
 	int	(*select_drive_strength)(struct sdhci_host *host,
 					 struct mmc_card *card,
diff --git a/drivers/mmc/host/ushc.c b/drivers/mmc/host/ushc.c
index d2c386f..1d84335 100644
--- a/drivers/mmc/host/ushc.c
+++ b/drivers/mmc/host/ushc.c
@@ -426,6 +426,9 @@
 	struct ushc_data *ushc;
 	int ret;
 
+	if (intf->cur_altsetting->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	mmc = mmc_alloc_host(sizeof(struct ushc_data), &intf->dev);
 	if (mmc == NULL)
 		return -ENOMEM;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
index bbef959..1592e1c 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
@@ -917,8 +917,8 @@
 #define RX_PACKET_ATTRIBUTES_CSUM_DONE_WIDTH	1
 #define RX_PACKET_ATTRIBUTES_VLAN_CTAG_INDEX	1
 #define RX_PACKET_ATTRIBUTES_VLAN_CTAG_WIDTH	1
-#define RX_PACKET_ATTRIBUTES_INCOMPLETE_INDEX	2
-#define RX_PACKET_ATTRIBUTES_INCOMPLETE_WIDTH	1
+#define RX_PACKET_ATTRIBUTES_LAST_INDEX		2
+#define RX_PACKET_ATTRIBUTES_LAST_WIDTH		1
 #define RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_INDEX	3
 #define RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_WIDTH	1
 #define RX_PACKET_ATTRIBUTES_CONTEXT_INDEX	4
@@ -927,6 +927,8 @@
 #define RX_PACKET_ATTRIBUTES_RX_TSTAMP_WIDTH	1
 #define RX_PACKET_ATTRIBUTES_RSS_HASH_INDEX	6
 #define RX_PACKET_ATTRIBUTES_RSS_HASH_WIDTH	1
+#define RX_PACKET_ATTRIBUTES_FIRST_INDEX	7
+#define RX_PACKET_ATTRIBUTES_FIRST_WIDTH	1
 
 #define RX_NORMAL_DESC0_OVT_INDEX		0
 #define RX_NORMAL_DESC0_OVT_WIDTH		16
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
index 1babcc1..ca106d4 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -1721,10 +1721,15 @@
 
 	/* Get the header length */
 	if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, FD)) {
+		XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
+			       FIRST, 1);
 		rdata->rx.hdr_len = XGMAC_GET_BITS_LE(rdesc->desc2,
 						      RX_NORMAL_DESC2, HL);
 		if (rdata->rx.hdr_len)
 			pdata->ext_stats.rx_split_header_packets++;
+	} else {
+		XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
+			       FIRST, 0);
 	}
 
 	/* Get the RSS hash */
@@ -1747,19 +1752,16 @@
 		}
 	}
 
-	/* Get the packet length */
-	rdata->rx.len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL);
-
-	if (!XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, LD)) {
-		/* Not all the data has been transferred for this packet */
-		XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
-			       INCOMPLETE, 1);
+	/* Not all the data has been transferred for this packet */
+	if (!XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, LD))
 		return 0;
-	}
 
 	/* This is the last of the data for this packet */
 	XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
-		       INCOMPLETE, 0);
+		       LAST, 1);
+
+	/* Get the packet length */
+	rdata->rx.len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL);
 
 	/* Set checksum done indicator as appropriate */
 	if (netdev->features & NETIF_F_RXCSUM)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index 7f9216d..0f0f3014 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -1752,13 +1752,12 @@
 {
 	struct sk_buff *skb;
 	u8 *packet;
-	unsigned int copy_len;
 
 	skb = napi_alloc_skb(napi, rdata->rx.hdr.dma_len);
 	if (!skb)
 		return NULL;
 
-	/* Start with the header buffer which may contain just the header
+	/* Pull in the header buffer which may contain just the header
 	 * or the header plus data
 	 */
 	dma_sync_single_range_for_cpu(pdata->dev, rdata->rx.hdr.dma_base,
@@ -1767,30 +1766,49 @@
 
 	packet = page_address(rdata->rx.hdr.pa.pages) +
 		 rdata->rx.hdr.pa.pages_offset;
-	copy_len = (rdata->rx.hdr_len) ? rdata->rx.hdr_len : len;
-	copy_len = min(rdata->rx.hdr.dma_len, copy_len);
-	skb_copy_to_linear_data(skb, packet, copy_len);
-	skb_put(skb, copy_len);
-
-	len -= copy_len;
-	if (len) {
-		/* Add the remaining data as a frag */
-		dma_sync_single_range_for_cpu(pdata->dev,
-					      rdata->rx.buf.dma_base,
-					      rdata->rx.buf.dma_off,
-					      rdata->rx.buf.dma_len,
-					      DMA_FROM_DEVICE);
-
-		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
-				rdata->rx.buf.pa.pages,
-				rdata->rx.buf.pa.pages_offset,
-				len, rdata->rx.buf.dma_len);
-		rdata->rx.buf.pa.pages = NULL;
-	}
+	skb_copy_to_linear_data(skb, packet, len);
+	skb_put(skb, len);
 
 	return skb;
 }
 
+static unsigned int xgbe_rx_buf1_len(struct xgbe_ring_data *rdata,
+				     struct xgbe_packet_data *packet)
+{
+	/* Always zero if not the first descriptor */
+	if (!XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, FIRST))
+		return 0;
+
+	/* First descriptor with split header, return header length */
+	if (rdata->rx.hdr_len)
+		return rdata->rx.hdr_len;
+
+	/* First descriptor but not the last descriptor and no split header,
+	 * so the full buffer was used
+	 */
+	if (!XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, LAST))
+		return rdata->rx.hdr.dma_len;
+
+	/* First descriptor and last descriptor and no split header, so
+	 * calculate how much of the buffer was used
+	 */
+	return min_t(unsigned int, rdata->rx.hdr.dma_len, rdata->rx.len);
+}
+
+static unsigned int xgbe_rx_buf2_len(struct xgbe_ring_data *rdata,
+				     struct xgbe_packet_data *packet,
+				     unsigned int len)
+{
+	/* Always the full buffer if not the last descriptor */
+	if (!XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, LAST))
+		return rdata->rx.buf.dma_len;
+
+	/* Last descriptor so calculate how much of the buffer was used
+	 * for the last bit of data
+	 */
+	return rdata->rx.len - len;
+}
+
 static int xgbe_tx_poll(struct xgbe_channel *channel)
 {
 	struct xgbe_prv_data *pdata = channel->pdata;
@@ -1873,8 +1891,8 @@
 	struct napi_struct *napi;
 	struct sk_buff *skb;
 	struct skb_shared_hwtstamps *hwtstamps;
-	unsigned int incomplete, error, context_next, context;
-	unsigned int len, rdesc_len, max_len;
+	unsigned int last, error, context_next, context;
+	unsigned int len, buf1_len, buf2_len, max_len;
 	unsigned int received = 0;
 	int packet_count = 0;
 
@@ -1884,7 +1902,7 @@
 	if (!ring)
 		return 0;
 
-	incomplete = 0;
+	last = 0;
 	context_next = 0;
 
 	napi = (pdata->per_channel_irq) ? &channel->napi : &pdata->napi;
@@ -1918,9 +1936,8 @@
 		received++;
 		ring->cur++;
 
-		incomplete = XGMAC_GET_BITS(packet->attributes,
-					    RX_PACKET_ATTRIBUTES,
-					    INCOMPLETE);
+		last = XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
+				      LAST);
 		context_next = XGMAC_GET_BITS(packet->attributes,
 					      RX_PACKET_ATTRIBUTES,
 					      CONTEXT_NEXT);
@@ -1929,7 +1946,7 @@
 					 CONTEXT);
 
 		/* Earlier error, just drain the remaining data */
-		if ((incomplete || context_next) && error)
+		if ((!last || context_next) && error)
 			goto read_again;
 
 		if (error || packet->errors) {
@@ -1941,16 +1958,22 @@
 		}
 
 		if (!context) {
-			/* Length is cumulative, get this descriptor's length */
-			rdesc_len = rdata->rx.len - len;
-			len += rdesc_len;
+			/* Get the data length in the descriptor buffers */
+			buf1_len = xgbe_rx_buf1_len(rdata, packet);
+			len += buf1_len;
+			buf2_len = xgbe_rx_buf2_len(rdata, packet, len);
+			len += buf2_len;
 
-			if (rdesc_len && !skb) {
+			if (!skb) {
 				skb = xgbe_create_skb(pdata, napi, rdata,
-						      rdesc_len);
-				if (!skb)
+						      buf1_len);
+				if (!skb) {
 					error = 1;
-			} else if (rdesc_len) {
+					goto skip_data;
+				}
+			}
+
+			if (buf2_len) {
 				dma_sync_single_range_for_cpu(pdata->dev,
 							rdata->rx.buf.dma_base,
 							rdata->rx.buf.dma_off,
@@ -1960,13 +1983,14 @@
 				skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
 						rdata->rx.buf.pa.pages,
 						rdata->rx.buf.pa.pages_offset,
-						rdesc_len,
+						buf2_len,
 						rdata->rx.buf.dma_len);
 				rdata->rx.buf.pa.pages = NULL;
 			}
 		}
 
-		if (incomplete || context_next)
+skip_data:
+		if (!last || context_next)
 			goto read_again;
 
 		if (!skb)
@@ -2024,7 +2048,7 @@
 	}
 
 	/* Check if we need to save state before leaving */
-	if (received && (incomplete || context_next)) {
+	if (received && (!last || context_next)) {
 		rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
 		rdata->state_saved = 1;
 		rdata->state.skb = skb;
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index a4e60e5..0975af2 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -3402,7 +3402,8 @@
 
 	bcmgenet_netif_stop(dev);
 
-	phy_suspend(priv->phydev);
+	if (!device_may_wakeup(d))
+		phy_suspend(priv->phydev);
 
 	netif_device_detach(dev);
 
@@ -3499,7 +3500,8 @@
 
 	netif_device_attach(dev);
 
-	phy_resume(priv->phydev);
+	if (!device_may_wakeup(d))
+		phy_resume(priv->phydev);
 
 	if (priv->eee.eee_enabled)
 		bcmgenet_eee_enable_set(dev, true);
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index e876076..2f92819 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -220,20 +220,6 @@
 	udelay(60);
 }
 
-static void bcmgenet_internal_phy_setup(struct net_device *dev)
-{
-	struct bcmgenet_priv *priv = netdev_priv(dev);
-	u32 reg;
-
-	/* Power up PHY */
-	bcmgenet_phy_power_set(dev, true);
-	/* enable APD */
-	reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
-	reg |= EXT_PWR_DN_EN_LD;
-	bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
-	bcmgenet_mii_reset(dev);
-}
-
 static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv)
 {
 	u32 reg;
@@ -281,7 +267,6 @@
 
 		if (priv->internal_phy) {
 			phy_name = "internal PHY";
-			bcmgenet_internal_phy_setup(dev);
 		} else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
 			phy_name = "MoCA";
 			bcmgenet_moca_phy_setup(priv);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index bfe410e..3f51a44 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -367,6 +367,8 @@
 	case MLX5_CMD_OP_QUERY_VPORT_COUNTER:
 	case MLX5_CMD_OP_ALLOC_Q_COUNTER:
 	case MLX5_CMD_OP_QUERY_Q_COUNTER:
+	case MLX5_CMD_OP_SET_RATE_LIMIT:
+	case MLX5_CMD_OP_QUERY_RATE_LIMIT:
 	case MLX5_CMD_OP_ALLOC_PD:
 	case MLX5_CMD_OP_ALLOC_UAR:
 	case MLX5_CMD_OP_CONFIG_INT_MODERATION:
@@ -500,6 +502,8 @@
 	MLX5_COMMAND_STR_CASE(ALLOC_Q_COUNTER);
 	MLX5_COMMAND_STR_CASE(DEALLOC_Q_COUNTER);
 	MLX5_COMMAND_STR_CASE(QUERY_Q_COUNTER);
+	MLX5_COMMAND_STR_CASE(SET_RATE_LIMIT);
+	MLX5_COMMAND_STR_CASE(QUERY_RATE_LIMIT);
 	MLX5_COMMAND_STR_CASE(ALLOC_PD);
 	MLX5_COMMAND_STR_CASE(DEALLOC_PD);
 	MLX5_COMMAND_STR_CASE(ALLOC_UAR);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 796bdf0..7309ae3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -602,6 +602,10 @@
 	if (lro_num_seg > 1) {
 		mlx5e_lro_update_hdr(skb, cqe, cqe_bcnt);
 		skb_shinfo(skb)->gso_size = DIV_ROUND_UP(cqe_bcnt, lro_num_seg);
+		/* Subtract one since we already counted this as one
+		 * "regular" packet in mlx5e_complete_rx_cqe()
+		 */
+		rq->stats.packets += lro_num_seg - 1;
 		rq->stats.lro_packets++;
 		rq->stats.lro_bytes += cqe_bcnt;
 	}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index a543ea6..3fd471a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -427,14 +427,16 @@
 		}
 
 		if (is_tcf_vlan(a)) {
-			if (tcf_vlan_action(a) == VLAN_F_POP) {
+			if (tcf_vlan_action(a) == TCA_VLAN_ACT_POP) {
 				attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP;
-			} else if (tcf_vlan_action(a) == VLAN_F_PUSH) {
+			} else if (tcf_vlan_action(a) == TCA_VLAN_ACT_PUSH) {
 				if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q))
 					return -EOPNOTSUPP;
 
 				attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
 				attr->vlan = tcf_vlan_push_vid(a);
+			} else { /* action is TCA_VLAN_ACT_MODIFY */
+				return -EOPNOTSUPP;
 			}
 			continue;
 		}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
index cfb6837..5743110 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -272,15 +272,18 @@
 			sq->stats.tso_bytes += skb->len - ihs;
 		}
 
+		sq->stats.packets += skb_shinfo(skb)->gso_segs;
 		num_bytes = skb->len + (skb_shinfo(skb)->gso_segs - 1) * ihs;
 	} else {
 		bf = sq->bf_budget &&
 		     !skb->xmit_more &&
 		     !skb_shinfo(skb)->nr_frags;
 		ihs = mlx5e_get_inline_hdr_size(sq, skb, bf);
+		sq->stats.packets++;
 		num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN);
 	}
 
+	sq->stats.bytes += num_bytes;
 	wi->num_bytes = num_bytes;
 
 	if (skb_vlan_tag_present(skb)) {
@@ -377,8 +380,6 @@
 	if (bf)
 		sq->bf_budget--;
 
-	sq->stats.packets++;
-	sq->stats.bytes += num_bytes;
 	return NETDEV_TX_OK;
 
 dma_unmap_wqe_err:
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 0c9ef87..7a196a0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -87,7 +87,7 @@
 	[2] = {
 		.mask		= MLX5_PROF_MASK_QP_SIZE |
 				  MLX5_PROF_MASK_MR_CACHE,
-		.log_max_qp	= 17,
+		.log_max_qp	= 18,
 		.mr_cache[0]	= {
 			.size	= 500,
 			.limit	= 250
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 24d5272..0d519a9 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -924,6 +924,8 @@
 	{QMI_FIXED_INTF(0x413c, 0x81a9, 8)},	/* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
 	{QMI_FIXED_INTF(0x413c, 0x81b1, 8)},	/* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
 	{QMI_FIXED_INTF(0x413c, 0x81b3, 8)},	/* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
+	{QMI_FIXED_INTF(0x413c, 0x81b6, 8)},	/* Dell Wireless 5811e */
+	{QMI_FIXED_INTF(0x413c, 0x81b6, 10)},	/* Dell Wireless 5811e */
 	{QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)},	/* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
 	{QMI_FIXED_INTF(0x22de, 0x9061, 3)},	/* WeTelecom WPD-600N */
 	{QMI_FIXED_INTF(0x1e0e, 0x9001, 5)},	/* SIMCom 7230E */
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index bc744ac..a2afb8e 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -467,8 +467,10 @@
 	}
 
 	if (rt6_local) {
-		if (rt6_local->rt6i_idev)
+		if (rt6_local->rt6i_idev) {
 			in6_dev_put(rt6_local->rt6i_idev);
+			rt6_local->rt6i_idev = NULL;
+		}
 
 		dst = &rt6_local->dst;
 		dev_put(dst->dev);
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index f00d429..91594de 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -25,3 +25,5 @@
 obj-$(CONFIG_USB_NET_RNDIS_WLAN)	+= rndis_wlan.o
 
 obj-$(CONFIG_MAC80211_HWSIM)	+= mac80211_hwsim.o
+
+obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/
diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
index 636f466..61de231 100644
--- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
+++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012,2014-2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012,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
@@ -207,6 +207,8 @@
 		print_stack_trace(&wcnss_allocs[i].trace, 1);
 	}
 }
+#else
+void wcnss_prealloc_check_memory_leak(void) {}
 #endif
 
 int wcnss_pre_alloc_reset(void)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 3c3c4f1..7a310c4 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -2700,6 +2700,21 @@
 	schedule_work(&pcie_work);
 }
 
+static void mwifiex_pcie_free_buffers(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
+	if (reg->sleep_cookie)
+		mwifiex_pcie_delete_sleep_cookie_buf(adapter);
+
+	mwifiex_pcie_delete_cmdrsp_buf(adapter);
+	mwifiex_pcie_delete_evtbd_ring(adapter);
+	mwifiex_pcie_delete_rxbd_ring(adapter);
+	mwifiex_pcie_delete_txbd_ring(adapter);
+	card->cmdrsp_buf = NULL;
+}
+
 /*
  * This function initializes the PCI-E host memory space, WCB rings, etc.
  *
@@ -2812,13 +2827,6 @@
 
 /*
  * This function cleans up the allocated card buffers.
- *
- * The following are freed by this function -
- *      - TXBD ring buffers
- *      - RXBD ring buffers
- *      - Event BD ring buffers
- *      - Command response ring buffer
- *      - Sleep cookie buffer
  */
 static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
 {
@@ -2834,6 +2842,8 @@
 				    "Failed to write driver not-ready signature\n");
 	}
 
+	mwifiex_pcie_free_buffers(adapter);
+
 	if (pdev) {
 		pci_iounmap(pdev, card->pci_mmap);
 		pci_iounmap(pdev, card->pci_mmap1);
@@ -3080,10 +3090,7 @@
 	pci_iounmap(pdev, card->pci_mmap1);
 }
 
-/* This function cleans up the PCI-E host memory space.
- * Some code is extracted from mwifiex_unregister_dev()
- *
- */
+/* This function cleans up the PCI-E host memory space. */
 static void mwifiex_pcie_down_dev(struct mwifiex_adapter *adapter)
 {
 	struct pcie_service_card *card = adapter->card;
@@ -3095,16 +3102,8 @@
 	adapter->seq_num = 0;
 	adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
 
-	if (card) {
-		if (reg->sleep_cookie)
-			mwifiex_pcie_delete_sleep_cookie_buf(adapter);
-
-		mwifiex_pcie_delete_cmdrsp_buf(adapter);
-		mwifiex_pcie_delete_evtbd_ring(adapter);
-		mwifiex_pcie_delete_rxbd_ring(adapter);
-		mwifiex_pcie_delete_txbd_ring(adapter);
-		card->cmdrsp_buf = NULL;
-	}
+	if (card)
+		mwifiex_pcie_free_buffers(adapter);
 
 	return;
 }
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index 3308427..4399de34 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -939,8 +939,10 @@
 	 * pardevice fields. -arca
 	 */
 	port->ops->init_state(par_dev, par_dev->state);
-	port->proc_device = par_dev;
-	parport_device_proc_register(par_dev);
+	if (!test_and_set_bit(PARPORT_DEVPROC_REGISTERED, &port->devflags)) {
+		port->proc_device = par_dev;
+		parport_device_proc_register(par_dev);
+	}
 
 	return par_dev;
 
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index b37b572..ad3e1e7 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -27,6 +27,9 @@
 #include <asm/cputype.h>
 #include <asm/irq_regs.h>
 
+#define USE_CPUHP_STATE CPUHP_AP_PERF_ARM_STARTING
+#define USE_CPUHP_STR "AP_PERF_ARM_STARTING"
+
 static int
 armpmu_map_cache_event(const unsigned (*cache_map)
 				      [PERF_COUNT_HW_CACHE_MAX]
@@ -366,6 +369,8 @@
 		return err;
 	}
 
+	armpmu->pmu_state = ARM_PMU_STATE_RUNNING;
+
 	return 0;
 }
 
@@ -568,6 +573,7 @@
 		.read		= armpmu_read,
 		.filter_match	= armpmu_filter_match,
 		.attr_groups	= armpmu->attr_groups,
+		.events_across_hotplug = 1,
 	};
 	armpmu->attr_groups[ARMPMU_ATTR_GROUP_COMMON] =
 		&armpmu_common_attr_group;
@@ -620,6 +626,8 @@
 	struct platform_device *pmu_device = cpu_pmu->plat_device;
 	struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events;
 
+	cpu_pmu->pmu_state = ARM_PMU_STATE_GOING_DOWN;
+
 	irqs = min(pmu_device->num_resources, num_possible_cpus());
 
 	irq = platform_get_irq(pmu_device, 0);
@@ -627,6 +635,7 @@
 		on_each_cpu_mask(&cpu_pmu->supported_cpus,
 				 cpu_pmu_disable_percpu_irq, &irq, 1);
 		free_percpu_irq(irq, &hw_events->percpu_pmu);
+		cpu_pmu->percpu_irq = -1;
 	} else {
 		for (i = 0; i < irqs; ++i) {
 			int cpu = i;
@@ -641,6 +650,7 @@
 				free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu));
 		}
 	}
+	cpu_pmu->pmu_state = ARM_PMU_STATE_OFF;
 }
 
 static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
@@ -670,6 +680,7 @@
 
 		on_each_cpu_mask(&cpu_pmu->supported_cpus,
 				 cpu_pmu_enable_percpu_irq, &irq, 1);
+		cpu_pmu->percpu_irq = irq;
 	} else {
 		for (i = 0; i < irqs; ++i) {
 			int cpu = i;
@@ -709,22 +720,12 @@
 	return 0;
 }
 
-/*
- * PMU hardware loses all context when a CPU goes offline.
- * When a CPU is hotplugged back in, since some hardware registers are
- * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
- * junk values out of them.
- */
-static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node)
-{
-	struct arm_pmu *pmu = hlist_entry_safe(node, struct arm_pmu, node);
-
-	if (!cpumask_test_cpu(cpu, &pmu->supported_cpus))
-		return 0;
-	if (pmu->reset)
-		pmu->reset(pmu);
-	return 0;
-}
+struct cpu_pm_pmu_args {
+	struct arm_pmu	*armpmu;
+	unsigned long	cmd;
+	int		cpu;
+	int		ret;
+};
 
 #ifdef CONFIG_CPU_PM
 static void cpu_pm_pmu_setup(struct arm_pmu *armpmu, unsigned long cmd)
@@ -772,15 +773,19 @@
 	}
 }
 
-static int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd,
-			     void *v)
+static void cpu_pm_pmu_common(void *info)
 {
-	struct arm_pmu *armpmu = container_of(b, struct arm_pmu, cpu_pm_nb);
+	struct cpu_pm_pmu_args *data	= info;
+	struct arm_pmu *armpmu		= data->armpmu;
+	unsigned long cmd		= data->cmd;
+	int cpu				= data->cpu;
 	struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events);
 	int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events);
 
-	if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus))
-		return NOTIFY_DONE;
+	if (!cpumask_test_cpu(cpu, &armpmu->supported_cpus)) {
+		data->ret = NOTIFY_DONE;
+		return;
+	}
 
 	/*
 	 * Always reset the PMU registers on power-up even if
@@ -789,8 +794,12 @@
 	if (cmd == CPU_PM_EXIT && armpmu->reset)
 		armpmu->reset(armpmu);
 
-	if (!enabled)
-		return NOTIFY_OK;
+	if (!enabled) {
+		data->ret = NOTIFY_OK;
+		return;
+	}
+
+	data->ret = NOTIFY_OK;
 
 	switch (cmd) {
 	case CPU_PM_ENTER:
@@ -798,15 +807,29 @@
 		cpu_pm_pmu_setup(armpmu, cmd);
 		break;
 	case CPU_PM_EXIT:
-		cpu_pm_pmu_setup(armpmu, cmd);
 	case CPU_PM_ENTER_FAILED:
+		cpu_pm_pmu_setup(armpmu, cmd);
 		armpmu->start(armpmu);
 		break;
 	default:
-		return NOTIFY_DONE;
+		data->ret = NOTIFY_DONE;
+		break;
 	}
 
-	return NOTIFY_OK;
+	return;
+}
+
+static int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd,
+			     void *v)
+{
+	struct cpu_pm_pmu_args data = {
+		.armpmu	= container_of(b, struct arm_pmu, cpu_pm_nb),
+		.cmd	= cmd,
+		.cpu	= smp_processor_id(),
+	};
+
+	cpu_pm_pmu_common(&data);
+	return data.ret;
 }
 
 static int cpu_pm_pmu_register(struct arm_pmu *cpu_pmu)
@@ -819,11 +842,75 @@
 {
 	cpu_pm_unregister_notifier(&cpu_pmu->cpu_pm_nb);
 }
+
 #else
 static inline int cpu_pm_pmu_register(struct arm_pmu *cpu_pmu) { return 0; }
 static inline void cpu_pm_pmu_unregister(struct arm_pmu *cpu_pmu) { }
+static void cpu_pm_pmu_common(void *info) { }
 #endif
 
+/*
+ * PMU hardware loses all context when a CPU goes offline.
+ * When a CPU is hotplugged back in, since some hardware registers are
+ * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
+ * junk values out of them.
+ */
+static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node)
+{
+	struct arm_pmu *pmu = hlist_entry_safe(node, struct arm_pmu, node);
+
+	struct cpu_pm_pmu_args data = {
+		.armpmu	= pmu,
+		.cpu	= (int)cpu,
+	};
+
+	if (!pmu || !cpumask_test_cpu(cpu, &pmu->supported_cpus))
+		return 0;
+
+	data.cmd    = CPU_PM_EXIT;
+	cpu_pm_pmu_common(&data);
+	if (data.ret == NOTIFY_DONE)
+		return 0;
+
+	if (data.armpmu->pmu_state != ARM_PMU_STATE_OFF &&
+		data.armpmu->plat_device) {
+		int irq = data.armpmu->percpu_irq;
+
+		if (irq > 0 && irq_is_percpu(irq))
+			cpu_pmu_enable_percpu_irq(&irq);
+
+	}
+
+	return 0;
+}
+
+static int arm_perf_stopping_cpu(unsigned int cpu, struct hlist_node *node)
+{
+	struct arm_pmu *pmu = hlist_entry_safe(node, struct arm_pmu, node);
+
+	struct cpu_pm_pmu_args data = {
+		.armpmu	= pmu,
+		.cpu	= (int)cpu,
+	};
+
+	if (!pmu || !cpumask_test_cpu(cpu, &pmu->supported_cpus))
+		return 0;
+
+	data.cmd = CPU_PM_ENTER;
+	cpu_pm_pmu_common(&data);
+	/* Disarm the PMU IRQ before disappearing. */
+	if (data.armpmu->pmu_state == ARM_PMU_STATE_RUNNING &&
+		data.armpmu->plat_device) {
+		int irq = data.armpmu->percpu_irq;
+
+		if (irq > 0 && irq_is_percpu(irq))
+			cpu_pmu_disable_percpu_irq(&irq);
+
+	}
+
+	return 0;
+}
+
 static int cpu_pmu_init(struct arm_pmu *cpu_pmu)
 {
 	int err;
@@ -834,14 +921,14 @@
 	if (!cpu_hw_events)
 		return -ENOMEM;
 
-	err = cpuhp_state_add_instance_nocalls(CPUHP_AP_PERF_ARM_STARTING,
+	err = cpuhp_state_add_instance_nocalls(USE_CPUHP_STATE,
 					       &cpu_pmu->node);
 	if (err)
 		goto out_free;
 
 	err = cpu_pm_pmu_register(cpu_pmu);
 	if (err)
-		goto out_unregister;
+		goto out_unreg_perf_starting;
 
 	for_each_possible_cpu(cpu) {
 		struct pmu_hw_events *events = per_cpu_ptr(cpu_hw_events, cpu);
@@ -872,8 +959,8 @@
 
 	return 0;
 
-out_unregister:
-	cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_STARTING,
+out_unreg_perf_starting:
+	cpuhp_state_remove_instance_nocalls(USE_CPUHP_STATE,
 					    &cpu_pmu->node);
 out_free:
 	free_percpu(cpu_hw_events);
@@ -883,7 +970,7 @@
 static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
 {
 	cpu_pm_pmu_unregister(cpu_pmu);
-	cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_STARTING,
+	cpuhp_state_remove_instance_nocalls(USE_CPUHP_STATE,
 					    &cpu_pmu->node);
 	free_percpu(cpu_pmu->hw_events);
 }
@@ -1064,6 +1151,9 @@
 	if (!__oprofile_cpu_pmu)
 		__oprofile_cpu_pmu = pmu;
 
+	pmu->pmu_state  = ARM_PMU_STATE_OFF;
+	pmu->percpu_irq = -1;
+
 	pr_info("enabled with %s PMU driver, %d counters available\n",
 			pmu->name, pmu->num_events);
 
@@ -1083,11 +1173,12 @@
 {
 	int ret;
 
-	ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_STARTING,
-				      "AP_PERF_ARM_STARTING",
-				      arm_perf_starting_cpu, NULL);
+	ret = cpuhp_setup_state_multi(USE_CPUHP_STATE,
+					USE_CPUHP_STR,
+					arm_perf_starting_cpu,
+					arm_perf_stopping_cpu);
 	if (ret)
-		pr_err("CPU hotplug notifier for ARM PMU could not be registered: %d\n",
+		pr_err("CPU hotplug ARM PMU STOPPING registering failed: %d\n",
 		       ret);
 	return ret;
 }
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 92fd916..f6b99d0 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -55,6 +55,7 @@
 obj-$(CONFIG_PHY_QCOM_UFS) 	+= phy-qcom-ufs-qmp-14nm.o
 obj-$(CONFIG_PHY_QCOM_UFS) 	+= phy-qcom-ufs-qmp-v3.o
 obj-$(CONFIG_PHY_QCOM_UFS) 	+= phy-qcom-ufs-qrbtc-sdm845.o
+obj-$(CONFIG_PHY_QCOM_UFS) 	+= phy-qcom-ufs-qmp-v3-660.o
 obj-$(CONFIG_PHY_TUSB1210)		+= phy-tusb1210.o
 obj-$(CONFIG_PHY_BRCM_SATA)		+= phy-brcm-sata.o
 obj-$(CONFIG_PHY_PISTACHIO_USB)		+= phy-pistachio-usb.o
diff --git a/drivers/phy/phy-qcom-ufs-i.h b/drivers/phy/phy-qcom-ufs-i.h
index 35179c8..b92bc89 100644
--- a/drivers/phy/phy-qcom-ufs-i.h
+++ b/drivers/phy/phy-qcom-ufs-i.h
@@ -97,6 +97,10 @@
 	struct ufs_qcom_phy_vreg vdda_pll;
 	struct ufs_qcom_phy_vreg vdda_phy;
 	struct ufs_qcom_phy_vreg vddp_ref_clk;
+
+	/* Number of lanes available (1 or 2) for Rx/Tx */
+	u32 lanes_per_direction;
+
 	unsigned int quirks;
 
 	/*
@@ -152,6 +156,7 @@
  * and writes to QSERDES_RX_SIGDET_CNTRL attribute
  * @configure_lpm: pointer to a function that configures the phy
  * for low power mode.
+ * @dbg_register_dump: pointer to a function that dumps phy registers for debug.
  */
 struct ufs_qcom_phy_specific_ops {
 	int (*calibrate_phy)(struct ufs_qcom_phy *phy, bool is_rate_B);
@@ -161,6 +166,7 @@
 	void (*ctrl_rx_linecfg)(struct ufs_qcom_phy *phy, bool ctrl);
 	void (*power_control)(struct ufs_qcom_phy *phy, bool val);
 	int (*configure_lpm)(struct ufs_qcom_phy *phy, bool enable);
+	void (*dbg_register_dump)(struct ufs_qcom_phy *phy);
 };
 
 struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy);
@@ -184,5 +190,6 @@
 void ufs_qcom_phy_write_tbl(struct ufs_qcom_phy *ufs_qcom_phy,
 				struct ufs_qcom_phy_calibration *tbl,
 				int tbl_size);
-
+void ufs_qcom_phy_dump_regs(struct ufs_qcom_phy *phy,
+			    int offset, int len, char *prefix);
 #endif
diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3-660.c b/drivers/phy/phy-qcom-ufs-qmp-v3-660.c
new file mode 100644
index 0000000..9450e18
--- /dev/null
+++ b/drivers/phy/phy-qcom-ufs-qmp-v3-660.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2013-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 "phy-qcom-ufs-qmp-v3-660.h"
+
+#define UFS_PHY_NAME "ufs_phy_qmp_v3_660"
+
+static
+int ufs_qcom_phy_qmp_v3_660_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
+					bool is_rate_B)
+{
+	int err;
+	int tbl_size_A, tbl_size_B;
+	struct ufs_qcom_phy_calibration *tbl_A, *tbl_B;
+	u8 major = ufs_qcom_phy->host_ctrl_rev_major;
+	u16 minor = ufs_qcom_phy->host_ctrl_rev_minor;
+	u16 step = ufs_qcom_phy->host_ctrl_rev_step;
+
+	tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
+	tbl_B = phy_cal_table_rate_B;
+
+	if ((major == 0x3) && (minor == 0x001) && (step == 0x001)) {
+		tbl_A = phy_cal_table_rate_A_3_1_1;
+		tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_3_1_1);
+	} else {
+		dev_err(ufs_qcom_phy->dev,
+			"%s: Unknown UFS-PHY version (major 0x%x minor 0x%x step 0x%x), no calibration values\n",
+			__func__, major, minor, step);
+		err = -ENODEV;
+		goto out;
+	}
+
+	err = ufs_qcom_phy_calibrate(ufs_qcom_phy,
+				     tbl_A, tbl_size_A,
+				     tbl_B, tbl_size_B,
+				     is_rate_B);
+
+	if (err)
+		dev_err(ufs_qcom_phy->dev,
+			"%s: ufs_qcom_phy_calibrate() failed %d\n",
+			__func__, err);
+
+out:
+	return err;
+}
+
+static int ufs_qcom_phy_qmp_v3_660_init(struct phy *generic_phy)
+{
+	struct ufs_qcom_phy_qmp_v3_660 *phy = phy_get_drvdata(generic_phy);
+	struct ufs_qcom_phy *phy_common = &phy->common_cfg;
+	int err;
+
+	err = ufs_qcom_phy_init_clks(generic_phy, phy_common);
+	if (err) {
+		dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n",
+			__func__, err);
+		goto out;
+	}
+
+	err = ufs_qcom_phy_init_vregulators(generic_phy, phy_common);
+	if (err) {
+		dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n",
+			__func__, err);
+		goto out;
+	}
+
+out:
+	return err;
+}
+
+static
+void ufs_qcom_phy_qmp_v3_660_power_control(struct ufs_qcom_phy *phy,
+					 bool power_ctrl)
+{
+	if (!power_ctrl) {
+		/* apply analog power collapse */
+		writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
+		/*
+		 * Make sure that PHY knows its analog rail is going to be
+		 * powered OFF.
+		 */
+		mb();
+	} else {
+		/* bring PHY out of analog power collapse */
+		writel_relaxed(0x1, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
+
+		/*
+		 * Before any transactions involving PHY, ensure PHY knows
+		 * that it's analog rail is powered ON.
+		 */
+		mb();
+	}
+}
+
+static inline
+void ufs_qcom_phy_qmp_v3_660_set_tx_lane_enable(struct ufs_qcom_phy *phy,
+						   u32 val)
+{
+	/*
+	 * v3 PHY does not have TX_LANE_ENABLE register.
+	 * Implement this function so as not to propagate error to caller.
+	 */
+}
+
+static
+void ufs_qcom_phy_qmp_v3_660_ctrl_rx_linecfg(struct ufs_qcom_phy *phy,
+						bool ctrl)
+{
+	u32 temp;
+
+	temp = readl_relaxed(phy->mmio + UFS_PHY_LINECFG_DISABLE);
+
+	if (ctrl) /* enable RX LineCfg */
+		temp &= ~UFS_PHY_RX_LINECFG_DISABLE_BIT;
+	else /* disable RX LineCfg */
+		temp |= UFS_PHY_RX_LINECFG_DISABLE_BIT;
+
+	writel_relaxed(temp, phy->mmio + UFS_PHY_LINECFG_DISABLE);
+	/* Make sure that RX LineCfg config applied before we return */
+	mb();
+}
+
+static inline void ufs_qcom_phy_qmp_v3_660_start_serdes(
+					struct ufs_qcom_phy *phy)
+{
+	u32 tmp;
+
+	tmp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START);
+	tmp &= ~MASK_SERDES_START;
+	tmp |= (1 << OFFSET_SERDES_START);
+	writel_relaxed(tmp, phy->mmio + UFS_PHY_PHY_START);
+	/* Ensure register value is committed */
+	mb();
+}
+
+static int ufs_qcom_phy_qmp_v3_660_is_pcs_ready(
+				struct ufs_qcom_phy *phy_common)
+{
+	int err = 0;
+	u32 val;
+
+	err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS,
+		val, (val & MASK_PCS_READY), 10, 1000000);
+	if (err)
+		dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n",
+			__func__, err);
+	return err;
+}
+
+static void ufs_qcom_phy_qmp_v3_660_dbg_register_dump(
+					struct ufs_qcom_phy *phy)
+{
+	ufs_qcom_phy_dump_regs(phy, COM_BASE, COM_SIZE,
+					"PHY QSERDES COM Registers ");
+	ufs_qcom_phy_dump_regs(phy, PHY_BASE, PHY_SIZE,
+					"PHY Registers ");
+	ufs_qcom_phy_dump_regs(phy, RX_BASE, RX_SIZE,
+					"PHY RX0 Registers ");
+	ufs_qcom_phy_dump_regs(phy, TX_BASE, TX_SIZE,
+					"PHY TX0 Registers ");
+}
+
+struct phy_ops ufs_qcom_phy_qmp_v3_660_phy_ops = {
+	.init		= ufs_qcom_phy_qmp_v3_660_init,
+	.exit		= ufs_qcom_phy_exit,
+	.power_on	= ufs_qcom_phy_power_on,
+	.power_off	= ufs_qcom_phy_power_off,
+	.owner		= THIS_MODULE,
+};
+
+struct ufs_qcom_phy_specific_ops phy_v3_660_ops = {
+	.calibrate_phy		= ufs_qcom_phy_qmp_v3_660_phy_calibrate,
+	.start_serdes		= ufs_qcom_phy_qmp_v3_660_start_serdes,
+	.is_physical_coding_sublayer_ready =
+				ufs_qcom_phy_qmp_v3_660_is_pcs_ready,
+	.set_tx_lane_enable	= ufs_qcom_phy_qmp_v3_660_set_tx_lane_enable,
+	.ctrl_rx_linecfg	= ufs_qcom_phy_qmp_v3_660_ctrl_rx_linecfg,
+	.power_control		= ufs_qcom_phy_qmp_v3_660_power_control,
+	.dbg_register_dump	= ufs_qcom_phy_qmp_v3_660_dbg_register_dump,
+};
+
+static int ufs_qcom_phy_qmp_v3_660_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct phy *generic_phy;
+	struct ufs_qcom_phy_qmp_v3_660 *phy;
+	int err = 0;
+
+	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+	if (!phy) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	generic_phy = ufs_qcom_phy_generic_probe(pdev, &phy->common_cfg,
+				&ufs_qcom_phy_qmp_v3_660_phy_ops,
+				&phy_v3_660_ops);
+
+	if (!generic_phy) {
+		dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
+			__func__);
+		err = -EIO;
+		goto out;
+	}
+
+	phy_set_drvdata(generic_phy, phy);
+
+	strlcpy(phy->common_cfg.name, UFS_PHY_NAME,
+		sizeof(phy->common_cfg.name));
+
+out:
+	return err;
+}
+
+static int ufs_qcom_phy_qmp_v3_660_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct phy *generic_phy = to_phy(dev);
+	struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
+	int err = 0;
+
+	err = ufs_qcom_phy_remove(generic_phy, ufs_qcom_phy);
+	if (err)
+		dev_err(dev, "%s: ufs_qcom_phy_remove failed = %d\n",
+			__func__, err);
+
+	return err;
+}
+
+static const struct of_device_id ufs_qcom_phy_qmp_v3_660_of_match[] = {
+	{.compatible = "qcom,ufs-phy-qmp-v3-660"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qmp_v3_660_of_match);
+
+static struct platform_driver ufs_qcom_phy_qmp_v3_660_driver = {
+	.probe = ufs_qcom_phy_qmp_v3_660_probe,
+	.remove = ufs_qcom_phy_qmp_v3_660_remove,
+	.driver = {
+		.of_match_table = ufs_qcom_phy_qmp_v3_660_of_match,
+		.name = "ufs_qcom_phy_qmp_v3_660",
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(ufs_qcom_phy_qmp_v3_660_driver);
+
+MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QMP v3 660");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3-660.h b/drivers/phy/phy-qcom-ufs-qmp-v3-660.h
new file mode 100644
index 0000000..89fa5d3
--- /dev/null
+++ b/drivers/phy/phy-qcom-ufs-qmp-v3-660.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2013-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.
+ *
+ */
+
+#ifndef UFS_QCOM_PHY_QMP_V3_660_H_
+#define UFS_QCOM_PHY_QMP_V3_660_H_
+
+#include "phy-qcom-ufs-i.h"
+
+/* QCOM UFS PHY control registers */
+#define COM_BASE	0x000
+#define COM_OFF(x)	(COM_BASE + x)
+#define COM_SIZE	0x1C0
+
+#define TX_BASE		0x400
+#define TX_OFF(x)	(TX_BASE + x)
+#define TX_SIZE		0x128
+
+#define RX_BASE		0x600
+#define RX_OFF(x)	(RX_BASE + x)
+#define RX_SIZE		0x1FC
+
+#define PHY_BASE	0xC00
+#define PHY_OFF(x)	(PHY_BASE + x)
+#define PHY_SIZE	0x1B4
+
+/* UFS PHY QSERDES COM registers */
+#define QSERDES_COM_ATB_SEL1			COM_OFF(0x00)
+#define QSERDES_COM_ATB_SEL2			COM_OFF(0x04)
+#define QSERDES_COM_FREQ_UPDATE			COM_OFF(0x08)
+#define QSERDES_COM_BG_TIMER			COM_OFF(0x0C)
+#define QSERDES_COM_SSC_EN_CENTER		COM_OFF(0x10)
+#define QSERDES_COM_SSC_ADJ_PER1		COM_OFF(0x14)
+#define QSERDES_COM_SSC_ADJ_PER2		COM_OFF(0x18)
+#define QSERDES_COM_SSC_PER1			COM_OFF(0x1C)
+#define QSERDES_COM_SSC_PER2			COM_OFF(0x20)
+#define QSERDES_COM_SSC_STEP_SIZE1		COM_OFF(0x24)
+#define QSERDES_COM_SSC_STEP_SIZE2		COM_OFF(0x28)
+#define QSERDES_COM_POST_DIV			COM_OFF(0x2C)
+#define QSERDES_COM_POST_DIV_MUX		COM_OFF(0x30)
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN		COM_OFF(0x34)
+#define QSERDES_COM_CLK_ENABLE1			COM_OFF(0x38)
+#define QSERDES_COM_SYS_CLK_CTRL		COM_OFF(0x3C)
+#define QSERDES_COM_SYSCLK_BUF_ENABLE		COM_OFF(0x40)
+#define QSERDES_COM_PLL_EN			COM_OFF(0x44)
+#define QSERDES_COM_PLL_IVCO			COM_OFF(0x48)
+#define QSERDES_COM_LOCK_CMP1_MODE0		COM_OFF(0X4C)
+#define QSERDES_COM_LOCK_CMP2_MODE0		COM_OFF(0X50)
+#define QSERDES_COM_LOCK_CMP3_MODE0		COM_OFF(0X54)
+#define QSERDES_COM_LOCK_CMP1_MODE1		COM_OFF(0X58)
+#define QSERDES_COM_LOCK_CMP2_MODE1		COM_OFF(0X5C)
+#define QSERDES_COM_LOCK_CMP3_MODE1		COM_OFF(0X60)
+#define QSERDES_COM_CMD_RSVD0			COM_OFF(0x64)
+#define QSERDES_COM_EP_CLOCK_DETECT_CTRL	COM_OFF(0x68)
+#define QSERDES_COM_SYSCLK_DET_COMP_STATUS	COM_OFF(0x6C)
+#define QSERDES_COM_BG_TRIM			COM_OFF(0x70)
+#define QSERDES_COM_CLK_EP_DIV			COM_OFF(0x74)
+#define QSERDES_COM_CP_CTRL_MODE0		COM_OFF(0x78)
+#define QSERDES_COM_CP_CTRL_MODE1		COM_OFF(0x7C)
+#define QSERDES_COM_CMN_RSVD1			COM_OFF(0x80)
+#define QSERDES_COM_PLL_RCTRL_MODE0		COM_OFF(0x84)
+#define QSERDES_COM_PLL_RCTRL_MODE1		COM_OFF(0x88)
+#define QSERDES_COM_CMN_RSVD2			COM_OFF(0x8C)
+#define QSERDES_COM_PLL_CCTRL_MODE0		COM_OFF(0x90)
+#define QSERDES_COM_PLL_CCTRL_MODE1		COM_OFF(0x94)
+#define QSERDES_COM_CMN_RSVD3			COM_OFF(0x98)
+#define QSERDES_COM_PLL_CNTRL			COM_OFF(0x9C)
+#define QSERDES_COM_PHASE_SEL_CTRL		COM_OFF(0xA0)
+#define QSERDES_COM_PHASE_SEL_DC		COM_OFF(0xA4)
+#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM		COM_OFF(0xA8)
+#define QSERDES_COM_SYSCLK_EN_SEL		COM_OFF(0xAC)
+#define QSERDES_COM_CML_SYSCLK_SEL		COM_OFF(0xB0)
+#define QSERDES_COM_RESETSM_CNTRL		COM_OFF(0xB4)
+#define QSERDES_COM_RESETSM_CNTRL2		COM_OFF(0xB8)
+#define QSERDES_COM_RESTRIM_CTRL		COM_OFF(0xBC)
+#define QSERDES_COM_RESTRIM_CTRL2		COM_OFF(0xC0)
+#define QSERDES_COM_LOCK_CMP_EN			COM_OFF(0xC8)
+#define QSERDES_COM_LOCK_CMP_CFG		COM_OFF(0xCC)
+#define QSERDES_COM_DEC_START_MODE0		COM_OFF(0xD0)
+#define QSERDES_COM_DEC_START_MODE1		COM_OFF(0xD4)
+#define QSERDES_COM_VCOCAL_DEADMAN_CTRL		COM_OFF(0xD8)
+#define QSERDES_COM_DIV_FRAC_START1_MODE0	COM_OFF(0xDC)
+#define QSERDES_COM_DIV_FRAC_START2_MODE0	COM_OFF(0xE0)
+#define QSERDES_COM_DIV_FRAC_START3_MODE0	COM_OFF(0xE4)
+#define QSERDES_COM_DIV_FRAC_START1_MODE1	COM_OFF(0xE8)
+#define QSERDES_COM_DIV_FRAC_START2_MODE1	COM_OFF(0xEC)
+#define QSERDES_COM_DIV_FRAC_START3_MODE1	COM_OFF(0xF0)
+#define QSERDES_COM_VCO_TUNE_MINVAL1		COM_OFF(0xF4)
+#define QSERDES_COM_VCO_TUNE_MINVAL2		COM_OFF(0xF8)
+#define QSERDES_COM_CMN_RSVD4			COM_OFF(0xFC)
+#define QSERDES_COM_INTEGLOOP_INITVAL		COM_OFF(0x100)
+#define QSERDES_COM_INTEGLOOP_EN		COM_OFF(0x104)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0	COM_OFF(0x108)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0	COM_OFF(0x10C)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1	COM_OFF(0x110)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1	COM_OFF(0x114)
+#define QSERDES_COM_VCO_TUNE_MAXVAL1		COM_OFF(0x118)
+#define QSERDES_COM_VCO_TUNE_MAXVAL2		COM_OFF(0x11C)
+#define QSERDES_COM_RES_TRIM_CONTROL2		COM_OFF(0x120)
+#define QSERDES_COM_VCO_TUNE_CTRL		COM_OFF(0x124)
+#define QSERDES_COM_VCO_TUNE_MAP		COM_OFF(0x128)
+#define QSERDES_COM_VCO_TUNE1_MODE0		COM_OFF(0x12C)
+#define QSERDES_COM_VCO_TUNE2_MODE0		COM_OFF(0x130)
+#define QSERDES_COM_VCO_TUNE1_MODE1		COM_OFF(0x134)
+#define QSERDES_COM_VCO_TUNE2_MODE1		COM_OFF(0x138)
+#define QSERDES_COM_VCO_TUNE_INITVAL1		COM_OFF(0x13C)
+#define QSERDES_COM_VCO_TUNE_INITVAL2		COM_OFF(0x140)
+#define QSERDES_COM_VCO_TUNE_TIMER1		COM_OFF(0x144)
+#define QSERDES_COM_VCO_TUNE_TIMER2		COM_OFF(0x148)
+#define QSERDES_COM_SAR				COM_OFF(0x14C)
+#define QSERDES_COM_SAR_CLK			COM_OFF(0x150)
+#define QSERDES_COM_SAR_CODE_OUT_STATUS		COM_OFF(0x154)
+#define QSERDES_COM_SAR_CODE_READY_STATUS	COM_OFF(0x158)
+#define QSERDES_COM_CMN_STATUS			COM_OFF(0x15C)
+#define QSERDES_COM_RESET_SM_STATUS		COM_OFF(0x160)
+#define QSERDES_COM_RESTRIM_CODE_STATUS		COM_OFF(0x164)
+#define QSERDES_COM_PLLCAL_CODE1_STATUS		COM_OFF(0x168)
+#define QSERDES_COM_PLLCAL_CODE2_STATUS		COM_OFF(0x16C)
+#define QSERDES_COM_BG_CTRL			COM_OFF(0x170)
+#define QSERDES_COM_CLK_SELECT			COM_OFF(0x174)
+#define QSERDES_COM_HSCLK_SEL			COM_OFF(0x178)
+#define QSERDES_COM_INTEGLOOP_BINCODE_STATUS	COM_OFF(0x17C)
+#define QSERDES_COM_PLL_ANALOG			COM_OFF(0x180)
+#define QSERDES_COM_CORECLK_DIV			COM_OFF(0x184)
+#define QSERDES_COM_SW_RESET			COM_OFF(0x188)
+#define QSERDES_COM_CORE_CLK_EN			COM_OFF(0x18C)
+#define QSERDES_COM_C_READY_STATUS		COM_OFF(0x190)
+#define QSERDES_COM_CMN_CONFIG			COM_OFF(0x194)
+#define QSERDES_COM_CMN_RATE_OVERRIDE		COM_OFF(0x198)
+#define QSERDES_COM_SVS_MODE_CLK_SEL		COM_OFF(0x19C)
+#define QSERDES_COM_DEBUG_BUS0			COM_OFF(0x1A0)
+#define QSERDES_COM_DEBUG_BUS1			COM_OFF(0x1A4)
+#define QSERDES_COM_DEBUG_BUS2			COM_OFF(0x1A8)
+#define QSERDES_COM_DEBUG_BUS3			COM_OFF(0x1AC)
+#define QSERDES_COM_DEBUG_BUS_SEL		COM_OFF(0x1B0)
+#define QSERDES_COM_CMN_MISC1			COM_OFF(0x1B4)
+#define QSERDES_COM_CORECLK_DIV_MODE1		COM_OFF(0x1BC)
+#define QSERDES_COM_CMN_RSVD5			COM_OFF(0x1C0)
+
+/* UFS PHY registers */
+#define UFS_PHY_PHY_START			PHY_OFF(0x00)
+#define UFS_PHY_POWER_DOWN_CONTROL		PHY_OFF(0x04)
+#define UFS_PHY_TX_LARGE_AMP_DRV_LVL		PHY_OFF(0x34)
+#define UFS_PHY_TX_SMALL_AMP_DRV_LVL		PHY_OFF(0x3C)
+#define UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAP	PHY_OFF(0xCC)
+#define UFS_PHY_LINECFG_DISABLE			PHY_OFF(0x138)
+#define UFS_PHY_RX_SYM_RESYNC_CTRL		PHY_OFF(0x13C)
+#define UFS_PHY_RX_SIGDET_CTRL2			PHY_OFF(0x148)
+#define UFS_PHY_RX_PWM_GEAR_BAND		PHY_OFF(0x154)
+#define UFS_PHY_PCS_READY_STATUS		PHY_OFF(0x168)
+
+/* UFS PHY TX registers */
+#define QSERDES_TX_HIGHZ_TRANSCEIVER_BIAS_DRVR_EN	TX_OFF(0x68)
+#define	QSERDES_TX_LANE_MODE				TX_OFF(0x94)
+
+/* UFS PHY RX registers */
+#define QSERDES_RX_UCDR_SVS_SO_GAIN_HALF	RX_OFF(0x30)
+#define QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER	RX_OFF(0x34)
+#define QSERDES_RX_UCDR_SVS_SO_GAIN_EIGHTH	RX_OFF(0x38)
+#define QSERDES_RX_UCDR_SVS_SO_GAIN		RX_OFF(0x3C)
+#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN	RX_OFF(0x40)
+#define QSERDES_RX_UCDR_SO_SATURATION_ENABLE	RX_OFF(0x48)
+#define QSERDES_RX_RX_TERM_BW			RX_OFF(0x90)
+#define QSERDES_RX_RX_EQ_GAIN1_LSB		RX_OFF(0xC4)
+#define QSERDES_RX_RX_EQ_GAIN1_MSB		RX_OFF(0xC8)
+#define QSERDES_RX_RX_EQ_GAIN2_LSB		RX_OFF(0xCC)
+#define QSERDES_RX_RX_EQ_GAIN2_MSB		RX_OFF(0xD0)
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2	RX_OFF(0xD8)
+#define QSERDES_RX_SIGDET_CNTRL			RX_OFF(0x114)
+#define QSERDES_RX_SIGDET_LVL			RX_OFF(0x118)
+#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL	RX_OFF(0x11C)
+#define QSERDES_RX_RX_INTERFACE_MODE		RX_OFF(0x12C)
+
+
+#define UFS_PHY_RX_LINECFG_DISABLE_BIT		BIT(1)
+
+/*
+ * This structure represents the v3 660 specific phy.
+ * common_cfg MUST remain the first field in this structure
+ * in case extra fields are added. This way, when calling
+ * get_ufs_qcom_phy() of generic phy, we can extract the
+ * common phy structure (struct ufs_qcom_phy) out of it
+ * regardless of the relevant specific phy.
+ */
+struct ufs_qcom_phy_qmp_v3_660 {
+	struct ufs_qcom_phy common_cfg;
+};
+
+static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_3_1_1[] = {
+	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CMN_CONFIG, 0x0e),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL, 0x14),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CLK_SELECT, 0x30),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYS_CLK_CTRL, 0x02),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BG_TIMER, 0x0a),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_HSCLK_SEL, 0x00),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV, 0x0a),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_EN, 0x01),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_CTRL, 0x00),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x20),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORE_CLK_EN, 0x00),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_CFG, 0x00),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER1, 0xff),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x04),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE0, 0x82),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE0, 0x0b),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE0, 0x28),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE0, 0x02),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0xff),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE1, 0x98),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE1, 0x0b),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE1, 0x16),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x28),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE1, 0x00),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE1, 0x00),
+
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_HIGHZ_TRANSCEIVER_BIAS_DRVR_EN, 0x45),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE, 0x06),
+
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_LVL, 0x24),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL, 0x0F),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_INTERFACE_MODE, 0x40),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x1E),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_TERM_BW, 0x5B),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xFF),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3F),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xFF),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x3F),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0D),
+
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IVCO, 0x0F),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BG_TRIM, 0x0F),
+	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_PWM_GEAR_BAND, 0x15),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SVS_SO_GAIN_HALF, 0x04),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SVS_SO_GAIN, 0x04),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SO_SATURATION_ENABLE, 0x4B),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL1, 0xFF),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL2, 0x00),
+	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL2, 0x6c),
+	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0A),
+	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x02),
+	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAP, 0x28),
+	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SYM_RESYNC_CTRL, 0x03),
+};
+
+static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = {
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x44),
+};
+
+#endif
diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3.c b/drivers/phy/phy-qcom-ufs-qmp-v3.c
index 6b8dbc2..0bfde0c7 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-v3.c
+++ b/drivers/phy/phy-qcom-ufs-qmp-v3.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-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
@@ -20,26 +20,24 @@
 int ufs_qcom_phy_qmp_v3_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
 					bool is_rate_B)
 {
-	int err;
-	int tbl_size_A, tbl_size_B;
-	struct ufs_qcom_phy_calibration *tbl_A, *tbl_B;
+	/*
+	 * Writing PHY calibration in this order:
+	 * 1. Write Rate-A calibration first (1-lane mode).
+	 * 2. Write 2nd lane configuration if needed.
+	 * 3. Write Rate-B calibration overrides
+	 */
+	ufs_qcom_phy_write_tbl(ufs_qcom_phy, phy_cal_table_rate_A,
+			       ARRAY_SIZE(phy_cal_table_rate_A));
+	if (ufs_qcom_phy->lanes_per_direction == 2)
+		ufs_qcom_phy_write_tbl(ufs_qcom_phy, phy_cal_table_2nd_lane,
+				       ARRAY_SIZE(phy_cal_table_2nd_lane));
+	if (is_rate_B)
+		ufs_qcom_phy_write_tbl(ufs_qcom_phy, phy_cal_table_rate_B,
+				       ARRAY_SIZE(phy_cal_table_rate_B));
+	/* flush buffered writes */
+	mb();
 
-	tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
-	tbl_B = phy_cal_table_rate_B;
-
-	tbl_A = phy_cal_table_rate_A;
-	tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A);
-
-	err = ufs_qcom_phy_calibrate(ufs_qcom_phy,
-				     tbl_A, tbl_size_A,
-				     tbl_B, tbl_size_B,
-				     is_rate_B);
-
-	if (err)
-		dev_err(ufs_qcom_phy->dev,
-			"%s: ufs_qcom_phy_calibrate() failed %d\n",
-			__func__, err);
-	return err;
+	return 0;
 }
 
 static int ufs_qcom_phy_qmp_v3_init(struct phy *generic_phy)
@@ -145,37 +143,20 @@
 	return err;
 }
 
-static
-int ufs_qcom_phy_qmp_v3_configure_lpm(struct ufs_qcom_phy *ufs_qcom_phy,
-					bool enable)
+static void ufs_qcom_phy_qmp_v3_dbg_register_dump(struct ufs_qcom_phy *phy)
 {
-	int err = 0;
-	int tbl_size;
-	struct ufs_qcom_phy_calibration *tbl = NULL;
-
-	/* The default low power mode configuration is SVS2 */
-	if (enable) {
-		tbl_size = ARRAY_SIZE(phy_cal_table_svs2_enable);
-		tbl = phy_cal_table_svs2_enable;
-	} else {
-		tbl_size = ARRAY_SIZE(phy_cal_table_svs2_disable);
-		tbl = phy_cal_table_svs2_disable;
-	}
-
-	if (!tbl) {
-		dev_err(ufs_qcom_phy->dev, "%s: tbl for SVS2 %s is NULL",
-			__func__, enable ? "enable" : "disable");
-		err = -EINVAL;
-		goto out;
-	}
-
-	ufs_qcom_phy_write_tbl(ufs_qcom_phy, tbl, tbl_size);
-
-	/* flush buffered writes */
-	mb();
-
-out:
-	return err;
+	ufs_qcom_phy_dump_regs(phy, COM_BASE, COM_SIZE,
+					"PHY QSERDES COM Registers ");
+	ufs_qcom_phy_dump_regs(phy, PHY_BASE, PHY_SIZE,
+					"PHY Registers ");
+	ufs_qcom_phy_dump_regs(phy, RX_BASE(0), RX_SIZE,
+					"PHY RX0 Registers ");
+	ufs_qcom_phy_dump_regs(phy, TX_BASE(0), TX_SIZE,
+					"PHY TX0 Registers ");
+	ufs_qcom_phy_dump_regs(phy, RX_BASE(1), RX_SIZE,
+					"PHY RX1 Registers ");
+	ufs_qcom_phy_dump_regs(phy, TX_BASE(1), TX_SIZE,
+					"PHY TX1 Registers ");
 }
 
 struct phy_ops ufs_qcom_phy_qmp_v3_phy_ops = {
@@ -193,7 +174,7 @@
 	.set_tx_lane_enable	= ufs_qcom_phy_qmp_v3_set_tx_lane_enable,
 	.ctrl_rx_linecfg	= ufs_qcom_phy_qmp_v3_ctrl_rx_linecfg,
 	.power_control		= ufs_qcom_phy_qmp_v3_power_control,
-	.configure_lpm		= ufs_qcom_phy_qmp_v3_configure_lpm,
+	.dbg_register_dump	= ufs_qcom_phy_qmp_v3_dbg_register_dump,
 };
 
 static int ufs_qcom_phy_qmp_v3_probe(struct platform_device *pdev)
diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3.h b/drivers/phy/phy-qcom-ufs-qmp-v3.h
index e9ac76b..4851aac 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-v3.h
+++ b/drivers/phy/phy-qcom-ufs-qmp-v3.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-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
@@ -18,10 +18,18 @@
 #include "phy-qcom-ufs-i.h"
 
 /* QCOM UFS PHY control registers */
-#define COM_OFF(x)	(0x000 + x)
-#define PHY_OFF(x)	(0xC00 + x)
-#define TX_OFF(n, x)	(0x400 + (0x400 * n) + x)
-#define RX_OFF(n, x)	(0x600 + (0x400 * n) + x)
+#define COM_BASE	0x000
+#define COM_SIZE	0x18C
+#define PHY_BASE	0xC00
+#define PHY_SIZE	0x1DC
+#define TX_BASE(n)	(0x400 + (0x400 * n))
+#define TX_SIZE		0x128
+#define RX_BASE(n)	(0x600 + (0x400 * n))
+#define RX_SIZE		0x1FC
+#define COM_OFF(x)	(COM_BASE + x)
+#define PHY_OFF(x)	(PHY_BASE + x)
+#define TX_OFF(n, x)	(TX_BASE(n) + x)
+#define RX_OFF(n, x)	(RX_BASE(n) + x)
 
 /* UFS PHY QSERDES COM registers */
 #define QSERDES_COM_ATB_SEL1			COM_OFF(0x00)
@@ -133,9 +141,13 @@
 #define UFS_PHY_TX_SMALL_AMP_DRV_LVL		PHY_OFF(0x34)
 #define UFS_PHY_LINECFG_DISABLE			PHY_OFF(0x130)
 #define UFS_PHY_RX_SYM_RESYNC_CTRL		PHY_OFF(0x134)
+#define UFS_PHY_RX_MIN_HIBERN8_TIME		PHY_OFF(0x138)
+#define UFS_PHY_RX_SIGDET_CTRL1			PHY_OFF(0x13C)
 #define UFS_PHY_RX_SIGDET_CTRL2			PHY_OFF(0x140)
 #define UFS_PHY_RX_PWM_GEAR_BAND		PHY_OFF(0x14C)
 #define UFS_PHY_PCS_READY_STATUS		PHY_OFF(0x160)
+#define UFS_PHY_TX_MID_TERM_CTRL1		PHY_OFF(0x1BC)
+#define UFS_PHY_MULTI_LANE_CTRL1		PHY_OFF(0x1C4)
 
 /* UFS PHY TX registers */
 #define QSERDES_TX0_TRANSCEIVER_BIAS_EN		TX_OFF(0, 0x5C)
@@ -143,6 +155,9 @@
 #define QSERDES_TX0_LANE_MODE_2			TX_OFF(0, 0x90)
 #define QSERDES_TX0_LANE_MODE_3			TX_OFF(0, 0x94)
 
+#define QSERDES_TX1_LANE_MODE_1			TX_OFF(1, 0x8C)
+
+
 /* UFS PHY RX registers */
 #define QSERDES_RX0_UCDR_SVS_SO_GAIN_HALF		RX_OFF(0, 0x24)
 #define QSERDES_RX0_UCDR_SVS_SO_GAIN_QUARTER		RX_OFF(0, 0x28)
@@ -163,6 +178,22 @@
 #define QSERDES_RX0_SIGDET_DEGLITCH_CNTRL		RX_OFF(0, 0x10C)
 #define QSERDES_RX0_RX_INTERFACE_MODE			RX_OFF(0, 0x11C)
 
+#define QSERDES_RX1_UCDR_SVS_SO_GAIN_HALF		RX_OFF(1, 0x24)
+#define QSERDES_RX1_UCDR_SVS_SO_GAIN_QUARTER		RX_OFF(1, 0x28)
+#define QSERDES_RX1_UCDR_SVS_SO_GAIN			RX_OFF(1, 0x2C)
+#define QSERDES_RX1_UCDR_FASTLOCK_FO_GAIN		RX_OFF(1, 0x30)
+#define QSERDES_RX1_UCDR_SO_SATURATION_AND_ENABLE	RX_OFF(1, 0x34)
+#define QSERDES_RX1_UCDR_FASTLOCK_COUNT_LOW		RX_OFF(1, 0x3C)
+#define QSERDES_RX1_UCDR_PI_CONTROLS			RX_OFF(1, 0x44)
+#define QSERDES_RX1_RX_TERM_BW				RX_OFF(1, 0x7C)
+#define QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL2		RX_OFF(1, 0xD4)
+#define QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL3		RX_OFF(1, 0xD8)
+#define QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL4		RX_OFF(1, 0xDC)
+#define QSERDES_RX1_SIGDET_CNTRL			RX_OFF(1, 0x104)
+#define QSERDES_RX1_SIGDET_LVL				RX_OFF(1, 0x108)
+#define QSERDES_RX1_SIGDET_DEGLITCH_CNTRL		RX_OFF(1, 0x10C)
+#define QSERDES_RX1_RX_INTERFACE_MODE			RX_OFF(1, 0x11C)
+
 #define UFS_PHY_RX_LINECFG_DISABLE_BIT		BIT(1)
 
 /*
@@ -181,6 +212,7 @@
 	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CMN_CONFIG, 0x06),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL, 0xD5),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x20),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CLK_SELECT, 0x30),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYS_CLK_CTRL, 0x02),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x04),
@@ -195,22 +227,22 @@
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL1, 0xFF),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL2, 0x00),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE0, 0x82),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE0, 0x08),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE0, 0x06),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE0, 0x34),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE0, 0x36),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x3F),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE0, 0xCB),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE0, 0xDA),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE0, 0x01),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0xFF),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x0C),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE1, 0x98),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE1, 0x08),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE1, 0x06),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE1, 0x16),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x34),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x36),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x3F),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE1, 0xB2),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE1, 0xC1),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE1, 0x00),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0F),
@@ -234,42 +266,33 @@
 	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0A),
 	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x02),
 	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SYM_RESYNC_CTRL, 0x03),
+	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_MID_TERM_CTRL1, 0x43),
+	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL1, 0x0F),
+	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_MIN_HIBERN8_TIME, 0x9A), /* 8 us */
+};
+
+static struct ufs_qcom_phy_calibration phy_cal_table_2nd_lane[] = {
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX1_LANE_MODE_1, 0x06),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_SIGDET_LVL, 0x24),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_SIGDET_CNTRL, 0x0F),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_SIGDET_DEGLITCH_CNTRL, 0x1E),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_INTERFACE_MODE, 0x40),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_FASTLOCK_FO_GAIN, 0x0B),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_TERM_BW, 0x5B),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL2, 0x06),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL3, 0x04),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL4, 0x1D),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SVS_SO_GAIN_HALF, 0x04),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SVS_SO_GAIN_QUARTER, 0x04),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SVS_SO_GAIN, 0x04),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SO_SATURATION_AND_ENABLE, 0x4B),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_PI_CONTROLS, 0xF1),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_FASTLOCK_COUNT_LOW, 0x80),
+	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_MULTI_LANE_CTRL1, 0x02),
 };
 
 static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = {
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x44),
 };
 
-static struct ufs_qcom_phy_calibration phy_cal_table_svs2_enable[] = {
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE0, 0x14),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE1, 0x14),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SVS_MODE_CLK_SEL, 0x0a),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x7e),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0x7f),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x06),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x7e),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x99),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x07),
-	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_MSB, 0x0b),
-	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_LSB, 0x66),
-};
-
-static struct ufs_qcom_phy_calibration phy_cal_table_svs2_disable[] = {
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE0, 0x0a),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0xff),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x3f),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f),
-	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_MSB, 0x16),
-	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_LSB, 0xcc),
-};
-
 #endif
diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c
index b8b9080..d18929f 100644
--- a/drivers/phy/phy-qcom-ufs.c
+++ b/drivers/phy/phy-qcom-ufs.c
@@ -15,13 +15,15 @@
 #include "phy-qcom-ufs-i.h"
 
 #define MAX_PROP_NAME              32
-#define VDDA_PHY_MIN_UV            1000000
-#define VDDA_PHY_MAX_UV            1000000
+#define VDDA_PHY_MIN_UV            800000
+#define VDDA_PHY_MAX_UV            925000
 #define VDDA_PLL_MIN_UV            1200000
 #define VDDA_PLL_MAX_UV            1800000
 #define VDDP_REF_CLK_MIN_UV        1200000
 #define VDDP_REF_CLK_MAX_UV        1200000
 
+#define UFS_PHY_DEFAULT_LANES_PER_DIRECTION	1
+
 static int __ufs_qcom_phy_init_vreg(struct phy *, struct ufs_qcom_phy_vreg *,
 				    const char *, bool);
 static int ufs_qcom_phy_init_vreg(struct phy *, struct ufs_qcom_phy_vreg *,
@@ -113,6 +115,19 @@
 		goto out;
 	}
 
+	if (of_property_read_u32(dev->of_node, "lanes-per-direction",
+				 &common_cfg->lanes_per_direction))
+		common_cfg->lanes_per_direction =
+			UFS_PHY_DEFAULT_LANES_PER_DIRECTION;
+
+	/*
+	 * UFS PHY power management is managed by its parent (UFS host
+	 * controller) hence set the no the no runtime PM callbacks flag
+	 * on UFS PHY device to avoid any accidental attempt to call the
+	 * PM callbacks for PHY device.
+	 */
+	pm_runtime_no_callbacks(&generic_phy->dev);
+
 	common_cfg->phy_spec_ops = phy_spec_ops;
 	common_cfg->dev = dev;
 
@@ -191,27 +206,20 @@
 		       struct ufs_qcom_phy *phy_common)
 {
 	int err;
-	struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
 
-	err = ufs_qcom_phy_clk_get(generic_phy, "tx_iface_clk",
-				   &phy_common->tx_iface_clk);
 	/*
 	 * tx_iface_clk does not exist in newer version of ufs-phy HW,
 	 * so don't return error if it is not found
 	 */
-	if (err)
-		dev_dbg(phy->dev, "%s: failed to get tx_iface_clk\n",
-			__func__);
+	__ufs_qcom_phy_clk_get(generic_phy, "tx_iface_clk",
+				   &phy_common->tx_iface_clk, false);
 
-	err = ufs_qcom_phy_clk_get(generic_phy, "rx_iface_clk",
-				   &phy_common->rx_iface_clk);
 	/*
 	 * rx_iface_clk does not exist in newer version of ufs-phy HW,
 	 * so don't return error if it is not found
 	 */
-	if (err)
-		dev_dbg(phy->dev, "%s: failed to get rx_iface_clk\n",
-			__func__);
+	__ufs_qcom_phy_clk_get(generic_phy, "rx_iface_clk",
+				   &phy_common->rx_iface_clk, false);
 
 	err = ufs_qcom_phy_clk_get(generic_phy, "ref_clk_src",
 				   &phy_common->ref_clk_src);
@@ -246,7 +254,6 @@
 			      struct ufs_qcom_phy *phy_common)
 {
 	int err;
-	int vdda_phy_uV;
 
 	err = ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vdda_pll,
 		"vdda-pll");
@@ -258,10 +265,6 @@
 	if (err)
 		goto out;
 
-	vdda_phy_uV = regulator_get_voltage(phy_common->vdda_phy.reg);
-	phy_common->vdda_phy.max_uV = vdda_phy_uV;
-	phy_common->vdda_phy.min_uV = vdda_phy_uV;
-
 	/* vddp-ref-clk-* properties are optional */
 	__ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vddp_ref_clk,
 				 "vddp-ref-clk", true);
@@ -279,6 +282,14 @@
 
 	char prop_name[MAX_PROP_NAME];
 
+	if (dev->of_node) {
+		snprintf(prop_name, MAX_PROP_NAME, "%s-supply", name);
+		if (!of_parse_phandle(dev->of_node, prop_name, 0)) {
+			dev_dbg(dev, "No vreg data found for %s\n", prop_name);
+			return optional ? err : -ENODATA;
+		}
+	}
+
 	vreg->name = kstrdup(name, GFP_KERNEL);
 	if (!vreg->name) {
 		err = -ENOMEM;
@@ -786,3 +797,21 @@
 	return ret;
 }
 EXPORT_SYMBOL(ufs_qcom_phy_configure_lpm);
+
+void ufs_qcom_phy_dump_regs(struct ufs_qcom_phy *phy, int offset,
+				int len, char *prefix)
+{
+	print_hex_dump(KERN_ERR, prefix,
+			len > 4 ? DUMP_PREFIX_OFFSET : DUMP_PREFIX_NONE,
+			16, 4, phy->mmio + offset, len, false);
+}
+EXPORT_SYMBOL(ufs_qcom_phy_dump_regs);
+
+void ufs_qcom_phy_dbg_register_dump(struct phy *generic_phy)
+{
+	struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
+
+	if (ufs_qcom_phy->phy_spec_ops->dbg_register_dump)
+		ufs_qcom_phy->phy_spec_ops->dbg_register_dump(ufs_qcom_phy);
+}
+EXPORT_SYMBOL(ufs_qcom_phy_dbg_register_dump);
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 522c724..ba6d5ce 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -146,4 +146,11 @@
 	  This is the pinctrl, pinmux, pinconf and gpiolib driver for the
 	  WCD gpio controller block.
 
+config PINCTRL_LPI
+	tristate "Qualcomm Technologies, Inc LPI pin controller driver"
+	depends on GPIOLIB && OF
+	help
+	  This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+	  LPI gpio controller block.
+
 endif
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 7c74288..5e05e897 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -18,3 +18,4 @@
 obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o
 obj-$(CONFIG_PINCTRL_SDM830) += pinctrl-sdm830.o
 obj-$(CONFIG_PINCTRL_WCD)	+= pinctrl-wcd.o
+obj-$(CONFIG_PINCTRL_LPI)	+= pinctrl-lpi.o
diff --git a/drivers/pinctrl/qcom/pinctrl-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpi.c
new file mode 100644
index 0000000..009e27bf
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-lpi.c
@@ -0,0 +1,638 @@
+/*
+ * 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
+ * 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/gpio.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/qdsp6v2/audio_notifier.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+
+#define LPI_ADDRESS_SIZE			0xC000
+
+#define LPI_GPIO_REG_VAL_CTL			0x00
+#define LPI_GPIO_REG_DIR_CTL			0x04
+
+#define LPI_GPIO_REG_PULL_SHIFT			0x0
+#define LPI_GPIO_REG_PULL_MASK			0x3
+
+#define LPI_GPIO_REG_FUNCTION_SHIFT		0x2
+#define LPI_GPIO_REG_FUNCTION_MASK		0x3C
+
+#define LPI_GPIO_REG_OUT_STRENGTH_SHIFT		0x6
+#define LPI_GPIO_REG_OUT_STRENGTH_MASK		0x1C0
+
+#define LPI_GPIO_REG_OE_SHIFT			0x9
+#define LPI_GPIO_REG_OE_MASK			0x200
+
+#define LPI_GPIO_REG_DIR_SHIFT			0x1
+#define LPI_GPIO_REG_DIR_MASK			0x2
+
+#define LPI_GPIO_BIAS_DISABLE			0x0
+#define LPI_GPIO_PULL_DOWN			0x1
+#define LPI_GPIO_KEEPER				0x2
+#define LPI_GPIO_PULL_UP			0x3
+
+#define LPI_GPIO_FUNC_GPIO			"gpio"
+#define LPI_GPIO_FUNC_FUNC1			"func1"
+#define LPI_GPIO_FUNC_FUNC2			"func2"
+#define LPI_GPIO_FUNC_FUNC3			"func3"
+#define LPI_GPIO_FUNC_FUNC4			"func4"
+#define LPI_GPIO_FUNC_FUNC5			"func5"
+
+static bool lpi_dev_up;
+
+/* The index of each function in lpi_gpio_functions[] array */
+enum lpi_gpio_func_index {
+	LPI_GPIO_FUNC_INDEX_GPIO	= 0x00,
+	LPI_GPIO_FUNC_INDEX_FUNC1	= 0x01,
+	LPI_GPIO_FUNC_INDEX_FUNC2	= 0x02,
+	LPI_GPIO_FUNC_INDEX_FUNC3	= 0x03,
+	LPI_GPIO_FUNC_INDEX_FUNC4	= 0x04,
+	LPI_GPIO_FUNC_INDEX_FUNC5	= 0x05,
+};
+
+/**
+ * struct lpi_gpio_pad - keep current GPIO settings
+ * @offset: Nth GPIO in supported GPIOs.
+ * @output_enabled: Set to true if GPIO output logic is enabled.
+ * @value: value of a pin
+ * @base: Address base of LPI GPIO PAD.
+ * @pullup: Constant current which flow through GPIO output buffer.
+ * @strength: No, Low, Medium, High
+ * @function: See lpi_gpio_functions[]
+ */
+struct lpi_gpio_pad {
+	u16		offset;
+	bool		output_enabled;
+	bool		value;
+	char __iomem	*base;
+	unsigned int	pullup;
+	unsigned int	strength;
+	unsigned int	function;
+};
+
+struct lpi_gpio_state {
+	struct device	*dev;
+	struct pinctrl_dev *ctrl;
+	struct gpio_chip chip;
+	char __iomem	*base;
+};
+
+static const char *const lpi_gpio_groups[] = {
+	"gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+	"gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+	"gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+	"gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+	"gpio29", "gpio30", "gpio31",
+};
+
+static const u32 lpi_offset[] = {
+	0x00000000,
+	0x00001000,
+	0x00002000,
+	0x00002010,
+	0x00003000,
+	0x00003010,
+	0x00004000,
+	0x00004010,
+	0x00005000,
+	0x00005010,
+	0x00005020,
+	0x00005030,
+	0x00005040,
+	0x00005050,
+	0x00006000,
+	0x00006010,
+	0x00007000,
+	0x00007010,
+	0x00008000,
+	0x00008010,
+	0x00008020,
+	0x00008030,
+	0x00008040,
+	0x00008050,
+	0x00008060,
+	0x00008070,
+	0x00009000,
+	0x00009010,
+	0x0000A000,
+	0x0000A010,
+	0x0000B000,
+	0x0000B010,
+};
+
+static const char *const lpi_gpio_functions[] = {
+	[LPI_GPIO_FUNC_INDEX_GPIO]	= LPI_GPIO_FUNC_GPIO,
+	[LPI_GPIO_FUNC_INDEX_FUNC1]	= LPI_GPIO_FUNC_FUNC1,
+	[LPI_GPIO_FUNC_INDEX_FUNC2]	= LPI_GPIO_FUNC_FUNC2,
+	[LPI_GPIO_FUNC_INDEX_FUNC3]	= LPI_GPIO_FUNC_FUNC3,
+	[LPI_GPIO_FUNC_INDEX_FUNC4]	= LPI_GPIO_FUNC_FUNC4,
+	[LPI_GPIO_FUNC_INDEX_FUNC5]	= LPI_GPIO_FUNC_FUNC5,
+};
+
+static int lpi_gpio_read(struct lpi_gpio_pad *pad, unsigned int addr)
+{
+	int ret;
+
+	if (!lpi_dev_up) {
+		pr_err_ratelimited("%s: ADSP is down due to SSR, return\n",
+				   __func__);
+		return 0;
+	}
+
+	ret = ioread32(pad->base + pad->offset + addr);
+	if (ret < 0)
+		pr_err("%s: read 0x%x failed\n", __func__, addr);
+
+	return ret;
+}
+
+static int lpi_gpio_write(struct lpi_gpio_pad *pad, unsigned int addr,
+			  unsigned int val)
+{
+	if (!lpi_dev_up) {
+		pr_err_ratelimited("%s: ADSP is down due to SSR, return\n",
+				   __func__);
+		return 0;
+	}
+
+	iowrite32(val, pad->base + pad->offset + addr);
+	return 0;
+}
+
+static int lpi_gpio_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	/* Every PIN is a group */
+	return pctldev->desc->npins;
+}
+
+static const char *lpi_gpio_get_group_name(struct pinctrl_dev *pctldev,
+					   unsigned int pin)
+{
+	return pctldev->desc->pins[pin].name;
+}
+
+static int lpi_gpio_get_group_pins(struct pinctrl_dev *pctldev,
+				   unsigned int pin,
+				   const unsigned int **pins,
+				   unsigned int *num_pins)
+{
+	*pins = &pctldev->desc->pins[pin].number;
+	*num_pins = 1;
+	return 0;
+}
+
+static const struct pinctrl_ops lpi_gpio_pinctrl_ops = {
+	.get_groups_count	= lpi_gpio_get_groups_count,
+	.get_group_name		= lpi_gpio_get_group_name,
+	.get_group_pins		= lpi_gpio_get_group_pins,
+	.dt_node_to_map		= pinconf_generic_dt_node_to_map_group,
+	.dt_free_map		= pinctrl_utils_free_map,
+};
+
+static int lpi_gpio_get_functions_count(struct pinctrl_dev *pctldev)
+{
+	return ARRAY_SIZE(lpi_gpio_functions);
+}
+
+static const char *lpi_gpio_get_function_name(struct pinctrl_dev *pctldev,
+					      unsigned int function)
+{
+	return lpi_gpio_functions[function];
+}
+
+static int lpi_gpio_get_function_groups(struct pinctrl_dev *pctldev,
+					unsigned int function,
+					const char *const **groups,
+					unsigned *const num_qgroups)
+{
+	*groups = lpi_gpio_groups;
+	*num_qgroups = pctldev->desc->npins;
+	return 0;
+}
+
+static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
+			    unsigned int pin)
+{
+	struct lpi_gpio_pad *pad;
+	unsigned int val;
+
+	pad = pctldev->desc->pins[pin].drv_data;
+
+	pad->function = function;
+
+	val = lpi_gpio_read(pad, LPI_GPIO_REG_VAL_CTL);
+	val &= ~(LPI_GPIO_REG_FUNCTION_MASK);
+	val |= pad->function << LPI_GPIO_REG_FUNCTION_SHIFT;
+	lpi_gpio_write(pad, LPI_GPIO_REG_VAL_CTL, val);
+	return 0;
+}
+
+static const struct pinmux_ops lpi_gpio_pinmux_ops = {
+	.get_functions_count	= lpi_gpio_get_functions_count,
+	.get_function_name	= lpi_gpio_get_function_name,
+	.get_function_groups	= lpi_gpio_get_function_groups,
+	.set_mux		= lpi_gpio_set_mux,
+};
+
+static int lpi_config_get(struct pinctrl_dev *pctldev,
+			  unsigned int pin, unsigned long *config)
+{
+	unsigned int param = pinconf_to_config_param(*config);
+	struct lpi_gpio_pad *pad;
+	unsigned int arg;
+
+	pad = pctldev->desc->pins[pin].drv_data;
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+		arg = pad->pullup = LPI_GPIO_BIAS_DISABLE;
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		arg = pad->pullup == LPI_GPIO_PULL_DOWN;
+		break;
+	case PIN_CONFIG_BIAS_BUS_HOLD:
+		arg = pad->pullup = LPI_GPIO_KEEPER;
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		arg = pad->pullup == LPI_GPIO_PULL_UP;
+		break;
+	case PIN_CONFIG_INPUT_ENABLE:
+	case PIN_CONFIG_OUTPUT:
+		arg = pad->output_enabled;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*config = pinconf_to_config_packed(param, arg);
+	return 0;
+}
+
+static unsigned int lpi_drive_to_regval(u32 arg)
+{
+	return (arg/2 - 1);
+}
+
+static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+			  unsigned long *configs, unsigned int nconfs)
+{
+	struct lpi_gpio_pad *pad;
+	unsigned int param, arg;
+	int i, ret = 0, val;
+
+	pad = pctldev->desc->pins[pin].drv_data;
+
+	for (i = 0; i < nconfs; i++) {
+		param = pinconf_to_config_param(configs[i]);
+		arg = pinconf_to_config_argument(configs[i]);
+
+		dev_dbg(pctldev->dev, "%s: param: %d arg: %d pin: %d\n",
+			__func__, param, arg, pin);
+
+		switch (param) {
+		case PIN_CONFIG_BIAS_DISABLE:
+			pad->pullup = LPI_GPIO_BIAS_DISABLE;
+			break;
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			pad->pullup = LPI_GPIO_PULL_DOWN;
+			break;
+		case PIN_CONFIG_BIAS_BUS_HOLD:
+			pad->pullup = LPI_GPIO_KEEPER;
+			break;
+		case PIN_CONFIG_BIAS_PULL_UP:
+			pad->pullup = LPI_GPIO_PULL_UP;
+			break;
+		case PIN_CONFIG_INPUT_ENABLE:
+			pad->output_enabled = false;
+			break;
+		case PIN_CONFIG_OUTPUT:
+			pad->output_enabled = true;
+			pad->value = arg;
+			break;
+		case PIN_CONFIG_DRIVE_STRENGTH:
+			pad->strength = arg;
+			break;
+		default:
+			ret = -EINVAL;
+			goto done;
+		}
+	}
+
+	val = lpi_gpio_read(pad, LPI_GPIO_REG_VAL_CTL);
+	val &= ~(LPI_GPIO_REG_PULL_MASK | LPI_GPIO_REG_OUT_STRENGTH_MASK |
+		 LPI_GPIO_REG_OE_MASK);
+	val |= pad->pullup << LPI_GPIO_REG_PULL_SHIFT;
+	val |= lpi_drive_to_regval(pad->strength) <<
+		LPI_GPIO_REG_OUT_STRENGTH_SHIFT;
+	if (pad->output_enabled)
+		val |= pad->value << LPI_GPIO_REG_OE_SHIFT;
+
+	lpi_gpio_write(pad, LPI_GPIO_REG_VAL_CTL, val);
+	lpi_gpio_write(pad, LPI_GPIO_REG_DIR_CTL,
+		       pad->output_enabled << LPI_GPIO_REG_DIR_SHIFT);
+done:
+	return ret;
+}
+
+static const struct pinconf_ops lpi_gpio_pinconf_ops = {
+	.is_generic			= true,
+	.pin_config_group_get		= lpi_config_get,
+	.pin_config_group_set		= lpi_config_set,
+};
+
+static int lpi_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
+{
+	struct lpi_gpio_state *state = gpiochip_get_data(chip);
+	unsigned long config;
+
+	config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
+
+	return lpi_config_set(state->ctrl, pin, &config, 1);
+}
+
+static int lpi_gpio_direction_output(struct gpio_chip *chip,
+				     unsigned int pin, int val)
+{
+	struct lpi_gpio_state *state = gpiochip_get_data(chip);
+	unsigned long config;
+
+	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
+
+	return lpi_config_set(state->ctrl, pin, &config, 1);
+}
+
+static int lpi_gpio_get(struct gpio_chip *chip, unsigned int pin)
+{
+	struct lpi_gpio_state *state = gpiochip_get_data(chip);
+	struct lpi_gpio_pad *pad;
+	int value;
+
+	pad = state->ctrl->desc->pins[pin].drv_data;
+
+	value = lpi_gpio_read(pad, LPI_GPIO_REG_VAL_CTL);
+	return value;
+}
+
+static void lpi_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)
+{
+	struct lpi_gpio_state *state = gpiochip_get_data(chip);
+	unsigned long config;
+
+	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
+
+	lpi_config_set(state->ctrl, pin, &config, 1);
+}
+
+static int lpi_notifier_service_cb(struct notifier_block *this,
+				   unsigned long opcode, void *ptr)
+{
+	pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
+
+	switch (opcode) {
+	case AUDIO_NOTIFIER_SERVICE_DOWN:
+		lpi_dev_up = false;
+		break;
+	case AUDIO_NOTIFIER_SERVICE_UP:
+		lpi_dev_up = true;
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block service_nb = {
+	.notifier_call  = lpi_notifier_service_cb,
+	.priority = -INT_MAX,
+};
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
+static unsigned int lpi_regval_to_drive(u32 val)
+{
+	return (val + 1) * 2;
+}
+
+static void lpi_gpio_dbg_show_one(struct seq_file *s,
+				  struct pinctrl_dev *pctldev,
+				  struct gpio_chip *chip,
+				  unsigned int offset,
+				  unsigned int gpio)
+{
+	struct pinctrl_pin_desc pindesc;
+	struct lpi_gpio_pad *pad;
+	unsigned int func;
+	int is_out;
+	int drive;
+	int pull;
+	u32 ctl_reg;
+
+	static const char * const pulls[] = {
+		"no pull",
+		"pull down",
+		"keeper",
+		"pull up"
+	};
+
+	pindesc = pctldev->desc->pins[offset];
+	pad = pctldev->desc->pins[offset].drv_data;
+	ctl_reg = lpi_gpio_read(pad, LPI_GPIO_REG_DIR_CTL);
+	is_out = (ctl_reg & LPI_GPIO_REG_DIR_MASK) >> LPI_GPIO_REG_DIR_SHIFT;
+	ctl_reg = lpi_gpio_read(pad, LPI_GPIO_REG_VAL_CTL);
+
+	func = (ctl_reg & LPI_GPIO_REG_FUNCTION_MASK) >>
+		LPI_GPIO_REG_FUNCTION_SHIFT;
+	drive = (ctl_reg & LPI_GPIO_REG_OUT_STRENGTH_MASK) >>
+		 LPI_GPIO_REG_OUT_STRENGTH_SHIFT;
+	pull = (ctl_reg & LPI_GPIO_REG_PULL_MASK) >> LPI_GPIO_REG_PULL_SHIFT;
+
+	seq_printf(s, " %-8s: %-3s %d",
+		   pindesc.name, is_out ? "out" : "in", func);
+	seq_printf(s, " %dmA", lpi_regval_to_drive(drive));
+	seq_printf(s, " %s", pulls[pull]);
+}
+
+static void lpi_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+	unsigned int gpio = chip->base;
+	unsigned int i;
+
+	for (i = 0; i < chip->ngpio; i++, gpio++) {
+		lpi_gpio_dbg_show_one(s, NULL, chip, i, gpio);
+		seq_puts(s, "\n");
+	}
+}
+
+#else
+#define lpi_gpio_dbg_show NULL
+#endif
+
+static const struct gpio_chip lpi_gpio_template = {
+	.direction_input	= lpi_gpio_direction_input,
+	.direction_output	= lpi_gpio_direction_output,
+	.get			= lpi_gpio_get,
+	.set			= lpi_gpio_set,
+	.request		= gpiochip_generic_request,
+	.free			= gpiochip_generic_free,
+	.dbg_show		= lpi_gpio_dbg_show,
+};
+
+static int lpi_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct pinctrl_pin_desc *pindesc;
+	struct pinctrl_desc *pctrldesc;
+	struct lpi_gpio_pad *pad, *pads;
+	struct lpi_gpio_state *state;
+	int ret, npins, i;
+	char __iomem *lpi_base;
+	u32 reg;
+
+	ret = of_property_read_u32(dev->of_node, "reg", &reg);
+	if (ret < 0) {
+		dev_err(dev, "missing base address\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "qcom,num-gpios", &npins);
+	if (ret < 0)
+		return ret;
+
+	WARN_ON(npins > ARRAY_SIZE(lpi_gpio_groups));
+
+	state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, state);
+
+	state->dev = &pdev->dev;
+
+	pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
+	if (!pindesc)
+		return -ENOMEM;
+
+	pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL);
+	if (!pads)
+		return -ENOMEM;
+
+	pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL);
+	if (!pctrldesc)
+		return -ENOMEM;
+
+	pctrldesc->pctlops = &lpi_gpio_pinctrl_ops;
+	pctrldesc->pmxops = &lpi_gpio_pinmux_ops;
+	pctrldesc->confops = &lpi_gpio_pinconf_ops;
+	pctrldesc->owner = THIS_MODULE;
+	pctrldesc->name = dev_name(dev);
+	pctrldesc->pins = pindesc;
+	pctrldesc->npins = npins;
+
+	lpi_base = devm_ioremap(dev, reg, LPI_ADDRESS_SIZE);
+	if (lpi_base == NULL) {
+		dev_err(dev, "%s devm_ioremap failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	state->base = lpi_base;
+
+	for (i = 0; i < npins; i++, pindesc++) {
+		pad = &pads[i];
+		pindesc->drv_data = pad;
+		pindesc->number = i;
+		pindesc->name = lpi_gpio_groups[i];
+
+		pad->base = lpi_base;
+		pad->offset = lpi_offset[i];
+	}
+
+	state->chip = lpi_gpio_template;
+	state->chip.parent = dev;
+	state->chip.base = -1;
+	state->chip.ngpio = npins;
+	state->chip.label = dev_name(dev);
+	state->chip.of_gpio_n_cells = 2;
+	state->chip.can_sleep = false;
+
+	state->ctrl = devm_pinctrl_register(dev, pctrldesc, state);
+	if (IS_ERR(state->ctrl))
+		return PTR_ERR(state->ctrl);
+
+	ret = gpiochip_add_data(&state->chip, state);
+	if (ret) {
+		dev_err(state->dev, "can't add gpio chip\n");
+		goto err_chip;
+	}
+
+	ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins);
+	if (ret) {
+		dev_err(dev, "failed to add pin range\n");
+		goto err_range;
+	}
+
+	lpi_dev_up = true;
+	ret = audio_notifier_register("lpi_tlmm", AUDIO_NOTIFIER_ADSP_DOMAIN,
+				      &service_nb);
+	if (ret < 0) {
+		pr_err("%s: Audio notifier register failed ret = %d\n",
+			__func__, ret);
+		goto err_range;
+	}
+
+	return 0;
+
+err_range:
+	gpiochip_remove(&state->chip);
+err_chip:
+	return ret;
+}
+
+static int lpi_pinctrl_remove(struct platform_device *pdev)
+{
+	struct lpi_gpio_state *state = platform_get_drvdata(pdev);
+
+	gpiochip_remove(&state->chip);
+	return 0;
+}
+
+static const struct of_device_id lpi_pinctrl_of_match[] = {
+	{ .compatible = "qcom,lpi-pinctrl" }, /* Generic */
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match);
+
+static struct platform_driver lpi_pinctrl_driver = {
+	.driver = {
+		   .name = "qcom-lpi-pinctrl",
+		   .of_match_table = lpi_pinctrl_of_match,
+	},
+	.probe = lpi_pinctrl_probe,
+	.remove = lpi_pinctrl_remove,
+};
+
+module_platform_driver(lpi_pinctrl_driver);
+
+MODULE_DESCRIPTION("QTI LPI GPIO pin control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index f9d483b..2a1367e 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -597,10 +597,6 @@
 
 	spin_lock_irqsave(&pctrl->lock, flags);
 
-	val = readl(pctrl->regs + g->intr_status_reg);
-	val &= ~BIT(g->intr_status_bit);
-	writel(val, pctrl->regs + g->intr_status_reg);
-
 	val = readl(pctrl->regs + g->intr_cfg_reg);
 	val |= BIT(g->intr_enable_bit);
 	writel(val, pctrl->regs + g->intr_cfg_reg);
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c
index 4b576cc..67adf58 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -727,6 +727,15 @@
 	msm_mux_reserved79,
 	msm_mux_reserved80,
 	msm_mux_qup15,
+	msm_mux_reserved81,
+	msm_mux_reserved82,
+	msm_mux_reserved83,
+	msm_mux_reserved84,
+	msm_mux_pcie1_pwrfault,
+	msm_mux_qup5,
+	msm_mux_reserved85,
+	msm_mux_pcie1_mrl,
+	msm_mux_reserved86,
 	msm_mux_reserved87,
 	msm_mux_reserved88,
 	msm_mux_tsif1_clk,
@@ -751,15 +760,6 @@
 	msm_mux_vfr_1,
 	msm_mux_tgu_ch2,
 	msm_mux_reserved92,
-	msm_mux_reserved81,
-	msm_mux_reserved82,
-	msm_mux_reserved83,
-	msm_mux_reserved84,
-	msm_mux_pcie1_pwrfault,
-	msm_mux_qup5,
-	msm_mux_reserved85,
-	msm_mux_pcie1_mrl,
-	msm_mux_reserved86,
 	msm_mux_tsif2_clk,
 	msm_mux_sdc4_clk,
 	msm_mux_qup7,
@@ -1681,6 +1681,33 @@
 static const char * const qup15_groups[] = {
 	"gpio81", "gpio82", "gpio83", "gpio84",
 };
+static const char * const reserved81_groups[] = {
+	"gpio81",
+};
+static const char * const reserved82_groups[] = {
+	"gpio82",
+};
+static const char * const reserved83_groups[] = {
+	"gpio83",
+};
+static const char * const reserved84_groups[] = {
+	"gpio84",
+};
+static const char * const pcie1_pwrfault_groups[] = {
+	"gpio85",
+};
+static const char * const qup5_groups[] = {
+	"gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const reserved85_groups[] = {
+	"gpio85",
+};
+static const char * const pcie1_mrl_groups[] = {
+	"gpio86",
+};
+static const char * const reserved86_groups[] = {
+	"gpio86",
+};
 static const char * const reserved87_groups[] = {
 	"gpio87",
 };
@@ -1753,33 +1780,6 @@
 static const char * const reserved92_groups[] = {
 	"gpio92",
 };
-static const char * const reserved81_groups[] = {
-	"gpio81",
-};
-static const char * const reserved82_groups[] = {
-	"gpio82",
-};
-static const char * const reserved83_groups[] = {
-	"gpio83",
-};
-static const char * const reserved84_groups[] = {
-	"gpio84",
-};
-static const char * const pcie1_pwrfault_groups[] = {
-	"gpio85",
-};
-static const char * const qup5_groups[] = {
-	"gpio85", "gpio86", "gpio87", "gpio88",
-};
-static const char * const reserved85_groups[] = {
-	"gpio85",
-};
-static const char * const pcie1_mrl_groups[] = {
-	"gpio86",
-};
-static const char * const reserved86_groups[] = {
-	"gpio86",
-};
 static const char * const tsif2_clk_groups[] = {
 	"gpio93",
 };
@@ -2113,6 +2113,15 @@
 	FUNCTION(reserved79),
 	FUNCTION(reserved80),
 	FUNCTION(qup15),
+	FUNCTION(reserved81),
+	FUNCTION(reserved82),
+	FUNCTION(reserved83),
+	FUNCTION(reserved84),
+	FUNCTION(pcie1_pwrfault),
+	FUNCTION(qup5),
+	FUNCTION(reserved85),
+	FUNCTION(pcie1_mrl),
+	FUNCTION(reserved86),
 	FUNCTION(reserved87),
 	FUNCTION(reserved88),
 	FUNCTION(tsif1_clk),
@@ -2137,15 +2146,6 @@
 	FUNCTION(vfr_1),
 	FUNCTION(tgu_ch2),
 	FUNCTION(reserved92),
-	FUNCTION(reserved81),
-	FUNCTION(reserved82),
-	FUNCTION(reserved83),
-	FUNCTION(reserved84),
-	FUNCTION(pcie1_pwrfault),
-	FUNCTION(qup5),
-	FUNCTION(reserved85),
-	FUNCTION(pcie1_mrl),
-	FUNCTION(reserved86),
 	FUNCTION(tsif2_clk),
 	FUNCTION(sdc4_clk),
 	FUNCTION(qup7),
@@ -2418,10 +2418,10 @@
 	PINGROUP(147, NORTH, NA, NA, reserved147, NA, NA, NA, NA, NA, NA),
 	PINGROUP(148, NORTH, NA, reserved148, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(149, NORTH, NA, reserved149, NA, NA, NA, NA, NA, NA, NA),
-	SDC_QDSD_PINGROUP(sdc2_clk, 0x59a000, 14, 6),
-	SDC_QDSD_PINGROUP(sdc2_cmd, 0x59a000, 11, 3),
-	SDC_QDSD_PINGROUP(sdc2_data, 0x59a000, 9, 0),
-	UFS_RESET(ufs_reset, 0x59f000),
+	SDC_QDSD_PINGROUP(sdc2_clk, 0x99a000, 14, 6),
+	SDC_QDSD_PINGROUP(sdc2_cmd, 0x99a000, 11, 3),
+	SDC_QDSD_PINGROUP(sdc2_data, 0x99a000, 9, 0),
+	UFS_RESET(ufs_reset, 0x99f000),
 };
 
 static const struct msm_pinctrl_soc_data sdm845_pinctrl = {
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index 77e9dd7..f06fb1f 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -138,6 +138,7 @@
  * struct pmic_gpio_pad - keep current GPIO settings
  * @base: Address base in SPMI device.
  * @irq: IRQ number which this GPIO generate.
+ * @gpio_idx: The index in GPIO's hardware number space (1-based)
  * @is_enabled: Set to false when GPIO should be put in high Z state.
  * @out_value: Cached pin output value
  * @have_buffer: Set to true if GPIO output could be configured in push-pull,
@@ -158,6 +159,7 @@
 struct pmic_gpio_pad {
 	u16		base;
 	int		irq;
+	int		gpio_idx;
 	bool		is_enabled;
 	bool		out_value;
 	bool		have_buffer;
@@ -179,6 +181,7 @@
 	struct regmap	*map;
 	struct pinctrl_dev *ctrl;
 	struct gpio_chip chip;
+	const char **gpio_groups;
 };
 
 static const struct pinconf_generic_params pmic_gpio_bindings[] = {
@@ -297,7 +300,9 @@
 					 const char *const **groups,
 					 unsigned *const num_qgroups)
 {
-	*groups = pmic_gpio_groups;
+	struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = state->gpio_groups;
 	*num_qgroups = pctldev->desc->npins;
 	return 0;
 }
@@ -637,7 +642,7 @@
 
 	pad = pctldev->desc->pins[pin].drv_data;
 
-	seq_printf(s, " gpio%-2d:", pin + PMIC_GPIO_PHYSICAL_OFFSET);
+	seq_printf(s, " gpio%-2d:", pad->gpio_idx);
 
 	val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_EN_CTL);
 
@@ -742,13 +747,29 @@
 			      const struct of_phandle_args *gpio_desc,
 			      u32 *flags)
 {
+	int i;
+	struct pmic_gpio_state *state = gpiochip_get_data(chip);
+	struct pinctrl_desc *desc = state->ctrl->desc;
+	struct pmic_gpio_pad *pad;
+
 	if (chip->of_gpio_n_cells < 2)
 		return -EINVAL;
 
 	if (flags)
 		*flags = gpio_desc->args[1];
 
-	return gpio_desc->args[0] - PMIC_GPIO_PHYSICAL_OFFSET;
+	for (i = 0; i < chip->ngpio; i++) {
+		pad = desc->pins[i].drv_data;
+		if (pad->gpio_idx == gpio_desc->args[0]) {
+			dev_dbg(state->dev, "gpio%-2d xlate to pin%-2d\n",
+						gpio_desc->args[0], i);
+			return i;
+		}
+	}
+
+	dev_err(state->dev, "Couldn't find pin for gpio %d\n",
+				gpio_desc->args[0]);
+	return -ENODEV;
 }
 
 static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
@@ -934,43 +955,124 @@
 	struct pinctrl_desc *pctrldesc;
 	struct pmic_gpio_pad *pad, *pads;
 	struct pmic_gpio_state *state;
-	int ret, npins, i;
-	u32 reg;
+	int ret, npins, ngpios, i, j, pin_idx;
+	int disallowed_count = 0;
+	u32 reg[2], start, size;
+	u32 *disallowed = NULL;
 
-	ret = of_property_read_u32(dev->of_node, "reg", &reg);
+	ret = of_property_read_u32_array(dev->of_node, "reg", reg, 2);
 	if (ret < 0) {
-		dev_err(dev, "missing base address");
+		dev_err(dev, "reg property reading failed\n");
 		return ret;
 	}
+	start = reg[0];
+	size = reg[1];
 
-	npins = platform_irq_count(pdev);
-	if (!npins)
+	ngpios = size / PMIC_GPIO_ADDRESS_RANGE;
+	if (ngpios == 0) {
+		dev_err(dev, "no gpios assigned\n");
+		return -ENODEV;
+	}
+
+	if (ngpios > ARRAY_SIZE(pmic_gpio_groups)) {
+		dev_err(dev, "reg property defines %d gpios, but only %d are allowed\n",
+				ngpios, (int)ARRAY_SIZE(pmic_gpio_groups));
 		return -EINVAL;
-	if (npins < 0)
-		return npins;
+	}
 
-	BUG_ON(npins > ARRAY_SIZE(pmic_gpio_groups));
+	if (of_find_property(dev->of_node, "qcom,gpios-disallowed",
+					&disallowed_count)) {
+		disallowed_count /= sizeof(u32);
+		if (disallowed_count == 0) {
+			dev_err(dev, "No data in gpios-disallowed\n");
+			return -EINVAL;
+		}
+
+		disallowed = kcalloc(disallowed_count, sizeof(u32), GFP_KERNEL);
+		if (disallowed == NULL)
+			return -ENOMEM;
+
+		ret = of_property_read_u32_array(dev->of_node,
+				"qcom,gpios-disallowed",
+				disallowed, disallowed_count);
+		if (ret < 0) {
+			dev_err(dev, "qcom,gpios-disallowed property reading failed, ret=%d\n",
+								ret);
+			goto err_free;
+		}
+
+		for (i = 0; i < disallowed_count; i++) {
+			if (disallowed[i] >= ngpios + PMIC_GPIO_PHYSICAL_OFFSET
+				|| disallowed[i] < PMIC_GPIO_PHYSICAL_OFFSET) {
+				dev_err(dev, "invalid gpio = %d specified in qcom,gpios-disallowed, supported values: %d to %d\n",
+					disallowed[i],
+					PMIC_GPIO_PHYSICAL_OFFSET,
+					ngpios - 1 + PMIC_GPIO_PHYSICAL_OFFSET);
+				ret = -EINVAL;
+				goto err_free;
+			}
+			for (j = 0; j < i; j++) {
+				if (disallowed[i] == disallowed[j]) {
+					dev_err(dev, "duplicate gpio = %d listed in qcom,gpios-disallowed\n",
+							disallowed[i]);
+					ret = -EINVAL;
+					goto err_free;
+				}
+			}
+			dev_dbg(dev, "gpio %d NOT supported\n", disallowed[i]);
+		}
+	} else {
+		disallowed_count = 0;
+	}
+
+	npins = ngpios - disallowed_count;
+	if (npins <= 0) {
+		dev_err(dev, "No pins assigned\n");
+		ret = -ENODEV;
+		goto err_free;
+	}
+	if (platform_irq_count(pdev) != npins) {
+		dev_err(dev, "%d IRQs defined but %d expected\n",
+				platform_irq_count(pdev), npins);
+		ret = -EINVAL;
+		goto err_free;
+	}
 
 	state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
-	if (!state)
-		return -ENOMEM;
+	if (!state) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
 
 	platform_set_drvdata(pdev, state);
 
 	state->dev = &pdev->dev;
 	state->map = dev_get_regmap(dev->parent, NULL);
 
+	state->gpio_groups = devm_kcalloc(dev, sizeof(*state->gpio_groups),
+						npins, GFP_KERNEL);
+	if (!state->gpio_groups) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
+
 	pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
-	if (!pindesc)
-		return -ENOMEM;
+	if (!pindesc) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
 
 	pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL);
-	if (!pads)
-		return -ENOMEM;
+	if (!pads) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
 
 	pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL);
-	if (!pctrldesc)
-		return -ENOMEM;
+	if (!pctrldesc) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
 
 	pctrldesc->pctlops = &pmic_gpio_pinctrl_ops;
 	pctrldesc->pmxops = &pmic_gpio_pinmux_ops;
@@ -984,22 +1086,42 @@
 #ifdef CONFIG_DEBUG_FS
 	pctrldesc->custom_conf_items = pmic_conf_items;
 #endif
+	for (pin_idx = 0, i = 0; i < ngpios; i++) {
+		for (j = 0; j < disallowed_count; j++) {
+			if (i + PMIC_GPIO_PHYSICAL_OFFSET == disallowed[j])
+				break;
+		}
+		if (j != disallowed_count)
+			continue;
 
-	for (i = 0; i < npins; i++, pindesc++) {
-		pad = &pads[i];
+		pad = &pads[pin_idx];
 		pindesc->drv_data = pad;
-		pindesc->number = i;
+		pindesc->number = pin_idx;
 		pindesc->name = pmic_gpio_groups[i];
 
-		pad->irq = platform_get_irq(pdev, i);
-		if (pad->irq < 0)
-			return pad->irq;
+		pad->gpio_idx = i + PMIC_GPIO_PHYSICAL_OFFSET;
+		pad->irq = platform_get_irq(pdev, pin_idx);
+		if (pad->irq < 0) {
+			dev_err(state->dev,
+				"failed to get irq for gpio %d (pin %d), ret=%d\n",
+					pad->gpio_idx, pin_idx, pad->irq);
+			ret = pad->irq;
+			goto err_free;
+		}
+		/* Every pin is a group */
+		state->gpio_groups[pin_idx] = pmic_gpio_groups[i];
 
-		pad->base = reg + i * PMIC_GPIO_ADDRESS_RANGE;
+		pad->base = start + i * PMIC_GPIO_ADDRESS_RANGE;
 
 		ret = pmic_gpio_populate(state, pad);
-		if (ret < 0)
-			return ret;
+		if (ret < 0) {
+			dev_err(state->dev,
+				"failed to populate gpio %d, ret=%d\n",
+							i, ret);
+			goto err_free;
+		}
+		pindesc++;
+		pin_idx++;
 	}
 
 	state->chip = pmic_gpio_gpio_template;
@@ -1011,25 +1133,29 @@
 	state->chip.can_sleep = false;
 
 	state->ctrl = devm_pinctrl_register(dev, pctrldesc, state);
-	if (IS_ERR(state->ctrl))
-		return PTR_ERR(state->ctrl);
+	if (IS_ERR(state->ctrl)) {
+		ret = PTR_ERR(state->ctrl);
+		dev_err(state->dev, "failed to register pinctrl device, ret=%d\n",
+							ret);
+		goto err_free;
+	}
 
 	ret = gpiochip_add_data(&state->chip, state);
 	if (ret) {
-		dev_err(state->dev, "can't add gpio chip\n");
-		return ret;
+		dev_err(state->dev, "can't add gpio chip, ret=%d\n", ret);
+		goto err_free;
 	}
 
 	ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins);
 	if (ret) {
-		dev_err(dev, "failed to add pin range\n");
-		goto err_range;
+		dev_err(dev, "failed to add pin range\n, ret=%d\n", ret);
+		gpiochip_remove(&state->chip);
+		goto err_free;
 	}
 
-	return 0;
+err_free:
+	kfree(disallowed);
 
-err_range:
-	gpiochip_remove(&state->chip);
 	return ret;
 }
 
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index fff8966..b7685cb 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -415,6 +415,16 @@
 {
 	uint32_t val;
 
+	/*
+	 * allocate new events for this channel first
+	 * before submitting the new TREs.
+	 * for TO_GSI channels the event ring doorbell is rang as part of
+	 * interrupt handling.
+	 */
+	if (ctx->evtr && ctx->props.dir == GSI_CHAN_DIR_FROM_GSI)
+		gsi_ring_evt_doorbell(ctx->evtr);
+	ctx->ring.wp = ctx->ring.wp_local;
+
 	/* write order MUST be MSB followed by LSB */
 	val = ((ctx->ring.wp_local >> 32) &
 			GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK) <<
@@ -470,8 +480,8 @@
 			cntr = 0;
 			rp = gsi_readl(gsi_ctx->base +
 				GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(i, ee));
-			rp |= ((uint64_t)gsi_readl(gsi_ctx->base +
-				GSI_EE_n_EV_CH_k_CNTXT_5_OFFS(i, ee))) << 32;
+			rp |= ctx->ring.rp & 0xFFFFFFFF00000000;
+
 			ctx->ring.rp = rp;
 			while (ctx->ring.rp_local != rp) {
 				++cntr;
@@ -1529,6 +1539,7 @@
 static int gsi_validate_channel_props(struct gsi_chan_props *props)
 {
 	uint64_t ra;
+	uint64_t last;
 
 	if (props->ch_id >= gsi_ctx->max_ch) {
 		GSIERR("ch_id %u invalid\n", props->ch_id);
@@ -1556,6 +1567,17 @@
 		return -GSI_STATUS_INVALID_PARAMS;
 	}
 
+	last = props->ring_base_addr + props->ring_len - props->re_size;
+
+	/* MSB should stay same within the ring */
+	if ((props->ring_base_addr & 0xFFFFFFFF00000000ULL) !=
+	    (last & 0xFFFFFFFF00000000ULL)) {
+		GSIERR("MSB is not fixed on ring base 0x%llx size 0x%x\n",
+			props->ring_base_addr,
+			props->ring_len);
+		return -GSI_STATUS_INVALID_PARAMS;
+	}
+
 	if (props->prot == GSI_CHAN_PROT_GPI &&
 			!props->ring_base_vaddr) {
 		GSIERR("protocol %u requires ring base VA\n", props->prot);
@@ -2128,29 +2150,22 @@
 		uint16_t *num_free_re)
 {
 	uint16_t start;
-	uint16_t start_hw;
 	uint16_t end;
 	uint64_t rp;
-	uint64_t rp_hw;
 	int ee = gsi_ctx->per.ee;
 	uint16_t used;
-	uint16_t used_hw;
-
-	rp_hw = gsi_readl(gsi_ctx->base +
-		GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(ctx->props.ch_id, ee));
-	rp_hw |= ((uint64_t)gsi_readl(gsi_ctx->base +
-		GSI_EE_n_GSI_CH_k_CNTXT_5_OFFS(ctx->props.ch_id, ee)))
-		<< 32;
 
 	if (!ctx->evtr) {
-		rp = rp_hw;
+		rp = gsi_readl(gsi_ctx->base +
+			GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(ctx->props.ch_id, ee));
+		rp |= ctx->ring.rp & 0xFFFFFFFF00000000;
+
 		ctx->ring.rp = rp;
 	} else {
 		rp = ctx->ring.rp_local;
 	}
 
 	start = gsi_find_idx_from_addr(&ctx->ring, rp);
-	start_hw = gsi_find_idx_from_addr(&ctx->ring, rp_hw);
 	end = gsi_find_idx_from_addr(&ctx->ring, ctx->ring.wp_local);
 
 	if (end >= start)
@@ -2158,13 +2173,7 @@
 	else
 		used = ctx->ring.max_num_elem + 1 - (start - end);
 
-	if (end >= start_hw)
-		used_hw = end - start_hw;
-	else
-		used_hw = ctx->ring.max_num_elem + 1 - (start_hw - end);
-
 	*num_free_re = ctx->ring.max_num_elem - used;
-	gsi_update_ch_dp_stats(ctx, used_hw);
 }
 
 int gsi_query_channel_info(unsigned long chan_hdl,
@@ -2274,14 +2283,12 @@
 
 	rp = gsi_readl(gsi_ctx->base +
 		GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(ctx->props.ch_id, ee));
-	rp |= ((uint64_t)gsi_readl(gsi_ctx->base +
-		GSI_EE_n_GSI_CH_k_CNTXT_5_OFFS(ctx->props.ch_id, ee))) << 32;
+	rp |= ctx->ring.rp & 0xFFFFFFFF00000000;
 	ctx->ring.rp = rp;
 
 	wp = gsi_readl(gsi_ctx->base +
 		GSI_EE_n_GSI_CH_k_CNTXT_6_OFFS(ctx->props.ch_id, ee));
-	wp |= ((uint64_t)gsi_readl(gsi_ctx->base +
-		GSI_EE_n_GSI_CH_k_CNTXT_7_OFFS(ctx->props.ch_id, ee))) << 32;
+	wp |= ctx->ring.wp & 0xFFFFFFFF00000000;
 	ctx->ring.wp = wp;
 
 	if (ctx->props.dir == GSI_CHAN_DIR_FROM_GSI)
@@ -2353,6 +2360,8 @@
 			tre.re_type = GSI_RE_XFER;
 		} else if (xfer[i].type == GSI_XFER_ELEM_IMME_CMD) {
 			tre.re_type = GSI_RE_IMMD_CMD;
+		} else if (xfer[i].type == GSI_XFER_ELEM_NOP) {
+			tre.re_type = GSI_RE_NOP;
 		} else {
 			GSIERR("chan_hdl=%lu bad RE type=%u\n", chan_hdl,
 				xfer[i].type);
@@ -2420,6 +2429,9 @@
 		return -GSI_STATUS_UNSUPPORTED_OP;
 	}
 
+	if (ctx->ring.wp == ctx->ring.wp_local)
+		return GSI_STATUS_SUCCESS;
+
 	gsi_ring_chan_doorbell(ctx);
 
 	return GSI_STATUS_SUCCESS;
@@ -2457,19 +2469,22 @@
 	}
 
 	spin_lock_irqsave(&ctx->evtr->ring.slock, flags);
-	rp = gsi_readl(gsi_ctx->base +
-		GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(ctx->evtr->id, ee));
-	rp |= ((uint64_t)gsi_readl(gsi_ctx->base +
-		GSI_EE_n_EV_CH_k_CNTXT_5_OFFS(ctx->evtr->id, ee))) << 32;
-	ctx->evtr->ring.rp = rp;
-	if (rp == ctx->evtr->ring.rp_local) {
+	if (ctx->evtr->ring.rp == ctx->evtr->ring.rp_local) {
+		/* update rp to see of we have anything new to process */
+		rp = gsi_readl(gsi_ctx->base +
+			GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(ctx->evtr->id, ee));
+		rp |= ctx->ring.rp & 0xFFFFFFFF00000000;
+
+		ctx->evtr->ring.rp = rp;
+	}
+
+	if (ctx->evtr->ring.rp == ctx->evtr->ring.rp_local) {
 		spin_unlock_irqrestore(&ctx->evtr->ring.slock, flags);
 		ctx->stats.poll_empty++;
 		return GSI_STATUS_POLL_EMPTY;
 	}
 
 	gsi_process_evt_re(ctx->evtr, notify, false);
-	gsi_ring_evt_doorbell(ctx->evtr);
 	spin_unlock_irqrestore(&ctx->evtr->ring.slock, flags);
 	ctx->stats.poll_ok++;
 
diff --git a/drivers/platform/msm/gsi/gsi.h b/drivers/platform/msm/gsi/gsi.h
index f53a4bd..32fb178 100644
--- a/drivers/platform/msm/gsi/gsi.h
+++ b/drivers/platform/msm/gsi/gsi.h
@@ -209,6 +209,7 @@
 enum gsi_re_type {
 	GSI_RE_XFER = 0x2,
 	GSI_RE_IMMD_CMD = 0x3,
+	GSI_RE_NOP = 0x4,
 };
 
 struct __packed gsi_tre {
diff --git a/drivers/platform/msm/gsi/gsi_dbg.c b/drivers/platform/msm/gsi/gsi_dbg.c
index 717c8917..b1d1dfa 100644
--- a/drivers/platform/msm/gsi/gsi_dbg.c
+++ b/drivers/platform/msm/gsi/gsi_dbg.c
@@ -490,11 +490,6 @@
 		goto error;
 	}
 
-	if (gsi_ctx->chan[ch_id].props.prot == GSI_CHAN_PROT_GPI) {
-		TERR("valid for non GPI channels only\n");
-		goto error;
-	}
-
 	if (gsi_ctx->chan[ch_id].enable_dp_stats == enable) {
 		TERR("ch_%d: already enabled/disabled\n", ch_id);
 		return -EFAULT;
@@ -631,7 +626,7 @@
 	else
 		used_hw = ctx->ring.max_num_elem + 1 - (start_hw - end_hw);
 
-	TERR("ch %d used %d\n", ctx->props.ch_id, used_hw);
+	TDBG("ch %d used %d\n", ctx->props.ch_id, used_hw);
 	gsi_update_ch_dp_stats(ctx, used_hw);
 }
 
@@ -641,7 +636,6 @@
 
 	for (ch_id = 0; ch_id < gsi_ctx->max_ch; ch_id++) {
 		if (gsi_ctx->chan[ch_id].allocated &&
-		    gsi_ctx->chan[ch_id].props.prot != GSI_CHAN_PROT_GPI &&
 		    gsi_ctx->chan[ch_id].enable_dp_stats)
 			gsi_dbg_update_ch_dp_stats(&gsi_ctx->chan[ch_id]);
 	}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 20b73d8..ca63518 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -2245,7 +2245,8 @@
 			reg_write.pipeline_clear_options =
 				IPAHAL_HPS_CLEAR;
 			reg_write.offset =
-				ipahal_get_reg_ofst(IPA_ENDP_STATUS_n);
+				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);
@@ -2845,6 +2846,13 @@
 		}
 	}
 
+	/* allocate the common PROD event ring */
+	if (ipa3_alloc_common_event_ring()) {
+		IPAERR("ipa3_alloc_common_event_ring failed.\n");
+		result = -EPERM;
+		goto fail_ch20_wa;
+	}
+
 	/* CMD OUT (AP->IPA) */
 	memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
 	sys_in.client = IPA_CLIENT_APPS_CMD_PROD;
@@ -4239,6 +4247,52 @@
 	return 0;
 }
 
+static int ipa3_alloc_pkt_init(void)
+{
+	struct ipa_mem_buffer mem;
+	struct ipahal_imm_cmd_pyld *cmd_pyld;
+	struct ipahal_imm_cmd_ip_packet_init cmd = {0};
+	int i;
+
+	cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_IP_PACKET_INIT,
+		&cmd, false);
+	if (!cmd_pyld) {
+		IPAERR("failed to construct IMM cmd\n");
+		return -ENOMEM;
+	}
+
+	mem.size = cmd_pyld->len * ipa3_ctx->ipa_num_pipes;
+	mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size,
+		&mem.phys_base, GFP_KERNEL);
+	if (!mem.base) {
+		IPAERR("failed to alloc DMA buff of size %d\n", mem.size);
+		ipahal_destroy_imm_cmd(cmd_pyld);
+		return -ENOMEM;
+	}
+	ipahal_destroy_imm_cmd(cmd_pyld);
+
+	memset(mem.base, 0, mem.size);
+	for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
+		cmd.destination_pipe_index = i;
+		cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_IP_PACKET_INIT,
+			&cmd, false);
+		if (!cmd_pyld) {
+			IPAERR("failed to construct IMM cmd\n");
+			dma_free_coherent(ipa3_ctx->pdev,
+				mem.size,
+				mem.base,
+				mem.phys_base);
+			return -ENOMEM;
+		}
+		memcpy(mem.base + i * cmd_pyld->len, cmd_pyld->data,
+			cmd_pyld->len);
+		ipa3_ctx->pkt_init_imm[i] = mem.phys_base + i * cmd_pyld->len;
+		ipahal_destroy_imm_cmd(cmd_pyld);
+	}
+
+	return 0;
+}
+
 /**
 * ipa3_pre_init() - Initialize the IPA Driver.
 * This part contains all initialization which doesn't require IPA HW, such
@@ -4648,6 +4702,13 @@
 		goto fail_create_apps_resource;
 	}
 
+	result = ipa3_alloc_pkt_init();
+	if (result) {
+		IPAERR("Failed to alloc pkt_init payload\n");
+		result = -ENODEV;
+		goto fail_create_apps_resource;
+	}
+
 	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5)
 		ipa3_enable_dcd();
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 9bb3e0e..343cc14 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -69,6 +69,9 @@
 #define IPA_GSI_CH_20_WA_VIRT_CHAN 29
 
 #define IPA_DEFAULT_SYS_YELLOW_WM 32
+#define IPA_REPL_XFER_THRESH 10
+
+#define IPA_TX_SEND_COMPL_NOP_DELAY_NS (2 * 1000 * 1000)
 
 /*
  * The transport descriptor size was changed to GSI_CHAN_RE_SIZE_16B, but
@@ -183,106 +186,64 @@
 {
 	struct ipa3_tx_pkt_wrapper *tx_pkt;
 	struct ipa3_sys_context *sys;
+	struct ipa3_tx_pkt_wrapper *this_pkt;
 
 	tx_pkt = container_of(work, struct ipa3_tx_pkt_wrapper, work);
 	sys = tx_pkt->sys;
-
+	spin_lock_bh(&sys->spinlock);
+	this_pkt = list_first_entry(&sys->head_desc_list,
+		struct ipa3_tx_pkt_wrapper, link);
+	while (tx_pkt != this_pkt) {
+		spin_unlock_bh(&sys->spinlock);
+		ipa3_wq_write_done_common(sys, this_pkt);
+		spin_lock_bh(&sys->spinlock);
+		this_pkt = list_first_entry(&sys->head_desc_list,
+			struct ipa3_tx_pkt_wrapper, link);
+	}
+	spin_unlock_bh(&sys->spinlock);
 	ipa3_wq_write_done_common(sys, tx_pkt);
 }
 
-/**
- * ipa3_send_one() - Send a single descriptor
- * @sys:	system pipe context
- * @desc:	descriptor to send
- * @in_atomic:  whether caller is in atomic context
- *
- * - Allocate tx_packet wrapper
- * - transfer data to the IPA
- * - after the transfer was done the user will be notified via provided
- *   callback
- *
- * Return codes: 0: success, -EFAULT: failure
- */
-int ipa3_send_one(struct ipa3_sys_context *sys, struct ipa3_desc *desc,
-		bool in_atomic)
+
+static void ipa3_send_nop_desc(struct work_struct *work)
 {
+	struct ipa3_sys_context *sys = container_of(work,
+		struct ipa3_sys_context, work);
+	struct gsi_xfer_elem nop_xfer;
 	struct ipa3_tx_pkt_wrapper *tx_pkt;
-	struct gsi_xfer_elem gsi_xfer;
-	int result;
-	dma_addr_t dma_address;
-	u32 mem_flag = GFP_ATOMIC;
 
-	if (unlikely(!in_atomic))
-		mem_flag = GFP_KERNEL;
-
-	tx_pkt = kmem_cache_zalloc(ipa3_ctx->tx_pkt_wrapper_cache, mem_flag);
+	IPADBG_LOW("gsi send NOP for ch: %lu\n", sys->ep->gsi_chan_hdl);
+	tx_pkt = kmem_cache_zalloc(ipa3_ctx->tx_pkt_wrapper_cache, GFP_KERNEL);
 	if (!tx_pkt) {
 		IPAERR("failed to alloc tx wrapper\n");
-		goto fail_mem_alloc;
-	}
-
-	if (!desc->dma_address_valid) {
-		dma_address = dma_map_single(ipa3_ctx->pdev, desc->pyld,
-			desc->len, DMA_TO_DEVICE);
-	} else {
-		dma_address = desc->dma_address;
-		tx_pkt->no_unmap_dma = true;
-	}
-	if (!dma_address) {
-		IPAERR("failed to DMA wrap\n");
-		goto fail_dma_map;
+		queue_work(sys->wq, &sys->work);
+		return;
 	}
 
 	INIT_LIST_HEAD(&tx_pkt->link);
-	tx_pkt->type = desc->type;
-	tx_pkt->cnt = 1;    /* only 1 desc in this "set" */
-
-	tx_pkt->mem.phys_base = dma_address;
-	tx_pkt->mem.base = desc->pyld;
-	tx_pkt->mem.size = desc->len;
-	tx_pkt->sys = sys;
-	tx_pkt->callback = desc->callback;
-	tx_pkt->user1 = desc->user1;
-	tx_pkt->user2 = desc->user2;
-
-	memset(&gsi_xfer, 0, sizeof(gsi_xfer));
-	gsi_xfer.addr = dma_address;
-	gsi_xfer.flags |= GSI_XFER_FLAG_EOT;
-	gsi_xfer.xfer_user_data = tx_pkt;
-	if (desc->type == IPA_IMM_CMD_DESC) {
-		gsi_xfer.len = desc->opcode;
-		gsi_xfer.type = GSI_XFER_ELEM_IMME_CMD;
-	} else {
-		gsi_xfer.len = desc->len;
-		gsi_xfer.type = GSI_XFER_ELEM_DATA;
-	}
-
+	tx_pkt->cnt = 1;
 	INIT_WORK(&tx_pkt->work, ipa3_wq_write_done);
-
+	tx_pkt->no_unmap_dma = true;
+	tx_pkt->sys = sys;
 	spin_lock_bh(&sys->spinlock);
 	list_add_tail(&tx_pkt->link, &sys->head_desc_list);
+	spin_unlock_bh(&sys->spinlock);
 
-	result = gsi_queue_xfer(sys->ep->gsi_chan_hdl, 1,
-				&gsi_xfer, true);
-	if (result != GSI_STATUS_SUCCESS) {
-		IPAERR("GSI xfer failed.\n");
-		goto fail_transport_send;
+	memset(&nop_xfer, 0, sizeof(nop_xfer));
+	nop_xfer.type = GSI_XFER_ELEM_NOP;
+	nop_xfer.flags = GSI_XFER_FLAG_EOT;
+	nop_xfer.xfer_user_data = tx_pkt;
+	if (gsi_queue_xfer(sys->ep->gsi_chan_hdl, 1, &nop_xfer, true)) {
+		IPAERR("gsi_queue_xfer for ch:%lu failed\n",
+			sys->ep->gsi_chan_hdl);
+		queue_work(sys->wq, &sys->work);
+		return;
 	}
+	sys->len_pending_xfer = 0;
 
-	spin_unlock_bh(&sys->spinlock);
-
-	return 0;
-
-fail_transport_send:
-	list_del(&tx_pkt->link);
-	spin_unlock_bh(&sys->spinlock);
-	dma_unmap_single(ipa3_ctx->pdev, dma_address, desc->len, DMA_TO_DEVICE);
-fail_dma_map:
-	kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt);
-fail_mem_alloc:
-	return -EFAULT;
 }
 
+
 /**
  * ipa3_send() - Send multiple descriptors in one HW transaction
  * @sys: system pipe context
@@ -437,19 +398,21 @@
 		}
 
 		if (i == (num_desc - 1)) {
-			gsi_xfer_elem_array[i].flags |=
-				GSI_XFER_FLAG_EOT;
-			if (sys->ep->client == IPA_CLIENT_APPS_WAN_PROD
-				&& sys->policy == IPA_POLICY_INTR_MODE)
+			if (!sys->use_comm_evt_ring) {
+				gsi_xfer_elem_array[i].flags |=
+					GSI_XFER_FLAG_EOT;
 				gsi_xfer_elem_array[i].flags |=
 					GSI_XFER_FLAG_BEI;
+			}
 			gsi_xfer_elem_array[i].xfer_user_data =
 				tx_pkt_first;
-		} else
-			gsi_xfer_elem_array[i].flags |=
-				GSI_XFER_FLAG_CHAIN;
+		} else {
+				gsi_xfer_elem_array[i].flags |=
+					GSI_XFER_FLAG_CHAIN;
+		}
 	}
 
+	IPADBG_LOW("ch:%lu queue xfer\n", sys->ep->gsi_chan_hdl);
 	result = gsi_queue_xfer(sys->ep->gsi_chan_hdl, num_desc,
 			gsi_xfer_elem_array, true);
 	if (result != GSI_STATUS_SUCCESS) {
@@ -459,6 +422,16 @@
 	kfree(gsi_xfer_elem_array);
 
 	spin_unlock_bh(&sys->spinlock);
+
+	/* set the timer for sending the NOP descriptor */
+	if (sys->use_comm_evt_ring && !hrtimer_active(&sys->db_timer)) {
+		ktime_t time = ktime_set(0, IPA_TX_SEND_COMPL_NOP_DELAY_NS);
+
+		IPADBG_LOW("scheduling timer for ch %lu\n",
+			sys->ep->gsi_chan_hdl);
+		hrtimer_start(&sys->db_timer, time, HRTIMER_MODE_REL);
+	}
+
 	return 0;
 
 failure:
@@ -491,6 +464,25 @@
 }
 
 /**
+ * ipa3_send_one() - Send a single descriptor
+ * @sys:	system pipe context
+ * @desc:	descriptor to send
+ * @in_atomic:  whether caller is in atomic context
+ *
+ * - Allocate tx_packet wrapper
+ * - transfer data to the IPA
+ * - after the transfer was done the SPS will
+ *   notify the sending user via ipa_sps_irq_comp_tx()
+ *
+ * Return codes: 0: success, -EFAULT: failure
+ */
+int ipa3_send_one(struct ipa3_sys_context *sys, struct ipa3_desc *desc,
+	bool in_atomic)
+{
+	return ipa3_send(sys, 1, desc, in_atomic);
+}
+
+/**
  * ipa3_transport_irq_cmd_ack - callback function which will be called by
  * the transport driver after an immediate command is complete.
  * @user1:	pointer to the descriptor of the transfer
@@ -771,15 +763,14 @@
 	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
 	do {
 		cnt = ipa3_handle_rx_core(sys, true, true);
-		if (cnt == 0) {
+		if (cnt == 0)
 			inactive_cycles++;
-			trace_idle_sleep_enter3(sys->ep->client);
-			usleep_range(POLLING_MIN_SLEEP_RX,
-					POLLING_MAX_SLEEP_RX);
-			trace_idle_sleep_exit3(sys->ep->client);
-		} else {
+		else
 			inactive_cycles = 0;
-		}
+
+		trace_idle_sleep_enter3(sys->ep->client);
+		usleep_range(POLLING_MIN_SLEEP_RX, POLLING_MAX_SLEEP_RX);
+		trace_idle_sleep_exit3(sys->ep->client);
 	} while (inactive_cycles <= POLLING_INACTIVITY_RX);
 
 	trace_poll_to_intr3(sys->ep->client);
@@ -808,6 +799,15 @@
 		ipa3_handle_rx(sys);
 }
 
+enum hrtimer_restart ipa3_ring_doorbell_timer_fn(struct hrtimer *param)
+{
+	struct ipa3_sys_context *sys = container_of(param,
+		struct ipa3_sys_context, db_timer);
+
+	queue_work(sys->wq, &sys->work);
+	return HRTIMER_NORESTART;
+}
+
 /**
  * ipa3_setup_sys_pipe() - Setup an IPA GPI pipe and perform
  * IPA EP configuration
@@ -889,6 +889,9 @@
 		INIT_LIST_HEAD(&ep->sys->head_desc_list);
 		INIT_LIST_HEAD(&ep->sys->rcycl_list);
 		spin_lock_init(&ep->sys->spinlock);
+		hrtimer_init(&ep->sys->db_timer, CLOCK_MONOTONIC,
+			HRTIMER_MODE_REL);
+		ep->sys->db_timer.function = ipa3_ring_doorbell_timer_fn;
 	} else {
 		memset(ep->sys, 0, offsetof(struct ipa3_sys_context, ep));
 	}
@@ -1071,7 +1074,10 @@
 	}
 
 	/* free event ring only when it is present */
-	if (ep->gsi_evt_ring_hdl != ~0) {
+	if (ep->sys->use_comm_evt_ring) {
+		ipa3_ctx->gsi_evt_comm_ring_rem +=
+			ep->gsi_mem_info.chan_ring_len;
+	} else if (ep->gsi_evt_ring_hdl != ~0) {
 		result = gsi_reset_evt_ring(ep->gsi_evt_ring_hdl);
 		if (result != GSI_STATUS_SUCCESS) {
 			IPAERR("Failed to reset evt ring: %d.\n",
@@ -1145,7 +1151,7 @@
 		dev_kfree_skb_any(skb);
 }
 
-static void ipa3_tx_cmd_comp(void *user1, int user2)
+void ipa3_tx_cmd_comp(void *user1, int user2)
 {
 	ipahal_destroy_imm_cmd(user1);
 }
@@ -1180,7 +1186,6 @@
 	struct ipa3_desc *desc;
 	struct ipa3_desc _desc[3];
 	int dst_ep_idx;
-	struct ipahal_imm_cmd_ip_packet_init cmd;
 	struct ipahal_imm_cmd_pyld *cmd_pyld = NULL;
 	struct ipa3_sys_context *sys;
 	int src_ep_idx;
@@ -1267,54 +1272,58 @@
 
 	if (dst_ep_idx != -1) {
 		/* SW data path */
-		cmd.destination_pipe_index = dst_ep_idx;
-		cmd_pyld = ipahal_construct_imm_cmd(
-			IPA_IMM_CMD_IP_PACKET_INIT, &cmd, true);
-		if (unlikely(!cmd_pyld)) {
-			IPAERR("failed to construct ip_packet_init imm cmd\n");
-			goto fail_mem;
+		data_idx = 0;
+		if (sys->policy == IPA_POLICY_NOINTR_MODE) {
+			/*
+			 * For non-interrupt mode channel (where there is no
+			 * event ring) TAG STATUS are used for completion
+			 * notification. IPA will generate a status packet with
+			 * tag info as a result of the TAG STATUS command.
+			 */
+			desc[data_idx].opcode =
+				ipahal_imm_cmd_get_opcode(
+				IPA_IMM_CMD_IP_PACKET_TAG_STATUS);
+			desc[data_idx].type = IPA_IMM_CMD_DESC;
+			desc[data_idx].callback = ipa3_tag_destroy_imm;
+			data_idx++;
 		}
-
-		/* the tag field will be populated in ipa3_send() function */
-		desc[0].opcode = ipahal_imm_cmd_get_opcode(
-			IPA_IMM_CMD_IP_PACKET_TAG_STATUS);
-		desc[0].type = IPA_IMM_CMD_DESC;
-		desc[0].callback = ipa3_tag_destroy_imm;
-		desc[1].opcode =
+		desc[data_idx].opcode =
 			ipahal_imm_cmd_get_opcode(IPA_IMM_CMD_IP_PACKET_INIT);
-		desc[1].pyld = cmd_pyld->data;
-		desc[1].len = cmd_pyld->len;
-		desc[1].type = IPA_IMM_CMD_DESC;
-		desc[1].callback = ipa3_tx_cmd_comp;
-		desc[1].user1 = cmd_pyld;
-		desc[2].pyld = skb->data;
-		desc[2].len = skb_headlen(skb);
-		desc[2].type = IPA_DATA_DESC_SKB;
-		desc[2].callback = ipa3_tx_comp_usr_notify_release;
-		desc[2].user1 = skb;
-		desc[2].user2 = (meta && meta->pkt_init_dst_ep_valid &&
+		desc[data_idx].dma_address_valid = true;
+		desc[data_idx].dma_address = ipa3_ctx->pkt_init_imm[dst_ep_idx];
+		desc[data_idx].type = IPA_IMM_CMD_DESC;
+		desc[data_idx].callback = NULL;
+		data_idx++;
+		desc[data_idx].pyld = skb->data;
+		desc[data_idx].len = skb_headlen(skb);
+		desc[data_idx].type = IPA_DATA_DESC_SKB;
+		desc[data_idx].callback = ipa3_tx_comp_usr_notify_release;
+		desc[data_idx].user1 = skb;
+		desc[data_idx].user2 = (meta && meta->pkt_init_dst_ep_valid &&
 				meta->pkt_init_dst_ep_remote) ?
 				src_ep_idx :
 				dst_ep_idx;
 		if (meta && meta->dma_address_valid) {
-			desc[2].dma_address_valid = true;
-			desc[2].dma_address = meta->dma_address;
+			desc[data_idx].dma_address_valid = true;
+			desc[data_idx].dma_address = meta->dma_address;
 		}
+		data_idx++;
 
 		for (f = 0; f < num_frags; f++) {
-			desc[3+f].frag = &skb_shinfo(skb)->frags[f];
-			desc[3+f].type = IPA_DATA_DESC_SKB_PAGED;
-			desc[3+f].len = skb_frag_size(desc[3+f].frag);
+			desc[data_idx + f].frag = &skb_shinfo(skb)->frags[f];
+			desc[data_idx + f].type = IPA_DATA_DESC_SKB_PAGED;
+			desc[data_idx + f].len =
+				skb_frag_size(desc[data_idx + f].frag);
 		}
 		/* don't free skb till frag mappings are released */
 		if (num_frags) {
-			desc[3+f-1].callback = desc[2].callback;
-			desc[3+f-1].user1 = desc[2].user1;
-			desc[3+f-1].user2 = desc[2].user2;
-			desc[2].callback = NULL;
+			desc[data_idx + f - 1].callback = desc[2].callback;
+			desc[data_idx + f - 1].user1 = desc[2].user1;
+			desc[data_idx + f - 1].user2 = desc[2].user2;
+			desc[data_idx - 1].callback = NULL;
 		}
 
-		if (ipa3_send(sys, num_frags + 3, desc, true)) {
+		if (ipa3_send(sys, num_frags + data_idx, desc, true)) {
 			IPAERR("fail to send skb %p num_frags %u SWP\n",
 				skb, num_frags);
 			goto fail_send;
@@ -1699,12 +1708,21 @@
 		gsi_xfer_elem_one.xfer_user_data = rx_pkt;
 
 		ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl,
-				1, &gsi_xfer_elem_one, true);
+				1, &gsi_xfer_elem_one, false);
 		if (ret != GSI_STATUS_SUCCESS) {
 			IPAERR("failed to provide buffer: %d\n",
 				ret);
 			goto fail_provide_rx_buffer;
 		}
+
+		/*
+		 * As doorbell is a costly operation, notify to GSI
+		 * of new buffers if threshold is exceeded
+		 */
+		if (++sys->len_pending_xfer >= IPA_REPL_XFER_THRESH) {
+			sys->len_pending_xfer = 0;
+			gsi_start_xfer(sys->ep->gsi_chan_hdl);
+		}
 	}
 
 	return;
@@ -1719,7 +1737,7 @@
 fail_skb_alloc:
 	kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache, rx_pkt);
 fail_kmem_cache_alloc:
-	if (rx_len_cached == 0)
+	if (rx_len_cached - sys->len_pending_xfer == 0)
 		queue_delayed_work(sys->wq, &sys->replenish_rx_work,
 				msecs_to_jiffies(1));
 }
@@ -1794,12 +1812,21 @@
 		gsi_xfer_elem_one.xfer_user_data = rx_pkt;
 
 		ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl,
-				1, &gsi_xfer_elem_one, true);
+				1, &gsi_xfer_elem_one, false);
 		if (ret != GSI_STATUS_SUCCESS) {
 			IPAERR("failed to provide buffer: %d\n",
 				ret);
 			goto fail_provide_rx_buffer;
 		}
+
+		/*
+		 * As doorbell is a costly operation, notify to GSI
+		 * of new buffers if threshold is exceeded
+		 */
+		if (++sys->len_pending_xfer >= IPA_REPL_XFER_THRESH) {
+			sys->len_pending_xfer = 0;
+			gsi_start_xfer(sys->ep->gsi_chan_hdl);
+		}
 	}
 
 	return;
@@ -1815,7 +1842,7 @@
 	INIT_LIST_HEAD(&rx_pkt->link);
 	spin_unlock_bh(&sys->spinlock);
 fail_kmem_cache_alloc:
-	if (rx_len_cached == 0)
+	if (rx_len_cached - sys->len_pending_xfer == 0)
 		queue_delayed_work(sys->wq, &sys->replenish_rx_work,
 		msecs_to_jiffies(1));
 }
@@ -1848,12 +1875,22 @@
 		gsi_xfer_elem_one.xfer_user_data = rx_pkt;
 
 		ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl, 1,
-			&gsi_xfer_elem_one, true);
+			&gsi_xfer_elem_one, false);
 		if (ret != GSI_STATUS_SUCCESS) {
 			IPAERR("failed to provide buffer: %d\n",
 				ret);
 			break;
 		}
+
+		/*
+		 * As doorbell is a costly operation, notify to GSI
+		 * of new buffers if threshold is exceeded
+		 */
+		if (++sys->len_pending_xfer >= IPA_REPL_XFER_THRESH) {
+			sys->len_pending_xfer = 0;
+			gsi_start_xfer(sys->ep->gsi_chan_hdl);
+		}
+
 		rx_len_cached = ++sys->len;
 		curr = (curr + 1) % sys->repl.capacity;
 		/* ensure write is done before setting head index */
@@ -1863,7 +1900,8 @@
 
 	queue_work(sys->repl_wq, &sys->repl_work);
 
-	if (rx_len_cached <= IPA_DEFAULT_SYS_YELLOW_WM) {
+	if (rx_len_cached - sys->len_pending_xfer
+		<= IPA_DEFAULT_SYS_YELLOW_WM) {
 		if (sys->ep->client == IPA_CLIENT_APPS_WAN_CONS)
 			IPA_STATS_INC_CNT(ipa3_ctx->stats.wan_rx_empty);
 		else if (sys->ep->client == IPA_CLIENT_APPS_LAN_CONS)
@@ -2641,6 +2679,7 @@
 	if (in->client == IPA_CLIENT_APPS_CMD_PROD ||
 		in->client == IPA_CLIENT_APPS_WAN_PROD) {
 		sys->policy = IPA_POLICY_INTR_MODE;
+		sys->use_comm_evt_ring = false;
 		return 0;
 	}
 
@@ -2652,12 +2691,12 @@
 	if (IPA_CLIENT_IS_PROD(in->client)) {
 		if (sys->ep->skip_ep_cfg) {
 			sys->policy = IPA_POLICY_INTR_POLL_MODE;
+			sys->use_comm_evt_ring = true;
 			atomic_set(&sys->curr_polling_state, 0);
 		} else {
-			sys->policy = IPA_POLICY_NOINTR_MODE;
-			sys->ep->status.status_en = true;
-			sys->ep->status.status_ep = ipa3_get_ep_mapping(
-					IPA_CLIENT_APPS_LAN_CONS);
+			sys->policy = IPA_POLICY_INTR_MODE;
+			sys->use_comm_evt_ring = true;
+			INIT_WORK(&sys->work, ipa3_send_nop_desc);
 		}
 	} else {
 		if (in->client == IPA_CLIENT_APPS_LAN_CONS ||
@@ -3325,6 +3364,46 @@
 	}
 }
 
+int ipa3_alloc_common_event_ring(void)
+{
+	struct gsi_evt_ring_props gsi_evt_ring_props;
+	dma_addr_t evt_dma_addr;
+	int result;
+
+	memset(&gsi_evt_ring_props, 0, sizeof(gsi_evt_ring_props));
+	gsi_evt_ring_props.intf = GSI_EVT_CHTYPE_GPI_EV;
+	gsi_evt_ring_props.intr = GSI_INTR_IRQ;
+	gsi_evt_ring_props.re_size = GSI_EVT_RING_RE_SIZE_16B;
+
+	gsi_evt_ring_props.ring_len = IPA_COMMON_EVENT_RING_SIZE;
+
+	gsi_evt_ring_props.ring_base_vaddr =
+		dma_alloc_coherent(ipa3_ctx->pdev,
+		gsi_evt_ring_props.ring_len, &evt_dma_addr, GFP_KERNEL);
+	if (!gsi_evt_ring_props.ring_base_vaddr) {
+		IPAERR("fail to dma alloc %u bytes\n",
+			gsi_evt_ring_props.ring_len);
+		return -ENOMEM;
+	}
+	gsi_evt_ring_props.ring_base_addr = evt_dma_addr;
+	gsi_evt_ring_props.int_modt = 0;
+	gsi_evt_ring_props.int_modc = 1; /* moderation comes from channel*/
+	gsi_evt_ring_props.rp_update_addr = 0;
+	gsi_evt_ring_props.exclusive = false;
+	gsi_evt_ring_props.err_cb = ipa_gsi_evt_ring_err_cb;
+	gsi_evt_ring_props.user_data = NULL;
+
+	result = gsi_alloc_evt_ring(&gsi_evt_ring_props,
+		ipa3_ctx->gsi_dev_hdl, &ipa3_ctx->gsi_evt_comm_hdl);
+	if (result) {
+		IPAERR("gsi_alloc_evt_ring failed %d\n", result);
+		return result;
+	}
+	ipa3_ctx->gsi_evt_comm_ring_rem = IPA_COMMON_EVENT_RING_SIZE;
+
+	return 0;
+}
+
 static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in,
 	struct ipa3_ep_context *ep)
 {
@@ -3344,11 +3423,18 @@
 	evt_dma_addr = 0;
 	ep->gsi_evt_ring_hdl = ~0;
 	memset(&gsi_evt_ring_props, 0, sizeof(gsi_evt_ring_props));
-	/*
-	 * allocate event ring for all interrupt-policy
-	 * pipes and IPA consumers pipes
-	 */
-	if (ep->sys->policy != IPA_POLICY_NOINTR_MODE ||
+	if (ep->sys->use_comm_evt_ring) {
+		if (ipa3_ctx->gsi_evt_comm_ring_rem < 2 * in->desc_fifo_sz) {
+			IPAERR("not enough space in common event ring\n");
+			IPAERR("available: %d needed: %d\n",
+				ipa3_ctx->gsi_evt_comm_ring_rem,
+				2 * in->desc_fifo_sz);
+			WARN_ON(1);
+			return -EFAULT;
+		}
+		ipa3_ctx->gsi_evt_comm_ring_rem -= (2 * in->desc_fifo_sz);
+		ep->gsi_evt_ring_hdl = ipa3_ctx->gsi_evt_comm_hdl;
+	} else if (ep->sys->policy != IPA_POLICY_NOINTR_MODE ||
 	     IPA_CLIENT_IS_CONS(ep->client)) {
 		gsi_evt_ring_props.intf = GSI_EVT_CHTYPE_GPI_EV;
 		gsi_evt_ring_props.intr = GSI_INTR_IRQ;
@@ -3375,10 +3461,7 @@
 			gsi_evt_ring_props.ring_base_vaddr;
 
 		gsi_evt_ring_props.int_modt = IPA_GSI_EVT_RING_INT_MODT;
-		if (ep->client == IPA_CLIENT_APPS_WAN_PROD)
-			gsi_evt_ring_props.int_modc = 248;
-		else
-			gsi_evt_ring_props.int_modc = 1;
+		gsi_evt_ring_props.int_modc = 1;
 
 		IPADBG("client=%d moderation threshold cycles=%u cnt=%u\n",
 			ep->client,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 1a0d3ad..7419a64 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -45,6 +45,7 @@
 #define IPA3_MAX_NUM_PIPES 31
 #define IPA_SYS_DESC_FIFO_SZ 0x800
 #define IPA_SYS_TX_DATA_DESC_FIFO_SZ 0x1000
+#define IPA_COMMON_EVENT_RING_SIZE 0x7C00
 #define IPA_LAN_RX_HEADER_LENGTH (2)
 #define IPA_QMAP_HEADER_LENGTH (4)
 #define IPA_DL_CHECKSUM_LENGTH (8)
@@ -591,9 +592,11 @@
  */
 struct ipa3_sys_context {
 	u32 len;
+	u32 len_pending_xfer;
 	atomic_t curr_polling_state;
 	struct delayed_work switch_to_intr_work;
 	enum ipa3_sys_pipe_policy policy;
+	bool use_comm_evt_ring;
 	int (*pyld_hdlr)(struct sk_buff *skb, struct ipa3_sys_context *sys);
 	struct sk_buff * (*get_skb)(unsigned int len, gfp_t flags);
 	void (*free_skb)(struct sk_buff *skb);
@@ -616,6 +619,7 @@
 	struct list_head head_desc_list;
 	struct list_head rcycl_list;
 	spinlock_t spinlock;
+	struct hrtimer db_timer;
 	struct workqueue_struct *wq;
 	struct workqueue_struct *repl_wq;
 	struct ipa3_status_stats *status_stat;
@@ -702,6 +706,7 @@
  * @user1: cookie1 for above callback
  * @user2: cookie2 for above callback
  * @xfer_done: completion object for sync completion
+ * @skip_db_ring: specifies whether GSI doorbell should not be rang
  */
 struct ipa3_desc {
 	enum ipa3_desc_type type;
@@ -715,6 +720,7 @@
 	void *user1;
 	int user2;
 	struct completion xfer_done;
+	bool skip_db_ring;
 };
 
 /**
@@ -1133,6 +1139,8 @@
 	struct workqueue_struct *transport_power_mgmt_wq;
 	bool tag_process_before_gating;
 	struct ipa3_transport_pm transport_pm;
+	unsigned long gsi_evt_comm_hdl;
+	u32 gsi_evt_comm_ring_rem;
 	u32 clnt_hdl_cmd;
 	u32 clnt_hdl_data_in;
 	u32 clnt_hdl_data_out;
@@ -1165,6 +1173,7 @@
 	u32 curr_ipa_clk_rate;
 	bool q6_proxy_clk_vote_valid;
 	u32 ipa_num_pipes;
+	dma_addr_t pkt_init_imm[IPA3_MAX_NUM_PIPES];
 
 	struct ipa3_wlan_comm_memb wc_memb;
 
@@ -1971,4 +1980,5 @@
 struct device *ipa3_get_pdev(void);
 void ipa3_enable_dcd(void);
 void ipa3_disable_prefetch(enum ipa_client_type client);
+int ipa3_alloc_common_event_ring(void);
 #endif /* _IPA3_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
index c69a3d0..799246b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
@@ -1207,6 +1207,8 @@
 		IPADBG("Skipping endpoint configuration.\n");
 	}
 
+	ipa3_enable_data_path(ipa_ep_idx);
+
 	out->clnt_hdl = ipa_ep_idx;
 
 	if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(in->sys.client))
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 757541b..6cfe25d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -335,12 +335,13 @@
 	[IPA_3_0][IPA_CLIENT_APPS_LAN_PROD] = {
 			14, IPA_v3_0_GROUP_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 14, 11, 8, 16, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_APPS_WAN_PROD] = {
 			3, IPA_v3_0_GROUP_UL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
 			QMB_MASTER_SELECT_DDR,
-			{ 14, 11, 8, 16, IPA_EE_AP } },
+			{ 3, 5, 16, 32, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_APPS_CMD_PROD]	  = {
 			22, IPA_v3_0_GROUP_IMM_CMD, false,
 			IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
@@ -568,8 +569,8 @@
 	[IPA_3_5][IPA_CLIENT_A2_EMBEDDED_PROD]    = IPA_CLIENT_NOT_USED,
 	[IPA_3_5][IPA_CLIENT_A2_TETHERED_PROD]    = IPA_CLIENT_NOT_USED,
 	[IPA_3_5][IPA_CLIENT_APPS_LAN_PROD]   = {
-			8, IPA_v3_5_GROUP_UL_DL, true,
-			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
+			8, IPA_v3_5_GROUP_UL_DL, false,
+			IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
 			QMB_MASTER_SELECT_DDR,
 			{ 8, 9, 8, 16, IPA_EE_AP } },
 	[IPA_3_5][IPA_CLIENT_APPS_WAN_PROD] = {
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index a74d8ca..d16e3e8 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -665,7 +665,7 @@
 	.set_cur_state = ps_set_cur_charge_cntl_limit,
 };
 
-static int psy_register_cooler(struct power_supply *psy)
+static int psy_register_cooler(struct device *dev, struct power_supply *psy)
 {
 	int i;
 
@@ -673,7 +673,13 @@
 	for (i = 0; i < psy->desc->num_properties; i++) {
 		if (psy->desc->properties[i] ==
 				POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT) {
-			psy->tcd = thermal_cooling_device_register(
+			if (dev)
+				psy->tcd = thermal_of_cooling_device_register(
+							dev_of_node(dev),
+							(char *)psy->desc->name,
+							psy, &psy_tcd_ops);
+			else
+				psy->tcd = thermal_cooling_device_register(
 							(char *)psy->desc->name,
 							psy, &psy_tcd_ops);
 			return PTR_ERR_OR_ZERO(psy->tcd);
@@ -698,7 +704,7 @@
 {
 }
 
-static int psy_register_cooler(struct power_supply *psy)
+static int psy_register_cooler(struct device *dev, struct power_supply *psy)
 {
 	return 0;
 }
@@ -770,7 +776,7 @@
 	if (rc)
 		goto register_thermal_failed;
 
-	rc = psy_register_cooler(psy);
+	rc = psy_register_cooler(parent, psy);
 	if (rc)
 		goto register_cooler_failed;
 
diff --git a/drivers/regulator/qpnp-labibb-regulator.c b/drivers/regulator/qpnp-labibb-regulator.c
index cf8f000..dbe2a08 100644
--- a/drivers/regulator/qpnp-labibb-regulator.c
+++ b/drivers/regulator/qpnp-labibb-regulator.c
@@ -19,16 +19,19 @@
 #include <linux/kernel.h>
 #include <linux/regmap.h>
 #include <linux/module.h>
+#include <linux/notifier.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
 #include <linux/spmi.h>
 #include <linux/platform_device.h>
 #include <linux/string.h>
+#include <linux/workqueue.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/qpnp/qpnp-revid.h>
+#include <linux/regulator/qpnp-labibb-regulator.h>
 
 #define QPNP_LABIBB_REGULATOR_DRIVER_NAME	"qcom,qpnp-labibb-regulator"
 
@@ -594,6 +597,7 @@
 	const struct lab_ver_ops	*lab_ver_ops;
 	struct mutex			bus_mutex;
 	enum qpnp_labibb_mode		mode;
+	struct work_struct		lab_vreg_ok_work;
 	bool				standalone;
 	bool				ttw_en;
 	bool				in_ttw_mode;
@@ -603,10 +607,13 @@
 	bool				ttw_force_lab_on;
 	bool				skip_2nd_swire_cmd;
 	bool				pfm_enable;
+	bool				notify_lab_vreg_ok_sts;
 	u32				swire_2nd_cmd_delay;
 	u32				swire_ibb_ps_enable_delay;
 };
 
+static RAW_NOTIFIER_HEAD(labibb_notifier);
+
 struct ibb_ver_ops {
 	int (*set_default_voltage)(struct qpnp_labibb *labibb,
 			bool use_default);
@@ -2124,6 +2131,36 @@
 	return rc;
 }
 
+static void qpnp_lab_vreg_notifier_work(struct work_struct *work)
+{
+	int rc = 0;
+	u16 retries = 1000, dly = 5000;
+	u8 val;
+	struct qpnp_labibb *labibb  = container_of(work, struct qpnp_labibb,
+							lab_vreg_ok_work);
+
+	while (retries--) {
+		rc = qpnp_labibb_read(labibb, labibb->lab_base +
+					REG_LAB_STATUS1, &val, 1);
+		if (rc < 0) {
+			pr_err("read register %x failed rc = %d\n",
+				REG_LAB_STATUS1, rc);
+			return;
+		}
+
+		if (val & LAB_STATUS1_VREG_OK) {
+			raw_notifier_call_chain(&labibb_notifier,
+						LAB_VREG_OK, NULL);
+			break;
+		}
+
+		usleep_range(dly, dly + 100);
+	}
+
+	if (!retries)
+		pr_err("LAB_VREG_OK not set, failed to notify\n");
+}
+
 static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb)
 {
 	int rc;
@@ -2326,6 +2363,9 @@
 		labibb->lab_vreg.vreg_enabled = 1;
 	}
 
+	if (labibb->notify_lab_vreg_ok_sts)
+		schedule_work(&labibb->lab_vreg_ok_work);
+
 	return 0;
 }
 
@@ -2578,6 +2618,9 @@
 		return rc;
 	}
 
+	labibb->notify_lab_vreg_ok_sts = of_property_read_bool(of_node,
+					"qcom,notify-lab-vreg-ok-sts");
+
 	rc = of_property_read_u32(of_node, "qcom,qpnp-lab-soft-start",
 					&(labibb->lab_vreg.soft_start));
 	if (!rc) {
@@ -3817,6 +3860,8 @@
 			goto fail_registration;
 		}
 	}
+
+	INIT_WORK(&labibb->lab_vreg_ok_work, qpnp_lab_vreg_notifier_work);
 	dev_set_drvdata(&pdev->dev, labibb);
 	pr_info("LAB/IBB registered successfully, lab_vreg enable=%d ibb_vreg enable=%d swire_control=%d\n",
 						labibb->lab_vreg.vreg_enabled,
@@ -3834,6 +3879,18 @@
 	return rc;
 }
 
+int qpnp_labibb_notifier_register(struct notifier_block *nb)
+{
+	return raw_notifier_chain_register(&labibb_notifier, nb);
+}
+EXPORT_SYMBOL(qpnp_labibb_notifier_register);
+
+int qpnp_labibb_notifier_unregister(struct notifier_block *nb)
+{
+	return raw_notifier_chain_unregister(&labibb_notifier, nb);
+}
+EXPORT_SYMBOL(qpnp_labibb_notifier_unregister);
+
 static int qpnp_labibb_regulator_remove(struct platform_device *pdev)
 {
 	struct qpnp_labibb *labibb = dev_get_drvdata(&pdev->dev);
@@ -3843,6 +3900,8 @@
 			regulator_unregister(labibb->lab_vreg.rdev);
 		if (labibb->ibb_vreg.rdev)
 			regulator_unregister(labibb->ibb_vreg.rdev);
+
+		cancel_work_sync(&labibb->lab_vreg_ok_work);
 	}
 	return 0;
 }
diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c
index a08ade6..aef28db 100644
--- a/drivers/regulator/qpnp-lcdb-regulator.c
+++ b/drivers/regulator/qpnp-lcdb-regulator.c
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
+#include <linux/ktime.h>
 #include <linux/module.h>
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
@@ -31,6 +32,13 @@
 
 #define INT_RT_STATUS_REG		0x10
 #define VREG_OK_RT_STS_BIT		BIT(0)
+#define SC_ERROR_RT_STS_BIT		BIT(1)
+
+#define LCDB_STS3_REG			0x0A
+#define LDO_VREG_OK_BIT			BIT(7)
+
+#define LCDB_STS4_REG			0x0B
+#define NCP_VREG_OK_BIT			BIT(7)
 
 #define LCDB_AUTO_TOUCH_WAKE_CTL_REG	0x40
 #define EN_AUTO_TOUCH_WAKE_BIT		BIT(7)
@@ -185,14 +193,21 @@
 	struct platform_device		*pdev;
 	struct regmap			*regmap;
 	u32				base;
+	int				sc_irq;
 
 	/* TTW params */
 	bool				ttw_enable;
 	bool				ttw_mode_sw;
 
+	/* top level DT params */
+	bool				force_module_reenable;
+
 	/* status parameters */
 	bool				lcdb_enabled;
 	bool				settings_saved;
+	bool				lcdb_sc_disable;
+	int				sc_count;
+	ktime_t				sc_module_enable_time;
 
 	struct mutex			lcdb_mutex;
 	struct mutex			read_write_mutex;
@@ -569,8 +584,11 @@
 	int rc = 0, timeout, delay;
 	u8 val = 0;
 
-	if (lcdb->lcdb_enabled)
+	if (lcdb->lcdb_enabled || lcdb->lcdb_sc_disable) {
+		pr_debug("lcdb_enabled=%d lcdb_sc_disable=%d\n",
+			lcdb->lcdb_enabled, lcdb->lcdb_sc_disable);
 		return 0;
+	}
 
 	if (lcdb->ttw_enable) {
 		rc = qpnp_lcdb_ttw_exit(lcdb);
@@ -588,6 +606,23 @@
 		goto fail_enable;
 	}
 
+	if (lcdb->force_module_reenable) {
+		val = 0;
+		rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
+								&val, 1);
+		if (rc < 0) {
+			pr_err("Failed to enable lcdb rc= %d\n", rc);
+			goto fail_enable;
+		}
+		val = MODULE_EN_BIT;
+		rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
+								&val, 1);
+		if (rc < 0) {
+			pr_err("Failed to disable lcdb rc= %d\n", rc);
+			goto fail_enable;
+		}
+	}
+
 	/* poll for vreg_ok */
 	timeout = 10;
 	delay = lcdb->bst.soft_start_us + lcdb->ldo.soft_start_us +
@@ -656,6 +691,111 @@
 	return rc;
 }
 
+#define LCDB_SC_RESET_CNT_DLY_US	1000000
+#define LCDB_SC_CNT_MAX			10
+static int qpnp_lcdb_handle_sc_event(struct qpnp_lcdb *lcdb)
+{
+	int rc = 0;
+	s64 elapsed_time_us;
+
+	mutex_lock(&lcdb->lcdb_mutex);
+	rc = qpnp_lcdb_disable(lcdb);
+	if (rc < 0) {
+		pr_err("Failed to disable lcdb rc=%d\n", rc);
+		goto unlock_mutex;
+	}
+
+	/* Check if the SC re-occurred immediately */
+	elapsed_time_us = ktime_us_delta(ktime_get(),
+			lcdb->sc_module_enable_time);
+	if (elapsed_time_us > LCDB_SC_RESET_CNT_DLY_US) {
+		lcdb->sc_count = 0;
+	} else if (lcdb->sc_count > LCDB_SC_CNT_MAX) {
+		pr_err("SC trigged %d times, disabling LCDB forever!\n",
+						lcdb->sc_count);
+		lcdb->lcdb_sc_disable = true;
+		goto unlock_mutex;
+	}
+	lcdb->sc_count++;
+	lcdb->sc_module_enable_time = ktime_get();
+
+	/* delay for SC to clear */
+	usleep_range(10000, 10100);
+
+	rc = qpnp_lcdb_enable(lcdb);
+	if (rc < 0)
+		pr_err("Failed to enable lcdb rc=%d\n", rc);
+
+unlock_mutex:
+	mutex_unlock(&lcdb->lcdb_mutex);
+	return rc;
+}
+
+static irqreturn_t qpnp_lcdb_sc_irq_handler(int irq, void *data)
+{
+	struct qpnp_lcdb *lcdb = data;
+	int rc;
+	u8 val, val2[2] = {0};
+
+	rc = qpnp_lcdb_read(lcdb, lcdb->base + INT_RT_STATUS_REG, &val, 1);
+	if (rc < 0)
+		goto irq_handled;
+
+	if (val & SC_ERROR_RT_STS_BIT) {
+		rc = qpnp_lcdb_read(lcdb,
+			lcdb->base + LCDB_MISC_CTL_REG, &val, 1);
+		if (rc < 0)
+			goto irq_handled;
+
+		if (val & EN_TOUCH_WAKE_BIT) {
+			/* blanking time */
+			usleep_range(300, 310);
+			/*
+			 * The status registers need to written with any value
+			 * before reading
+			 */
+			rc = qpnp_lcdb_write(lcdb,
+				lcdb->base + LCDB_STS3_REG, val2, 2);
+			if (rc < 0)
+				goto irq_handled;
+
+			rc = qpnp_lcdb_read(lcdb,
+				lcdb->base + LCDB_STS3_REG, val2, 2);
+			if (rc < 0)
+				goto irq_handled;
+
+			if (!(val2[0] & LDO_VREG_OK_BIT) ||
+					!(val2[1] & NCP_VREG_OK_BIT)) {
+				rc = qpnp_lcdb_handle_sc_event(lcdb);
+				if (rc < 0) {
+					pr_err("Failed to handle SC rc=%d\n",
+								rc);
+					goto irq_handled;
+				}
+			}
+		} else {
+			/* blanking time */
+			usleep_range(2000, 2100);
+			/* Read the SC status again to confirm true SC */
+			rc = qpnp_lcdb_read(lcdb,
+				lcdb->base + INT_RT_STATUS_REG, &val, 1);
+			if (rc < 0)
+				goto irq_handled;
+
+			if (val & SC_ERROR_RT_STS_BIT) {
+				rc = qpnp_lcdb_handle_sc_event(lcdb);
+				if (rc < 0) {
+					pr_err("Failed to handle SC rc=%d\n",
+								rc);
+					goto irq_handled;
+				}
+			}
+		}
+	}
+irq_handled:
+	return IRQ_HANDLED;
+}
+
 #define MIN_BST_VOLTAGE_MV			4700
 #define MAX_BST_VOLTAGE_MV			6250
 #define MIN_VOLTAGE_MV				4000
@@ -1534,6 +1674,18 @@
 		return rc;
 	}
 
+	if (lcdb->sc_irq >= 0) {
+		lcdb->sc_count = 0;
+		rc = devm_request_threaded_irq(lcdb->dev, lcdb->sc_irq,
+				NULL, qpnp_lcdb_sc_irq_handler, IRQF_ONESHOT,
+				"qpnp_lcdb_sc_irq", lcdb);
+		if (rc < 0) {
+			pr_err("Unable to request sc(%d) irq rc=%d\n",
+						lcdb->sc_irq, rc);
+			return rc;
+		}
+	}
+
 	if (!is_lcdb_enabled(lcdb)) {
 		rc = qpnp_lcdb_read(lcdb, lcdb->base +
 				LCDB_MODULE_RDY_REG, &val, 1);
@@ -1590,6 +1742,9 @@
 		}
 	}
 
+	lcdb->force_module_reenable = of_property_read_bool(node,
+					"qcom,force-module-reenable");
+
 	if (of_property_read_bool(node, "qcom,ttw-enable")) {
 		rc = qpnp_lcdb_parse_ttw(lcdb);
 		if (rc < 0) {
@@ -1599,6 +1754,10 @@
 		lcdb->ttw_enable = true;
 	}
 
+	lcdb->sc_irq = platform_get_irq_byname(lcdb->pdev, "sc-irq");
+	if (lcdb->sc_irq < 0)
+		pr_debug("sc irq is not defined\n");
+
 	return rc;
 }
 
diff --git a/drivers/regulator/qpnp-oledb-regulator.c b/drivers/regulator/qpnp-oledb-regulator.c
index 8d017fb..c012f37 100644
--- a/drivers/regulator/qpnp-oledb-regulator.c
+++ b/drivers/regulator/qpnp-oledb-regulator.c
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/notifier.h>
 #include <linux/of.h>
 #include <linux/regmap.h>
 #include <linux/spmi.h>
@@ -24,6 +25,8 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/of_regulator.h>
+#include <linux/regulator/qpnp-labibb-regulator.h>
+#include <linux/qpnp/qpnp-pbs.h>
 
 #define QPNP_OLEDB_REGULATOR_DRIVER_NAME	"qcom,qpnp-oledb-regulator"
 #define OLEDB_VOUT_STEP_MV				100
@@ -91,6 +94,12 @@
 #define OLEDB_ENABLE_NLIMIT_BIT_SHIFT			7
 #define OLEDB_NLIMIT_PGM_MASK				GENMASK(1, 0)
 
+#define OLEDB_SPARE_CTL					0xE9
+#define OLEDB_FORCE_PD_CTL_SPARE_BIT			BIT(7)
+
+#define OLEDB_PD_PBS_TRIGGER_BIT			BIT(0)
+
+#define OLEDB_SEC_UNLOCK_CODE				0xA5
 #define OLEDB_PSM_HYS_CTRL_MIN				13
 #define OLEDB_PSM_HYS_CTRL_MAX				26
 
@@ -150,6 +159,9 @@
 	struct qpnp_oledb_psm_ctl		psm_ctl;
 	struct qpnp_oledb_pfm_ctl		pfm_ctl;
 	struct qpnp_oledb_fast_precharge_ctl	fast_prechg_ctl;
+	struct notifier_block			oledb_nb;
+	struct mutex				bus_lock;
+	struct device_node			*pbs_dev_node;
 
 	u32					base;
 	u8					mod_enable;
@@ -168,6 +180,7 @@
 	bool					ext_pin_control;
 	bool					dynamic_ext_pinctl_config;
 	bool					pbs_control;
+	bool					force_pd_control;
 };
 
 static const u16 oledb_warmup_dly_ns[] = {6700, 13300, 26700, 53400};
@@ -184,11 +197,13 @@
 	int rc = 0;
 	struct platform_device *pdev = oledb->pdev;
 
+	mutex_lock(&oledb->bus_lock);
 	rc = regmap_bulk_read(oledb->regmap, address, val, count);
 	if (rc)
 		pr_err("Failed to read address=0x%02x sid=0x%02x rc=%d\n",
 			address, to_spmi_device(pdev->dev.parent)->usid, rc);
 
+	mutex_unlock(&oledb->bus_lock);
 	return rc;
 }
 
@@ -197,6 +212,7 @@
 {
 	int rc;
 
+	mutex_lock(&oledb->bus_lock);
 	rc = regmap_update_bits(oledb->regmap, address, mask, val);
 	if (rc < 0)
 		pr_err("Failed to write address 0x%04X, rc = %d\n",
@@ -205,6 +221,31 @@
 		pr_debug("Wrote 0x%02X to addr 0x%04X\n",
 			val, address);
 
+	mutex_unlock(&oledb->bus_lock);
+	return rc;
+}
+
+#define OLEDB_SEC_ACCESS	0xD0
+static int qpnp_oledb_sec_masked_write(struct qpnp_oledb *oledb, u16 address,
+							 u8 mask, u8 val)
+{
+	int rc = 0;
+	u8 sec_val = OLEDB_SEC_UNLOCK_CODE;
+	u16 sec_reg_addr = (address & 0xFF00) | OLEDB_SEC_ACCESS;
+
+	mutex_lock(&oledb->bus_lock);
+	rc = regmap_write(oledb->regmap, sec_reg_addr, sec_val);
+	if (rc < 0) {
+		pr_err("register %x failed rc = %d\n", sec_reg_addr, rc);
+		goto error;
+	}
+
+	rc = regmap_update_bits(oledb->regmap, address, mask, val);
+	if (rc < 0)
+		pr_err("spmi write failed: addr=%03X, rc=%d\n", address, rc);
+
+error:
+	mutex_unlock(&oledb->bus_lock);
 	return rc;
 }
 
@@ -214,6 +255,7 @@
 	int rc = 0;
 	struct platform_device *pdev = oledb->pdev;
 
+	mutex_lock(&oledb->bus_lock);
 	rc = regmap_bulk_write(oledb->regmap, address, val, count);
 	if (rc)
 		pr_err("Failed to write address=0x%02x sid=0x%02x rc=%d\n",
@@ -222,7 +264,8 @@
 		pr_debug("Wrote 0x%02X to addr 0x%04X\n",
 			*val, address);
 
-	return 0;
+	mutex_unlock(&oledb->bus_lock);
+	return rc;
 }
 
 static int qpnp_oledb_regulator_enable(struct regulator_dev *rdev)
@@ -285,6 +328,8 @@
 static int qpnp_oledb_regulator_disable(struct regulator_dev *rdev)
 {
 	int rc = 0;
+	u8 trigger_bitmap = OLEDB_PD_PBS_TRIGGER_BIT;
+	u8 val;
 
 	struct qpnp_oledb *oledb  = rdev_get_drvdata(rdev);
 
@@ -314,6 +359,27 @@
 		pr_debug("Register-control mode, module disabled\n");
 	}
 
+	if (oledb->force_pd_control) {
+		rc = qpnp_oledb_read(oledb, oledb->base + OLEDB_SPARE_CTL,
+						&val, 1);
+		if (rc < 0) {
+			pr_err("Failed to read OLEDB_SPARE_CTL rc=%d\n", rc);
+			return rc;
+		}
+
+		if (val & OLEDB_FORCE_PD_CTL_SPARE_BIT) {
+			rc = qpnp_pbs_trigger_event(oledb->pbs_dev_node,
+							trigger_bitmap);
+			if (rc < 0) {
+				pr_err("Failed to trigger the PBS sequence\n");
+				return rc;
+			}
+			pr_debug("PBS event triggered\n");
+		} else {
+			pr_debug("OLEDB_SPARE_CTL register bit not set\n");
+		}
+	}
+
 	oledb->mod_enable = false;
 
 	return rc;
@@ -1034,6 +1100,18 @@
 	oledb->pbs_control =
 			of_property_read_bool(of_node, "qcom,pbs-control");
 
+	oledb->force_pd_control =
+			of_property_read_bool(of_node, "qcom,force-pd-control");
+
+	if (oledb->force_pd_control) {
+		oledb->pbs_dev_node = of_parse_phandle(of_node,
+						"qcom,pbs-client", 0);
+		if (!oledb->pbs_dev_node) {
+			pr_err("Missing qcom,pbs-client property\n");
+			return -EINVAL;
+		}
+	}
+
 	oledb->current_voltage = -EINVAL;
 	rc = of_property_read_u32(of_node, "qcom,oledb-init-voltage-mv",
 						&oledb->current_voltage);
@@ -1116,6 +1194,52 @@
 	return rc;
 }
 
+static int qpnp_oledb_force_pulldown_config(struct qpnp_oledb *oledb)
+{
+	int rc = 0;
+	u8 val;
+
+	rc = qpnp_oledb_sec_masked_write(oledb, oledb->base +
+		    OLEDB_SPARE_CTL, OLEDB_FORCE_PD_CTL_SPARE_BIT, 0);
+	if (rc < 0) {
+		pr_err("Failed to write SPARE_CTL rc=%d\n", rc);
+		return rc;
+	}
+
+	val = 1;
+	rc = qpnp_oledb_write(oledb, oledb->base + OLEDB_PD_CTL,
+							&val, 1);
+	if (rc < 0) {
+		pr_err("Failed to write PD_CTL rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_oledb_masked_write(oledb, oledb->base +
+		OLEDB_SWIRE_CONTROL, OLEDB_EN_SWIRE_PD_UPD_BIT, 0);
+	if (rc < 0)
+		pr_err("Failed to write SWIRE_CTL for pbs mode rc=%d\n",
+					rc);
+
+	return rc;
+}
+
+static int qpnp_labibb_notifier_cb(struct notifier_block *nb,
+					unsigned long action, void *data)
+{
+	int rc = 0;
+	struct qpnp_oledb *oledb = container_of(nb, struct qpnp_oledb,
+								oledb_nb);
+
+	if (action == LAB_VREG_OK) {
+		/* Disable SWIRE pull down control and enable via spmi mode */
+		rc = qpnp_oledb_force_pulldown_config(oledb);
+		if (rc < 0)
+			return NOTIFY_STOP;
+	}
+
+	return NOTIFY_OK;
+}
+
 static int qpnp_oledb_regulator_probe(struct platform_device *pdev)
 {
 	int rc = 0;
@@ -1143,6 +1267,7 @@
 		return rc;
 	}
 
+	mutex_init(&(oledb->bus_lock));
 	oledb->base = val;
 	rc = qpnp_oledb_parse_dt(oledb);
 	if (rc < 0) {
@@ -1156,18 +1281,47 @@
 		return rc;
 	}
 
+	if (oledb->force_pd_control) {
+		oledb->oledb_nb.notifier_call = qpnp_labibb_notifier_cb;
+		rc = qpnp_labibb_notifier_register(&oledb->oledb_nb);
+		if (rc < 0) {
+			pr_err("Failed to register qpnp_labibb_notifier_cb\n");
+			return rc;
+		}
+	}
+
 	rc = qpnp_oledb_register_regulator(oledb);
-	if (!rc)
-		pr_info("OLEDB registered successfully, ext_pin_en=%d mod_en=%d cuurent_voltage=%d mV\n",
+	if (rc < 0) {
+		pr_err("Failed to register regulator rc=%d\n", rc);
+		goto out;
+	}
+	pr_info("OLEDB registered successfully, ext_pin_en=%d mod_en=%d current_voltage=%d mV\n",
 			oledb->ext_pin_control, oledb->mod_enable,
 						oledb->current_voltage);
+	return 0;
+
+out:
+	if (oledb->force_pd_control) {
+		rc  = qpnp_labibb_notifier_unregister(&oledb->oledb_nb);
+		if (rc < 0)
+			pr_err("Failed to unregister lab_vreg_ok notifier\n");
+	}
 
 	return rc;
 }
 
 static int qpnp_oledb_regulator_remove(struct platform_device *pdev)
 {
-	return 0;
+	int rc = 0;
+	struct qpnp_oledb *oledb = platform_get_drvdata(pdev);
+
+	if (oledb->force_pd_control) {
+		rc  = qpnp_labibb_notifier_unregister(&oledb->oledb_nb);
+		if (rc < 0)
+			pr_err("Failed to unregister lab_vreg_ok notifier\n");
+	}
+
+	return rc;
 }
 
 const struct of_device_id qpnp_oledb_regulator_match_table[] = {
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index 6607fd4..bc2d2d4 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
@@ -1412,8 +1412,10 @@
 	struct ufs_hba *hba = filp->f_mapping->host->i_private;
 	unsigned long flags;
 
-	spin_lock_irqsave(hba->host->host_lock, flags);
+	pm_runtime_get_sync(hba->dev);
+	ufshcd_hold(hba, false);
 
+	spin_lock_irqsave(hba->host->host_lock, flags);
 	/*
 	 * simulating a dummy error in order to "convince"
 	 * eh_work to actually reset the controller
@@ -1421,9 +1423,13 @@
 	hba->saved_err |= INT_FATAL_ERRORS;
 	hba->silence_err_logs = true;
 	schedule_work(&hba->eh_work);
-
 	spin_unlock_irqrestore(hba->host->host_lock, flags);
 
+	flush_work(&hba->eh_work);
+
+	ufshcd_release(hba, false);
+	pm_runtime_put_sync(hba->dev);
+
 	return cnt;
 }
 
@@ -1471,8 +1477,8 @@
 void ufsdbg_add_debugfs(struct ufs_hba *hba)
 {
 	if (!hba) {
-		dev_err(hba->dev, "%s: NULL hba, exiting", __func__);
-		goto err_no_root;
+		pr_err("%s: NULL hba, exiting", __func__);
+		return;
 	}
 
 	hba->debugfs_files.debugfs_root = debugfs_create_dir(dev_name(hba->dev),
diff --git a/drivers/scsi/ufs/ufs-qcom-debugfs.c b/drivers/scsi/ufs/ufs-qcom-debugfs.c
index 8532439..4547a6d 100644
--- a/drivers/scsi/ufs/ufs-qcom-debugfs.c
+++ b/drivers/scsi/ufs/ufs-qcom-debugfs.c
@@ -67,6 +67,7 @@
 static int ufs_qcom_dbg_testbus_en_set(void *data, u64 attr_id)
 {
 	struct ufs_qcom_host *host = data;
+	int ret = 0;
 
 	if (!host)
 		return -EINVAL;
@@ -76,7 +77,13 @@
 	else
 		host->dbg_print_en &= ~UFS_QCOM_DBG_PRINT_TEST_BUS_EN;
 
-	return ufs_qcom_testbus_config(host);
+	pm_runtime_get_sync(host->hba->dev);
+	ufshcd_hold(host->hba, false);
+	ret = ufs_qcom_testbus_config(host);
+	ufshcd_release(host->hba, false);
+	pm_runtime_put_sync(host->hba->dev);
+
+	return ret;
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(ufs_qcom_dbg_testbus_en_ops,
@@ -142,7 +149,11 @@
 	 * Sanity check of the {major, minor} tuple is done in the
 	 * config function
 	 */
+	pm_runtime_get_sync(host->hba->dev);
+	ufshcd_hold(host->hba, false);
 	ret = ufs_qcom_testbus_config(host);
+	ufshcd_release(host->hba, false);
+	pm_runtime_put_sync(host->hba->dev);
 	if (!ret)
 		dev_dbg(host->hba->dev,
 				"%s: New configuration: major=%d, minor=%d\n",
diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c
index 1ba4f2b..814d1dc 100644
--- a/drivers/scsi/ufs/ufs-qcom-ice.c
+++ b/drivers/scsi/ufs/ufs-qcom-ice.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,6 +14,7 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/blkdev.h>
+#include <linux/spinlock.h>
 #include <crypto/ice.h>
 
 #include "ufs-qcom-ice.h"
@@ -168,13 +169,23 @@
 
 static void ufs_qcom_ice_cfg_work(struct work_struct *work)
 {
+	unsigned long flags;
 	struct ice_data_setting ice_set;
 	struct ufs_qcom_host *qcom_host =
 		container_of(work, struct ufs_qcom_host, ice_cfg_work);
+	struct request *req_pending = NULL;
 
-	if (!qcom_host->ice.vops->config_start || !qcom_host->req_pending)
+	if (!qcom_host->ice.vops->config_start)
 		return;
 
+	spin_lock_irqsave(&qcom_host->ice_work_lock, flags);
+	req_pending = qcom_host->req_pending;
+	if (!req_pending) {
+		spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);
+		return;
+	}
+	spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);
+
 	/*
 	 * config_start is called again as previous attempt returned -EAGAIN,
 	 * this call shall now take care of the necessary key setup.
@@ -185,12 +196,17 @@
 	qcom_host->ice.vops->config_start(qcom_host->ice.pdev,
 		qcom_host->req_pending, &ice_set, false);
 
+	spin_lock_irqsave(&qcom_host->ice_work_lock, flags);
+	qcom_host->req_pending = NULL;
+	spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);
+
 	/*
 	 * Resume with requests processing. We assume config_start has been
 	 * successful, but even if it wasn't we still must resume in order to
 	 * allow for the request to be retried.
 	 */
 	ufshcd_scsi_unblock_requests(qcom_host->hba);
+
 }
 
 /**
@@ -246,6 +262,7 @@
 	struct ice_data_setting ice_set;
 	char cmd_op = cmd->cmnd[0];
 	int err;
+	unsigned long flags;
 
 	if (!qcom_host->ice.pdev || !qcom_host->ice.vops) {
 		dev_dbg(qcom_host->hba->dev, "%s: ice device is not enabled\n",
@@ -255,6 +272,10 @@
 
 	if (qcom_host->ice.vops->config_start) {
 		memset(&ice_set, 0, sizeof(ice_set));
+
+		spin_lock_irqsave(
+			&qcom_host->ice_work_lock, flags);
+
 		err = qcom_host->ice.vops->config_start(qcom_host->ice.pdev,
 			cmd->request, &ice_set, true);
 		if (err) {
@@ -272,19 +293,41 @@
 				dev_dbg(qcom_host->hba->dev,
 					"%s: scheduling task for ice setup\n",
 					__func__);
-				qcom_host->req_pending = cmd->request;
-				if (schedule_work(&qcom_host->ice_cfg_work))
+
+				if (!qcom_host->req_pending) {
 					ufshcd_scsi_block_requests(
 						qcom_host->hba);
+					qcom_host->req_pending = cmd->request;
+
+					if (!schedule_work(
+						&qcom_host->ice_cfg_work)) {
+						qcom_host->req_pending = NULL;
+
+						spin_unlock_irqrestore(
+						&qcom_host->ice_work_lock,
+						flags);
+
+						ufshcd_scsi_unblock_requests(
+							qcom_host->hba);
+						return err;
+					}
+				}
+
 			} else {
-				dev_err(qcom_host->hba->dev,
-					"%s: error in ice_vops->config %d\n",
-					__func__, err);
+				if (err != -EBUSY)
+					dev_err(qcom_host->hba->dev,
+						"%s: error in ice_vops->config %d\n",
+						__func__, err);
 			}
 
+			spin_unlock_irqrestore(&qcom_host->ice_work_lock,
+				flags);
+
 			return err;
 		}
 
+		spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);
+
 		if (ufs_qcom_is_data_cmd(cmd_op, true))
 			*enable = !ice_set.encr_bypass;
 		else if (ufs_qcom_is_data_cmd(cmd_op, false))
@@ -320,6 +363,7 @@
 	unsigned int bypass = 0;
 	struct request *req;
 	char cmd_op;
+	unsigned long flags;
 
 	if (!qcom_host->ice.pdev || !qcom_host->ice.vops) {
 		dev_dbg(dev, "%s: ice device is not enabled\n", __func__);
@@ -339,7 +383,8 @@
 
 	req = cmd->request;
 	if (req->bio)
-		lba = req->bio->bi_iter.bi_sector;
+		lba = (req->bio->bi_iter.bi_sector) >>
+			UFS_QCOM_ICE_TR_DATA_UNIT_4_KB;
 
 	slot = req->tag;
 	if (slot < 0 || slot > qcom_host->hba->nutrs) {
@@ -348,8 +393,13 @@
 		return -EINVAL;
 	}
 
-	memset(&ice_set, 0, sizeof(ice_set));
+
 	if (qcom_host->ice.vops->config_start) {
+		memset(&ice_set, 0, sizeof(ice_set));
+
+		spin_lock_irqsave(
+			&qcom_host->ice_work_lock, flags);
+
 		err = qcom_host->ice.vops->config_start(qcom_host->ice.pdev,
 							req, &ice_set, true);
 		if (err) {
@@ -364,13 +414,44 @@
 			 * request processing.
 			 */
 			if (err == -EAGAIN) {
-				qcom_host->req_pending = req;
-				if (schedule_work(&qcom_host->ice_cfg_work))
+
+				dev_dbg(qcom_host->hba->dev,
+					"%s: scheduling task for ice setup\n",
+					__func__);
+
+				if (!qcom_host->req_pending) {
 					ufshcd_scsi_block_requests(
+						qcom_host->hba);
+					qcom_host->req_pending = cmd->request;
+					if (!schedule_work(
+						&qcom_host->ice_cfg_work)) {
+						qcom_host->req_pending = NULL;
+
+						spin_unlock_irqrestore(
+						&qcom_host->ice_work_lock,
+						flags);
+
+						ufshcd_scsi_unblock_requests(
 							qcom_host->hba);
+						return err;
+					}
+				}
+
+			} else {
+				if (err != -EBUSY)
+					dev_err(qcom_host->hba->dev,
+						"%s: error in ice_vops->config %d\n",
+						__func__, err);
 			}
-			goto out;
+
+			spin_unlock_irqrestore(
+				&qcom_host->ice_work_lock, flags);
+
+			return err;
 		}
+
+		spin_unlock_irqrestore(
+			&qcom_host->ice_work_lock, flags);
 	}
 
 	cmd_op = cmd->cmnd[0];
@@ -390,6 +471,7 @@
 		bypass = ice_set.decr_bypass ? UFS_QCOM_ICE_ENABLE_BYPASS :
 						UFS_QCOM_ICE_DISABLE_BYPASS;
 
+
 	/* Configure ICE index */
 	ctrl_info_val =
 		(ice_set.crypto_data.key_index &
@@ -398,8 +480,7 @@
 
 	/* Configure data unit size of transfer request */
 	ctrl_info_val |=
-		(UFS_QCOM_ICE_TR_DATA_UNIT_4_KB &
-		 MASK_UFS_QCOM_ICE_CTRL_INFO_CDU)
+		UFS_QCOM_ICE_TR_DATA_UNIT_4_KB
 		 << OFFSET_UFS_QCOM_ICE_CTRL_INFO_CDU;
 
 	/* Configure ICE bypass mode */
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 9706273..d326b80 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, 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
@@ -33,6 +33,9 @@
 #include "ufs-qcom-ice.h"
 #include "ufs-qcom-debugfs.h"
 
+#define MAX_PROP_SIZE		   32
+#define VDDP_REF_CLK_MIN_UV        1200000
+#define VDDP_REF_CLK_MAX_UV        1200000
 /* TODO: further tuning for this parameter may be required */
 #define UFS_QCOM_PM_QOS_UNVOTE_TIMEOUT_US	(10000) /* microseconds */
 
@@ -97,13 +100,10 @@
 	int err = 0;
 
 	clk = devm_clk_get(dev, name);
-	if (IS_ERR(clk)) {
+	if (IS_ERR(clk))
 		err = PTR_ERR(clk);
-		dev_err(dev, "%s: failed to get %s err %d",
-				__func__, name, err);
-	} else {
+	else
 		*clk_out = clk;
-	}
 
 	return err;
 }
@@ -182,20 +182,29 @@
 
 	err = ufs_qcom_host_clk_get(dev,
 			"rx_lane0_sync_clk", &host->rx_l0_sync_clk);
-	if (err)
+	if (err) {
+		dev_err(dev, "%s: failed to get rx_lane0_sync_clk, err %d",
+				__func__, err);
 		goto out;
+	}
 
 	err = ufs_qcom_host_clk_get(dev,
 			"tx_lane0_sync_clk", &host->tx_l0_sync_clk);
-	if (err)
+	if (err) {
+		dev_err(dev, "%s: failed to get tx_lane0_sync_clk, err %d",
+				__func__, err);
 		goto out;
+	}
 
 	/* In case of single lane per direction, don't read lane1 clocks */
 	if (host->hba->lanes_per_direction > 1) {
 		err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk",
 			&host->rx_l1_sync_clk);
-		if (err)
+		if (err) {
+			dev_err(dev, "%s: failed to get rx_lane1_sync_clk, err %d",
+					__func__, err);
 			goto out;
+		}
 
 		/* The tx lane1 clk could be muxed, hence keep this optional */
 		ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
@@ -387,8 +396,9 @@
 /**
  * Returns zero for success and non-zero in case of a failure
  */
-static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
-			       u32 hs, u32 rate, bool update_link_startup_timer)
+static int __ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
+			       u32 hs, u32 rate, bool update_link_startup_timer,
+			       bool is_pre_scale_up)
 {
 	int ret = 0;
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -435,8 +445,12 @@
 	}
 
 	list_for_each_entry(clki, &hba->clk_list_head, list) {
-		if (!strcmp(clki->name, "core_clk"))
-			core_clk_rate = clk_get_rate(clki->clk);
+		if (!strcmp(clki->name, "core_clk")) {
+			if (is_pre_scale_up)
+				core_clk_rate = clki->max_freq;
+			else
+				core_clk_rate = clk_get_rate(clki->clk);
+		}
 	}
 
 	/* If frequency is smaller than 1MHz, set to 1MHz */
@@ -533,6 +547,13 @@
 	return ret;
 }
 
+static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
+			       u32 hs, u32 rate, bool update_link_startup_timer)
+{
+	return  __ufs_qcom_cfg_timers(hba, gear, hs, rate,
+				      update_link_startup_timer, false);
+}
+
 static int ufs_qcom_link_startup_pre_change(struct ufs_hba *hba)
 {
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -666,40 +687,105 @@
 	return err;
 }
 
+
+static int ufs_qcom_config_vreg(struct device *dev,
+		struct ufs_vreg *vreg, bool on)
+{
+	int ret = 0;
+	struct regulator *reg;
+	int min_uV, uA_load;
+
+	if (!vreg) {
+		WARN_ON(1);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	reg = vreg->reg;
+	if (regulator_count_voltages(reg) > 0) {
+		min_uV = on ? vreg->min_uV : 0;
+		ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);
+		if (ret) {
+			dev_err(dev, "%s: %s set voltage failed, err=%d\n",
+					__func__, vreg->name, ret);
+			goto out;
+		}
+
+		uA_load = on ? vreg->max_uA : 0;
+		ret = regulator_set_load(vreg->reg, uA_load);
+		if (ret)
+			goto out;
+	}
+out:
+	return ret;
+}
+
+static int ufs_qcom_enable_vreg(struct device *dev, struct ufs_vreg *vreg)
+{
+	int ret = 0;
+
+	if (vreg->enabled)
+		return ret;
+
+	ret = ufs_qcom_config_vreg(dev, vreg, true);
+	if (ret)
+		goto out;
+
+	ret = regulator_enable(vreg->reg);
+	if (ret)
+		goto out;
+
+	vreg->enabled = true;
+out:
+	return ret;
+}
+
+static int ufs_qcom_disable_vreg(struct device *dev, struct ufs_vreg *vreg)
+{
+	int ret = 0;
+
+	if (!vreg->enabled)
+		return ret;
+
+	ret = regulator_disable(vreg->reg);
+	if (ret)
+		goto out;
+
+	ret = ufs_qcom_config_vreg(dev, vreg, false);
+	if (ret)
+		goto out;
+
+	vreg->enabled = false;
+out:
+	return ret;
+}
+
 static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 {
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
 	struct phy *phy = host->generic_phy;
 	int ret = 0;
 
-	if (ufs_qcom_is_link_off(hba)) {
-		/*
-		 * Disable the tx/rx lane symbol clocks before PHY is
-		 * powered down as the PLL source should be disabled
-		 * after downstream clocks are disabled.
-		 */
-		ufs_qcom_disable_lane_clks(host);
-		phy_power_off(phy);
-		ret = ufs_qcom_ice_suspend(host);
-		if (ret)
-			dev_err(hba->dev, "%s: failed ufs_qcom_ice_suspend %d\n",
-					__func__, ret);
-
-		/* Assert PHY soft reset */
-		ufs_qcom_assert_reset(hba);
-		goto out;
-	}
-
 	/*
-	 * If UniPro link is not active, PHY ref_clk, main PHY analog power
-	 * rail and low noise analog power rail for PLL can be switched off.
+	 * If UniPro link is not active or OFF, PHY ref_clk, main PHY analog
+	 * power rail and low noise analog power rail for PLL can be
+	 * switched off.
 	 */
 	if (!ufs_qcom_is_link_active(hba)) {
 		ufs_qcom_disable_lane_clks(host);
 		phy_power_off(phy);
-		ufs_qcom_ice_suspend(host);
-	}
 
+		if (host->vddp_ref_clk && ufs_qcom_is_link_off(hba))
+			ret = ufs_qcom_disable_vreg(hba->dev,
+					host->vddp_ref_clk);
+		ufs_qcom_ice_suspend(host);
+
+		if (ufs_qcom_is_link_off(hba)) {
+			/* Assert PHY soft reset */
+			ufs_qcom_assert_reset(hba);
+			goto out;
+		}
+	}
 	/* Unvote PM QoS */
 	ufs_qcom_pm_qos_suspend(host);
 
@@ -720,6 +806,11 @@
 		goto out;
 	}
 
+	if (host->vddp_ref_clk && (hba->rpm_lvl > UFS_PM_LVL_3 ||
+				   hba->spm_lvl > UFS_PM_LVL_3))
+		ufs_qcom_enable_vreg(hba->dev,
+				      host->vddp_ref_clk);
+
 	err = ufs_qcom_enable_lane_clks(host);
 	if (err)
 		goto out;
@@ -739,7 +830,35 @@
 
 static int ufs_qcom_full_reset(struct ufs_hba *hba)
 {
-	return -ENOTSUPP;
+	int ret = -ENOTSUPP;
+
+	if (!hba->core_reset) {
+		dev_err(hba->dev, "%s: failed, err = %d\n", __func__,
+			ret);
+		goto out;
+	}
+
+	ret = reset_control_assert(hba->core_reset);
+	if (ret) {
+		dev_err(hba->dev, "%s: core_reset assert failed, err = %d\n",
+				__func__, ret);
+		goto out;
+	}
+
+	/*
+	 * The hardware requirement for delay between assert/deassert
+	 * is at least 3-4 sleep clock (32.7KHz) cycles, which comes to
+	 * ~125us (4/32768). To be on the safe side add 200us delay.
+	 */
+	usleep_range(200, 210);
+
+	ret = reset_control_deassert(hba->core_reset);
+	if (ret)
+		dev_err(hba->dev, "%s: core_reset deassert failed, err = %d\n",
+				__func__, ret);
+
+out:
+	return ret;
 }
 
 #ifdef CONFIG_SCSI_UFS_QCOM_ICE
@@ -757,7 +876,8 @@
 
 	/* Use request LBA as the DUN value */
 	if (req->bio)
-		*dun = req->bio->bi_iter.bi_sector;
+		*dun = (req->bio->bi_iter.bi_sector) >>
+				UFS_QCOM_ICE_TR_DATA_UNIT_4_KB;
 
 	ret = ufs_qcom_ice_req_setup(host, lrbp->cmd, cc_index, enable);
 
@@ -978,7 +1098,7 @@
 	}
 }
 
-static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote)
+static int __ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote)
 {
 	int err = 0;
 
@@ -1009,7 +1129,7 @@
 
 	vote = ufs_qcom_get_bus_vote(host, mode);
 	if (vote >= 0)
-		err = ufs_qcom_set_bus_vote(host, vote);
+		err = __ufs_qcom_set_bus_vote(host, vote);
 	else
 		err = vote;
 
@@ -1020,6 +1140,35 @@
 	return err;
 }
 
+static int ufs_qcom_set_bus_vote(struct ufs_hba *hba, bool on)
+{
+	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+	int vote, err;
+
+	/*
+	 * In case ufs_qcom_init() is not yet done, simply ignore.
+	 * This ufs_qcom_set_bus_vote() shall be called from
+	 * ufs_qcom_init() after init is done.
+	 */
+	if (!host)
+		return 0;
+
+	if (on) {
+		vote = host->bus_vote.saved_vote;
+		if (vote == host->bus_vote.min_bw_vote)
+			ufs_qcom_update_bus_bw_vote(host);
+	} else {
+		vote = host->bus_vote.min_bw_vote;
+	}
+
+	err = __ufs_qcom_set_bus_vote(host, vote);
+	if (err)
+		dev_err(hba->dev, "%s: set bus vote failed %d\n",
+				__func__, err);
+
+	return err;
+}
+
 static ssize_t
 show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
 			char *buf)
@@ -1096,7 +1245,7 @@
 	return 0;
 }
 
-static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote)
+static int ufs_qcom_set_bus_vote(struct ufs_hba *hba, bool on)
 {
 	return 0;
 }
@@ -1373,7 +1522,6 @@
 {
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
 	int err;
-	int vote = 0;
 
 	/*
 	 * In case ufs_qcom_init() is not yet done, simply ignore.
@@ -1398,9 +1546,6 @@
 		/* enable the device ref clock for HS mode*/
 		if (ufshcd_is_hs_mode(&hba->pwr_info))
 			ufs_qcom_dev_ref_clk_ctrl(host, true);
-		vote = host->bus_vote.saved_vote;
-		if (vote == host->bus_vote.min_bw_vote)
-			ufs_qcom_update_bus_bw_vote(host);
 
 		err = ufs_qcom_ice_resume(host);
 		if (err)
@@ -1412,21 +1557,19 @@
 
 		/* M-PHY RMMI interface clocks can be turned off */
 		ufs_qcom_phy_disable_iface_clk(host->generic_phy);
-		if (!ufs_qcom_is_link_active(hba)) {
-			if (!is_gating_context)
-				/* turn off UFS local PHY ref_clk */
-				ufs_qcom_phy_disable_ref_clk(host->generic_phy);
+		/*
+		 * If auto hibern8 is supported then the link will already
+		 * be in hibern8 state and the ref clock can be gated.
+		 */
+		if (ufshcd_is_auto_hibern8_supported(hba) ||
+		    !ufs_qcom_is_link_active(hba)) {
+			/* turn off UFS local PHY ref_clk */
+			ufs_qcom_phy_disable_ref_clk(host->generic_phy);
 			/* disable device ref_clk */
 			ufs_qcom_dev_ref_clk_ctrl(host, false);
 		}
-		vote = host->bus_vote.min_bw_vote;
 	}
 
-	err = ufs_qcom_set_bus_vote(host, vote);
-	if (err)
-		dev_err(hba->dev, "%s: set bus vote failed %d\n",
-				__func__, err);
-
 out:
 	return err;
 }
@@ -1850,6 +1993,57 @@
 		dev_err(hba->dev, "invalid host index %d\n", id);
 }
 
+static int ufs_qcom_parse_reg_info(struct ufs_qcom_host *host, char *name,
+				   struct ufs_vreg **out_vreg)
+{
+	int ret = 0;
+	char prop_name[MAX_PROP_SIZE];
+	struct ufs_vreg *vreg = NULL;
+	struct device *dev = host->hba->dev;
+	struct device_node *np = dev->of_node;
+
+	if (!np) {
+		dev_err(dev, "%s: non DT initialization\n", __func__);
+		goto out;
+	}
+
+	snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", name);
+	if (!of_parse_phandle(np, prop_name, 0)) {
+		dev_info(dev, "%s: Unable to find %s regulator, assuming enabled\n",
+			 __func__, prop_name);
+		ret = -ENODEV;
+		goto out;
+	}
+
+	vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+	if (!vreg)
+		return -ENOMEM;
+
+	vreg->name = name;
+
+	snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", name);
+	ret = of_property_read_u32(np, prop_name, &vreg->max_uA);
+	if (ret) {
+		dev_err(dev, "%s: unable to find %s err %d\n",
+			__func__, prop_name, ret);
+		goto out;
+	}
+
+	vreg->reg = devm_regulator_get(dev, vreg->name);
+	if (IS_ERR(vreg->reg)) {
+		ret = PTR_ERR(vreg->reg);
+		dev_err(dev, "%s: %s get failed, err=%d\n",
+			__func__, vreg->name, ret);
+	}
+	vreg->min_uV = VDDP_REF_CLK_MIN_UV;
+	vreg->max_uV = VDDP_REF_CLK_MAX_UV;
+
+out:
+	if (!ret)
+		*out_vreg = vreg;
+	return ret;
+}
+
 /**
  * ufs_qcom_init - bind phy with controller
  * @hba: host controller instance
@@ -1877,14 +2071,9 @@
 
 	/* Make a two way bind between the qcom host and the hba */
 	host->hba = hba;
-	ufshcd_set_variant(hba, host);
+	spin_lock_init(&host->ice_work_lock);
 
-	/*
-	 * voting/devoting device ref_clk source is time consuming hence
-	 * skip devoting it during aggressive clock gating. This clock
-	 * will still be gated off during runtime suspend.
-	 */
-	hba->no_ref_clk_gating = true;
+	ufshcd_set_variant(hba, host);
 
 	err = ufs_qcom_ice_get_dev(host);
 	if (err == -EPROBE_DEFER) {
@@ -1969,14 +2158,24 @@
 	ufs_qcom_phy_save_controller_version(host->generic_phy,
 		host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step);
 
+	err = ufs_qcom_parse_reg_info(host, "qcom,vddp-ref-clk",
+				      &host->vddp_ref_clk);
 	phy_init(host->generic_phy);
 	err = phy_power_on(host->generic_phy);
 	if (err)
 		goto out_unregister_bus;
+	if (host->vddp_ref_clk) {
+		err = ufs_qcom_enable_vreg(dev, host->vddp_ref_clk);
+		if (err) {
+			dev_err(dev, "%s: failed enabling ref clk supply: %d\n",
+				__func__, err);
+			goto out_disable_phy;
+		}
+	}
 
 	err = ufs_qcom_init_lane_clks(host);
 	if (err)
-		goto out_disable_phy;
+		goto out_disable_vddp;
 
 	ufs_qcom_parse_lpm(host);
 	if (host->disable_lpm)
@@ -1984,6 +2183,7 @@
 	ufs_qcom_set_caps(hba);
 	ufs_qcom_advertise_quirks(hba);
 
+	ufs_qcom_set_bus_vote(hba, true);
 	ufs_qcom_setup_clocks(hba, true, false);
 
 	host->dbg_print_en |= UFS_QCOM_DEFAULT_DBG_PRINT_EN;
@@ -1999,6 +2199,9 @@
 
 	goto out;
 
+out_disable_vddp:
+	if (host->vddp_ref_clk)
+		ufs_qcom_disable_vreg(dev, host->vddp_ref_clk);
 out_disable_phy:
 	phy_power_off(host->generic_phy);
 out_unregister_bus:
@@ -2049,79 +2252,21 @@
 	return err;
 }
 
-static inline int ufs_qcom_configure_lpm(struct ufs_hba *hba, bool enable)
-{
-	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
-	struct phy *phy = host->generic_phy;
-	int err = 0;
-
-	/* The default low power mode configuration is SVS2 */
-	if (!ufs_qcom_cap_svs2(host))
-		goto out;
-
-	/*
-	 * The link should be put in hibern8 state before
-	 * configuring the PHY to enter/exit SVS2 mode.
-	 */
-	err = ufshcd_uic_hibern8_enter(hba);
-	if (err)
-		goto out;
-
-	err = ufs_qcom_phy_configure_lpm(phy, enable);
-	if (err)
-		goto out;
-
-	err = ufshcd_uic_hibern8_exit(hba);
-out:
-	return err;
-}
-
 static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba)
 {
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
-
-	if (!ufs_qcom_cap_qunipro(host))
-		return 0;
-
-	return ufs_qcom_configure_lpm(hba, false);
-}
-
-static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba)
-{
-	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
-
-	if (!ufs_qcom_cap_qunipro(host))
-		return 0;
-
-	/* set unipro core clock cycles to 150 and clear clock divider */
-	return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150);
-}
-
-static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba)
-{
-	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
-	u32 core_clk_ctrl_reg;
+	struct ufs_pa_layer_attr *attr = &host->dev_req_params;
 	int err = 0;
 
 	if (!ufs_qcom_cap_qunipro(host))
 		goto out;
 
-	err = ufs_qcom_configure_lpm(hba, true);
-	if (err)
-		goto out;
+	if (attr)
+		__ufs_qcom_cfg_timers(hba, attr->gear_rx, attr->pwr_rx,
+				      attr->hs_rate, false, true);
 
-	err = ufshcd_dme_get(hba,
-			    UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
-			    &core_clk_ctrl_reg);
-
-	/* make sure CORE_CLK_DIV_EN is cleared */
-	if (!err &&
-	    (core_clk_ctrl_reg & DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT)) {
-		core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT;
-		err = ufshcd_dme_set(hba,
-				    UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
-				    core_clk_ctrl_reg);
-	}
+	/* set unipro core clock cycles to 150 and clear clock divider */
+	err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150);
 out:
 	return err;
 }
@@ -2129,11 +2274,16 @@
 static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba)
 {
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+	struct ufs_pa_layer_attr *attr = &host->dev_req_params;
 	int err = 0;
 
 	if (!ufs_qcom_cap_qunipro(host))
 		return 0;
 
+	if (attr)
+		ufs_qcom_cfg_timers(hba, attr->gear_rx, attr->pwr_rx,
+				    attr->hs_rate, false);
+
 	if (ufs_qcom_cap_svs2(host))
 		/*
 		 * For SVS2 set unipro core clock cycles to 37 and
@@ -2154,30 +2304,17 @@
 		bool scale_up, enum ufs_notify_change_status status)
 {
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
-	struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params;
 	int err = 0;
 
 	switch (status) {
 	case PRE_CHANGE:
 		if (scale_up)
 			err = ufs_qcom_clk_scale_up_pre_change(hba);
-		else
-			err = ufs_qcom_clk_scale_down_pre_change(hba);
 		break;
 	case POST_CHANGE:
-		if (scale_up)
-			err = ufs_qcom_clk_scale_up_post_change(hba);
-		else
+		if (!scale_up)
 			err = ufs_qcom_clk_scale_down_post_change(hba);
 
-		if (err || !dev_req_params)
-			goto out;
-
-		ufs_qcom_cfg_timers(hba,
-				    dev_req_params->gear_rx,
-				    dev_req_params->pwr_rx,
-				    dev_req_params->hs_rate,
-				    false);
 		ufs_qcom_update_bus_bw_vote(host);
 		break;
 	default:
@@ -2186,7 +2323,6 @@
 		break;
 	}
 
-out:
 	return err;
 }
 
@@ -2277,17 +2413,21 @@
 
 static void ufs_qcom_enable_test_bus(struct ufs_qcom_host *host)
 {
-	if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
+	if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN) {
+		ufshcd_rmwl(host->hba, UFS_REG_TEST_BUS_EN,
+				UFS_REG_TEST_BUS_EN, REG_UFS_CFG1);
 		ufshcd_rmwl(host->hba, TEST_BUS_EN, TEST_BUS_EN, REG_UFS_CFG1);
-	else
+	} else {
+		ufshcd_rmwl(host->hba, UFS_REG_TEST_BUS_EN, 0, REG_UFS_CFG1);
 		ufshcd_rmwl(host->hba, TEST_BUS_EN, 0, REG_UFS_CFG1);
+	}
 }
 
 static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host)
 {
 	/* provide a legal default configuration */
-	host->testbus.select_major = TSTBUS_UAWM;
-	host->testbus.select_minor = 1;
+	host->testbus.select_major = TSTBUS_UNIPRO;
+	host->testbus.select_minor = 37;
 }
 
 static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
@@ -2304,7 +2444,7 @@
 	 * mappings of select_minor, since there is no harm in
 	 * configuring a non-existent select_minor
 	 */
-	if (host->testbus.select_minor > 0x1F) {
+	if (host->testbus.select_minor > 0xFF) {
 		dev_err(host->hba->dev,
 			"%s: 0x%05X is not a legal testbus option\n",
 			__func__, host->testbus.select_minor);
@@ -2314,6 +2454,11 @@
 	return true;
 }
 
+/*
+ * The caller of this function must make sure that the controller
+ * is out of runtime suspend and appropriate clocks are enabled
+ * before accessing.
+ */
 int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
 {
 	int reg;
@@ -2373,7 +2518,8 @@
 		break;
 	case TSTBUS_UNIPRO:
 		reg = UFS_UNIPRO_CFG;
-		offset = 1;
+		offset = 20;
+		mask = 0xFFF;
 		break;
 	/*
 	 * No need for a default case, since
@@ -2383,8 +2529,6 @@
 	}
 	mask <<= offset;
 
-	pm_runtime_get_sync(host->hba->dev);
-	ufshcd_hold(host->hba, false);
 	ufshcd_rmwl(host->hba, TEST_BUS_SEL,
 		    (u32)host->testbus.select_major << 19,
 		    REG_UFS_CFG1);
@@ -2392,8 +2536,11 @@
 		    (u32)host->testbus.select_minor << offset,
 		    reg);
 	ufs_qcom_enable_test_bus(host);
-	ufshcd_release(host->hba, false);
-	pm_runtime_put_sync(host->hba->dev);
+	/*
+	 * Make sure the test bus configuration is
+	 * committed before returning.
+	 */
+	mb();
 
 	return 0;
 }
@@ -2403,15 +2550,47 @@
 	ufs_qcom_dump_regs(hba, UFS_TEST_BUS, 1, "UFS_TEST_BUS ");
 }
 
-static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
+static void ufs_qcom_print_unipro_testbus(struct ufs_hba *hba)
 {
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+	u32 *testbus = NULL;
+	int i, nminor = 256, testbus_len = nminor * sizeof(u32);
+
+	testbus = kmalloc(testbus_len, GFP_KERNEL);
+	if (!testbus)
+		return;
+
+	host->testbus.select_major = TSTBUS_UNIPRO;
+	for (i = 0; i < nminor; i++) {
+		host->testbus.select_minor = i;
+		ufs_qcom_testbus_config(host);
+		testbus[i] = ufshcd_readl(hba, UFS_TEST_BUS);
+	}
+	print_hex_dump(KERN_ERR, "UNIPRO_TEST_BUS ", DUMP_PREFIX_OFFSET,
+			16, 4, testbus, testbus_len, false);
+	kfree(testbus);
+}
+
+static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba, bool no_sleep)
+{
+	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+	struct phy *phy = host->generic_phy;
 
 	ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16,
 			"HCI Vendor Specific Registers ");
-
 	ufs_qcom_print_hw_debug_reg_all(hba, NULL, ufs_qcom_dump_regs_wrapper);
+
+	if (no_sleep)
+		return;
+
+	/* sleep a bit intermittently as we are dumping too much data */
+	usleep_range(1000, 1100);
 	ufs_qcom_testbus_read(hba);
+	usleep_range(1000, 1100);
+	ufs_qcom_print_unipro_testbus(hba);
+	usleep_range(1000, 1100);
+	ufs_qcom_phy_dbg_register_dump(phy);
+	usleep_range(1000, 1100);
 	ufs_qcom_ice_print_regs(host);
 }
 
@@ -2436,6 +2615,7 @@
 	.full_reset		= ufs_qcom_full_reset,
 	.update_sec_cfg		= ufs_qcom_update_sec_cfg,
 	.get_scale_down_gear	= ufs_qcom_get_scale_down_gear,
+	.set_bus_vote		= ufs_qcom_set_bus_vote,
 	.dbg_register_dump	= ufs_qcom_dump_dbg_regs,
 #ifdef CONFIG_DEBUG_FS
 	.add_debugfs		= ufs_qcom_dbg_add_debugfs,
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index 42e7aad8..792ae42 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
@@ -100,6 +100,7 @@
 #define QUNIPRO_SEL	UFS_BIT(0)
 #define TEST_BUS_EN		BIT(18)
 #define TEST_BUS_SEL		GENMASK(22, 19)
+#define UFS_REG_TEST_BUS_EN	BIT(30)
 
 /* bit definitions for REG_UFS_CFG2 register */
 #define UAWM_HW_CGC_EN		(1 << 0)
@@ -369,8 +370,10 @@
 	u32 dbg_print_en;
 	struct ufs_qcom_testbus testbus;
 
+	spinlock_t ice_work_lock;
 	struct work_struct ice_cfg_work;
 	struct request *req_pending;
+	struct ufs_vreg *vddp_ref_clk;
 };
 
 static inline u32
diff --git a/drivers/scsi/ufs/ufs_quirks.c b/drivers/scsi/ufs/ufs_quirks.c
index b22a4c4..3210d60 100644
--- a/drivers/scsi/ufs/ufs_quirks.c
+++ b/drivers/scsi/ufs/ufs_quirks.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-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
@@ -30,6 +30,20 @@
 	UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL,
 		UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME),
 	UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ),
+	UFS_FIX(UFS_VENDOR_SKHYNIX, "hB8aL1",
+		UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
+	UFS_FIX(UFS_VENDOR_SKHYNIX, "hC8aL1",
+		UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
+	UFS_FIX(UFS_VENDOR_SKHYNIX, "hD8aL1",
+		UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
+	UFS_FIX(UFS_VENDOR_SKHYNIX, "hC8aM1",
+		UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
+	UFS_FIX(UFS_VENDOR_SKHYNIX, "h08aM1",
+		UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
+	UFS_FIX(UFS_VENDOR_SKHYNIX, "hC8GL1",
+		UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
+	UFS_FIX(UFS_VENDOR_SKHYNIX, "hC8HL1",
+		UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
 
 	END_FIX
 };
diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h
index f7182ed..e7a59d4 100644
--- a/drivers/scsi/ufs/ufs_quirks.h
+++ b/drivers/scsi/ufs/ufs_quirks.h
@@ -1,4 +1,4 @@
-/* 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
@@ -130,6 +130,14 @@
  */
 #define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME	(1 << 7)
 
+/*
+ * Some UFS devices may stop responding after switching from HS-G1 to HS-G3.
+ * Also, it is found that these devices work fine if we do 2 steps switch:
+ * HS-G1 to HS-G2 followed by HS-G2 to HS-G3. Enabling this quirk for such
+ * device would apply this 2 steps gear switch workaround.
+ */
+#define UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH (1 << 8)
+
 struct ufs_hba;
 void ufs_advertise_fixup_device(struct ufs_hba *hba);
 
diff --git a/drivers/scsi/ufs/ufs_test.c b/drivers/scsi/ufs/ufs_test.c
index 8953722e8..d41871a 100644
--- a/drivers/scsi/ufs/ufs_test.c
+++ b/drivers/scsi/ufs/ufs_test.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
@@ -689,13 +689,13 @@
 	__blk_put_request(test_iosched->req_q, test_rq->rq);
 	spin_unlock_irqrestore(&test_iosched->lock, flags);
 
-	test_iosched_free_test_req_data_buffer(test_rq);
-	kfree(test_rq);
-
 	if (err)
 		pr_err("%s: request %d completed, err=%d", __func__,
 			test_rq->req_id, err);
 
+	test_iosched_free_test_req_data_buffer(test_rq);
+	kfree(test_rq);
+
 	check_test_completion(test_iosched);
 }
 
@@ -984,14 +984,14 @@
 		return;
 	}
 
-	test_iosched_free_test_req_data_buffer(test_rq);
-	kfree(test_rq);
-	utd->completed_req_count++;
-
 	if (err)
 		pr_err("%s: request %d completed, err=%d", __func__,
 			test_rq->req_id, err);
 
+	test_iosched_free_test_req_data_buffer(test_rq);
+	kfree(test_rq);
+	utd->completed_req_count++;
+
 	check_test_completion(test_iosched);
 }
 
@@ -1007,7 +1007,7 @@
 static int run_long_test(struct test_iosched *test_iosched)
 {
 	int ret = 0;
-	int direction, num_bios_per_request;
+	int direction, num_bios_per_request = 1;
 	static unsigned int inserted_requests;
 	u32 sector, seed, num_bios, seq_sector_delta;
 	struct ufs_test_data *utd = test_iosched->blk_dev_test_data;
@@ -1028,14 +1028,12 @@
 	/* Set test parameters */
 	switch (test_iosched->test_info.testcase) {
 	case  UFS_TEST_LONG_RANDOM_READ:
-		num_bios_per_request = 1;
 		utd->long_test_num_reqs = (utd->sector_range * SECTOR_SIZE) /
 			(LONG_RAND_TEST_REQ_RATIO * TEST_BIO_SIZE *
 					num_bios_per_request);
 		direction = READ;
 		break;
 	case  UFS_TEST_LONG_RANDOM_WRITE:
-		num_bios_per_request = 1;
 		utd->long_test_num_reqs = (utd->sector_range * SECTOR_SIZE) /
 			(LONG_RAND_TEST_REQ_RATIO * TEST_BIO_SIZE *
 					num_bios_per_request);
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 9c8473e..de6ecbd 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -40,6 +40,22 @@
 #include "ufshcd.h"
 #include "ufshcd-pltfrm.h"
 
+static int ufshcd_parse_reset_info(struct ufs_hba *hba)
+{
+	int ret = 0;
+
+	hba->core_reset = devm_reset_control_get(hba->dev,
+				"core_reset");
+	if (IS_ERR(hba->core_reset)) {
+		ret = PTR_ERR(hba->core_reset);
+		dev_err(hba->dev, "core_reset unavailable,err = %d\n",
+				ret);
+		hba->core_reset = NULL;
+	}
+
+	return ret;
+}
+
 static int ufshcd_parse_clock_info(struct ufs_hba *hba)
 {
 	int ret = 0;
@@ -297,6 +313,20 @@
 		hba->dev_ref_clk_freq = REF_CLK_FREQ_26_MHZ;
 }
 
+static int ufshcd_parse_pinctrl_info(struct ufs_hba *hba)
+{
+	int ret = 0;
+
+	/* Try to obtain pinctrl handle */
+	hba->pctrl = devm_pinctrl_get(hba->dev);
+	if (IS_ERR(hba->pctrl)) {
+		ret = PTR_ERR(hba->pctrl);
+		hba->pctrl = NULL;
+	}
+
+	return ret;
+}
+
 #ifdef CONFIG_SMP
 /**
  * ufshcd_pltfrm_suspend - suspend power management function
@@ -401,6 +431,20 @@
 		goto dealloc_host;
 	}
 
+	err = ufshcd_parse_reset_info(hba);
+	if (err) {
+		dev_err(&pdev->dev, "%s: reset parse failed %d\n",
+				__func__, err);
+		goto dealloc_host;
+	}
+
+	err = ufshcd_parse_pinctrl_info(hba);
+	if (err) {
+		dev_dbg(&pdev->dev, "%s: unable to parse pinctrl data %d\n",
+				__func__, err);
+		/* let's not fail the probe */
+	}
+
 	ufshcd_parse_dev_ref_clk_freq(hba);
 	ufshcd_parse_pm_levels(hba);
 	ufshcd_parse_gear_limits(hba);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 7552357..712de81 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -47,6 +47,7 @@
 #include "ufshci.h"
 #include "ufs_quirks.h"
 #include "ufs-debugfs.h"
+#include "ufs-qcom.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/ufs.h>
@@ -367,7 +368,7 @@
 }
 
 static irqreturn_t ufshcd_intr(int irq, void *__hba);
-static void ufshcd_tmc_handler(struct ufs_hba *hba);
+static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba);
 static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 static int ufshcd_reset_and_restore(struct ufs_hba *hba);
 static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd);
@@ -389,6 +390,28 @@
 static void ufshcd_release_all(struct ufs_hba *hba);
 static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba);
 static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba);
+static int ufshcd_devfreq_target(struct device *dev,
+				unsigned long *freq, u32 flags);
+static int ufshcd_devfreq_get_dev_status(struct device *dev,
+		struct devfreq_dev_status *stat);
+
+#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)
+static struct devfreq_simple_ondemand_data ufshcd_ondemand_data = {
+	.upthreshold = 35,
+	.downdifferential = 30,
+	.simple_scaling = 1,
+};
+
+static void *gov_data = &ufshcd_ondemand_data;
+#else
+static void *gov_data;
+#endif
+
+static struct devfreq_dev_profile ufs_devfreq_profile = {
+	.polling_ms	= 40,
+	.target		= ufshcd_devfreq_target,
+	.get_dev_status	= ufshcd_devfreq_get_dev_status,
+};
 
 static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
 {
@@ -441,10 +464,67 @@
 }
 EXPORT_SYMBOL(ufshcd_scsi_block_requests);
 
+static int ufshcd_device_reset_ctrl(struct ufs_hba *hba, bool ctrl)
+{
+	int ret = 0;
+
+	if (!hba->pctrl)
+		return 0;
+
+	/* Assert reset if ctrl == true */
+	if (ctrl)
+		ret = pinctrl_select_state(hba->pctrl,
+			pinctrl_lookup_state(hba->pctrl, "dev-reset-assert"));
+	else
+		ret = pinctrl_select_state(hba->pctrl,
+			pinctrl_lookup_state(hba->pctrl, "dev-reset-deassert"));
+
+	if (ret < 0)
+		dev_err(hba->dev, "%s: %s failed with err %d\n",
+			__func__, ctrl ? "Assert" : "Deassert", ret);
+
+	return ret;
+}
+
+static inline int ufshcd_assert_device_reset(struct ufs_hba *hba)
+{
+	return ufshcd_device_reset_ctrl(hba, true);
+}
+
+static inline int ufshcd_deassert_device_reset(struct ufs_hba *hba)
+{
+	return ufshcd_device_reset_ctrl(hba, false);
+}
+
+static int ufshcd_reset_device(struct ufs_hba *hba)
+{
+	int ret;
+
+	/* reset the connected UFS device */
+	ret = ufshcd_assert_device_reset(hba);
+	if (ret)
+		goto out;
+	/*
+	 * The reset signal is active low.
+	 * The UFS device shall detect more than or equal to 1us of positive
+	 * or negative RST_n pulse width.
+	 * To be on safe side, keep the reset low for atleast 10us.
+	 */
+	usleep_range(10, 15);
+
+	ret = ufshcd_deassert_device_reset(hba);
+	if (ret)
+		goto out;
+	/* same as assert, wait for atleast 10us after deassert */
+	usleep_range(10, 15);
+out:
+	return ret;
+}
+
 /* replace non-printable or non-ASCII characters with spaces */
 static inline void ufshcd_remove_non_printable(char *val)
 {
-	if (!val)
+	if (!val || !*val)
 		return;
 
 	if (*val < 0x20 || *val > 0x7e)
@@ -534,7 +614,7 @@
 	}
 }
 
-static void ufshcd_print_host_regs(struct ufs_hba *hba)
+static inline void __ufshcd_print_host_regs(struct ufs_hba *hba, bool no_sleep)
 {
 	if (!(hba->ufshcd_dbg_print & UFSHCD_DBG_PRINT_HOST_REGS_EN))
 		return;
@@ -567,7 +647,12 @@
 
 	ufshcd_print_clk_freqs(hba);
 
-	ufshcd_vops_dbg_register_dump(hba);
+	ufshcd_vops_dbg_register_dump(hba, no_sleep);
+}
+
+static void ufshcd_print_host_regs(struct ufs_hba *hba)
+{
+	__ufshcd_print_host_regs(hba, false);
 }
 
 static
@@ -1172,6 +1257,12 @@
 	return ret;
 }
 
+static inline void ufshcd_cancel_gate_work(struct ufs_hba *hba)
+{
+	hrtimer_cancel(&hba->clk_gating.gate_hrtimer);
+	cancel_work_sync(&hba->clk_gating.gate_work);
+}
+
 static void ufshcd_ungate_work(struct work_struct *work)
 {
 	int ret;
@@ -1179,7 +1270,7 @@
 	struct ufs_hba *hba = container_of(work, struct ufs_hba,
 			clk_gating.ungate_work);
 
-	cancel_delayed_work_sync(&hba->clk_gating.gate_work);
+	ufshcd_cancel_gate_work(hba);
 
 	spin_lock_irqsave(hba->host->host_lock, flags);
 	if (hba->clk_gating.state == CLKS_ON) {
@@ -1250,14 +1341,18 @@
 		}
 		break;
 	case REQ_CLKS_OFF:
-		if (cancel_delayed_work(&hba->clk_gating.gate_work)) {
+		/*
+		 * If the timer was active but the callback was not running
+		 * we have nothing to do, just change state and return.
+		 */
+		if (hrtimer_try_to_cancel(&hba->clk_gating.gate_hrtimer) == 1) {
 			hba->clk_gating.state = CLKS_ON;
 			trace_ufshcd_clk_gating(dev_name(hba->dev),
 				hba->clk_gating.state);
 			break;
 		}
 		/*
-		 * If we here, it means gating work is either done or
+		 * If we are here, it means gating work is either done or
 		 * currently running. Hence, fall through to cancel gating
 		 * work and to enable clocks.
 		 */
@@ -1266,7 +1361,8 @@
 		hba->clk_gating.state = REQ_CLKS_ON;
 		trace_ufshcd_clk_gating(dev_name(hba->dev),
 			hba->clk_gating.state);
-		schedule_work(&hba->clk_gating.ungate_work);
+		queue_work(hba->clk_gating.ungating_workq,
+				&hba->clk_gating.ungate_work);
 		/*
 		 * fall through to check if we should wait for this
 		 * work to be done or not.
@@ -1297,11 +1393,18 @@
 static void ufshcd_gate_work(struct work_struct *work)
 {
 	struct ufs_hba *hba = container_of(work, struct ufs_hba,
-			clk_gating.gate_work.work);
+						clk_gating.gate_work);
 	unsigned long flags;
 
 	spin_lock_irqsave(hba->host->host_lock, flags);
-	if (hba->clk_gating.is_suspended) {
+	/*
+	 * In case you are here to cancel this work the gating state
+	 * would be marked as REQ_CLKS_ON. In this case save time by
+	 * skipping the gating work and exit after changing the clock
+	 * state to CLKS_ON.
+	 */
+	if (hba->clk_gating.is_suspended ||
+		(hba->clk_gating.state == REQ_CLKS_ON)) {
 		hba->clk_gating.state = CLKS_ON;
 		trace_ufshcd_clk_gating(dev_name(hba->dev),
 			hba->clk_gating.state);
@@ -1335,7 +1438,12 @@
 		ufshcd_set_link_hibern8(hba);
 	}
 
-	if (!ufshcd_is_link_active(hba) && !hba->no_ref_clk_gating)
+	/*
+	 * If auto hibern8 is supported then the link will already
+	 * be in hibern8 state and the ref clock can be gated.
+	 */
+	if ((ufshcd_is_auto_hibern8_supported(hba) ||
+	     !ufshcd_is_link_active(hba)) && !hba->no_ref_clk_gating)
 		ufshcd_disable_clocks(hba, true);
 	else
 		/* If link is active, device ref_clk can't be switched off */
@@ -1383,8 +1491,9 @@
 	hba->clk_gating.state = REQ_CLKS_OFF;
 	trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state);
 
-	schedule_delayed_work(&hba->clk_gating.gate_work,
-			      msecs_to_jiffies(hba->clk_gating.delay_ms));
+	hrtimer_start(&hba->clk_gating.gate_hrtimer,
+			ms_to_ktime(hba->clk_gating.delay_ms),
+			HRTIMER_MODE_REL);
 }
 
 void ufshcd_release(struct ufs_hba *hba, bool no_sched)
@@ -1512,36 +1621,57 @@
 	return count;
 }
 
+static enum hrtimer_restart ufshcd_clkgate_hrtimer_handler(
+					struct hrtimer *timer)
+{
+	struct ufs_hba *hba = container_of(timer, struct ufs_hba,
+					   clk_gating.gate_hrtimer);
+
+	schedule_work(&hba->clk_gating.gate_work);
+
+	return HRTIMER_NORESTART;
+}
+
 static void ufshcd_init_clk_gating(struct ufs_hba *hba)
 {
 	struct ufs_clk_gating *gating = &hba->clk_gating;
+	char wq_name[sizeof("ufs_clk_ungating_00")];
 
 	hba->clk_gating.state = CLKS_ON;
 
 	if (!ufshcd_is_clkgating_allowed(hba))
 		return;
 
-	INIT_DELAYED_WORK(&gating->gate_work, ufshcd_gate_work);
+	/*
+	 * Disable hibern8 during clk gating if
+	 * auto hibern8 is supported
+	 */
+	if (ufshcd_is_auto_hibern8_supported(hba))
+		hba->caps &= ~UFSHCD_CAP_HIBERN8_WITH_CLK_GATING;
+
+	INIT_WORK(&gating->gate_work, ufshcd_gate_work);
 	INIT_WORK(&gating->ungate_work, ufshcd_ungate_work);
+	/*
+	 * Clock gating work must be executed only after auto hibern8
+	 * timeout has expired in the hardware or after aggressive
+	 * hibern8 on idle software timeout. Using jiffy based low
+	 * resolution delayed work is not reliable to guarantee this,
+	 * hence use a high resolution timer to make sure we schedule
+	 * the gate work precisely more than hibern8 timeout.
+	 *
+	 * Always make sure gating->delay_ms > hibern8_on_idle->delay_ms
+	 */
+	hrtimer_init(&gating->gate_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	gating->gate_hrtimer.function = ufshcd_clkgate_hrtimer_handler;
+
+	snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_ungating_%d",
+			hba->host->host_no);
+	hba->clk_gating.ungating_workq = create_singlethread_workqueue(wq_name);
 
 	gating->is_enabled = true;
 
-	/*
-	 * Scheduling the delayed work after 1 jiffies will make the work to
-	 * get schedule any time from 0ms to 1000/HZ ms which is not desirable
-	 * for hibern8 enter work as it may impact the performance if it gets
-	 * scheduled almost immediately. Hence make sure that hibern8 enter
-	 * work gets scheduled atleast after 2 jiffies (any time between
-	 * 1000/HZ ms to 2000/HZ ms).
-	 */
-	gating->delay_ms_pwr_save = jiffies_to_msecs(
-		max_t(unsigned long,
-		      msecs_to_jiffies(UFSHCD_CLK_GATING_DELAY_MS_PWR_SAVE),
-		      2));
-	gating->delay_ms_perf = jiffies_to_msecs(
-		max_t(unsigned long,
-		      msecs_to_jiffies(UFSHCD_CLK_GATING_DELAY_MS_PERF),
-		      2));
+	gating->delay_ms_pwr_save = UFSHCD_CLK_GATING_DELAY_MS_PWR_SAVE;
+	gating->delay_ms_perf = UFSHCD_CLK_GATING_DELAY_MS_PERF;
 
 	/* start with performance mode */
 	gating->delay_ms = gating->delay_ms_perf;
@@ -1598,8 +1728,9 @@
 		device_remove_file(hba->dev, &hba->clk_gating.delay_attr);
 	}
 	device_remove_file(hba->dev, &hba->clk_gating.enable_attr);
+	ufshcd_cancel_gate_work(hba);
 	cancel_work_sync(&hba->clk_gating.ungate_work);
-	cancel_delayed_work_sync(&hba->clk_gating.gate_work);
+	destroy_workqueue(hba->clk_gating.ungating_workq);
 }
 
 static void ufshcd_set_auto_hibern8_timer(struct ufs_hba *hba, u32 delay)
@@ -1910,6 +2041,7 @@
 		return;
 
 	if (ufshcd_is_auto_hibern8_supported(hba)) {
+		hba->hibern8_on_idle.delay_ms = 1;
 		hba->hibern8_on_idle.state = AUTO_HIBERN8;
 		/*
 		 * Disable SW hibern8 enter on idle in case
@@ -1917,13 +2049,13 @@
 		 */
 		hba->caps &= ~UFSHCD_CAP_HIBERN8_ENTER_ON_IDLE;
 	} else {
+		hba->hibern8_on_idle.delay_ms = 10;
 		INIT_DELAYED_WORK(&hba->hibern8_on_idle.enter_work,
 				  ufshcd_hibern8_enter_work);
 		INIT_WORK(&hba->hibern8_on_idle.exit_work,
 			  ufshcd_hibern8_exit_work);
 	}
 
-	hba->hibern8_on_idle.delay_ms = 10;
 	hba->hibern8_on_idle.is_enabled = true;
 
 	hba->hibern8_on_idle.delay_attr.show =
@@ -2360,9 +2492,6 @@
 		goto out;
 
 	req_desc->header.dword_0 |= cc_index | UTRD_CRYPTO_ENABLE;
-	if (lrbp->cmd->request && lrbp->cmd->request->bio)
-		dun = lrbp->cmd->request->bio->bi_iter.bi_sector;
-
 	req_desc->header.dword_1 = (u32)(dun & 0xFFFFFFFF);
 	req_desc->header.dword_3 = (u32)((dun >> 32) & 0xFFFFFFFF);
 out:
@@ -2587,6 +2716,61 @@
 }
 
 /**
+ * ufshcd_get_write_lock - synchronize between shutdown, scaling &
+ * arrival of requests
+ * @hba: ufs host
+ *
+ * Lock is predominantly held by shutdown context thus, ensuring
+ * that no requests from any other context may sneak through.
+ */
+static inline void ufshcd_get_write_lock(struct ufs_hba *hba)
+{
+	down_write(&hba->lock);
+}
+
+/**
+ * ufshcd_get_read_lock - synchronize between shutdown, scaling &
+ * arrival of requests
+ * @hba: ufs host
+ *
+ * Returns 1 if acquired, < 0 on contention
+ *
+ * After shutdown's initiated, allow requests only directed to the
+ * well known device lun. The sync between scaling & issue is maintained
+ * as is and this restructuring syncs shutdown with these too.
+ */
+static int ufshcd_get_read_lock(struct ufs_hba *hba, u64 lun)
+{
+	int err = 0;
+
+	err = down_read_trylock(&hba->lock);
+	if (err > 0)
+		goto out;
+	/* let requests for well known device lun to go through */
+	if (ufshcd_scsi_to_upiu_lun(lun) == UFS_UPIU_UFS_DEVICE_WLUN)
+		return 0;
+	else if (!ufshcd_is_shutdown_ongoing(hba))
+		return -EAGAIN;
+	else
+		return -EPERM;
+
+out:
+	return err;
+}
+
+/**
+ * ufshcd_put_read_lock - synchronize between shutdown, scaling &
+ * arrival of requests
+ * @hba: ufs host
+ *
+ * Returns none
+ */
+static inline void ufshcd_put_read_lock(struct ufs_hba *hba)
+{
+	up_read(&hba->lock);
+}
+
+/**
  * ufshcd_queuecommand - main entry point for SCSI requests
  * @cmd: command from SCSI Midlayer
  * @done: call back function
@@ -2600,9 +2784,13 @@
 	unsigned long flags;
 	int tag;
 	int err = 0;
+	bool has_read_lock = false;
 
 	hba = shost_priv(host);
 
+	if (!cmd || !cmd->request || !hba)
+		return -EINVAL;
+
 	tag = cmd->request->tag;
 	if (!ufshcd_valid_tag(hba, tag)) {
 		dev_err(hba->dev,
@@ -2611,10 +2799,27 @@
 		BUG();
 	}
 
-	if (!down_read_trylock(&hba->clk_scaling_lock))
-		return SCSI_MLQUEUE_HOST_BUSY;
+	err = ufshcd_get_read_lock(hba, cmd->device->lun);
+	if (unlikely(err < 0)) {
+		if (err == -EPERM) {
+			set_host_byte(cmd, DID_ERROR);
+			cmd->scsi_done(cmd);
+			return 0;
+		}
+		if (err == -EAGAIN)
+			return SCSI_MLQUEUE_HOST_BUSY;
+	} else if (err == 1) {
+		has_read_lock = true;
+	}
 
 	spin_lock_irqsave(hba->host->host_lock, flags);
+
+	/* if error handling is in progress, return host busy */
+	if (ufshcd_eh_in_progress(hba)) {
+		err = SCSI_MLQUEUE_HOST_BUSY;
+		goto out_unlock;
+	}
+
 	switch (hba->ufshcd_state) {
 	case UFSHCD_STATE_OPERATIONAL:
 		break;
@@ -2632,13 +2837,6 @@
 		cmd->scsi_done(cmd);
 		goto out_unlock;
 	}
-
-	/* if error handling is in progress, don't issue commands */
-	if (ufshcd_eh_in_progress(hba)) {
-		set_host_byte(cmd, DID_ERROR);
-		cmd->scsi_done(cmd);
-		goto out_unlock;
-	}
 	spin_unlock_irqrestore(hba->host->host_lock, flags);
 
 	hba->req_abort_count = 0;
@@ -2679,13 +2877,12 @@
 	ufshcd_vops_pm_qos_req_start(hba, cmd->request);
 
 	/* IO svc time latency histogram */
-	if (hba != NULL && cmd->request != NULL) {
-		if (hba->latency_hist_enabled &&
-		    (cmd->request->cmd_type == REQ_TYPE_FS)) {
-			cmd->request->lat_hist_io_start = ktime_get();
-			cmd->request->lat_hist_enabled = 1;
-		} else
-			cmd->request->lat_hist_enabled = 0;
+	if (hba->latency_hist_enabled &&
+	    (cmd->request->cmd_type == REQ_TYPE_FS)) {
+		cmd->request->lat_hist_io_start = ktime_get();
+		cmd->request->lat_hist_enabled = 1;
+	} else {
+		cmd->request->lat_hist_enabled = 0;
 	}
 
 	WARN_ON(hba->clk_gating.state != CLKS_ON);
@@ -2764,7 +2961,8 @@
 out_unlock:
 	spin_unlock_irqrestore(hba->host->host_lock, flags);
 out:
-	up_read(&hba->clk_scaling_lock);
+	if (has_read_lock)
+		ufshcd_put_read_lock(hba);
 	return err;
 }
 
@@ -2956,7 +3154,12 @@
 	struct completion wait;
 	unsigned long flags;
 
-	down_read(&hba->clk_scaling_lock);
+	/*
+	 * May get invoked from shutdown and IOCTL contexts.
+	 * In shutdown context, it comes in with lock acquired.
+	 */
+	if (!ufshcd_is_shutdown_ongoing(hba))
+		down_read(&hba->lock);
 
 	/*
 	 * Get free slot, sleep if slots are unavailable.
@@ -2989,7 +3192,8 @@
 out_put_tag:
 	ufshcd_put_dev_cmd_tag(hba, tag);
 	wake_up(&hba->dev_cmd.tag_wq);
-	up_read(&hba->clk_scaling_lock);
+	if (!ufshcd_is_shutdown_ongoing(hba))
+		up_read(&hba->lock);
 	return err;
 }
 
@@ -3466,7 +3670,7 @@
 			goto out;
 		}
 
-		buff_ascii = kmalloc(ascii_len, GFP_KERNEL);
+		buff_ascii = kzalloc(ascii_len, GFP_KERNEL);
 		if (!buff_ascii) {
 			dev_err(hba->dev, "%s: Failed allocating %d bytes\n",
 					__func__, ascii_len);
@@ -3929,8 +4133,12 @@
 		ret = (status != PWR_OK) ? status : -1;
 	}
 out:
-	if (ret)
+	if (ret) {
 		ufsdbg_set_err_state(hba);
+		ufshcd_print_host_state(hba);
+		ufshcd_print_pwr_info(hba);
+		ufshcd_print_host_regs(hba);
+	}
 
 	ufshcd_save_tstamp_of_last_dme_cmd(hba);
 	spin_lock_irqsave(hba->host->host_lock, flags);
@@ -3954,17 +4162,17 @@
 
 	ufshcd_hold_all(hba);
 	spin_lock_irqsave(hba->host->host_lock, flags);
-	if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
-		ret = -EBUSY;
-		goto out;
-	}
-
 	/*
 	 * Wait for all the outstanding tasks/transfer requests.
 	 * Verify by checking the doorbell registers are clear.
 	 */
 	start = ktime_get();
 	do {
+		if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
+			ret = -EBUSY;
+			goto out;
+		}
+
 		tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
 		tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
 		if (!tm_doorbell && !tr_doorbell) {
@@ -4036,32 +4244,50 @@
 
 static int ufshcd_link_recovery(struct ufs_hba *hba)
 {
-	int ret;
+	int ret = 0;
 	unsigned long flags;
 
-	spin_lock_irqsave(hba->host->host_lock, flags);
-	hba->ufshcd_state = UFSHCD_STATE_RESET;
-	ufshcd_set_eh_in_progress(hba);
+	/*
+	 * Check if there is any race with fatal error handling.
+	 * If so, wait for it to complete. Even though fatal error
+	 * handling does reset and restore in some cases, don't assume
+	 * anything out of it. We are just avoiding race here.
+	 */
+	do {
+		spin_lock_irqsave(hba->host->host_lock, flags);
+		if (!(work_pending(&hba->eh_work) ||
+				hba->ufshcd_state == UFSHCD_STATE_RESET))
+			break;
+		spin_unlock_irqrestore(hba->host->host_lock, flags);
+		dev_dbg(hba->dev, "%s: reset in progress\n", __func__);
+		flush_work(&hba->eh_work);
+	} while (1);
+
+
+	/*
+	 * we don't know if previous reset had really reset the host controller
+	 * or not. So let's force reset here to be sure.
+	 */
+	hba->ufshcd_state = UFSHCD_STATE_ERROR;
+	hba->force_host_reset = true;
+	schedule_work(&hba->eh_work);
+
+	/* wait for the reset work to finish */
+	do {
+		if (!(work_pending(&hba->eh_work) ||
+				hba->ufshcd_state == UFSHCD_STATE_RESET))
+			break;
+		spin_unlock_irqrestore(hba->host->host_lock, flags);
+		dev_dbg(hba->dev, "%s: reset in progress\n", __func__);
+		flush_work(&hba->eh_work);
+		spin_lock_irqsave(hba->host->host_lock, flags);
+	} while (1);
+
+	if (!((hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) &&
+	      ufshcd_is_link_active(hba)))
+		ret = -ENOLINK;
 	spin_unlock_irqrestore(hba->host->host_lock, flags);
 
-	ret = ufshcd_vops_full_reset(hba);
-	if (ret)
-		dev_warn(hba->dev,
-			"full reset returned %d, trying to recover the link\n",
-			ret);
-
-	ret = ufshcd_host_reset_and_restore(hba);
-
-	spin_lock_irqsave(hba->host->host_lock, flags);
-	if (ret)
-		hba->ufshcd_state = UFSHCD_STATE_ERROR;
-	ufshcd_clear_eh_in_progress(hba);
-	spin_unlock_irqrestore(hba->host->host_lock, flags);
-
-	if (ret)
-		dev_err(hba->dev, "%s: link recovery failed, err %d",
-			__func__, ret);
-
 	return ret;
 }
 
@@ -4076,7 +4302,13 @@
 	trace_ufshcd_profile_hibern8(dev_name(hba->dev), "enter",
 			     ktime_to_us(ktime_sub(ktime_get(), start)), ret);
 
-	if (ret) {
+	/*
+	 * Do full reinit if enter failed or if LINERESET was detected during
+	 * Hibern8 operation. After LINERESET, link moves to default PWM-G1
+	 * mode hence full reinit is required to move link to HS speeds.
+	 */
+	if (ret || hba->full_init_linereset) {
+		hba->full_init_linereset = false;
 		ufshcd_update_error_stats(hba, UFS_ERR_HIBERN8_ENTER);
 		dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d",
 			__func__, ret);
@@ -4084,8 +4316,7 @@
 		 * If link recovery fails then return error so that caller
 		 * don't retry the hibern8 enter again.
 		 */
-		if (ufshcd_link_recovery(hba))
-			ret = -ENOLINK;
+		ret = ufshcd_link_recovery(hba);
 	} else {
 		dev_dbg(hba->dev, "%s: Hibern8 Enter at %lld us", __func__,
 			ktime_to_us(ktime_get()));
@@ -4121,6 +4352,7 @@
 	trace_ufshcd_profile_hibern8(dev_name(hba->dev), "exit",
 			     ktime_to_us(ktime_sub(ktime_get(), start)), ret);
 
+	/* Do full reinit if exit failed */
 	if (ret) {
 		ufshcd_update_error_stats(hba, UFS_ERR_HIBERN8_EXIT);
 		dev_err(hba->dev, "%s: hibern8 exit failed. ret = %d",
@@ -4642,6 +4874,7 @@
 out:
 	if (ret)
 		dev_err(hba->dev, "link startup failed %d\n", ret);
+
 	return ret;
 }
 
@@ -5023,7 +5256,12 @@
 		dev_err(hba->dev,
 				"OCS error from controller = %x for tag %d\n",
 				ocs, lrbp->task_tag);
-		ufshcd_print_host_regs(hba);
+		/*
+		 * This is called in interrupt context, hence avoid sleep
+		 * while printing debug registers. Also print only the minimum
+		 * debug registers needed to debug OCS failure.
+		 */
+		__ufshcd_print_host_regs(hba, true);
 		ufshcd_print_host_state(hba);
 		break;
 	} /* end of switch */
@@ -5045,19 +5283,48 @@
  * ufshcd_uic_cmd_compl - handle completion of uic command
  * @hba: per adapter instance
  * @intr_status: interrupt status generated by the controller
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE    - If invalid interrupt
  */
-static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
+static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
 {
+	irqreturn_t retval = IRQ_NONE;
+
 	if ((intr_status & UIC_COMMAND_COMPL) && hba->active_uic_cmd) {
 		hba->active_uic_cmd->argument2 |=
 			ufshcd_get_uic_cmd_result(hba);
 		hba->active_uic_cmd->argument3 =
 			ufshcd_get_dme_attr_val(hba);
 		complete(&hba->active_uic_cmd->done);
+		retval = IRQ_HANDLED;
 	}
 
-	if ((intr_status & UFSHCD_UIC_PWR_MASK) && hba->uic_async_done)
-		complete(hba->uic_async_done);
+	if (intr_status & UFSHCD_UIC_PWR_MASK) {
+		if (hba->uic_async_done) {
+			complete(hba->uic_async_done);
+			retval = IRQ_HANDLED;
+		} else if (ufshcd_is_auto_hibern8_supported(hba)) {
+			/*
+			 * If uic_async_done flag is not set then this
+			 * is an Auto hibern8 err interrupt.
+			 * Perform a host reset followed by a full
+			 * link recovery.
+			 */
+			hba->ufshcd_state = UFSHCD_STATE_ERROR;
+			hba->force_host_reset = true;
+			dev_err(hba->dev, "%s: Auto Hibern8 %s failed - status: 0x%08x, upmcrs: 0x%08x\n",
+				__func__, (intr_status & UIC_HIBERNATE_ENTER) ?
+				"Enter" : "Exit",
+				intr_status, ufshcd_get_upmcrs(hba));
+			__ufshcd_print_host_regs(hba, true);
+			ufshcd_print_host_state(hba);
+			schedule_work(&hba->eh_work);
+			retval = IRQ_HANDLED;
+		}
+	}
+	return retval;
 }
 
 /**
@@ -5201,8 +5468,12 @@
 /**
  * ufshcd_transfer_req_compl - handle SCSI and query command completion
  * @hba: per adapter instance
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE    - If invalid interrupt
  */
-static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
+static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba)
 {
 	unsigned long completed_reqs;
 	u32 tr_doorbell;
@@ -5220,7 +5491,12 @@
 	tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
 	completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
 
-	__ufshcd_transfer_req_compl(hba, completed_reqs);
+	if (completed_reqs) {
+		__ufshcd_transfer_req_compl(hba, completed_reqs);
+		return IRQ_HANDLED;
+	} else {
+		return IRQ_NONE;
+	}
 }
 
 /**
@@ -5637,17 +5913,32 @@
 	int err = 0;
 	int tag;
 	bool needs_reset = false;
+	bool clks_enabled = false;
 
 	hba = container_of(work, struct ufs_hba, eh_work);
 
-	ufsdbg_set_err_state(hba);
-	pm_runtime_get_sync(hba->dev);
-	ufshcd_hold_all(hba);
-
 	spin_lock_irqsave(hba->host->host_lock, flags);
+	ufsdbg_set_err_state(hba);
+
 	if (hba->ufshcd_state == UFSHCD_STATE_RESET)
 		goto out;
 
+	/*
+	 * Make sure the clocks are ON before we proceed with err
+	 * handling. For the majority of cases err handler would be
+	 * run with clocks ON. There is a possibility that the err
+	 * handler was scheduled due to auto hibern8 error interrupt,
+	 * in which case the clocks could be gated or be in the
+	 * process of gating when the err handler runs.
+	 */
+	if (unlikely((hba->clk_gating.state != CLKS_ON) &&
+	    ufshcd_is_auto_hibern8_supported(hba))) {
+		spin_unlock_irqrestore(hba->host->host_lock, flags);
+		ufshcd_hold(hba, false);
+		spin_lock_irqsave(hba->host->host_lock, flags);
+		clks_enabled = true;
+	}
+
 	hba->ufshcd_state = UFSHCD_STATE_RESET;
 	ufshcd_set_eh_in_progress(hba);
 
@@ -5674,14 +5965,18 @@
 		dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 0x%x",
 			__func__, hba->saved_err, hba->saved_uic_err);
 		if (!hba->silence_err_logs) {
+			/* release lock as print host regs sleeps */
+			spin_unlock_irqrestore(hba->host->host_lock, flags);
 			ufshcd_print_host_regs(hba);
 			ufshcd_print_host_state(hba);
 			ufshcd_print_pwr_info(hba);
 			ufshcd_print_tmrs(hba, hba->outstanding_tasks);
+			spin_lock_irqsave(hba->host->host_lock, flags);
 		}
 	}
 
-	if ((hba->saved_err & INT_FATAL_ERRORS) || hba->saved_ce_err ||
+	if ((hba->saved_err & INT_FATAL_ERRORS)
+	    || hba->saved_ce_err || hba->force_host_reset ||
 	    ((hba->saved_err & UIC_ERROR) &&
 	    (hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR |
 				   UFSHCD_UIC_DL_NAC_RECEIVED_ERROR |
@@ -5769,6 +6064,7 @@
 		hba->saved_err = 0;
 		hba->saved_uic_err = 0;
 		hba->saved_ce_err = 0;
+		hba->force_host_reset = false;
 	}
 
 skip_err_handling:
@@ -5780,12 +6076,12 @@
 	}
 
 	hba->silence_err_logs = false;
-	ufshcd_clear_eh_in_progress(hba);
+
+	if (clks_enabled)
+		__ufshcd_release(hba, false);
 out:
+	ufshcd_clear_eh_in_progress(hba);
 	spin_unlock_irqrestore(hba->host->host_lock, flags);
-	ufshcd_scsi_unblock_requests(hba);
-	ufshcd_release_all(hba);
-	pm_runtime_put_sync(hba->dev);
 }
 
 static void ufshcd_update_uic_reg_hist(struct ufs_uic_err_reg_hist *reg_hist,
@@ -5799,16 +6095,20 @@
 /**
  * ufshcd_update_uic_error - check and set fatal UIC error flags.
  * @hba: per-adapter instance
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE    - If invalid interrupt
  */
-static void ufshcd_update_uic_error(struct ufs_hba *hba)
+static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba)
 {
 	u32 reg;
+	irqreturn_t retval = IRQ_NONE;
 
 	/* PHY layer lane error */
 	reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
-	/* Ignore LINERESET indication, as this is not an error */
 	if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) &&
-			(reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) {
+	    (reg & UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK)) {
 		/*
 		 * To know whether this error is fatal or not, DB timeout
 		 * must be checked but this error is handled separately.
@@ -5816,61 +6116,95 @@
 		dev_dbg(hba->dev, "%s: UIC Lane error reported, reg 0x%x\n",
 				__func__, reg);
 		ufshcd_update_uic_reg_hist(&hba->ufs_stats.pa_err, reg);
+
+		/*
+		 * Don't ignore LINERESET indication during hibern8
+		 * enter operation.
+		 */
+		if (reg & UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR) {
+			struct uic_command *cmd = hba->active_uic_cmd;
+
+			if (cmd) {
+				if (cmd->command == UIC_CMD_DME_HIBER_ENTER) {
+					dev_err(hba->dev, "%s: LINERESET during hibern8 enter, reg 0x%x\n",
+						__func__, reg);
+					hba->full_init_linereset = true;
+				}
+			}
+		}
+		retval |= IRQ_HANDLED;
 	}
 
 	/* PA_INIT_ERROR is fatal and needs UIC reset */
 	reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER);
-	if (reg)
+	if ((reg & UIC_DATA_LINK_LAYER_ERROR) &&
+	    (reg & UIC_DATA_LINK_LAYER_ERROR_CODE_MASK)) {
 		ufshcd_update_uic_reg_hist(&hba->ufs_stats.dl_err, reg);
 
-	if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT) {
-		hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR;
-	} else if (hba->dev_info.quirks &
-		   UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) {
-		if (reg & UIC_DATA_LINK_LAYER_ERROR_NAC_RECEIVED)
-			hba->uic_error |=
-				UFSHCD_UIC_DL_NAC_RECEIVED_ERROR;
-		else if (reg & UIC_DATA_LINK_LAYER_ERROR_TCx_REPLAY_TIMEOUT)
-			hba->uic_error |= UFSHCD_UIC_DL_TCx_REPLAY_ERROR;
+		if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT) {
+			hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR;
+		} else if (hba->dev_info.quirks &
+			   UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) {
+			if (reg & UIC_DATA_LINK_LAYER_ERROR_NAC_RECEIVED)
+				hba->uic_error |=
+					UFSHCD_UIC_DL_NAC_RECEIVED_ERROR;
+			else if (reg &
+				 UIC_DATA_LINK_LAYER_ERROR_TCx_REPLAY_TIMEOUT)
+				hba->uic_error |=
+					UFSHCD_UIC_DL_TCx_REPLAY_ERROR;
+		}
+		retval |= IRQ_HANDLED;
 	}
 
 	/* UIC NL/TL/DME errors needs software retry */
 	reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER);
-	if (reg) {
+	if ((reg & UIC_NETWORK_LAYER_ERROR) &&
+	    (reg & UIC_NETWORK_LAYER_ERROR_CODE_MASK)) {
 		ufshcd_update_uic_reg_hist(&hba->ufs_stats.nl_err, reg);
 		hba->uic_error |= UFSHCD_UIC_NL_ERROR;
+		retval |= IRQ_HANDLED;
 	}
 
 	reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_TRANSPORT_LAYER);
-	if (reg) {
+	if ((reg & UIC_TRANSPORT_LAYER_ERROR) &&
+	    (reg & UIC_TRANSPORT_LAYER_ERROR_CODE_MASK)) {
 		ufshcd_update_uic_reg_hist(&hba->ufs_stats.tl_err, reg);
 		hba->uic_error |= UFSHCD_UIC_TL_ERROR;
+		retval |= IRQ_HANDLED;
 	}
 
 	reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DME);
-	if (reg) {
+	if ((reg & UIC_DME_ERROR) &&
+	    (reg & UIC_DME_ERROR_CODE_MASK)) {
 		ufshcd_update_uic_reg_hist(&hba->ufs_stats.dme_err, reg);
 		hba->uic_error |= UFSHCD_UIC_DME_ERROR;
+		retval |= IRQ_HANDLED;
 	}
 
 	dev_dbg(hba->dev, "%s: UIC error flags = 0x%08x\n",
 			__func__, hba->uic_error);
+	return retval;
 }
 
 /**
  * ufshcd_check_errors - Check for errors that need s/w attention
  * @hba: per-adapter instance
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE    - If invalid interrupt
  */
-static void ufshcd_check_errors(struct ufs_hba *hba)
+static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba)
 {
 	bool queue_eh_work = false;
+	irqreturn_t retval = IRQ_NONE;
 
 	if (hba->errors & INT_FATAL_ERRORS || hba->ce_error)
 		queue_eh_work = true;
 
 	if (hba->errors & UIC_ERROR) {
 		hba->uic_error = 0;
-		ufshcd_update_uic_error(hba);
+		retval = ufshcd_update_uic_error(hba);
 		if (hba->uic_error)
 			queue_eh_work = true;
 	}
@@ -5886,12 +6220,16 @@
 
 		/* handle fatal errors only when link is functional */
 		if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) {
-			/* block commands from scsi mid-layer */
-			__ufshcd_scsi_block_requests(hba);
+			/*
+			 * Set error handling in progress flag early so that we
+			 * don't issue new requests any more.
+			 */
+			ufshcd_set_eh_in_progress(hba);
 
 			hba->ufshcd_state = UFSHCD_STATE_ERROR;
 			schedule_work(&hba->eh_work);
 		}
+		retval |= IRQ_HANDLED;
 	}
 	/*
 	 * if (!queue_eh_work) -
@@ -5899,28 +6237,44 @@
 	 * itself without s/w intervention or errors that will be
 	 * handled by the SCSI core layer.
 	 */
+	return retval;
 }
 
 /**
  * ufshcd_tmc_handler - handle task management function completion
  * @hba: per adapter instance
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE    - If invalid interrupt
  */
-static void ufshcd_tmc_handler(struct ufs_hba *hba)
+static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba)
 {
 	u32 tm_doorbell;
 
 	tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
 	hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks;
-	wake_up(&hba->tm_wq);
+	if (hba->tm_condition) {
+		wake_up(&hba->tm_wq);
+		return IRQ_HANDLED;
+	} else {
+		return IRQ_NONE;
+	}
 }
 
 /**
  * ufshcd_sl_intr - Interrupt service routine
  * @hba: per adapter instance
  * @intr_status: contains interrupts generated by the controller
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE    - If invalid interrupt
  */
-static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
+static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
 {
+	irqreturn_t retval = IRQ_NONE;
+
 	ufsdbg_error_inject_dispatcher(hba,
 		ERR_INJECT_INTR, intr_status, &intr_status);
 
@@ -5928,16 +6282,18 @@
 
 	hba->errors = UFSHCD_ERROR_MASK & intr_status;
 	if (hba->errors || hba->ce_error)
-		ufshcd_check_errors(hba);
+		retval |= ufshcd_check_errors(hba);
 
 	if (intr_status & UFSHCD_UIC_MASK)
-		ufshcd_uic_cmd_compl(hba, intr_status);
+		retval |= ufshcd_uic_cmd_compl(hba, intr_status);
 
 	if (intr_status & UTP_TASK_REQ_COMPL)
-		ufshcd_tmc_handler(hba);
+		retval |= ufshcd_tmc_handler(hba);
 
 	if (intr_status & UTP_TRANSFER_REQ_COMPL)
-		ufshcd_transfer_req_compl(hba);
+		retval |= ufshcd_transfer_req_compl(hba);
+
+	return retval;
 }
 
 /**
@@ -5945,27 +6301,44 @@
  * @irq: irq number
  * @__hba: pointer to adapter instance
  *
- * Returns IRQ_HANDLED - If interrupt is valid
- *		IRQ_NONE - If invalid interrupt
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE    - If invalid interrupt
  */
 static irqreturn_t ufshcd_intr(int irq, void *__hba)
 {
 	u32 intr_status, enabled_intr_status;
 	irqreturn_t retval = IRQ_NONE;
 	struct ufs_hba *hba = __hba;
+	int retries = hba->nutrs;
 
 	spin_lock(hba->host->host_lock);
 	intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
-	enabled_intr_status =
-		intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
 
-	if (intr_status)
-		ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+	/*
+	 * There could be max of hba->nutrs reqs in flight and in worst case
+	 * if the reqs get finished 1 by 1 after the interrupt status is
+	 * read, make sure we handle them by checking the interrupt status
+	 * again in a loop until we process all of the reqs before returning.
+	 */
+	do {
+		enabled_intr_status =
+			intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+		if (intr_status)
+			ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+		if (enabled_intr_status)
+			retval |= ufshcd_sl_intr(hba, enabled_intr_status);
 
-	if (enabled_intr_status) {
-		ufshcd_sl_intr(hba, enabled_intr_status);
-		retval = IRQ_HANDLED;
+		intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
+	} while (intr_status && --retries);
+
+	if (retval == IRQ_NONE) {
+		dev_err(hba->dev, "%s: Unhandled interrupt 0x%08x\n",
+					__func__, intr_status);
+		ufshcd_hex_dump(hba, "host regs: ", hba->mmio_base,
+					UFSHCI_REG_SPACE_SIZE);
 	}
+
 	spin_unlock(hba->host->host_lock);
 	return retval;
 }
@@ -6391,6 +6764,16 @@
 	int retries = MAX_HOST_RESET_RETRIES;
 
 	do {
+		err = ufshcd_vops_full_reset(hba);
+		if (err)
+			dev_warn(hba->dev, "%s: full reset returned %d\n",
+				 __func__, err);
+
+		err = ufshcd_reset_device(hba);
+		if (err)
+			dev_warn(hba->dev, "%s: device reset failed. err %d\n",
+				 __func__, err);
+
 		err = ufshcd_host_reset_and_restore(hba);
 	} while (err && --retries);
 
@@ -6420,13 +6803,12 @@
  */
 static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd)
 {
-	int err;
+	int err = SUCCESS;
 	unsigned long flags;
 	struct ufs_hba *hba;
 
 	hba = shost_priv(cmd->device->host);
 
-	ufshcd_hold_all(hba);
 	/*
 	 * Check if there is any race with fatal error handling.
 	 * If so, wait for it to complete. Even though fatal error
@@ -6439,29 +6821,37 @@
 				hba->ufshcd_state == UFSHCD_STATE_RESET))
 			break;
 		spin_unlock_irqrestore(hba->host->host_lock, flags);
-		dev_dbg(hba->dev, "%s: reset in progress\n", __func__);
+		dev_err(hba->dev, "%s: reset in progress - 1\n", __func__);
 		flush_work(&hba->eh_work);
 	} while (1);
 
-	hba->ufshcd_state = UFSHCD_STATE_RESET;
-	ufshcd_set_eh_in_progress(hba);
-	spin_unlock_irqrestore(hba->host->host_lock, flags);
+	/*
+	 * we don't know if previous reset had really reset the host controller
+	 * or not. So let's force reset here to be sure.
+	 */
+	hba->ufshcd_state = UFSHCD_STATE_ERROR;
+	hba->force_host_reset = true;
+	schedule_work(&hba->eh_work);
 
-	ufshcd_update_error_stats(hba, UFS_ERR_EH);
-	err = ufshcd_reset_and_restore(hba);
+	/* wait for the reset work to finish */
+	do {
+		if (!(work_pending(&hba->eh_work) ||
+				hba->ufshcd_state == UFSHCD_STATE_RESET))
+			break;
+		spin_unlock_irqrestore(hba->host->host_lock, flags);
+		dev_err(hba->dev, "%s: reset in progress - 2\n", __func__);
+		flush_work(&hba->eh_work);
+		spin_lock_irqsave(hba->host->host_lock, flags);
+	} while (1);
 
-	spin_lock_irqsave(hba->host->host_lock, flags);
-	if (!err) {
-		err = SUCCESS;
-		hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
-	} else {
+	if (!((hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) &&
+	      ufshcd_is_link_active(hba))) {
 		err = FAILED;
 		hba->ufshcd_state = UFSHCD_STATE_ERROR;
 	}
-	ufshcd_clear_eh_in_progress(hba);
+
 	spin_unlock_irqrestore(hba->host->host_lock, flags);
 
-	ufshcd_release_all(hba);
 	return err;
 }
 
@@ -6978,11 +7368,6 @@
 	if (ret)
 		goto out;
 
-	/* Enable auto hibern8 if supported */
-	if (ufshcd_is_auto_hibern8_supported(hba))
-		ufshcd_set_auto_hibern8_timer(hba,
-					      hba->hibern8_on_idle.delay_ms);
-
 	/* Debug counters initialization */
 	ufshcd_clear_dbg_ufs_stats(hba);
 	/* set the default level for urgent bkops */
@@ -7064,20 +7449,38 @@
 		if (ufshcd_scsi_add_wlus(hba))
 			goto out;
 
+		/* Initialize devfreq after UFS device is detected */
+		if (ufshcd_is_clkscaling_supported(hba)) {
+			memcpy(&hba->clk_scaling.saved_pwr_info.info,
+			    &hba->pwr_info, sizeof(struct ufs_pa_layer_attr));
+			hba->clk_scaling.saved_pwr_info.is_valid = true;
+			hba->clk_scaling.is_scaled_up = true;
+			if (!hba->devfreq) {
+				hba->devfreq = devfreq_add_device(hba->dev,
+							&ufs_devfreq_profile,
+							"simple_ondemand",
+							gov_data);
+				if (IS_ERR(hba->devfreq)) {
+					ret = PTR_ERR(hba->devfreq);
+					dev_err(hba->dev, "Unable to register with devfreq %d\n",
+						ret);
+					goto out;
+				}
+			}
+			hba->clk_scaling.is_allowed = true;
+		}
+
 		scsi_scan_host(hba->host);
 		pm_runtime_put_sync(hba->dev);
 	}
 
-	/* Resume devfreq after UFS device is detected */
-	if (ufshcd_is_clkscaling_supported(hba)) {
-		memcpy(&hba->clk_scaling.saved_pwr_info.info, &hba->pwr_info,
-		       sizeof(struct ufs_pa_layer_attr));
-		hba->clk_scaling.saved_pwr_info.is_valid = true;
-		hba->clk_scaling.is_scaled_up = true;
-		ufshcd_resume_clkscaling(hba);
-		hba->clk_scaling.is_allowed = true;
-	}
-
+	/*
+	 * Enable auto hibern8 if supported, after full host and
+	 * device initialization.
+	 */
+	if (ufshcd_is_auto_hibern8_supported(hba))
+		ufshcd_set_auto_hibern8_timer(hba,
+				      hba->hibern8_on_idle.delay_ms);
 out:
 	/*
 	 * If we failed to initialize the device or the device is not
@@ -7670,6 +8073,13 @@
 	if (!head || list_empty(head))
 		goto out;
 
+	/* call vendor specific bus vote before enabling the clocks */
+	if (on) {
+		ret = ufshcd_vops_set_bus_vote(hba, on);
+		if (ret)
+			return ret;
+	}
+
 	/*
 	 * vendor specific setup_clocks ops may depend on clocks managed by
 	 * this standard driver hence call the vendor specific setup_clocks
@@ -7708,11 +8118,24 @@
 	 * this standard driver hence call the vendor specific setup_clocks
 	 * after enabling the clocks managed here.
 	 */
-	if (on)
+	if (on) {
 		ret = ufshcd_vops_setup_clocks(hba, on, is_gating_context);
+		if (ret)
+			goto out;
+	}
+
+	/*
+	 * call vendor specific bus vote to remove the vote after
+	 * disabling the clocks.
+	 */
+	if (!on)
+		ret = ufshcd_vops_set_bus_vote(hba, on);
 
 out:
 	if (ret) {
+		if (on)
+			/* Can't do much if this fails */
+			(void) ufshcd_vops_set_bus_vote(hba, false);
 		list_for_each_entry(clki, head, list) {
 			if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled)
 				clk_disable_unprepare(clki->clk);
@@ -7884,7 +8307,8 @@
 		ufshcd_variant_hba_exit(hba);
 		ufshcd_setup_vreg(hba, false);
 		if (ufshcd_is_clkscaling_supported(hba)) {
-			ufshcd_suspend_clkscaling(hba);
+			if (hba->devfreq)
+				ufshcd_suspend_clkscaling(hba);
 			destroy_workqueue(hba->clk_scaling.workq);
 		}
 		ufshcd_disable_clocks(hba, false);
@@ -8335,9 +8759,13 @@
 			goto vendor_suspend;
 		}
 	} else if (ufshcd_is_link_off(hba)) {
-		ret = ufshcd_host_reset_and_restore(hba);
 		/*
-		 * ufshcd_host_reset_and_restore() should have already
+		 * A full initialization of the host and the device is required
+		 * since the link was put to off during suspend.
+		 */
+		ret = ufshcd_reset_and_restore(hba);
+		/*
+		 * ufshcd_reset_and_restore() should have already
 		 * set the link state as active
 		 */
 		if (ret || !ufshcd_is_link_active(hba))
@@ -8676,6 +9104,35 @@
 	ufshcd_add_spm_lvl_sysfs_nodes(hba);
 }
 
+static void ufshcd_shutdown_clkscaling(struct ufs_hba *hba)
+{
+	bool suspend = false;
+	unsigned long flags;
+
+	spin_lock_irqsave(hba->host->host_lock, flags);
+	if (hba->clk_scaling.is_allowed) {
+		hba->clk_scaling.is_allowed = false;
+		suspend = true;
+	}
+	spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+	/**
+	 * Scaling may be scheduled before, hence make sure it
+	 * doesn't race with shutdown
+	 */
+	if (ufshcd_is_clkscaling_supported(hba)) {
+		device_remove_file(hba->dev, &hba->clk_scaling.enable_attr);
+		cancel_work_sync(&hba->clk_scaling.suspend_work);
+		cancel_work_sync(&hba->clk_scaling.resume_work);
+		if (suspend)
+			ufshcd_suspend_clkscaling(hba);
+	}
+
+	/* Unregister so that devfreq_monitor can't race with shutdown */
+	if (hba->devfreq)
+		devfreq_remove_device(hba->devfreq);
+}
+
 /**
  * ufshcd_shutdown - shutdown routine
  * @hba: per adapter instance
@@ -8686,11 +9143,35 @@
  */
 int ufshcd_shutdown(struct ufs_hba *hba)
 {
-	/*
-	 * TODO: This function should send the power down notification to
-	 * UFS device and then power off the UFS link. But we need to be sure
-	 * that there will not be any new UFS requests issued after this.
+	int ret = 0;
+
+	if (ufshcd_is_ufs_dev_poweroff(hba) && ufshcd_is_link_off(hba))
+		goto out;
+
+	pm_runtime_get_sync(hba->dev);
+	ufshcd_hold_all(hba);
+	ufshcd_mark_shutdown_ongoing(hba);
+	ufshcd_shutdown_clkscaling(hba);
+	/**
+	 * (1) Acquire the lock to stop any more requests
+	 * (2) Wait for all issued requests to complete
 	 */
+	ufshcd_get_write_lock(hba);
+	ufshcd_scsi_block_requests(hba);
+	ret = ufshcd_wait_for_doorbell_clr(hba, U64_MAX);
+	if (ret)
+		dev_err(hba->dev, "%s: waiting for DB clear: failed: %d\n",
+			__func__, ret);
+	/* Requests may have errored out above, let it be handled */
+	flush_work(&hba->eh_work);
+	/* reqs issued from contexts other than shutdown will fail from now */
+	ufshcd_scsi_unblock_requests(hba);
+	ufshcd_release_all(hba);
+	ret = ufshcd_suspend(hba, UFS_SHUTDOWN_PM);
+out:
+	if (ret)
+		dev_err(hba->dev, "%s failed, err %d\n", __func__, ret);
+	/* allow force shutdown even in case of errors */
 	return 0;
 }
 EXPORT_SYMBOL(ufshcd_shutdown);
@@ -8886,6 +9367,32 @@
 	if (scale_up) {
 		memcpy(&new_pwr_info, &hba->clk_scaling.saved_pwr_info.info,
 		       sizeof(struct ufs_pa_layer_attr));
+		/*
+		 * Some UFS devices may stop responding after switching from
+		 * HS-G1 to HS-G3. Also, it is found that these devices work
+		 * fine if we do 2 steps switch: HS-G1 to HS-G2 followed by
+		 * HS-G2 to HS-G3. If UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH
+		 * quirk is enabled for such devices, this 2 steps gear switch
+		 * workaround will be applied.
+		 */
+		if ((hba->dev_info.quirks &
+		     UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH)
+		    && (hba->pwr_info.gear_tx == UFS_HS_G1)
+		    && (new_pwr_info.gear_tx == UFS_HS_G3)) {
+			/* scale up to G2 first */
+			new_pwr_info.gear_tx = UFS_HS_G2;
+			new_pwr_info.gear_rx = UFS_HS_G2;
+			ret = ufshcd_change_power_mode(hba, &new_pwr_info);
+			if (ret)
+				goto out;
+
+			/* scale up to G3 now */
+			new_pwr_info.gear_tx = UFS_HS_G3;
+			new_pwr_info.gear_rx = UFS_HS_G3;
+			ret = ufshcd_change_power_mode(hba, &new_pwr_info);
+			if (ret)
+				goto out;
+		}
 	} else {
 		memcpy(&new_pwr_info, &hba->pwr_info,
 		       sizeof(struct ufs_pa_layer_attr));
@@ -8905,10 +9412,10 @@
 				new_pwr_info.pwr_rx = FASTAUTO_MODE;
 			}
 		}
+		ret = ufshcd_change_power_mode(hba, &new_pwr_info);
 	}
 
-	ret = ufshcd_change_power_mode(hba, &new_pwr_info);
-
+out:
 	if (ret)
 		dev_err(hba->dev, "%s: failed err %d, old gear: (tx %d rx %d), new gear: (tx %d rx %d), scale_up = %d",
 			__func__, ret,
@@ -8928,10 +9435,10 @@
 	 * clock scaling is in progress
 	 */
 	ufshcd_scsi_block_requests(hba);
-	down_write(&hba->clk_scaling_lock);
+	down_write(&hba->lock);
 	if (ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) {
 		ret = -EBUSY;
-		up_write(&hba->clk_scaling_lock);
+		up_write(&hba->lock);
 		ufshcd_scsi_unblock_requests(hba);
 	}
 
@@ -8940,7 +9447,7 @@
 
 static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba)
 {
-	up_write(&hba->clk_scaling_lock);
+	up_write(&hba->lock);
 	ufshcd_scsi_unblock_requests(hba);
 }
 
@@ -8971,10 +9478,29 @@
 			goto clk_scaling_unprepare;
 	}
 
+	/*
+	 * If auto hibern8 is supported then put the link in
+	 * hibern8 manually, this is to avoid auto hibern8
+	 * racing during clock frequency scaling sequence.
+	 */
+	if (ufshcd_is_auto_hibern8_supported(hba)) {
+		ret = ufshcd_uic_hibern8_enter(hba);
+		if (ret)
+			/* link will be bad state so no need to scale_up_gear */
+			return ret;
+	}
+
 	ret = ufshcd_scale_clks(hba, scale_up);
 	if (ret)
 		goto scale_up_gear;
 
+	if (ufshcd_is_auto_hibern8_supported(hba)) {
+		ret = ufshcd_uic_hibern8_exit(hba);
+		if (ret)
+			/* link will be bad state so no need to scale_up_gear */
+			return ret;
+	}
+
 	/* scale up the gear after scaling up clocks */
 	if (scale_up) {
 		ret = ufshcd_scale_gear(hba, true);
@@ -9220,23 +9746,6 @@
 	return 0;
 }
 
-#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)
-static struct devfreq_simple_ondemand_data ufshcd_ondemand_data = {
-	.upthreshold = 35,
-	.downdifferential = 30,
-	.simple_scaling = 1,
-};
-
-static void *gov_data = &ufshcd_ondemand_data;
-#else
-static void *gov_data;
-#endif
-
-static struct devfreq_dev_profile ufs_devfreq_profile = {
-	.polling_ms	= 40,
-	.target		= ufshcd_devfreq_target,
-	.get_dev_status	= ufshcd_devfreq_get_dev_status,
-};
 static void ufshcd_clkscaling_init_sysfs(struct ufs_hba *hba)
 {
 	hba->clk_scaling.enable_attr.show = ufshcd_clkscale_enable_show;
@@ -9352,7 +9861,7 @@
 	/* Initialize mutex for device management commands */
 	mutex_init(&hba->dev_cmd.lock);
 
-	init_rwsem(&hba->clk_scaling_lock);
+	init_rwsem(&hba->lock);
 
 	/* Initialize device management tag acquire wait queue */
 	init_waitqueue_head(&hba->dev_cmd.tag_wq);
@@ -9389,6 +9898,15 @@
 		goto exit_gating;
 	}
 
+	/* Reset controller to power on reset (POR) state */
+	ufshcd_vops_full_reset(hba);
+
+	/* reset connected UFS device */
+	err = ufshcd_reset_device(hba);
+	if (err)
+		dev_warn(hba->dev, "%s: device reset failed. err %d\n",
+			 __func__, err);
+
 	/* Host controller enable */
 	err = ufshcd_hba_enable(hba);
 	if (err) {
@@ -9401,16 +9919,6 @@
 	if (ufshcd_is_clkscaling_supported(hba)) {
 		char wq_name[sizeof("ufs_clkscaling_00")];
 
-		hba->devfreq = devfreq_add_device(dev, &ufs_devfreq_profile,
-						   "simple_ondemand", gov_data);
-		if (IS_ERR(hba->devfreq)) {
-			dev_err(hba->dev, "Unable to register with devfreq %ld\n",
-					PTR_ERR(hba->devfreq));
-			err = PTR_ERR(hba->devfreq);
-			goto out_remove_scsi_host;
-		}
-		hba->clk_scaling.is_suspended = false;
-
 		INIT_WORK(&hba->clk_scaling.suspend_work,
 			  ufshcd_clk_scaling_suspend_work);
 		INIT_WORK(&hba->clk_scaling.resume_work,
@@ -9420,8 +9928,6 @@
 			 host->host_no);
 		hba->clk_scaling.workq = create_singlethread_workqueue(wq_name);
 
-		/* Suspend devfreq until the UFS device is detected */
-		ufshcd_suspend_clkscaling(hba);
 		ufshcd_clkscaling_init_sysfs(hba);
 	}
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 709801f..b70606b 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -3,7 +3,7 @@
  *
  * This code is based on drivers/scsi/ufs/ufshcd.h
  * Copyright (C) 2011-2013 Samsung India Software Operations
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
  *
  * Authors:
  *	Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -39,6 +39,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/hrtimer.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -55,6 +56,7 @@
 #include <linux/clk.h>
 #include <linux/completion.h>
 #include <linux/regulator/consumer.h>
+#include <linux/reset.h>
 #include "unipro.h"
 
 #include <asm/irq.h>
@@ -309,6 +311,7 @@
  * @update_sec_cfg: called to restore host controller secure configuration
  * @get_scale_down_gear: called to get the minimum supported gear to
  *			 scale down
+ * @set_bus_vote: called to vote for the required bus bandwidth
  * @add_debugfs: used to add debugfs entries
  * @remove_debugfs: used to remove debugfs entries
  */
@@ -332,9 +335,10 @@
 	int	(*suspend)(struct ufs_hba *, enum ufs_pm_op);
 	int	(*resume)(struct ufs_hba *, enum ufs_pm_op);
 	int	(*full_reset)(struct ufs_hba *);
-	void	(*dbg_register_dump)(struct ufs_hba *hba);
+	void	(*dbg_register_dump)(struct ufs_hba *hba, bool no_sleep);
 	int	(*update_sec_cfg)(struct ufs_hba *hba, bool restore_sec_cfg);
 	u32	(*get_scale_down_gear)(struct ufs_hba *);
+	int	(*set_bus_vote)(struct ufs_hba *, bool);
 #ifdef CONFIG_DEBUG_FS
 	void	(*add_debugfs)(struct ufs_hba *hba, struct dentry *root);
 	void	(*remove_debugfs)(struct ufs_hba *hba);
@@ -393,8 +397,9 @@
 
 /**
  * struct ufs_clk_gating - UFS clock gating related info
- * @gate_work: worker to turn off clocks after some delay as specified in
- * delay_ms
+ * @gate_hrtimer: hrtimer to invoke @gate_work after some delay as
+ * specified in @delay_ms
+ * @gate_work: worker to turn off clocks
  * @ungate_work: worker to turn on clocks that will be used in case of
  * interrupt context
  * @state: the current clocks state
@@ -412,7 +417,8 @@
  * completion before gating clocks.
  */
 struct ufs_clk_gating {
-	struct delayed_work gate_work;
+	struct hrtimer gate_hrtimer;
+	struct work_struct gate_work;
 	struct work_struct ungate_work;
 	enum clk_gating_state state;
 	unsigned long delay_ms;
@@ -425,6 +431,7 @@
 	struct device_attribute enable_attr;
 	bool is_enabled;
 	int active_reqs;
+	struct workqueue_struct *ungating_workq;
 };
 
 /* Hibern8 state  */
@@ -801,6 +808,7 @@
 	u32 saved_uic_err;
 	u32 saved_ce_err;
 	bool silence_err_logs;
+	bool force_host_reset;
 
 	/* Device management request data */
 	struct ufs_dev_cmd dev_cmd;
@@ -882,17 +890,33 @@
 	enum bkops_status urgent_bkops_lvl;
 	bool is_urgent_bkops_lvl_checked;
 
-	struct rw_semaphore clk_scaling_lock;
+	/* sync b/w diff contexts */
+	struct rw_semaphore lock;
+	unsigned long shutdown_in_prog;
 
+	struct reset_control *core_reset;
 	/* If set, don't gate device ref_clk during clock gating */
 	bool no_ref_clk_gating;
 
 	int scsi_block_reqs_cnt;
 
+	bool full_init_linereset;
+	struct pinctrl *pctrl;
+
 	int latency_hist_enabled;
 	struct io_latency_state io_lat_s;
 };
 
+static inline void ufshcd_mark_shutdown_ongoing(struct ufs_hba *hba)
+{
+	set_bit(0, &hba->shutdown_in_prog);
+}
+
+static inline bool ufshcd_is_shutdown_ongoing(struct ufs_hba *hba)
+{
+	return !!(test_bit(0, &hba->shutdown_in_prog));
+}
+
 /* Returns true if clocks can be gated. Otherwise false */
 static inline bool ufshcd_is_clkgating_allowed(struct ufs_hba *hba)
 {
@@ -1233,10 +1257,11 @@
 }
 
 
-static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
+static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba,
+						 bool no_sleep)
 {
 	if (hba->var && hba->var->vops && hba->var->vops->dbg_register_dump)
-		hba->var->vops->dbg_register_dump(hba);
+		hba->var->vops->dbg_register_dump(hba, no_sleep);
 }
 
 static inline int ufshcd_vops_update_sec_cfg(struct ufs_hba *hba,
@@ -1255,6 +1280,13 @@
 	return UFS_HS_G1;
 }
 
+static inline int ufshcd_vops_set_bus_vote(struct ufs_hba *hba, bool on)
+{
+	if (hba->var && hba->var->vops && hba->var->vops->set_bus_vote)
+		return hba->var->vops->set_bus_vote(hba, on);
+	return 0;
+}
+
 #ifdef CONFIG_DEBUG_FS
 static inline void ufshcd_vops_add_debugfs(struct ufs_hba *hba,
 						struct dentry *root)
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index d65dad0..c0e4650 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -190,6 +190,7 @@
 
 /* UECPA - Host UIC Error Code PHY Adapter Layer 38h */
 #define UIC_PHY_ADAPTER_LAYER_ERROR			UFS_BIT(31)
+#define UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR		UFS_BIT(4)
 #define UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK		0x1F
 #define UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK		0xF
 
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index cf715e5..0f8d9b6 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -214,6 +214,15 @@
 	  deadlocks. It does not run during the bootup process, so it will
 	  not catch any early lockups.
 
+config QPNP_PBS
+	tristate "PBS trigger support for QPNP PMIC"
+	depends on SPMI
+	help
+	  This driver supports configuring software PBS trigger event through PBS
+	  RAM on Qualcomm Technologies, Inc. QPNP PMICs. This module provides
+	  the APIs to the client drivers that wants to send the PBS trigger
+	  event to the PBS RAM.
+
 config QCOM_MEMORY_DUMP_V2
 	bool "QCOM Memory Dump V2 Support"
 	help
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 45384668..00a1284 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -3,6 +3,7 @@
 obj-$(CONFIG_QCOM_LLCC) += llcc-core.o llcc-slice.o
 obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o
 obj-$(CONFIG_QCOM_LLCC_AMON) += llcc-amon.o
+obj-$(CONFIG_QPNP_PBS) += qpnp-pbs.o
 obj-$(CONFIG_QCOM_PM)	+=	spm.o
 obj-$(CONFIG_QCOM_SMD) +=	smd.o
 obj-$(CONFIG_QCOM_SMD_RPM)	+= smd-rpm.o
diff --git a/drivers/soc/qcom/avtimer.c b/drivers/soc/qcom/avtimer.c
index 04e351d..1819d46 100644
--- a/drivers/soc/qcom/avtimer.c
+++ b/drivers/soc/qcom/avtimer.c
@@ -64,6 +64,7 @@
 	void __iomem *p_avtimer_msw;
 	void __iomem *p_avtimer_lsw;
 	uint32_t clk_div;
+	uint32_t clk_mult;
 	atomic_t adsp_ready;
 	int num_retries;
 };
@@ -292,7 +293,6 @@
 int avcs_core_query_timer(uint64_t *avtimer_tick)
 {
 	uint32_t avtimer_msw = 0, avtimer_lsw = 0;
-	uint32_t res = 0;
 	uint64_t avtimer_tick_temp;
 
 	if (!atomic_read(&avtimer.adsp_ready)) {
@@ -302,13 +302,13 @@
 	avtimer_lsw = ioread32(avtimer.p_avtimer_lsw);
 	avtimer_msw = ioread32(avtimer.p_avtimer_msw);
 
-	avtimer_tick_temp =
-		(uint64_t)((uint64_t)avtimer_msw << 32)
-			| avtimer_lsw;
-	res = do_div(avtimer_tick_temp, avtimer.clk_div);
-	*avtimer_tick = avtimer_tick_temp;
+	avtimer_tick_temp = (uint64_t)((uint64_t)avtimer_msw << 32)
+			    | avtimer_lsw;
+	*avtimer_tick = mul_u64_u32_div(avtimer_tick_temp, avtimer.clk_mult,
+					avtimer.clk_div);
 	pr_debug_ratelimited("%s:Avtimer: msw: %u, lsw: %u, tick: %llu\n",
 			__func__,
+			avtimer_msw, avtimer_lsw, *avtimer_tick);
 	return 0;
 }
 EXPORT_SYMBOL(avcs_core_query_timer);
@@ -374,6 +374,7 @@
 	struct device *device_handle;
 	struct resource *reg_lsb = NULL, *reg_msb = NULL;
 	uint32_t clk_div_val;
+	uint32_t clk_mult_val;
 
 	if (!pdev) {
 		pr_err("%s: Invalid params\n", __func__);
@@ -462,7 +463,14 @@
 	else
 		avtimer.clk_div = clk_div_val;
 
-	pr_debug("avtimer.clk_div = %d\n", avtimer.clk_div);
+	if (of_property_read_u32(pdev->dev.of_node,
+			"qcom,clk-mult", &clk_mult_val))
+		avtimer.clk_mult = 1;
+	else
+		avtimer.clk_mult = clk_mult_val;
+
+	pr_debug("%s: avtimer.clk_div = %d, avtimer.clk_mult = %d\n",
+		 __func__, avtimer.clk_div, avtimer.clk_mult);
 	return 0;
 
 class_destroy:
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 722127d..0b35caa 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -48,6 +48,11 @@
 #include <soc/qcom/socinfo.h>
 #include <soc/qcom/ramdump.h>
 
+#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
+#include <net/cnss_prealloc.h>
+#endif
+
+
 #include "wlan_firmware_service_v01.h"
 
 #ifdef CONFIG_ICNSS_DEBUG
@@ -62,7 +67,7 @@
 #define WLFW_CLIENT_ID			0x4b4e454c
 #define MAX_PROP_SIZE			32
 #define NUM_LOG_PAGES			10
-#define NUM_REG_LOG_PAGES		4
+#define NUM_LOG_LONG_PAGES		4
 #define ICNSS_MAGIC			0x5abc5abc
 
 #define ICNSS_SERVICE_LOCATION_CLIENT_NAME			"ICNSS-WLAN"
@@ -77,14 +82,10 @@
 		ipc_log_string(icnss_ipc_log_context, _x);		\
 	} while (0)
 
-#ifdef CONFIG_ICNSS_DEBUG
 #define icnss_ipc_log_long_string(_x...) do {				\
 	if (icnss_ipc_log_long_context)					\
 		ipc_log_string(icnss_ipc_log_long_context, _x);		\
 	} while (0)
-#else
-#define icnss_ipc_log_long_string(_x...)
-#endif
 
 #define icnss_pr_err(_fmt, ...) do {					\
 		pr_err(_fmt, ##__VA_ARGS__);				\
@@ -110,28 +111,25 @@
 				     ##__VA_ARGS__);			\
 	} while (0)
 
-#define icnss_reg_dbg(_fmt, ...) do {				\
+#define icnss_pr_vdbg(_fmt, ...) do {					\
 		pr_debug(_fmt, ##__VA_ARGS__);				\
-		icnss_ipc_log_long_string("REG: " pr_fmt(_fmt),		\
+		icnss_ipc_log_long_string("DBG: " pr_fmt(_fmt),		\
 				     ##__VA_ARGS__);			\
 	} while (0)
 
 #ifdef CONFIG_ICNSS_DEBUG
 #define ICNSS_ASSERT(_condition) do {					\
 		if (!(_condition)) {					\
-			icnss_pr_err("ASSERT at line %d\n",		\
-				     __LINE__);				\
+			icnss_pr_err("ASSERT at line %d\n", __LINE__);	\
 			BUG_ON(1);					\
 		}							\
 	} while (0)
+
+bool ignore_qmi_timeout;
+#define ICNSS_QMI_ASSERT() ICNSS_ASSERT(ignore_qmi_timeout)
 #else
-#define ICNSS_ASSERT(_condition) do {					\
-		if (!(_condition)) {					\
-			icnss_pr_err("ASSERT at line %d\n",		\
-				     __LINE__);				\
-			WARN_ON(1);					\
-		}							\
-	} while (0)
+#define ICNSS_ASSERT(_condition) do { } while (0)
+#define ICNSS_QMI_ASSERT() do { } while (0)
 #endif
 
 enum icnss_debug_quirks {
@@ -156,10 +154,7 @@
 module_param(dynamic_feature_mask, ullong, 0600);
 
 void *icnss_ipc_log_context;
-
-#ifdef CONFIG_ICNSS_DEBUG
 void *icnss_ipc_log_long_context;
-#endif
 
 #define ICNSS_EVENT_PENDING			2989
 
@@ -181,6 +176,7 @@
 struct icnss_event_pd_service_down_data {
 	bool crashed;
 	bool fw_rejuvenate;
+	bool wdog_bite;
 };
 
 struct icnss_driver_event {
@@ -205,6 +201,7 @@
 	ICNSS_PD_RESTART,
 	ICNSS_MSA0_ASSIGNED,
 	ICNSS_WLFW_EXISTS,
+	ICNSS_WDOG_BITE,
 };
 
 struct ce_irq_list {
@@ -212,6 +209,38 @@
 	irqreturn_t (*handler)(int, void *);
 };
 
+struct icnss_vreg_info {
+	struct regulator *reg;
+	const char *name;
+	u32 min_v;
+	u32 max_v;
+	u32 load_ua;
+	unsigned long settle_delay;
+	bool required;
+};
+
+struct icnss_clk_info {
+	struct clk *handle;
+	const char *name;
+	u32 freq;
+	bool required;
+};
+
+static struct icnss_vreg_info icnss_vreg_info[] = {
+	{NULL, "vdd-0.8-cx-mx", 800000, 800000, 0, 0, false},
+	{NULL, "vdd-1.8-xo", 1800000, 1800000, 0, 0, false},
+	{NULL, "vdd-1.3-rfa", 1304000, 1304000, 0, 0, false},
+	{NULL, "vdd-3.3-ch0", 3312000, 3312000, 0, 0, false},
+};
+
+#define ICNSS_VREG_INFO_SIZE		ARRAY_SIZE(icnss_vreg_info)
+
+static struct icnss_clk_info icnss_clk_info[] = {
+	{NULL, "cxo_ref_clk_pin", 0, false},
+};
+
+#define ICNSS_CLK_INFO_SIZE		ARRAY_SIZE(icnss_clk_info)
+
 struct icnss_stats {
 	struct {
 		uint32_t posted;
@@ -265,6 +294,7 @@
 	uint32_t rejuvenate_ack_req;
 	uint32_t rejuvenate_ack_resp;
 	uint32_t rejuvenate_ack_err;
+	uint32_t trigger_recovery;
 };
 
 #define MAX_NO_OF_MAC_ADDR 4
@@ -284,6 +314,8 @@
 	struct platform_device *pdev;
 	struct icnss_driver_ops *ops;
 	struct ce_irq_list ce_irq_list[ICNSS_MAX_IRQ_REGISTRATIONS];
+	struct icnss_vreg_info vreg_info[ICNSS_VREG_INFO_SIZE];
+	struct icnss_clk_info clk_info[ICNSS_CLK_INFO_SIZE];
 	u32 ce_irqs[ICNSS_MAX_IRQ_REGISTRATIONS];
 	phys_addr_t mem_base_pa;
 	void __iomem *mem_base_va;
@@ -310,8 +342,9 @@
 	u32 pwr_pin_result;
 	u32 phy_io_pin_result;
 	u32 rf_pin_result;
+	uint32_t nr_mem_region;
 	struct icnss_mem_region_info
-		icnss_mem_region[QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01];
+		mem_region[QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01];
 	struct dentry *root_dentry;
 	spinlock_t on_off_lock;
 	struct icnss_stats stats;
@@ -334,14 +367,24 @@
 	struct ramdump_device *msa0_dump_dev;
 	bool is_wlan_mac_set;
 	struct icnss_wlan_mac_addr wlan_mac_addr;
+	bool bypass_s1_smmu;
 } *penv;
 
+#ifdef CONFIG_ICNSS_DEBUG
+static void icnss_ignore_qmi_timeout(bool ignore)
+{
+	ignore_qmi_timeout = ignore;
+}
+#else
+static void icnss_ignore_qmi_timeout(bool ignore) { }
+#endif
+
 static void icnss_pm_stay_awake(struct icnss_priv *priv)
 {
 	if (atomic_inc_return(&priv->pm_count) != 1)
 		return;
 
-	icnss_pr_dbg("PM stay awake, state: 0x%lx, count: %d\n", priv->state,
+	icnss_pr_vdbg("PM stay awake, state: 0x%lx, count: %d\n", priv->state,
 		     atomic_read(&priv->pm_count));
 
 	pm_stay_awake(&priv->pdev->dev);
@@ -358,7 +401,7 @@
 	if (r != 0)
 		return;
 
-	icnss_pr_dbg("PM relax, state: 0x%lx, count: %d\n", priv->state,
+	icnss_pr_vdbg("PM relax, state: 0x%lx, count: %d\n", priv->state,
 		     atomic_read(&priv->pm_count));
 
 	pm_relax(&priv->pdev->dev);
@@ -680,41 +723,220 @@
 	return ret;
 }
 
+static int icnss_vreg_on(struct icnss_priv *priv)
+{
+	int ret = 0;
+	struct icnss_vreg_info *vreg_info;
+	int i;
+
+	for (i = 0; i < ICNSS_VREG_INFO_SIZE; i++) {
+		vreg_info = &priv->vreg_info[i];
+
+		if (!vreg_info->reg)
+			continue;
+
+		icnss_pr_vdbg("Regulator %s being enabled\n", vreg_info->name);
+
+		ret = regulator_set_voltage(vreg_info->reg, vreg_info->min_v,
+					    vreg_info->max_v);
+		if (ret) {
+			icnss_pr_err("Regulator %s, can't set voltage: min_v: %u, max_v: %u, ret: %d\n",
+				     vreg_info->name, vreg_info->min_v,
+				     vreg_info->max_v, ret);
+			break;
+		}
+
+		if (vreg_info->load_ua) {
+			ret = regulator_set_load(vreg_info->reg,
+						 vreg_info->load_ua);
+			if (ret < 0) {
+				icnss_pr_err("Regulator %s, can't set load: %u, ret: %d\n",
+					     vreg_info->name,
+					     vreg_info->load_ua, ret);
+				break;
+			}
+		}
+
+		ret = regulator_enable(vreg_info->reg);
+		if (ret) {
+			icnss_pr_err("Regulator %s, can't enable: %d\n",
+				     vreg_info->name, ret);
+			break;
+		}
+
+		if (vreg_info->settle_delay)
+			udelay(vreg_info->settle_delay);
+	}
+
+	if (!ret)
+		return 0;
+
+	for (; i >= 0; i--) {
+		vreg_info = &priv->vreg_info[i];
+
+		if (!vreg_info->reg)
+			continue;
+
+		regulator_disable(vreg_info->reg);
+		regulator_set_load(vreg_info->reg, 0);
+		regulator_set_voltage(vreg_info->reg, 0, vreg_info->max_v);
+	}
+
+	return ret;
+}
+
+static int icnss_vreg_off(struct icnss_priv *priv)
+{
+	int ret = 0;
+	struct icnss_vreg_info *vreg_info;
+	int i;
+
+	for (i = ICNSS_VREG_INFO_SIZE - 1; i >= 0; i--) {
+		vreg_info = &priv->vreg_info[i];
+
+		if (!vreg_info->reg)
+			continue;
+
+		icnss_pr_vdbg("Regulator %s being disabled\n", vreg_info->name);
+
+		ret = regulator_disable(vreg_info->reg);
+		if (ret)
+			icnss_pr_err("Regulator %s, can't disable: %d\n",
+				     vreg_info->name, ret);
+
+		ret = regulator_set_load(vreg_info->reg, 0);
+		if (ret < 0)
+			icnss_pr_err("Regulator %s, can't set load: %d\n",
+				     vreg_info->name, ret);
+
+		ret = regulator_set_voltage(vreg_info->reg, 0,
+					    vreg_info->max_v);
+		if (ret)
+			icnss_pr_err("Regulator %s, can't set voltage: %d\n",
+				     vreg_info->name, ret);
+	}
+
+	return ret;
+}
+
+static int icnss_clk_init(struct icnss_priv *priv)
+{
+	struct icnss_clk_info *clk_info;
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < ICNSS_CLK_INFO_SIZE; i++) {
+		clk_info = &priv->clk_info[i];
+
+		if (!clk_info->handle)
+			continue;
+
+		icnss_pr_vdbg("Clock %s being enabled\n", clk_info->name);
+
+		if (clk_info->freq) {
+			ret = clk_set_rate(clk_info->handle, clk_info->freq);
+
+			if (ret) {
+				icnss_pr_err("Clock %s, can't set frequency: %u, ret: %d\n",
+					     clk_info->name, clk_info->freq,
+					     ret);
+				break;
+			}
+		}
+
+		ret = clk_prepare_enable(clk_info->handle);
+		if (ret) {
+			icnss_pr_err("Clock %s, can't enable: %d\n",
+				     clk_info->name, ret);
+			break;
+		}
+	}
+
+	if (ret == 0)
+		return 0;
+
+	for (; i >= 0; i--) {
+		clk_info = &priv->clk_info[i];
+
+		if (!clk_info->handle)
+			continue;
+
+		clk_disable_unprepare(clk_info->handle);
+	}
+
+	return ret;
+}
+
+static int icnss_clk_deinit(struct icnss_priv *priv)
+{
+	struct icnss_clk_info *clk_info;
+	int i;
+
+	for (i = 0; i < ICNSS_CLK_INFO_SIZE; i++) {
+		clk_info = &priv->clk_info[i];
+
+		if (!clk_info->handle)
+			continue;
+
+		icnss_pr_vdbg("Clock %s being disabled\n", clk_info->name);
+
+		clk_disable_unprepare(clk_info->handle);
+	}
+
+	return 0;
+}
+
 static int icnss_hw_power_on(struct icnss_priv *priv)
 {
 	int ret = 0;
-	unsigned long flags;
 
 	icnss_pr_dbg("HW Power on: state: 0x%lx\n", priv->state);
 
-	spin_lock_irqsave(&priv->on_off_lock, flags);
+	spin_lock(&priv->on_off_lock);
 	if (test_bit(ICNSS_POWER_ON, &priv->state)) {
-		spin_unlock_irqrestore(&priv->on_off_lock, flags);
+		spin_unlock(&priv->on_off_lock);
 		return ret;
 	}
 	set_bit(ICNSS_POWER_ON, &priv->state);
-	spin_unlock_irqrestore(&priv->on_off_lock, flags);
+	spin_unlock(&priv->on_off_lock);
 
+	ret = icnss_vreg_on(priv);
+	if (ret)
+		goto out;
+
+	ret = icnss_clk_init(priv);
+	if (ret)
+		goto vreg_off;
+
+	return ret;
+
+vreg_off:
+	icnss_vreg_off(priv);
+out:
+	clear_bit(ICNSS_POWER_ON, &priv->state);
 	return ret;
 }
 
 static int icnss_hw_power_off(struct icnss_priv *priv)
 {
 	int ret = 0;
-	unsigned long flags;
 
 	if (test_bit(HW_ALWAYS_ON, &quirks))
 		return 0;
 
 	icnss_pr_dbg("HW Power off: 0x%lx\n", priv->state);
 
-	spin_lock_irqsave(&priv->on_off_lock, flags);
+	spin_lock(&priv->on_off_lock);
 	if (!test_bit(ICNSS_POWER_ON, &priv->state)) {
-		spin_unlock_irqrestore(&priv->on_off_lock, flags);
+		spin_unlock(&priv->on_off_lock);
 		return ret;
 	}
 	clear_bit(ICNSS_POWER_ON, &priv->state);
-	spin_unlock_irqrestore(&priv->on_off_lock, flags);
+	spin_unlock(&priv->on_off_lock);
+
+	icnss_clk_deinit(priv);
+
+	ret = icnss_vreg_off(priv);
 
 	return ret;
 }
@@ -760,7 +982,7 @@
 }
 EXPORT_SYMBOL(icnss_power_off);
 
-static int icnss_map_msa_permissions(struct icnss_priv *priv, u32 index)
+static int icnss_map_msa_permissions(struct icnss_mem_region_info *mem_region)
 {
 	int ret = 0;
 	phys_addr_t addr;
@@ -773,10 +995,10 @@
 	int source_nelems = sizeof(source_vmlist)/sizeof(u32);
 	int dest_nelems = 0;
 
-	addr = priv->icnss_mem_region[index].reg_addr;
-	size = priv->icnss_mem_region[index].size;
+	addr = mem_region->reg_addr;
+	size = mem_region->size;
 
-	if (!priv->icnss_mem_region[index].secure_flag) {
+	if (!mem_region->secure_flag) {
 		dest_vmids[2] = VMID_WLAN_CE;
 		dest_nelems = 3;
 	} else {
@@ -786,19 +1008,20 @@
 	ret = hyp_assign_phys(addr, size, source_vmlist, source_nelems,
 			      dest_vmids, dest_perms, dest_nelems);
 	if (ret) {
-		icnss_pr_err("Region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n",
-			     index, &addr, size, ret);
+		icnss_pr_err("Hyperviser map failed for PA=%pa size=%u err=%d\n",
+			     &addr, size, ret);
 		goto out;
 	}
-	icnss_pr_dbg("Hypervisor map for region %u: source=%x, dest_nelems=%d, dest[0]=%x, dest[1]=%x, dest[2]=%x\n",
-		     index, source_vmlist[0], dest_nelems,
-		     dest_vmids[0], dest_vmids[1], dest_vmids[2]);
+
+	icnss_pr_dbg("Hypervisor map for source=%x, dest_nelems=%d, dest[0]=%x, dest[1]=%x, dest[2]=%x\n",
+		     source_vmlist[0], dest_nelems, dest_vmids[0],
+		     dest_vmids[1], dest_vmids[2]);
 out:
 	return ret;
 
 }
 
-static int icnss_unmap_msa_permissions(struct icnss_priv *priv, u32 index)
+static int icnss_unmap_msa_permissions(struct icnss_mem_region_info *mem_region)
 {
 	int ret = 0;
 	phys_addr_t addr;
@@ -809,9 +1032,10 @@
 	int source_nelems = 0;
 	int dest_nelems = sizeof(dest_vmids)/sizeof(u32);
 
-	addr = priv->icnss_mem_region[index].reg_addr;
-	size = priv->icnss_mem_region[index].size;
-	if (!priv->icnss_mem_region[index].secure_flag) {
+	addr = mem_region->reg_addr;
+	size = mem_region->size;
+
+	if (!mem_region->secure_flag) {
 		source_vmlist[2] = VMID_WLAN_CE;
 		source_nelems = 3;
 	} else {
@@ -822,14 +1046,13 @@
 	ret = hyp_assign_phys(addr, size, source_vmlist, source_nelems,
 			      dest_vmids, dest_perms, dest_nelems);
 	if (ret) {
-		icnss_pr_err("Region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n",
-			     index, &addr, size, ret);
+		icnss_pr_err("Hyperviser unmap failed for PA=%pa size=%u err=%d\n",
+			     &addr, size, ret);
 		goto out;
 	}
-	icnss_pr_dbg("hypervisor unmap for region %u, source_nelems=%d, source[0]=%x, source[1]=%x, source[2]=%x, dest=%x\n",
-		     index, source_nelems,
-		     source_vmlist[0], source_vmlist[1], source_vmlist[2],
-		     dest_vmids[0]);
+	icnss_pr_dbg("Hypervisor unmap for source_nelems=%d, source[0]=%x, source[1]=%x, source[2]=%x, dest=%x\n",
+		     source_nelems, source_vmlist[0], source_vmlist[1],
+		     source_vmlist[2], dest_vmids[0]);
 out:
 	return ret;
 }
@@ -837,34 +1060,37 @@
 static int icnss_setup_msa_permissions(struct icnss_priv *priv)
 {
 	int ret;
+	int i;
 
 	if (test_bit(ICNSS_MSA0_ASSIGNED, &priv->state))
 		return 0;
 
-	ret = icnss_map_msa_permissions(priv, 0);
-	if (ret)
-		return ret;
+	for (i = 0; i < priv->nr_mem_region; i++) {
 
-	ret = icnss_map_msa_permissions(priv, 1);
-	if (ret)
-		goto err_map_msa;
+		ret = icnss_map_msa_permissions(&priv->mem_region[i]);
+		if (ret)
+			goto err_unmap;
+	}
 
 	set_bit(ICNSS_MSA0_ASSIGNED, &priv->state);
 
-	return ret;
+	return 0;
 
-err_map_msa:
-	icnss_unmap_msa_permissions(priv, 0);
+err_unmap:
+	for (i--; i >= 0; i--)
+		icnss_unmap_msa_permissions(&priv->mem_region[i]);
 	return ret;
 }
 
 static void icnss_remove_msa_permissions(struct icnss_priv *priv)
 {
+	int i;
+
 	if (!test_bit(ICNSS_MSA0_ASSIGNED, &priv->state))
 		return;
 
-	icnss_unmap_msa_permissions(priv, 0);
-	icnss_unmap_msa_permissions(priv, 1);
+	for (i = 0; i < priv->nr_mem_region; i++)
+		icnss_unmap_msa_permissions(&priv->mem_region[i]);
 
 	clear_bit(ICNSS_MSA0_ASSIGNED, &priv->state);
 }
@@ -915,7 +1141,7 @@
 	icnss_pr_dbg("Receive mem_region_info_len: %d\n",
 		     resp.mem_region_info_len);
 
-	if (resp.mem_region_info_len > 2) {
+	if (resp.mem_region_info_len > QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01) {
 		icnss_pr_err("Invalid memory region length received: %d\n",
 			     resp.mem_region_info_len);
 		ret = -EINVAL;
@@ -923,24 +1149,25 @@
 	}
 
 	penv->stats.msa_info_resp++;
+	penv->nr_mem_region = resp.mem_region_info_len;
 	for (i = 0; i < resp.mem_region_info_len; i++) {
-		penv->icnss_mem_region[i].reg_addr =
+		penv->mem_region[i].reg_addr =
 			resp.mem_region_info[i].region_addr;
-		penv->icnss_mem_region[i].size =
+		penv->mem_region[i].size =
 			resp.mem_region_info[i].size;
-		penv->icnss_mem_region[i].secure_flag =
+		penv->mem_region[i].secure_flag =
 			resp.mem_region_info[i].secure_flag;
 		icnss_pr_dbg("Memory Region: %d Addr: 0x%llx Size: 0x%x Flag: 0x%08x\n",
-			 i, penv->icnss_mem_region[i].reg_addr,
-			 penv->icnss_mem_region[i].size,
-			 penv->icnss_mem_region[i].secure_flag);
+			     i, penv->mem_region[i].reg_addr,
+			     penv->mem_region[i].size,
+			     penv->mem_region[i].secure_flag);
 	}
 
 	return 0;
 
 out:
 	penv->stats.msa_info_err++;
-	ICNSS_ASSERT(false);
+	ICNSS_QMI_ASSERT();
 	return ret;
 }
 
@@ -988,7 +1215,7 @@
 
 out:
 	penv->stats.msa_ready_err++;
-	ICNSS_ASSERT(false);
+	ICNSS_QMI_ASSERT();
 	return ret;
 }
 
@@ -1051,7 +1278,7 @@
 
 out:
 	penv->stats.ind_register_err++;
-	ICNSS_ASSERT(false);
+	ICNSS_QMI_ASSERT();
 	return ret;
 }
 
@@ -1120,7 +1347,7 @@
 
 out:
 	penv->stats.cap_err++;
-	ICNSS_ASSERT(false);
+	ICNSS_QMI_ASSERT();
 	return ret;
 }
 
@@ -1181,7 +1408,7 @@
 
 out:
 	penv->stats.mode_req_err++;
-	ICNSS_ASSERT(false);
+	ICNSS_QMI_ASSERT();
 	return ret;
 }
 
@@ -1231,7 +1458,7 @@
 
 out:
 	penv->stats.cfg_req_err++;
-	ICNSS_ASSERT(false);
+	ICNSS_QMI_ASSERT();
 	return ret;
 }
 
@@ -1284,7 +1511,7 @@
 
 out:
 	penv->stats.ini_req_err++;
-	ICNSS_ASSERT(false);
+	ICNSS_QMI_ASSERT();
 	return ret;
 }
 
@@ -1339,7 +1566,7 @@
 		goto out;
 	}
 
-	if (!resp->data_valid || resp->data_len <= data_len) {
+	if (!resp->data_valid || resp->data_len < data_len) {
 		icnss_pr_err("Athdiag read data is invalid, data_valid = %u, data_len = %u\n",
 			     resp->data_valid, resp->data_len);
 		ret = -EINVAL;
@@ -1450,7 +1677,7 @@
 
 out:
 	priv->stats.rejuvenate_ack_err++;
-	ICNSS_ASSERT(false);
+	ICNSS_QMI_ASSERT();
 	return ret;
 }
 
@@ -1524,7 +1751,7 @@
 	if (!penv || !penv->wlfw_clnt)
 		return;
 
-	icnss_pr_dbg("Receiving Event in work queue context\n");
+	icnss_pr_vdbg("Receiving Event in work queue context\n");
 
 	do {
 	} while ((ret = qmi_recv_msg(penv->wlfw_clnt)) == 0);
@@ -1532,13 +1759,13 @@
 	if (ret != -ENOMSG)
 		icnss_pr_err("Error receiving message: %d\n", ret);
 
-	icnss_pr_dbg("Receiving Event completed\n");
+	icnss_pr_vdbg("Receiving Event completed\n");
 }
 
 static void icnss_qmi_wlfw_clnt_notify(struct qmi_handle *handle,
 			     enum qmi_event_type event, void *notify_priv)
 {
-	icnss_pr_dbg("QMI client notify: %d\n", event);
+	icnss_pr_vdbg("QMI client notify: %d\n", event);
 
 	if (!penv || !penv->wlfw_clnt)
 		return;
@@ -1553,11 +1780,29 @@
 	}
 }
 
+static int icnss_call_driver_uevent(struct icnss_priv *priv,
+				    enum icnss_uevent uevent, void *data)
+{
+	struct icnss_uevent_data uevent_data;
+
+	if (!priv->ops || !priv->ops->uevent)
+		return 0;
+
+	icnss_pr_dbg("Calling driver uevent state: 0x%lx, uevent: %d\n",
+		     priv->state, uevent);
+
+	uevent_data.uevent = uevent;
+	uevent_data.data = data;
+
+	return priv->ops->uevent(&priv->pdev->dev, &uevent_data);
+}
+
 static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle,
 			  unsigned int msg_id, void *msg,
 			  unsigned int msg_len, void *ind_cb_priv)
 {
 	struct icnss_event_pd_service_down_data *event_data;
+	struct icnss_uevent_fw_down_data fw_down_data;
 
 	if (!penv)
 		return;
@@ -1582,11 +1827,16 @@
 	case QMI_WLFW_REJUVENATE_IND_V01:
 		icnss_pr_dbg("Received Rejuvenate Indication msg_id 0x%x, state: 0x%lx\n",
 			     msg_id, penv->state);
+
+		icnss_ignore_qmi_timeout(true);
 		event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
 		if (event_data == NULL)
 			return;
 		event_data->crashed = true;
 		event_data->fw_rejuvenate = true;
+		fw_down_data.crashed = true;
+		icnss_call_driver_uevent(penv, ICNSS_UEVENT_FW_DOWN,
+					 &fw_down_data);
 		icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
 					0, event_data);
 		break;
@@ -1707,6 +1957,9 @@
 	if (!priv->ops || !priv->ops->probe)
 		return 0;
 
+	if (test_bit(ICNSS_DRIVER_PROBED, &priv->state))
+		return -EINVAL;
+
 	icnss_pr_dbg("Calling driver probe state: 0x%lx\n", priv->state);
 
 	icnss_hw_power_on(priv);
@@ -1715,6 +1968,8 @@
 	if (ret < 0) {
 		icnss_pr_err("Driver probe failed: %d, state: 0x%lx\n",
 			     ret, priv->state);
+		wcnss_prealloc_check_memory_leak();
+		wcnss_pre_alloc_reset();
 		goto out;
 	}
 
@@ -1727,17 +1982,39 @@
 	return ret;
 }
 
+static int icnss_call_driver_shutdown(struct icnss_priv *priv)
+{
+	if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state))
+		goto out;
+
+	if (!priv->ops || !priv->ops->shutdown)
+		goto out;
+
+	icnss_pr_dbg("Calling driver shutdown state: 0x%lx\n", priv->state);
+
+	priv->ops->shutdown(&priv->pdev->dev);
+
+out:
+	return 0;
+}
+
 static int icnss_pd_restart_complete(struct icnss_priv *priv)
 {
 	int ret;
 
-	clear_bit(ICNSS_PD_RESTART, &priv->state);
 	icnss_pm_relax(priv);
 
+	if (test_bit(ICNSS_WDOG_BITE, &priv->state)) {
+		icnss_call_driver_shutdown(priv);
+		clear_bit(ICNSS_WDOG_BITE, &priv->state);
+	}
+
+	clear_bit(ICNSS_PD_RESTART, &priv->state);
+
 	if (!priv->ops || !priv->ops->reinit)
 		goto out;
 
-	if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state))
+	if (!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
 		goto call_probe;
 
 	icnss_pr_dbg("Calling driver reinit state: 0x%lx\n", priv->state);
@@ -1774,6 +2051,8 @@
 
 	set_bit(ICNSS_FW_READY, &penv->state);
 
+	icnss_call_driver_uevent(penv, ICNSS_UEVENT_FW_READY, NULL);
+
 	icnss_pr_info("WLAN FW is ready: 0x%lx\n", penv->state);
 
 	icnss_hw_power_off(penv);
@@ -1820,6 +2099,8 @@
 	if (ret) {
 		icnss_pr_err("Driver probe failed: %d, state: 0x%lx\n",
 			     ret, penv->state);
+		wcnss_prealloc_check_memory_leak();
+		wcnss_pre_alloc_reset();
 		goto power_off;
 	}
 
@@ -1845,6 +2126,8 @@
 		penv->ops->remove(&penv->pdev->dev);
 
 	clear_bit(ICNSS_DRIVER_PROBED, &penv->state);
+	wcnss_prealloc_check_memory_leak();
+	wcnss_pre_alloc_reset();
 
 	penv->ops = NULL;
 
@@ -1869,27 +2152,39 @@
 	penv->ops->remove(&priv->pdev->dev);
 
 	clear_bit(ICNSS_DRIVER_PROBED, &priv->state);
+	wcnss_prealloc_check_memory_leak();
+	wcnss_pre_alloc_reset();
+
+	icnss_hw_power_off(penv);
 
 	return 0;
 }
 
-static int icnss_call_driver_shutdown(struct icnss_priv *priv)
+static int icnss_fw_crashed(struct icnss_priv *priv,
+			    struct icnss_event_pd_service_down_data *event_data)
 {
-	icnss_pr_dbg("Calling driver shutdown state: 0x%lx\n", priv->state);
+	icnss_pr_dbg("FW crashed, state: 0x%lx, wdog_bite: %d\n",
+		     priv->state, event_data->wdog_bite);
 
 	set_bit(ICNSS_PD_RESTART, &priv->state);
 	clear_bit(ICNSS_FW_READY, &priv->state);
 
 	icnss_pm_stay_awake(priv);
 
-	if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state))
-		return 0;
+	if (test_bit(ICNSS_DRIVER_PROBED, &priv->state))
+		icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL);
 
-	if (!priv->ops || !priv->ops->shutdown)
-		return 0;
+	if (event_data->wdog_bite) {
+		set_bit(ICNSS_WDOG_BITE, &priv->state);
+		goto out;
+	}
 
-	priv->ops->shutdown(&priv->pdev->dev);
+	icnss_call_driver_shutdown(priv);
 
+	if (event_data->fw_rejuvenate)
+		wlfw_rejuvenate_ack_send_sync_msg(priv);
+
+out:
 	return 0;
 }
 
@@ -1900,7 +2195,7 @@
 	struct icnss_event_pd_service_down_data *event_data = data;
 
 	if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state))
-		return 0;
+		goto out;
 
 	if (test_bit(ICNSS_PD_RESTART, &priv->state)) {
 		icnss_pr_err("PD Down while recovery inprogress, crashed: %d, state: 0x%lx\n",
@@ -1910,18 +2205,15 @@
 	}
 
 	if (event_data->crashed)
-		icnss_call_driver_shutdown(priv);
+		icnss_fw_crashed(priv, event_data);
 	else
 		icnss_call_driver_remove(priv);
 
-	if (event_data->fw_rejuvenate)
-		wlfw_rejuvenate_ack_send_sync_msg(priv);
-
 out:
-	ret = icnss_hw_power_off(priv);
-
 	kfree(data);
 
+	icnss_ignore_qmi_timeout(false);
+
 	return ret;
 }
 
@@ -2046,8 +2338,9 @@
 	struct notif_data *notif = data;
 	struct icnss_priv *priv = container_of(nb, struct icnss_priv,
 					       modem_ssr_nb);
+	struct icnss_uevent_fw_down_data fw_down_data;
 
-	icnss_pr_dbg("Modem-Notify: event %lu\n", code);
+	icnss_pr_vdbg("Modem-Notify: event %lu\n", code);
 
 	if (code == SUBSYS_AFTER_SHUTDOWN &&
 		notif->crashed == CRASH_STATUS_ERR_FATAL) {
@@ -2063,7 +2356,10 @@
 	if (test_bit(ICNSS_PDR_ENABLED, &priv->state))
 		return NOTIFY_OK;
 
-	icnss_pr_info("Modem went down, state: %lx\n", priv->state);
+	icnss_pr_info("Modem went down, state: 0x%lx, crashed: %d\n",
+		      priv->state, notif->crashed);
+
+	icnss_ignore_qmi_timeout(true);
 
 	event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
 
@@ -2072,6 +2368,12 @@
 
 	event_data->crashed = notif->crashed;
 
+	if (notif->crashed == CRASH_STATUS_WDOG_BITE)
+		event_data->wdog_bite = true;
+
+	fw_down_data.crashed = !!notif->crashed;
+	icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data);
+
 	icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
 				ICNSS_EVENT_SYNC, event_data);
 
@@ -2135,31 +2437,47 @@
 					       service_notifier_nb);
 	enum pd_subsys_state *state = data;
 	struct icnss_event_pd_service_down_data *event_data;
+	struct icnss_uevent_fw_down_data fw_down_data;
 
-	switch (notification) {
-	case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01:
-		icnss_pr_info("Service down, data: 0x%p, state: 0x%lx\n", data,
-			      priv->state);
-		event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
+	icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n",
+		     notification, priv->state);
 
-		if (event_data == NULL)
-			return notifier_from_errno(-ENOMEM);
+	if (notification != SERVREG_NOTIF_SERVICE_STATE_DOWN_V01)
+		goto done;
 
-		if (state == NULL || *state != ROOT_PD_SHUTDOWN)
-			event_data->crashed = true;
+	event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
 
-		icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
-					ICNSS_EVENT_SYNC, event_data);
-		break;
-	case SERVREG_NOTIF_SERVICE_STATE_UP_V01:
-		icnss_pr_dbg("Service up, state: 0x%lx\n", priv->state);
-		break;
-	default:
-		icnss_pr_dbg("Service state Unknown, notification: 0x%lx, state: 0x%lx\n",
-			     notification, priv->state);
-		return NOTIFY_DONE;
+	if (event_data == NULL)
+		return notifier_from_errno(-ENOMEM);
+
+	if (state == NULL) {
+		event_data->crashed = true;
+		goto event_post;
 	}
 
+	icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx\n",
+		      *state, priv->state);
+
+	switch (*state) {
+	case ROOT_PD_WDOG_BITE:
+		event_data->crashed = true;
+		event_data->wdog_bite = true;
+		break;
+	case ROOT_PD_SHUTDOWN:
+		break;
+	default:
+		event_data->crashed = true;
+		break;
+	}
+
+event_post:
+	icnss_ignore_qmi_timeout(true);
+
+	fw_down_data.crashed = event_data->crashed;
+	icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data);
+	icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
+				ICNSS_EVENT_SYNC, event_data);
+done:
 	return NOTIFY_OK;
 }
 
@@ -2265,7 +2583,7 @@
 
 	return 0;
 out:
-	icnss_pr_err("PD restart not enabled: %d\n", ret);
+	icnss_pr_err("Failed to enable PD restart: %d\n", ret);
 	return ret;
 
 }
@@ -2375,7 +2693,7 @@
 		goto out;
 	}
 
-	icnss_pr_dbg("CE request IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
+	icnss_pr_vdbg("CE request IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
 
 	if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
 		icnss_pr_err("Invalid CE ID, ce_id: %d\n", ce_id);
@@ -2401,7 +2719,7 @@
 	irq_entry->irq = irq;
 	irq_entry->handler = handler;
 
-	icnss_pr_dbg("IRQ requested: %d, ce_id: %d\n", irq, ce_id);
+	icnss_pr_vdbg("IRQ requested: %d, ce_id: %d\n", irq, ce_id);
 
 	penv->stats.ce_irqs[ce_id].request++;
 out:
@@ -2420,7 +2738,7 @@
 		goto out;
 	}
 
-	icnss_pr_dbg("CE free IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
+	icnss_pr_vdbg("CE free IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
 
 	if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
 		icnss_pr_err("Invalid CE ID to free, ce_id: %d\n", ce_id);
@@ -2454,7 +2772,7 @@
 		return;
 	}
 
-	icnss_pr_dbg("Enable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
+	icnss_pr_vdbg("Enable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
 		     penv->state);
 
 	if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
@@ -2478,7 +2796,7 @@
 		return;
 	}
 
-	icnss_pr_dbg("Disable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
+	icnss_pr_vdbg("Disable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
 		     penv->state);
 
 	if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
@@ -2878,12 +3196,25 @@
 		goto out;
 	}
 
-	if (!priv->service_notifier[0].handle) {
-		icnss_pr_err("Invalid handle during recovery\n");
+	if (!test_bit(ICNSS_PDR_ENABLED, &priv->state)) {
+		icnss_pr_err("PD restart not enabled to trigger recovery: state: 0x%lx\n",
+			     priv->state);
+		ret = -EOPNOTSUPP;
+		goto out;
+	}
+
+	if (!priv->service_notifier || !priv->service_notifier[0].handle) {
+		icnss_pr_err("Invalid handle during recovery, state: 0x%lx\n",
+			     priv->state);
 		ret = -EINVAL;
 		goto out;
 	}
 
+	WARN_ON(1);
+	icnss_pr_warn("Initiate PD restart at WLAN FW, state: 0x%lx\n",
+		      priv->state);
+	priv->stats.trigger_recovery++;
+
 	/*
 	 * Initiate PDR, required only for the first instance
 	 */
@@ -2914,13 +3245,15 @@
 		goto map_fail;
 	}
 
-	ret = iommu_domain_set_attr(mapping->domain,
-				    DOMAIN_ATTR_ATOMIC,
-				    &atomic_ctx);
-	if (ret < 0) {
-		icnss_pr_err("Set atomic_ctx attribute failed, err = %d\n",
-			     ret);
-		goto set_attr_fail;
+	if (!priv->bypass_s1_smmu) {
+		ret = iommu_domain_set_attr(mapping->domain,
+					    DOMAIN_ATTR_ATOMIC,
+					    &atomic_ctx);
+		if (ret < 0) {
+			icnss_pr_err("Set atomic_ctx attribute failed, err = %d\n",
+				     ret);
+			goto set_attr_fail;
+		}
 	}
 
 	ret = iommu_domain_set_attr(mapping->domain,
@@ -2959,6 +3292,114 @@
 	priv->smmu_mapping = NULL;
 }
 
+static int icnss_get_vreg_info(struct device *dev,
+			       struct icnss_vreg_info *vreg_info)
+{
+	int ret = 0;
+	char prop_name[MAX_PROP_SIZE];
+	struct regulator *reg;
+	const __be32 *prop;
+	int len = 0;
+	int i;
+
+	reg = devm_regulator_get_optional(dev, vreg_info->name);
+	if (PTR_ERR(reg) == -EPROBE_DEFER) {
+		icnss_pr_err("EPROBE_DEFER for regulator: %s\n",
+			     vreg_info->name);
+		ret = PTR_ERR(reg);
+		goto out;
+	}
+
+	if (IS_ERR(reg)) {
+		ret = PTR_ERR(reg);
+
+		if (vreg_info->required) {
+			icnss_pr_err("Regulator %s doesn't exist: %d\n",
+				     vreg_info->name, ret);
+			goto out;
+		} else {
+			icnss_pr_dbg("Optional regulator %s doesn't exist: %d\n",
+				     vreg_info->name, ret);
+			goto done;
+		}
+	}
+
+	vreg_info->reg = reg;
+
+	snprintf(prop_name, MAX_PROP_SIZE,
+		 "qcom,%s-config", vreg_info->name);
+
+	prop = of_get_property(dev->of_node, prop_name, &len);
+
+	icnss_pr_dbg("Got regulator config, prop: %s, len: %d\n",
+		     prop_name, len);
+
+	if (!prop || len < (2 * sizeof(__be32))) {
+		icnss_pr_dbg("Property %s %s\n", prop_name,
+			     prop ? "invalid format" : "doesn't exist");
+		goto done;
+	}
+
+	for (i = 0; (i * sizeof(__be32)) < len; i++) {
+		switch (i) {
+		case 0:
+			vreg_info->min_v = be32_to_cpup(&prop[0]);
+			break;
+		case 1:
+			vreg_info->max_v = be32_to_cpup(&prop[1]);
+			break;
+		case 2:
+			vreg_info->load_ua = be32_to_cpup(&prop[2]);
+			break;
+		case 3:
+			vreg_info->settle_delay = be32_to_cpup(&prop[3]);
+			break;
+		default:
+			icnss_pr_dbg("Property %s, ignoring value at %d\n",
+				     prop_name, i);
+			break;
+		}
+	}
+
+done:
+	icnss_pr_dbg("Regulator: %s, min_v: %u, max_v: %u, load: %u, delay: %lu\n",
+		     vreg_info->name, vreg_info->min_v, vreg_info->max_v,
+		     vreg_info->load_ua, vreg_info->settle_delay);
+
+	return 0;
+
+out:
+	return ret;
+}
+
+static int icnss_get_clk_info(struct device *dev,
+			      struct icnss_clk_info *clk_info)
+{
+	struct clk *handle;
+	int ret = 0;
+
+	handle = devm_clk_get(dev, clk_info->name);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		if (clk_info->required) {
+			icnss_pr_err("Clock %s isn't available: %d\n",
+				     clk_info->name, ret);
+			goto out;
+		} else {
+			icnss_pr_dbg("Ignoring clock %s: %d\n", clk_info->name,
+				     ret);
+			ret = 0;
+			goto out;
+		}
+	}
+
+	icnss_pr_dbg("Clock: %s, freq: %u\n", clk_info->name, clk_info->freq);
+
+	clk_info->handle = handle;
+out:
+	return ret;
+}
+
 static int icnss_fw_debug_show(struct seq_file *s, void *data)
 {
 	struct icnss_priv *priv = s->private;
@@ -2969,6 +3410,7 @@
 	seq_puts(s, "  VAL: 0 (Test mode disable)\n");
 	seq_puts(s, "  VAL: 1 (WLAN FW test)\n");
 	seq_puts(s, "  VAL: 2 (CCPM test)\n");
+	seq_puts(s, "  VAL: 3 (Trigger Recovery)\n");
 
 	seq_puts(s, "\nCMD: dynamic_feature_mask\n");
 	seq_puts(s, "  VAL: (64 bit feature mask)\n");
@@ -3223,6 +3665,9 @@
 		case ICNSS_WLFW_EXISTS:
 			seq_puts(s, "WLAN FW EXISTS");
 			continue;
+		case ICNSS_WDOG_BITE:
+			seq_puts(s, "MODEM WDOG BITE");
+			continue;
 		}
 
 		seq_printf(s, "UNKNOWN-%d", i);
@@ -3321,6 +3766,7 @@
 	ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_req);
 	ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_resp);
 	ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_err);
+	ICNSS_STATS_DUMP(s, priv, trigger_recovery);
 
 	seq_puts(s, "\n<------------------ PM stats ------------------->\n");
 	ICNSS_STATS_DUMP(s, priv, pm_suspend);
@@ -3666,6 +4112,26 @@
 	if (ret == -EPROBE_DEFER)
 		goto out;
 
+	memcpy(priv->vreg_info, icnss_vreg_info, sizeof(icnss_vreg_info));
+	for (i = 0; i < ICNSS_VREG_INFO_SIZE; i++) {
+		ret = icnss_get_vreg_info(dev, &priv->vreg_info[i]);
+
+		if (ret)
+			goto out;
+	}
+
+	memcpy(priv->clk_info, icnss_clk_info, sizeof(icnss_clk_info));
+	for (i = 0; i < ICNSS_CLK_INFO_SIZE; i++) {
+		ret = icnss_get_clk_info(dev, &priv->clk_info[i]);
+		if (ret)
+			goto out;
+	}
+
+	if (of_property_read_bool(pdev->dev.of_node, "qcom,smmu-s1-bypass"))
+		priv->bypass_s1_smmu = true;
+
+	icnss_pr_dbg("SMMU S1 BYPASS = %d\n", priv->bypass_s1_smmu);
+
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "membase");
 	if (!res) {
 		icnss_pr_err("Memory base not found in DT\n");
@@ -3830,7 +4296,7 @@
 		return -EINVAL;
 	}
 
-	icnss_pr_dbg("PM Suspend, state: 0x%lx\n", priv->state);
+	icnss_pr_vdbg("PM Suspend, state: 0x%lx\n", priv->state);
 
 	if (!priv->ops || !priv->ops->pm_suspend ||
 	    !test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -3859,7 +4325,7 @@
 		return -EINVAL;
 	}
 
-	icnss_pr_dbg("PM resume, state: 0x%lx\n", priv->state);
+	icnss_pr_vdbg("PM resume, state: 0x%lx\n", priv->state);
 
 	if (!priv->ops || !priv->ops->pm_resume ||
 	    !test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -3888,7 +4354,7 @@
 		return -EINVAL;
 	}
 
-	icnss_pr_dbg("PM suspend_noirq, state: 0x%lx\n", priv->state);
+	icnss_pr_vdbg("PM suspend_noirq, state: 0x%lx\n", priv->state);
 
 	if (!priv->ops || !priv->ops->suspend_noirq ||
 	    !test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -3917,7 +4383,7 @@
 		return -EINVAL;
 	}
 
-	icnss_pr_dbg("PM resume_noirq, state: 0x%lx\n", priv->state);
+	icnss_pr_vdbg("PM resume_noirq, state: 0x%lx\n", priv->state);
 
 	if (!priv->ops || !priv->ops->resume_noirq ||
 	    !test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -3961,26 +4427,6 @@
 	},
 };
 
-#ifdef CONFIG_ICNSS_DEBUG
-static void __init icnss_ipc_log_long_context_init(void)
-{
-	icnss_ipc_log_long_context = ipc_log_context_create(NUM_REG_LOG_PAGES,
-							   "icnss_long", 0);
-	if (!icnss_ipc_log_long_context)
-		icnss_pr_err("Unable to create register log context\n");
-}
-
-static void __exit icnss_ipc_log_long_context_destroy(void)
-{
-	ipc_log_context_destroy(icnss_ipc_log_long_context);
-	icnss_ipc_log_long_context = NULL;
-}
-#else
-
-static void __init icnss_ipc_log_long_context_init(void) { }
-static void __exit icnss_ipc_log_long_context_destroy(void) { }
-#endif
-
 static int __init icnss_initialize(void)
 {
 	icnss_ipc_log_context = ipc_log_context_create(NUM_LOG_PAGES,
@@ -3988,7 +4434,10 @@
 	if (!icnss_ipc_log_context)
 		icnss_pr_err("Unable to create log context\n");
 
-	icnss_ipc_log_long_context_init();
+	icnss_ipc_log_long_context = ipc_log_context_create(NUM_LOG_LONG_PAGES,
+						       "icnss_long", 0);
+	if (!icnss_ipc_log_long_context)
+		icnss_pr_err("Unable to create log long context\n");
 
 	return platform_driver_register(&icnss_driver);
 }
@@ -3998,8 +4447,8 @@
 	platform_driver_unregister(&icnss_driver);
 	ipc_log_context_destroy(icnss_ipc_log_context);
 	icnss_ipc_log_context = NULL;
-
-	icnss_ipc_log_long_context_destroy();
+	ipc_log_context_destroy(icnss_ipc_log_long_context);
+	icnss_ipc_log_long_context = NULL;
 }
 
 
diff --git a/drivers/soc/qcom/llcc-core.c b/drivers/soc/qcom/llcc-core.c
index fc88c71..3d6b002 100644
--- a/drivers/soc/qcom/llcc-core.c
+++ b/drivers/soc/qcom/llcc-core.c
@@ -33,42 +33,39 @@
 #define SB_DB_TRP_INTERRUPT_ENABLE	0x3
 #define TRP0_INTERRUPT_ENABLE	0x1
 #define DRP0_INTERRUPT_ENABLE	BIT(6)
-#define COMMON_INTERRUPT_0_AMON BIT(8)
 #define SB_DB_DRP_INTERRUPT_ENABLE	0x3
 
-static void qcom_llcc_core_setup(struct regmap *llcc_regmap)
+static void qcom_llcc_core_setup(struct regmap *llcc_regmap, uint32_t b_off)
 {
 	u32 sb_err_threshold;
 
 	/* Enable TRP in instance 2 of common interrupt enable register */
-	regmap_update_bits(llcc_regmap, CMN_INTERRUPT_2_ENABLE,
+	regmap_update_bits(llcc_regmap, b_off + CMN_INTERRUPT_2_ENABLE,
 			   TRP0_INTERRUPT_ENABLE, TRP0_INTERRUPT_ENABLE);
 
 	/* Enable ECC interrupts on Tag Ram */
-	regmap_update_bits(llcc_regmap, TRP_INTERRUPT_0_ENABLE,
+	regmap_update_bits(llcc_regmap, b_off + TRP_INTERRUPT_0_ENABLE,
 		SB_DB_TRP_INTERRUPT_ENABLE, SB_DB_TRP_INTERRUPT_ENABLE);
 
 	/* Enable SB error for Data RAM */
 	sb_err_threshold = (SB_ERROR_THRESHOLD << SB_ERROR_THRESHOLD_SHIFT);
-	regmap_write(llcc_regmap, DRP_ECC_ERROR_CFG, sb_err_threshold);
+	regmap_write(llcc_regmap, b_off + DRP_ECC_ERROR_CFG, sb_err_threshold);
 
 	/* Enable DRP in instance 2 of common interrupt enable register */
-	regmap_update_bits(llcc_regmap, CMN_INTERRUPT_2_ENABLE,
+	regmap_update_bits(llcc_regmap, b_off + CMN_INTERRUPT_2_ENABLE,
 			   DRP0_INTERRUPT_ENABLE, DRP0_INTERRUPT_ENABLE);
 
 	/* Enable ECC interrupts on Data Ram */
-	regmap_write(llcc_regmap, DRP_INTERRUPT_ENABLE,
+	regmap_write(llcc_regmap, b_off + DRP_INTERRUPT_ENABLE,
 		     SB_DB_DRP_INTERRUPT_ENABLE);
-
-	/* Enable AMON interrupt in the common interrupt register */
-	regmap_update_bits(llcc_regmap, CMN_INTERRUPT_0_ENABLE,
-			COMMON_INTERRUPT_0_AMON, COMMON_INTERRUPT_0_AMON);
 }
 
 static int qcom_llcc_core_probe(struct platform_device *pdev)
 {
 	struct regmap *llcc_regmap;
 	struct device *dev = &pdev->dev;
+	u32 b_off = 0;
+	int ret = 0;
 
 	llcc_regmap = syscon_node_to_regmap(dev->of_node);
 
@@ -77,7 +74,14 @@
 		return PTR_ERR(llcc_regmap);
 	}
 
-	qcom_llcc_core_setup(llcc_regmap);
+	ret = of_property_read_u32(dev->of_node,
+			"qcom,llcc-broadcast-off", &b_off);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to read broadcast-off\n");
+		return -EINVAL;
+	}
+
+	qcom_llcc_core_setup(llcc_regmap, b_off);
 
 	return 0;
 }
diff --git a/drivers/soc/qcom/llcc-slice.c b/drivers/soc/qcom/llcc-slice.c
index 77c2ae6..5ca0941 100644
--- a/drivers/soc/qcom/llcc-slice.c
+++ b/drivers/soc/qcom/llcc-slice.c
@@ -44,6 +44,7 @@
 
 #define CACHE_LINE_SIZE_SHIFT 6
 #define SIZE_PER_LLCC_SHIFT   2
+
 #define MAX_CAP_TO_BYTES(n) (n * 1024)
 #define LLCC_TRP_ACT_CTRLn(n) (n * 0x1000)
 #define LLCC_TRP_STATUSn(n)   (4 + n * 0x1000)
@@ -63,6 +64,7 @@
 	struct mutex slice_mutex;
 	u32 llcc_config_data_sz;
 	u32 max_slices;
+	u32 b_off;
 	unsigned long *llcc_slice_map;
 };
 
@@ -172,8 +174,8 @@
 	u32 slice_status;
 	unsigned long timeout;
 
-	act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid);
-	status_reg = LLCC_TRP_STATUSn(sid);
+	act_ctrl_reg = drv->b_off + LLCC_TRP_ACT_CTRLn(sid);
+	status_reg = drv->b_off + LLCC_TRP_STATUSn(sid);
 
 	regmap_write(drv->llcc_map, act_ctrl_reg, act_ctrl_reg_val);
 
@@ -323,13 +325,14 @@
 	const struct llcc_slice_config *llcc_table;
 	struct llcc_drv_data *drv = platform_get_drvdata(pdev);
 	struct llcc_slice_desc desc;
+	u32 b_off = drv->b_off;
 
 	sz = drv->llcc_config_data_sz;
 	llcc_table = drv->slice_data;
 
 	for (i = 0; i < sz; i++) {
-		attr1_cfg = LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
-		attr0_cfg = LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
+		attr1_cfg = b_off + LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
+		attr0_cfg = b_off + LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
 
 		attr1_val = llcc_table[i].cache_mode;
 		attr1_val |= (llcc_table[i].probe_target_ways <<
@@ -386,7 +389,15 @@
 	rc = of_property_read_u32(pdev->dev.of_node, "max-slices",
 				  &drv_data->max_slices);
 	if (rc) {
-		dev_info(&pdev->dev, "Invalid max-slices dt entry\n");
+		dev_err(&pdev->dev, "Invalid max-slices dt entry\n");
+		devm_kfree(&pdev->dev, drv_data);
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.parent->of_node,
+			"qcom,llcc-broadcast-off", &drv_data->b_off);
+	if (rc) {
+		dev_err(&pdev->dev, "Invalid qcom,broadcast-off entry\n");
 		devm_kfree(&pdev->dev, drv_data);
 		return rc;
 	}
diff --git a/drivers/soc/qcom/msm-core.c b/drivers/soc/qcom/msm-core.c
index 5a0b261..de2a1ce 100644
--- a/drivers/soc/qcom/msm-core.c
+++ b/drivers/soc/qcom/msm-core.c
@@ -107,7 +107,6 @@
 static struct cpu_activity_info activity[NR_CPUS];
 DEFINE_PER_CPU(struct cpu_pstate_pwr *, ptable);
 static struct cpu_pwr_stats cpu_stats[NR_CPUS];
-static uint32_t scaling_factor;
 ALLOCATE_2D_ARRAY(uint32_t);
 
 static int poll_ms;
@@ -402,9 +401,9 @@
 		return -EINVAL;
 
 	get_user(cluster, &argp->cluster);
-	mpidr = (argp->cluster << (MAX_CORES_PER_CLUSTER *
+	mpidr = (cluster << (MAX_CORES_PER_CLUSTER *
 			MAX_NUM_OF_CLUSTERS));
-	cpumask = argp->cpumask;
+	get_user(cpumask, &argp->cpumask);
 
 	switch (cmd) {
 	case EA_LEAKAGE:
@@ -603,54 +602,6 @@
 	return ret;
 }
 
-static int msm_core_tsens_init(struct device_node *node, int cpu)
-{
-	int ret = 0;
-	char *key = NULL;
-	struct device_node *phandle;
-	const char *sensor_type = NULL;
-	struct cpu_activity_info *cpu_node = &activity[cpu];
-
-	if (!node)
-		return -ENODEV;
-
-	key = "sensor";
-	phandle = of_parse_phandle(node, key, 0);
-	if (!phandle) {
-		pr_info("%s: No sensor mapping found for the core\n",
-				__func__);
-		/* Do not treat this as error as some targets might have
-		 * temperature notification only in userspace.
-		 * Use default temperature for the core. Userspace might
-		 * update the temperature once it is up.
-		 */
-		cpu_node->sensor_id = -ENODEV;
-		cpu_node->temp = DEFAULT_TEMP;
-		return 0;
-	}
-
-	key = "qcom,sensor-name";
-	ret = of_property_read_string(phandle, key,
-				&sensor_type);
-	if (ret) {
-		pr_err("%s: Cannot read tsens id\n", __func__);
-		return ret;
-	}
-
-	if (cpu_node->sensor_id < 0)
-		return cpu_node->sensor_id;
-
-	key = "qcom,scaling-factor";
-	ret = of_property_read_u32(phandle, key,
-				&scaling_factor);
-	if (ret) {
-		pr_info("%s: Cannot read tsens scaling factor\n", __func__);
-		scaling_factor = DEFAULT_SCALING_FACTOR;
-	}
-
-	return ret;
-}
-
 static int msm_core_mpidr_init(struct device_node *phandle)
 {
 	int ret = 0;
@@ -779,8 +730,6 @@
 	int ret = 0;
 	unsigned long cpu = 0;
 	struct device_node *child_node = NULL;
-	struct device_node *ea_node = NULL;
-	char *key = NULL;
 	int mpidr;
 
 	for_each_possible_cpu(cpu) {
@@ -793,23 +742,8 @@
 		if (mpidr < 0)
 			return mpidr;
 
-		if (cpu >= num_possible_cpus())
-			continue;
-
 		activity[cpu].mpidr = mpidr;
 
-		key = "qcom,ea";
-		ea_node = of_parse_phandle(child_node, key, 0);
-		if (!ea_node) {
-			pr_err("%s Couldn't find the ea_node for cpu%lu\n",
-				__func__, cpu);
-			return -ENODEV;
-		}
-
-		ret = msm_core_tsens_init(ea_node, cpu);
-		if (ret)
-			return ret;
-
 		if (!activity[cpu].sp->table)
 			continue;
 
@@ -858,49 +792,6 @@
 	}
 }
 
-static int uio_init(struct platform_device *pdev)
-{
-	int ret = 0;
-	struct uio_info *info = NULL;
-	struct resource *clnt_res = NULL;
-	u32 ea_mem_size = 0;
-	phys_addr_t ea_mem_pyhsical = 0;
-
-	clnt_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!clnt_res) {
-		pr_err("resource not found\n");
-		return -ENODEV;
-	}
-
-	info = devm_kzalloc(&pdev->dev, sizeof(struct uio_info), GFP_KERNEL);
-	if (!info)
-		return -ENOMEM;
-
-	ea_mem_size = resource_size(clnt_res);
-	ea_mem_pyhsical = clnt_res->start;
-
-	if (ea_mem_size == 0) {
-		pr_err("msm-core: memory size is zero");
-		return -EINVAL;
-	}
-
-	/* Setup device */
-	info->name = clnt_res->name;
-	info->version = "1.0";
-	info->mem[0].addr = ea_mem_pyhsical;
-	info->mem[0].size = ea_mem_size;
-	info->mem[0].memtype = UIO_MEM_PHYS;
-
-	ret = uio_register_device(&pdev->dev, info);
-	if (ret) {
-		pr_err("uio register failed ret=%d", ret);
-		return ret;
-	}
-	dev_set_drvdata(&pdev->dev, info);
-
-	return 0;
-}
-
 static int msm_core_dev_probe(struct platform_device *pdev)
 {
 	int ret = 0;
@@ -934,10 +825,6 @@
 	key = "qcom,throttling-temp";
 	ret = of_property_read_u32(node, key, &max_throttling_temp);
 
-	ret = uio_init(pdev);
-	if (ret)
-		return ret;
-
 	ret = msm_core_freq_init();
 	if (ret)
 		goto failed;
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
index 1f5cfc0..beb5c2b 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -983,7 +983,6 @@
 	if (IS_ERR_OR_NULL(rscdev->mbox)) {
 		MSM_BUS_ERR("%s: Failed to get mbox:%s", __func__,
 						node_dev->node_info->name);
-		return PTR_ERR(rscdev->mbox);
 	}
 
 	// Add way to count # of VCDs, initialize LL
@@ -1532,21 +1531,22 @@
 				goto exit_device_probe;
 			}
 		}
-		if (pdata->info[i].node_info->is_bcm_dev)
+		if (pdata->info[i].node_info->is_bcm_dev) {
 			ret = msm_bus_bcm_init(node_dev, &pdata->info[i]);
 			if (ret) {
 				MSM_BUS_ERR("%s: Error intializing bcm %d",
 					__func__, pdata->info[i].node_info->id);
 				goto exit_device_probe;
 			}
-		if (pdata->info[i].node_info->is_rsc_dev)
+		}
+		if (pdata->info[i].node_info->is_rsc_dev) {
 			ret = msm_bus_rsc_init(pdev, node_dev, &pdata->info[i]);
 			if (ret) {
 				MSM_BUS_ERR("%s: Error intializing rsc %d",
 					__func__, pdata->info[i].node_info->id);
 				goto exit_device_probe;
 			}
-
+		}
 	}
 
 	ret = bus_for_each_dev(&msm_bus_type, NULL, NULL,
diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
index 40a539e..40aac6a 100644
--- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
+++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
@@ -17,7 +17,6 @@
 #include <linux/uaccess.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
-#include <linux/list.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/errno.h>
@@ -33,16 +32,10 @@
 #define APR_MAXIMUM_NUM_OF_RETRIES 2
 
 struct apr_tx_buf {
-	struct list_head list;
 	struct apr_pkt_priv pkt_priv;
 	char buf[APR_MAX_BUF];
 };
 
-struct apr_buf_list {
-	struct list_head list;
-	spinlock_t lock;
-};
-
 struct link_state {
 	uint32_t dest;
 	void *handle;
@@ -51,7 +44,6 @@
 };
 
 static struct link_state link_state[APR_DEST_MAX];
-static struct apr_buf_list buf_list;
 
 static char *svc_names[APR_DEST_MAX][APR_CLIENT_MAX] = {
 	{
@@ -67,43 +59,36 @@
 static struct apr_svc_ch_dev
 	apr_svc_ch[APR_DL_MAX][APR_DEST_MAX][APR_CLIENT_MAX];
 
-static struct apr_tx_buf *apr_get_free_buf(int len)
+static struct apr_tx_buf *apr_alloc_buf(int len)
 {
-	struct apr_tx_buf *tx_buf;
-	unsigned long flags;
 
 	if (len > APR_MAX_BUF) {
 		pr_err("%s: buf too large [%d]\n", __func__, len);
 		return ERR_PTR(-EINVAL);
 	}
 
-	spin_lock_irqsave(&buf_list.lock, flags);
-	if (list_empty(&buf_list.list)) {
-		spin_unlock_irqrestore(&buf_list.lock, flags);
-		pr_err("%s: No buf available\n", __func__);
-		return ERR_PTR(-ENOMEM);
+	return kzalloc(sizeof(struct apr_tx_buf), GFP_ATOMIC);
+}
+
+static void apr_free_buf(const void *ptr)
+{
+
+	struct apr_pkt_priv *apr_pkt_priv = (struct apr_pkt_priv *)ptr;
+	struct apr_tx_buf *tx_buf;
+
+	if (!apr_pkt_priv) {
+		pr_err("%s: Invalid apr_pkt_priv\n", __func__);
+		return;
 	}
 
-	tx_buf = list_first_entry(&buf_list.list, struct apr_tx_buf, list);
-	list_del(&tx_buf->list);
-	spin_unlock_irqrestore(&buf_list.lock, flags);
-
-	return tx_buf;
+	if (apr_pkt_priv->pkt_owner == APR_PKT_OWNER_DRIVER) {
+		tx_buf = container_of((void *)apr_pkt_priv,
+				      struct apr_tx_buf, pkt_priv);
+		pr_debug("%s: Freeing buffer %pK", __func__, tx_buf);
+		kfree(tx_buf);
+	}
 }
 
-static void apr_buf_add_tail(const void *buf)
-{
-	struct apr_tx_buf *list;
-	unsigned long flags;
-
-	if (!buf)
-		return;
-
-	spin_lock_irqsave(&buf_list.lock, flags);
-	list = container_of((void *)buf, struct apr_tx_buf, buf);
-	list_add_tail(&list->list, &buf_list.list);
-	spin_unlock_irqrestore(&buf_list.lock, flags);
-}
 
 static int __apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data,
 			   struct apr_pkt_priv *pkt_priv, int len)
@@ -129,14 +114,14 @@
 {
 	int rc = 0, retries = 0;
 	void *pkt_data = NULL;
-	struct apr_tx_buf *tx_buf;
+	struct apr_tx_buf *tx_buf = NULL;
 	struct apr_pkt_priv *pkt_priv_ptr = pkt_priv;
 
 	if (!apr_ch->handle || !pkt_priv)
 		return -EINVAL;
 
 	if (pkt_priv->pkt_owner == APR_PKT_OWNER_DRIVER) {
-		tx_buf = apr_get_free_buf(len);
+		tx_buf = apr_alloc_buf(len);
 		if (IS_ERR_OR_NULL(tx_buf)) {
 			rc = -EINVAL;
 			goto exit;
@@ -159,7 +144,7 @@
 	if (rc < 0) {
 		pr_err("%s: Unable to send the packet, rc:%d\n", __func__, rc);
 		if (pkt_priv->pkt_owner == APR_PKT_OWNER_DRIVER)
-			apr_buf_add_tail(pkt_data);
+			kfree(tx_buf);
 	}
 exit:
 	return rc;
@@ -188,39 +173,17 @@
 static void apr_tal_notify_tx_abort(void *handle, const void *priv,
 				    const void *pkt_priv)
 {
-	struct apr_pkt_priv *apr_pkt_priv_ptr =
-				(struct apr_pkt_priv *)pkt_priv;
-	struct apr_tx_buf *list_node;
-
-	if (!apr_pkt_priv_ptr) {
-		pr_err("%s: Invalid pkt_priv\n", __func__);
-		return;
-	}
-
-	pr_debug("%s: tx_abort received for apr_pkt_priv_ptr:%pK\n",
-		 __func__, apr_pkt_priv_ptr);
-
-	if (apr_pkt_priv_ptr->pkt_owner == APR_PKT_OWNER_DRIVER) {
-		list_node = container_of(apr_pkt_priv_ptr,
-					 struct apr_tx_buf, pkt_priv);
-		apr_buf_add_tail(list_node->buf);
-	}
+	pr_debug("%s: tx_abort received for pkt_priv:%pK\n",
+		 __func__, pkt_priv);
+	apr_free_buf(pkt_priv);
 }
 
 void apr_tal_notify_tx_done(void *handle, const void *priv,
 			    const void *pkt_priv, const void *ptr)
 {
-	struct apr_pkt_priv *apr_pkt_priv = (struct apr_pkt_priv *)pkt_priv;
-
-	if (!pkt_priv || !ptr) {
-		pr_err("%s: Invalid pkt_priv or ptr\n", __func__);
-		return;
-	}
-
-	pr_debug("%s: tx_done received\n", __func__);
-
-	if (apr_pkt_priv->pkt_owner == APR_PKT_OWNER_DRIVER)
-		apr_buf_add_tail(ptr);
+	pr_debug("%s: tx_done received for pkt_priv:%pK\n",
+		 __func__, pkt_priv);
+	apr_free_buf(pkt_priv);
 }
 
 bool apr_tal_notify_rx_intent_req(void *handle, const void *priv,
@@ -254,6 +217,7 @@
 	 */
 	pr_debug("%s: remote queued an intent\n", __func__);
 	apr_ch->if_remote_intent_ready = true;
+	wake_up(&apr_ch->wait);
 }
 
 void apr_tal_notify_state(void *handle, const void *priv, unsigned int event)
@@ -456,8 +420,6 @@
 static int __init apr_tal_init(void)
 {
 	int i, j, k;
-	struct apr_tx_buf *buf;
-	struct list_head *ptr, *next;
 
 	for (i = 0; i < APR_DL_MAX; i++) {
 		for (j = 0; j < APR_DEST_MAX; j++) {
@@ -473,21 +435,6 @@
 	for (i = 0; i < APR_DEST_MAX; i++)
 		init_waitqueue_head(&link_state[i].wait);
 
-	spin_lock_init(&buf_list.lock);
-	INIT_LIST_HEAD(&buf_list.list);
-	for (i = 0; i < APR_NUM_OF_TX_BUF; i++) {
-		buf = kzalloc(sizeof(struct apr_tx_buf), GFP_KERNEL);
-		if (!buf) {
-			pr_err("%s: Unable to allocate tx buf\n", __func__);
-			goto tx_buf_alloc_fail;
-		}
-
-		INIT_LIST_HEAD(&buf->list);
-		spin_lock(&buf_list.lock);
-		list_add_tail(&buf->list, &buf_list.list);
-		spin_unlock(&buf_list.lock);
-	}
-
 	link_state[APR_DEST_MODEM].link_state = GLINK_LINK_STATE_DOWN;
 	link_state[APR_DEST_MODEM].handle =
 		glink_register_link_state_cb(&mpss_link_info, NULL);
@@ -501,13 +448,5 @@
 		pr_err("%s: Unable to register lpass link state\n", __func__);
 
 	return 0;
-
-tx_buf_alloc_fail:
-	list_for_each_safe(ptr, next, &buf_list.list) {
-		buf = list_entry(ptr, struct apr_tx_buf, list);
-		list_del(&buf->list);
-		kfree(buf);
-	}
-	return -ENOMEM;
 }
 device_initcall(apr_tal_init);
diff --git a/drivers/soc/qcom/qdsp6v2/audio_notifier.c b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
index a2b0f0e..414c123 100644
--- a/drivers/soc/qcom/qdsp6v2/audio_notifier.c
+++ b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
@@ -394,8 +394,8 @@
 	int ret;
 
 	list_for_each_safe(ptr, next, &client_list) {
-		client_data = list_entry(ptr,
-			struct client_data, list);
+		client_data = list_entry(ptr, struct client_data, list);
+
 		ret = audio_notifer_reg_client(client_data);
 		if (ret < 0)
 			pr_err("%s: audio_notifer_reg_client failed for client %s, ret %d\n",
@@ -518,9 +518,8 @@
 		goto done;
 	}
 	mutex_lock(&notifier_mutex);
-	list_for_each_safe(ptr, next, &client_data->list) {
-		client_data = list_entry(ptr, struct client_data,
-					list);
+	list_for_each_safe(ptr, next, &client_list) {
+		client_data = list_entry(ptr, struct client_data, list);
 		if (!strcmp(client_name, client_data->client_name)) {
 			ret2 = audio_notifer_dereg_client(client_data);
 			if (ret2 < 0) {
diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c
index 07e8991..f3b1b83 100644
--- a/drivers/soc/qcom/qdsp6v2/voice_svc.c
+++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c
@@ -42,6 +42,12 @@
 	struct list_head response_queue;
 	wait_queue_head_t response_wait;
 	spinlock_t response_lock;
+	/*
+	 * This mutex ensures responses are processed in sequential order and
+	 * that no two threads access and free the same response at the same
+	 * time.
+	 */
+	struct mutex response_mutex_lock;
 };
 
 struct apr_data {
@@ -361,6 +367,9 @@
 	struct voice_svc_prvt *prtd;
 	struct voice_svc_write_msg *data = NULL;
 	uint32_t cmd;
+	struct voice_svc_register *register_data = NULL;
+	struct voice_svc_cmd_request *request_data = NULL;
+	uint32_t request_payload_size;
 
 	pr_debug("%s\n", __func__);
 
@@ -409,12 +418,19 @@
 		 */
 		if (count == (sizeof(struct voice_svc_write_msg) +
 			      sizeof(struct voice_svc_register))) {
-			ret = process_reg_cmd(
-			(struct voice_svc_register *)data->payload, prtd);
+			register_data =
+				(struct voice_svc_register *)data->payload;
+			if (register_data == NULL) {
+				pr_err("%s: register data is NULL", __func__);
+				ret = -EINVAL;
+				goto done;
+			}
+			ret = process_reg_cmd(register_data, prtd);
 			if (!ret)
 				ret = count;
 		} else {
-			pr_err("%s: invalid payload size\n", __func__);
+			pr_err("%s: invalid data payload size for register command\n",
+				__func__);
 			ret = -EINVAL;
 			goto done;
 		}
@@ -423,19 +439,40 @@
 		/*
 		 * Check that count reflects the expected size to ensure
 		 * sufficient memory was allocated. Since voice_svc_cmd_request
-		 * has a variable size, check the minimum value count must be.
+		 * has a variable size, check the minimum value count must be to
+		 * parse the message request then check the minimum size to hold
+		 * the payload of the message request.
 		 */
 		if (count >= (sizeof(struct voice_svc_write_msg) +
 			      sizeof(struct voice_svc_cmd_request))) {
-		ret = voice_svc_send_req(
-			(struct voice_svc_cmd_request *)data->payload, prtd);
-		if (!ret)
-			ret = count;
-	} else {
-		pr_err("%s: invalid payload size\n", __func__);
-		ret = -EINVAL;
-		goto done;
-	}
+			request_data =
+				(struct voice_svc_cmd_request *)data->payload;
+			if (request_data == NULL) {
+				pr_err("%s: request data is NULL", __func__);
+				ret = -EINVAL;
+				goto done;
+			}
+
+			request_payload_size = request_data->payload_size;
+
+			if (count >= (sizeof(struct voice_svc_write_msg) +
+				      sizeof(struct voice_svc_cmd_request) +
+				      request_payload_size)) {
+				ret = voice_svc_send_req(request_data, prtd);
+				if (!ret)
+					ret = count;
+			} else {
+				pr_err("%s: invalid request payload size\n",
+					__func__);
+				ret = -EINVAL;
+				goto done;
+			}
+		} else {
+			pr_err("%s: invalid data payload size for request command\n",
+				__func__);
+			ret = -EINVAL;
+			goto done;
+		}
 		break;
 	default:
 		pr_debug("%s: Invalid command: %u\n", __func__, cmd);
@@ -466,6 +503,7 @@
 		goto done;
 	}
 
+	mutex_lock(&prtd->response_mutex_lock);
 	spin_lock_irqsave(&prtd->response_lock, spin_flags);
 
 	if (list_empty(&prtd->response_queue)) {
@@ -479,7 +517,7 @@
 			pr_debug("%s: Read timeout\n", __func__);
 
 			ret = -ETIMEDOUT;
-			goto done;
+			goto unlock;
 		} else if (ret > 0 && !list_empty(&prtd->response_queue)) {
 			pr_debug("%s: Interrupt received for response\n",
 				 __func__);
@@ -487,7 +525,7 @@
 			pr_debug("%s: Interrupted by SIGNAL %d\n",
 				 __func__, ret);
 
-			goto done;
+			goto unlock;
 		}
 
 		spin_lock_irqsave(&prtd->response_lock, spin_flags);
@@ -506,7 +544,7 @@
 		       __func__, count, size);
 
 		ret = -ENOMEM;
-		goto done;
+		goto unlock;
 	}
 
 	if (!access_ok(VERIFY_WRITE, arg, size)) {
@@ -514,7 +552,7 @@
 		       __func__);
 
 		ret = -EPERM;
-		goto done;
+		goto unlock;
 	}
 
 	ret = copy_to_user(arg, &resp->resp,
@@ -524,7 +562,7 @@
 		pr_err("%s: copy_to_user failed %d\n", __func__, ret);
 
 		ret = -EPERM;
-		goto done;
+		goto unlock;
 	}
 
 	spin_lock_irqsave(&prtd->response_lock, spin_flags);
@@ -538,6 +576,8 @@
 
 	ret = count;
 
+unlock:
+	mutex_unlock(&prtd->response_mutex_lock);
 done:
 	return ret;
 }
@@ -591,6 +631,7 @@
 	INIT_LIST_HEAD(&prtd->response_queue);
 	init_waitqueue_head(&prtd->response_wait);
 	spin_lock_init(&prtd->response_lock);
+	mutex_init(&prtd->response_mutex_lock);
 	file->private_data = (void *)prtd;
 
 	/* Current APR implementation doesn't support session based
@@ -641,6 +682,7 @@
 			pr_err("%s: Failed to dereg MVM %d\n", __func__, ret);
 	}
 
+	mutex_lock(&prtd->response_mutex_lock);
 	spin_lock_irqsave(&prtd->response_lock, spin_flags);
 
 	while (!list_empty(&prtd->response_queue)) {
@@ -654,6 +696,9 @@
 	}
 
 	spin_unlock_irqrestore(&prtd->response_lock, spin_flags);
+	mutex_unlock(&prtd->response_mutex_lock);
+
+	mutex_destroy(&prtd->response_mutex_lock);
 
 	kfree(file->private_data);
 	file->private_data = NULL;
diff --git a/drivers/soc/qcom/qpnp-pbs.c b/drivers/soc/qcom/qpnp-pbs.c
new file mode 100644
index 0000000..287c8a2
--- /dev/null
+++ b/drivers/soc/qcom/qpnp-pbs.c
@@ -0,0 +1,361 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt)	"PBS: %s: " fmt, __func__
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/qpnp/qpnp-pbs.h>
+
+#define QPNP_PBS_DEV_NAME "qcom,qpnp-pbs"
+
+#define PBS_CLIENT_TRIG_CTL		0x42
+#define PBS_CLIENT_SW_TRIG_BIT		BIT(7)
+#define PBS_CLIENT_SCRATCH1		0x50
+#define PBS_CLIENT_SCRATCH2		0x51
+
+static LIST_HEAD(pbs_dev_list);
+static DEFINE_MUTEX(pbs_list_lock);
+
+struct qpnp_pbs {
+	struct platform_device	*pdev;
+	struct device		*dev;
+	struct device_node	*dev_node;
+	struct regmap		*regmap;
+	struct mutex		pbs_lock;
+	struct list_head	link;
+
+	u32			base;
+};
+
+static int qpnp_pbs_read(struct qpnp_pbs *pbs, u32 address,
+					u8 *val, int count)
+{
+	int rc = 0;
+	struct platform_device *pdev = pbs->pdev;
+
+	rc = regmap_bulk_read(pbs->regmap, address, val, count);
+	if (rc)
+		pr_err("Failed to read address=0x%02x sid=0x%02x rc=%d\n",
+			address, to_spmi_device(pdev->dev.parent)->usid, rc);
+
+	return rc;
+}
+
+static int qpnp_pbs_write(struct qpnp_pbs *pbs, u16 address,
+					u8 *val, int count)
+{
+	int rc = 0;
+	struct platform_device *pdev = pbs->pdev;
+
+	rc = regmap_bulk_write(pbs->regmap, address, val, count);
+	if (rc < 0)
+		pr_err("Failed to write address =0x%02x sid=0x%02x rc=%d\n",
+			  address, to_spmi_device(pdev->dev.parent)->usid, rc);
+	else
+		pr_debug("Wrote 0x%02X to addr 0x%04x\n", *val, address);
+
+	return rc;
+}
+
+static int qpnp_pbs_masked_write(struct qpnp_pbs *pbs, u16 address,
+						   u8 mask, u8 val)
+{
+	int rc;
+
+	rc = regmap_update_bits(pbs->regmap, address, mask, val);
+	if (rc < 0)
+		pr_err("Failed to write address 0x%04X, rc = %d\n",
+					address, rc);
+	else
+		pr_debug("Wrote 0x%02X to addr 0x%04X\n",
+			val, address);
+
+	return rc;
+}
+
+static struct qpnp_pbs *get_pbs_client_node(struct device_node *dev_node)
+{
+	struct qpnp_pbs *pbs;
+
+	mutex_lock(&pbs_list_lock);
+	list_for_each_entry(pbs, &pbs_dev_list, link) {
+		if (dev_node == pbs->dev_node) {
+			mutex_unlock(&pbs_list_lock);
+			return pbs;
+		}
+	}
+
+	mutex_unlock(&pbs_list_lock);
+	return ERR_PTR(-EINVAL);
+}
+
+static int qpnp_pbs_wait_for_ack(struct qpnp_pbs *pbs, u8 bit_pos)
+{
+	int rc = 0;
+	u16 retries = 2000, dly = 1000;
+	u8 val;
+
+	while (retries--) {
+		rc = qpnp_pbs_read(pbs, pbs->base +
+					PBS_CLIENT_SCRATCH2, &val, 1);
+		if (rc < 0) {
+			pr_err("Failed to read register %x rc = %d\n",
+						PBS_CLIENT_SCRATCH2, rc);
+			return rc;
+		}
+
+		if (val == 0xFF) {
+			/* PBS error - clear SCRATCH2 register */
+			rc = qpnp_pbs_write(pbs, pbs->base +
+					PBS_CLIENT_SCRATCH2, 0, 1);
+			if (rc < 0) {
+				pr_err("Failed to clear register %x rc=%d\n",
+						PBS_CLIENT_SCRATCH2, rc);
+				return rc;
+			}
+
+			pr_err("NACK from PBS for bit %d\n", bit_pos);
+			return -EINVAL;
+		}
+
+		if (val & BIT(bit_pos)) {
+			pr_debug("PBS sequence for bit %d executed!\n",
+						 bit_pos);
+			break;
+		}
+
+		usleep_range(dly, dly + 100);
+	}
+
+	if (!retries) {
+		pr_err("Timeout for PBS ACK/NACK for bit %d\n", bit_pos);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+/**
+ * qpnp_pbs_trigger_event - Trigger the PBS RAM sequence
+ *
+ * Returns = 0 If the PBS RAM sequence executed successfully.
+ *
+ * Returns < 0 for errors.
+ *
+ * This function is used to trigger the PBS RAM sequence to be
+ * executed by the client driver.
+ *
+ * The PBS trigger sequence involves
+ * 1. setting the PBS sequence bit in PBS_CLIENT_SCRATCH1
+ * 2. Initiating the SW PBS trigger
+ * 3. Checking the equivalent bit in PBS_CLIENT_SCRATCH2 for the
+ *    completion of the sequence.
+ * 4. If PBS_CLIENT_SCRATCH2 == 0xFF, the PBS sequence failed to execute
+ */
+int qpnp_pbs_trigger_event(struct device_node *dev_node, u8 bitmap)
+{
+	struct qpnp_pbs *pbs;
+	int rc = 0;
+	u16 bit_pos = 0;
+	u8 val, mask  = 0;
+
+	if (!dev_node)
+		return -EINVAL;
+
+	if (!bitmap) {
+		pr_err("Invalid bitmap passed by client\n");
+		return -EINVAL;
+	}
+
+	pbs = get_pbs_client_node(dev_node);
+	if (IS_ERR_OR_NULL(pbs)) {
+		pr_err("Unable to find the PBS dev_node\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&pbs->pbs_lock);
+	rc = qpnp_pbs_read(pbs, pbs->base + PBS_CLIENT_SCRATCH2, &val, 1);
+	if (rc < 0) {
+		pr_err("read register %x failed rc = %d\n",
+					PBS_CLIENT_SCRATCH2, rc);
+		goto out;
+	}
+
+	if (val == 0xFF) {
+		/* PBS error - clear SCRATCH2 register */
+		rc = qpnp_pbs_write(pbs, pbs->base + PBS_CLIENT_SCRATCH2, 0, 1);
+		if (rc < 0) {
+			pr_err("Failed to clear register %x rc=%d\n",
+						PBS_CLIENT_SCRATCH2, rc);
+			goto out;
+		}
+	}
+
+	for (bit_pos = 0; bit_pos < 8; bit_pos++) {
+		if (bitmap & BIT(bit_pos)) {
+			/*
+			 * Clear the PBS sequence bit position in
+			 * PBS_CLIENT_SCRATCH2 mask register.
+			 */
+			rc = qpnp_pbs_masked_write(pbs, pbs->base +
+					 PBS_CLIENT_SCRATCH2, BIT(bit_pos), 0);
+			if (rc < 0) {
+				pr_err("Failed to clear %x reg bit rc=%d\n",
+						PBS_CLIENT_SCRATCH2, rc);
+				goto error;
+			}
+
+			/*
+			 * Set the PBS sequence bit position in
+			 * PBS_CLIENT_SCRATCH1 register.
+			 */
+			val = mask = BIT(bit_pos);
+			rc = qpnp_pbs_masked_write(pbs, pbs->base +
+						PBS_CLIENT_SCRATCH1, mask, val);
+			if (rc < 0) {
+				pr_err("Failed to set %x reg bit rc=%d\n",
+						PBS_CLIENT_SCRATCH1, rc);
+				goto error;
+			}
+
+			/* Initiate the SW trigger */
+			val = mask = PBS_CLIENT_SW_TRIG_BIT;
+			rc = qpnp_pbs_masked_write(pbs, pbs->base +
+						PBS_CLIENT_TRIG_CTL, mask, val);
+			if (rc < 0) {
+				pr_err("Failed to write register %x rc=%d\n",
+						PBS_CLIENT_TRIG_CTL, rc);
+				goto error;
+			}
+
+			rc = qpnp_pbs_wait_for_ack(pbs, bit_pos);
+			if (rc < 0) {
+				pr_err("Error during wait_for_ack\n");
+				goto error;
+			}
+
+			/*
+			 * Clear the PBS sequence bit position in
+			 * PBS_CLIENT_SCRATCH1 register.
+			 */
+			rc = qpnp_pbs_masked_write(pbs, pbs->base +
+					PBS_CLIENT_SCRATCH1, BIT(bit_pos), 0);
+			if (rc < 0) {
+				pr_err("Failed to clear %x reg bit rc=%d\n",
+						PBS_CLIENT_SCRATCH1, rc);
+				goto error;
+			}
+
+			/*
+			 * Clear the PBS sequence bit position in
+			 * PBS_CLIENT_SCRATCH2 mask register.
+			 */
+			rc = qpnp_pbs_masked_write(pbs, pbs->base +
+					PBS_CLIENT_SCRATCH2, BIT(bit_pos), 0);
+			if (rc < 0) {
+				pr_err("Failed to clear %x reg bit rc=%d\n",
+						PBS_CLIENT_SCRATCH2, rc);
+				goto error;
+			}
+
+		}
+	}
+
+error:
+	/* Clear all the requested bitmap */
+	rc = qpnp_pbs_masked_write(pbs, pbs->base + PBS_CLIENT_SCRATCH1,
+						bitmap, 0);
+	if (rc < 0)
+		pr_err("Failed to clear %x reg bit rc=%d\n",
+					PBS_CLIENT_SCRATCH1, rc);
+out:
+	mutex_unlock(&pbs->pbs_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_pbs_trigger_event);
+
+static int qpnp_pbs_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	u32 val = 0;
+	struct qpnp_pbs *pbs;
+
+	pbs = devm_kzalloc(&pdev->dev, sizeof(*pbs), GFP_KERNEL);
+	if (!pbs)
+		return -ENOMEM;
+
+	pbs->pdev = pdev;
+	pbs->dev = &pdev->dev;
+	pbs->dev_node = pdev->dev.of_node;
+	pbs->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!pbs->regmap) {
+		dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node, "reg", &val);
+	if (rc < 0) {
+		dev_err(&pdev->dev,
+			"Couldn't find reg in node = %s rc = %d\n",
+			pdev->dev.of_node->full_name, rc);
+		return rc;
+	}
+
+	pbs->base = val;
+	mutex_init(&pbs->pbs_lock);
+
+	dev_set_drvdata(&pdev->dev, pbs);
+
+	mutex_lock(&pbs_list_lock);
+	list_add(&pbs->link, &pbs_dev_list);
+	mutex_unlock(&pbs_list_lock);
+
+	return 0;
+}
+
+static const struct of_device_id qpnp_pbs_match_table[] = {
+	{ .compatible = QPNP_PBS_DEV_NAME },
+	{}
+};
+
+static struct platform_driver qpnp_pbs_driver = {
+	.driver	= {
+		.name		= QPNP_PBS_DEV_NAME,
+		.owner		= THIS_MODULE,
+		.of_match_table	= qpnp_pbs_match_table,
+	},
+	.probe	= qpnp_pbs_probe,
+};
+
+static int __init qpnp_pbs_init(void)
+{
+	return platform_driver_register(&qpnp_pbs_driver);
+}
+arch_initcall(qpnp_pbs_init);
+
+static void __exit qpnp_pbs_exit(void)
+{
+	return platform_driver_unregister(&qpnp_pbs_driver);
+}
+module_exit(qpnp_pbs_exit);
+
+MODULE_DESCRIPTION("QPNP PBS DRIVER");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" QPNP_PBS_DEV_NAME);
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 996ce64..aeecf29 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -454,7 +454,7 @@
  * @n: The array of count of elements in each batch, 0 terminated.
  *
  * Write a request to the mailbox controller without caching. If the request
- * state is ACTIVE_ONLY, then the requests are treated as completion requests
+ * state is ACTIVE or AWAKE, then the requests are treated as completion request
  * and sent to the controller immediately. The function waits until all the
  * commands are complete. If the request was to SLEEP or WAKE_ONLY, then the
  * request is sent as fire-n-forget and no ack is expected.
@@ -468,7 +468,8 @@
 	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
 	atomic_t wait_count = ATOMIC_INIT(0); /* overwritten */
 	int count = 0;
-	int ret, i = 0;
+	int ret, i, j, k;
+	bool complete_set;
 
 	if (rpmh_standalone)
 		return 0;
@@ -479,6 +480,27 @@
 	if (count >= RPMH_MAX_REQ_IN_BATCH)
 		return -EINVAL;
 
+	if (state == RPMH_ACTIVE_ONLY_STATE || state == RPMH_AWAKE_STATE) {
+		/*
+		 * Ensure the 'complete' bit is set for atleast one command in
+		 * each set for active/awake requests.
+		 */
+		for (i = 0, k = 0; i < count; i++, k += n[i]) {
+			complete_set = false;
+			for (j = 0; j < n[i]; j++) {
+				if (cmd[k + j].complete) {
+					complete_set = true;
+					break;
+				}
+			}
+			if (!complete_set) {
+				dev_err(rc->dev, "No completion set for batch");
+				return -EINVAL;
+			}
+		}
+	}
+
+	/* Create async request batches */
 	for (i = 0; i < count; i++) {
 		rpm_msg[i] = __get_rpmh_msg_async(rc, state, cmd, n[i], false);
 		if (IS_ERR_OR_NULL(rpm_msg[i]))
@@ -488,11 +510,11 @@
 		cmd += n[i];
 	}
 
-	if (state == RPMH_ACTIVE_ONLY_STATE) {
+	/* Send if Active or Awake and wait for the whole set to complete */
+	if (state == RPMH_ACTIVE_ONLY_STATE || state == RPMH_AWAKE_STATE) {
 		might_sleep();
 		atomic_set(&wait_count, count);
 		for (i = 0; i < count; i++) {
-			rpm_msg[i]->msg.is_complete = true;
 			/* Bypass caching and write to mailbox directly */
 			ret = mbox_send_message(rc->chan, &rpm_msg[i]->msg);
 			if (ret < 0)
@@ -501,6 +523,7 @@
 		return wait_event_interruptible(waitq,
 					atomic_read(&wait_count) == 0);
 	} else {
+		/* Send Sleep requests to the controller, expect no response */
 		for (i = 0; i < count; i++) {
 			ret = mbox_send_controller_data(rc->chan,
 						&rpm_msg[i]->msg);
diff --git a/drivers/soc/qcom/secure_buffer.c b/drivers/soc/qcom/secure_buffer.c
index b2627f2..f1e7347 100644
--- a/drivers/soc/qcom/secure_buffer.c
+++ b/drivers/soc/qcom/secure_buffer.c
@@ -365,28 +365,19 @@
 			int source_nelems, int *dest_vmids,
 			int *dest_perms, int dest_nelems)
 {
-	struct sg_table *table;
+	struct sg_table table;
 	int ret;
 
-	table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
-	if (!table)
-		return -ENOMEM;
-	ret = sg_alloc_table(table, 1, GFP_KERNEL);
+	ret = sg_alloc_table(&table, 1, GFP_KERNEL);
 	if (ret)
-		goto err1;
+		return ret;
 
-	sg_set_page(table->sgl, phys_to_page(addr), size, 0);
+	sg_set_page(table.sgl, phys_to_page(addr), size, 0);
 
-	ret = hyp_assign_table(table, source_vm_list, source_nelems, dest_vmids,
-						dest_perms, dest_nelems);
-	if (ret)
-		goto err2;
+	ret = hyp_assign_table(&table, source_vm_list, source_nelems,
+			       dest_vmids, dest_perms, dest_nelems);
 
-	return ret;
-err2:
-	sg_free_table(table);
-err1:
-	kfree(table);
+	sg_free_table(&table);
 	return ret;
 }
 
diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c
index 8e9ad9b..b40d678 100644
--- a/drivers/soc/qcom/service-locator.c
+++ b/drivers/soc/qcom/service-locator.c
@@ -378,6 +378,7 @@
 	if (!pqw) {
 		rc = -ENOMEM;
 		pr_err("Allocation failed\n");
+		kfree(pqcd);
 		goto err;
 	}
 	pqw->notifier = locator_nb;
diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c
index 758f627..034ddd3 100644
--- a/drivers/soc/qcom/wcd-dsp-glink.c
+++ b/drivers/soc/qcom/wcd-dsp-glink.c
@@ -25,8 +25,10 @@
 #include "sound/wcd-dsp-glink.h"
 
 #define WDSP_GLINK_DRIVER_NAME "wcd-dsp-glink"
-#define WDSP_MAX_WRITE_SIZE (512 * 1024)
+#define WDSP_MAX_WRITE_SIZE (256 * 1024)
 #define WDSP_MAX_READ_SIZE (4 * 1024)
+#define WDSP_MAX_NO_OF_INTENTS (20)
+#define WDSP_MAX_NO_OF_CHANNELS (10)
 
 #define MINOR_NUMBER_COUNT 1
 #define WDSP_EDGE "wdsp"
@@ -532,15 +534,30 @@
 	payload = (u8 *)pkt->payload;
 	no_of_channels = pkt->no_of_channels;
 
+	if (no_of_channels > WDSP_MAX_NO_OF_CHANNELS) {
+		dev_info(wpriv->dev, "%s: no_of_channels = %d are limited to %d\n",
+			 __func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS);
+		no_of_channels = WDSP_MAX_NO_OF_CHANNELS;
+	}
 	ch = kcalloc(no_of_channels, sizeof(struct wdsp_glink_ch *),
 		     GFP_KERNEL);
 	if (!ch) {
 		ret = -ENOMEM;
 		goto done;
 	}
+	wpriv->ch = ch;
+	wpriv->no_of_channels = no_of_channels;
 
 	for (i = 0; i < no_of_channels; i++) {
 		ch_cfg = (struct wdsp_glink_ch_cfg *)payload;
+
+		if (ch_cfg->no_of_intents > WDSP_MAX_NO_OF_INTENTS) {
+			dev_err(wpriv->dev, "%s: Invalid no_of_intents = %d\n",
+				__func__, ch_cfg->no_of_intents);
+			ret = -EINVAL;
+			goto err_ch_mem;
+		}
+
 		ch_cfg_size = sizeof(struct wdsp_glink_ch_cfg) +
 					(sizeof(u32) * ch_cfg->no_of_intents);
 		ch_size = sizeof(struct wdsp_glink_ch) +
@@ -564,8 +581,6 @@
 		INIT_WORK(&ch[i]->lcl_ch_cls_wrk, wdsp_glink_lcl_ch_cls_wrk);
 		init_waitqueue_head(&ch[i]->ch_connect_wait);
 	}
-	wpriv->ch = ch;
-	wpriv->no_of_channels = no_of_channels;
 
 	INIT_WORK(&wpriv->ch_open_cls_wrk, wdsp_glink_ch_open_cls_wrk);
 
@@ -746,15 +761,17 @@
 		goto done;
 	}
 
-	dev_dbg(wpriv->dev, "%s: count = %zd\n", __func__, count);
-
-	if (count > WDSP_MAX_WRITE_SIZE) {
-		dev_info(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_WRITE_SIZE\n",
+	if ((count < sizeof(struct wdsp_write_pkt)) ||
+	    (count > WDSP_MAX_WRITE_SIZE)) {
+		dev_err(wpriv->dev, "%s: Invalid count = %zd\n",
 			__func__, count);
-		count = WDSP_MAX_WRITE_SIZE;
+		ret = -EINVAL;
+		goto done;
 	}
 
-	tx_buf_size = count + sizeof(struct wdsp_glink_tx_buf);
+	dev_dbg(wpriv->dev, "%s: count = %zd\n", __func__, count);
+
+	tx_buf_size = WDSP_MAX_WRITE_SIZE + sizeof(struct wdsp_glink_tx_buf);
 	tx_buf = kzalloc(tx_buf_size, GFP_KERNEL);
 	if (!tx_buf) {
 		ret = -ENOMEM;
@@ -772,6 +789,13 @@
 	wpkt = (struct wdsp_write_pkt *)tx_buf->buf;
 	switch (wpkt->pkt_type) {
 	case WDSP_REG_PKT:
+		if (count <= (sizeof(struct wdsp_write_pkt) +
+			      sizeof(struct wdsp_reg_pkt))) {
+			dev_err(wpriv->dev, "%s: Invalid reg pkt size = %zd\n",
+				__func__, count);
+			ret = -EINVAL;
+			goto free_buf;
+		}
 		ret = wdsp_glink_ch_info_init(wpriv,
 					(struct wdsp_reg_pkt *)wpkt->payload);
 		if (ret < 0)
@@ -794,6 +818,13 @@
 		kfree(tx_buf);
 		break;
 	case WDSP_CMD_PKT:
+		if (count <= (sizeof(struct wdsp_write_pkt) +
+			      sizeof(struct wdsp_cmd_pkt))) {
+			dev_err(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n",
+				__func__, count);
+			ret = -EINVAL;
+			goto free_buf;
+		}
 		mutex_lock(&wpriv->glink_mutex);
 		if (wpriv->glink_state.link_state == GLINK_LINK_STATE_DOWN) {
 			mutex_unlock(&wpriv->glink_mutex);
diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c
index ea886c7..7e33e8b 100644
--- a/drivers/soundwire/swr-wcd-ctrl.c
+++ b/drivers/soundwire/swr-wcd-ctrl.c
@@ -64,6 +64,8 @@
 	{6, 10, 7800},		/* UC15: 2*(Spkr + SB + VI) */
 	{2, 3, 3600},		/* UC16: Spkr + VI */
 	{4, 6, 7200},		/* UC17: 2*(Spkr + VI) */
+	{3, 7, 4200},		/* UC18: Spkr + Comp + VI */
+	{6, 14, 8400},		/* UC19: 2*(Spkr + Comp + VI) */
 };
 #define MAX_USECASE	ARRAY_SIZE(uc)
 
@@ -178,6 +180,21 @@
 		{7, 6, 0},
 		{15, 10, 0},
 	},
+	/* UC 18 */
+	{
+		{7, 1, 0},
+		{31, 2, 0},
+		{15, 7, 0},
+	},
+	/* UC 19 */
+	{
+		{7, 1, 0},
+		{31, 2, 0},
+		{15, 7, 0},
+		{7, 6, 0},
+		{31, 18, 0},
+		{15, 10, 0},
+	},
 };
 
 enum {
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 4c86197..403c799 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -119,30 +119,30 @@
 	int div = 0;
 	int idx;
 	struct se_geni_rsc *rsc = &mas->spi_rsc;
-	int ret = 0;
 	u32 clk_sel = geni_read_reg(mas->base, SE_GENI_CLK_SEL);
 	u32 m_clk_cfg = geni_read_reg(mas->base, GENI_SER_M_CLK_CFG);
+	int ret;
 
 	clk_sel &= ~CLK_SEL_MSK;
 	m_clk_cfg &= ~CLK_DIV_MSK;
 
 	idx = get_sclk(speed_hz, &sclk_freq);
-	if (idx < 0) {
-		ret = -EINVAL;
-		goto spi_clk_cfg_exit;
-	}
-	div = (sclk_freq / (SPI_OVERSAMPLING / speed_hz));
+	if (idx < 0)
+		return -EINVAL;
+
+	div = ((sclk_freq / SPI_OVERSAMPLING) / speed_hz);
+	if (!div)
+		return -EINVAL;
 
 	clk_sel |= (idx & CLK_SEL_MSK);
 	m_clk_cfg |= ((div << CLK_DIV_SHFT) | SER_CLK_EN);
 	ret = clk_set_rate(rsc->se_clk, sclk_freq);
 	if (ret)
-		goto spi_clk_cfg_exit;
+		return ret;
 
 	geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL);
 	geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG);
-spi_clk_cfg_exit:
-	return ret;
+	return 0;
 }
 
 static void spi_setup_word_len(struct spi_geni_master *mas, u32 mode,
@@ -195,7 +195,8 @@
 
 	ret = do_spi_clk_cfg(mas->cur_speed_hz, mas);
 	if (ret) {
-		dev_err(&spi_mas->dev, "Err setting clks ret %d\n", ret);
+		dev_err(&spi_mas->dev, "Err setting clks ret(%d) for %d\n",
+							ret, mas->cur_speed_hz);
 		goto prepare_message_exit;
 	}
 	spi_setup_word_len(mas, spi_slv->mode, spi_slv->bits_per_word);
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 2fda339..2db473a 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -118,6 +118,16 @@
 	help
 	  Enable this to let the user space manage the platform thermals.
 
+config THERMAL_GOV_LOW_LIMITS
+	bool "Low limits mitigation governor"
+	help
+	  Enable this to manage platform limits using low limits
+	  governor.
+
+	  Enable this governor to monitor and trigger floor mitigation.
+	  This governor will monitor the limits going below a
+	  trip threshold to trigger a floor mitigation.
+
 config THERMAL_GOV_POWER_ALLOCATOR
 	bool "Power allocator thermal governor"
 	help
@@ -454,6 +464,16 @@
 	  the sensor. Also able to set threshold temperature for both hot and cold
 	  and update when a threshold is reached.
 
+config THERMAL_TSENS
+	tristate "Qualcomm Technologies Inc. TSENS Temperature driver"
+	depends on THERMAL
+	help
+	  This enables the thermal sysfs driver for the TSENS device. It shows
+	  up in Sysfs as a thermal zone with multiple trip points. Also able
+	  to set threshold temperature for both warm and cool and update
+	  thermal userspace client when a threshold is reached. Warm/Cool
+	  temperature thresholds can be set independently for each sensor.
+
 menu "Qualcomm thermal drivers"
 depends on (ARCH_QCOM && OF) || COMPILE_TEST
 source "drivers/thermal/qcom/Kconfig"
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index d9489a7..2faed7f 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -14,6 +14,7 @@
 thermal_sys-$(CONFIG_THERMAL_GOV_BANG_BANG)	+= gov_bang_bang.o
 thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE)	+= step_wise.o
 thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE)	+= user_space.o
+thermal_sys-$(CONFIG_THERMAL_GOV_LOW_LIMITS) += gov_low_limits.o
 thermal_sys-$(CONFIG_THERMAL_GOV_POWER_ALLOCATOR)	+= power_allocator.o
 
 # cpufreq cooling
@@ -57,3 +58,4 @@
 obj-$(CONFIG_MTK_THERMAL)	+= mtk_thermal.o
 obj-$(CONFIG_GENERIC_ADC_THERMAL)	+= thermal-generic-adc.o
 obj-$(CONFIG_THERMAL_QPNP_ADC_TM)	+= qpnp-adc-tm.o
+obj-$(CONFIG_THERMAL_TSENS)	+= msm-tsens.o tsens2xxx.o tsens-dbg.o
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 9ce0e9e..a6245d5 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -30,6 +30,8 @@
 #include <linux/slab.h>
 #include <linux/cpu.h>
 #include <linux/cpu_cooling.h>
+#include <linux/sched.h>
+#include <linux/of_device.h>
 
 #include <trace/events/thermal.h>
 
@@ -45,6 +47,7 @@
  *	level 0 --> 1st Max Freq
  *	level 1 --> 2nd Max Freq
  *	...
+ *	leven n --> core isolated
  */
 
 /**
@@ -70,8 +73,12 @@
  *	cooling	devices.
  * @clipped_freq: integer value representing the absolute value of the clipped
  *	frequency.
- * @max_level: maximum cooling level. One less than total number of valid
- *	cpufreq frequencies.
+ * @cpufreq_floor_state: integer value representing the frequency floor state
+ *	of cpufreq cooling devices.
+ * @floor_freq: integer value representing the absolute value of the floor
+ *	frequency.
+ * @max_level: maximum cooling level. [0..max_level-1: <freq>
+ *	max_level: Core unavailable]
  * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device.
  * @node: list_head to link all cpufreq_cooling_device together.
  * @last_load: load measured by the latest call to cpufreq_get_requested_power()
@@ -92,6 +99,8 @@
 	struct thermal_cooling_device *cool_dev;
 	unsigned int cpufreq_state;
 	unsigned int clipped_freq;
+	unsigned int cpufreq_floor_state;
+	unsigned int floor_freq;
 	unsigned int max_level;
 	unsigned int *freq_table;	/* In descending order */
 	struct cpumask allowed_cpus;
@@ -103,6 +112,7 @@
 	int dyn_power_table_entries;
 	struct device *cpu_dev;
 	get_static_t plat_get_static_power;
+	struct cpu_cooling_ops *plat_ops;
 };
 static DEFINE_IDR(cpufreq_idr);
 static DEFINE_MUTEX(cooling_cpufreq_lock);
@@ -162,7 +172,7 @@
 {
 	unsigned long level;
 
-	for (level = 0; level <= cpufreq_dev->max_level; level++) {
+	for (level = 0; level < cpufreq_dev->max_level; level++) {
 		if (freq == cpufreq_dev->freq_table[level])
 			return level;
 
@@ -218,7 +228,7 @@
 				    unsigned long event, void *data)
 {
 	struct cpufreq_policy *policy = data;
-	unsigned long clipped_freq;
+	unsigned long clipped_freq, floor_freq;
 	struct cpufreq_cooling_device *cpufreq_dev;
 
 	if (event != CPUFREQ_ADJUST)
@@ -239,11 +249,16 @@
 		 *
 		 * But, if clipped_freq is greater than policy->max, we don't
 		 * need to do anything.
+		 *
+		 * Similarly, if policy minimum set by the user is less than
+		 * the floor_frequency, then adjust the policy->min.
 		 */
 		clipped_freq = cpufreq_dev->clipped_freq;
+		floor_freq = cpufreq_dev->floor_freq;
 
-		if (policy->max > clipped_freq)
-			cpufreq_verify_within_limits(policy, 0, clipped_freq);
+		if (policy->max > clipped_freq || policy->min < floor_freq)
+			cpufreq_verify_within_limits(policy, floor_freq,
+						     clipped_freq);
 		break;
 	}
 	mutex_unlock(&cooling_list_lock);
@@ -491,6 +506,58 @@
 }
 
 /**
+ * cpufreq_get_min_state - callback function to get the device floor state.
+ * @cdev: thermal cooling device pointer.
+ * @state: fill this variable with the cooling device floor.
+ *
+ * Callback for the thermal cooling device to return the cpufreq
+ * floor state.
+ *
+ * Return: 0 on success, an error code otherwise.
+ */
+static int cpufreq_get_min_state(struct thermal_cooling_device *cdev,
+				 unsigned long *state)
+{
+	struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
+
+	*state = cpufreq_device->cpufreq_floor_state;
+
+	return 0;
+}
+
+/**
+ * cpufreq_set_min_state - callback function to set the device floor state.
+ * @cdev: thermal cooling device pointer.
+ * @state: set this variable to the current cooling state.
+ *
+ * Callback for the thermal cooling device to change the cpufreq
+ * floor state.
+ *
+ * Return: 0 on success, an error code otherwise.
+ */
+static int cpufreq_set_min_state(struct thermal_cooling_device *cdev,
+				 unsigned long state)
+{
+	struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
+	unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus);
+	unsigned int floor_freq;
+
+	if (state > cpufreq_device->max_level)
+		state = cpufreq_device->max_level;
+
+	if (cpufreq_device->cpufreq_floor_state == state)
+		return 0;
+
+	floor_freq = cpufreq_device->freq_table[state];
+	cpufreq_device->cpufreq_floor_state = state;
+	cpufreq_device->floor_freq = floor_freq;
+
+	cpufreq_update_policy(cpu);
+
+	return 0;
+}
+
+/**
  * cpufreq_get_cur_state - callback function to get the current cooling state.
  * @cdev: thermal cooling device pointer.
  * @state: fill this variable with the current cooling state.
@@ -535,11 +602,27 @@
 	if (cpufreq_device->cpufreq_state == state)
 		return 0;
 
+	/* If state is the last, isolate the CPU */
+	if (state == cpufreq_device->max_level)
+		return sched_isolate_cpu(cpu);
+	else if (state < cpufreq_device->max_level)
+		sched_unisolate_cpu(cpu);
+
 	clip_freq = cpufreq_device->freq_table[state];
 	cpufreq_device->cpufreq_state = state;
 	cpufreq_device->clipped_freq = clip_freq;
 
-	cpufreq_update_policy(cpu);
+	/* Check if the device has a platform mitigation function that
+	 * can handle the CPU freq mitigation, if not, notify cpufreq
+	 * framework.
+	 */
+	if (cpufreq_device->plat_ops) {
+		if (cpufreq_device->plat_ops->ceil_limit)
+			cpufreq_device->plat_ops->ceil_limit(cpu,
+						clip_freq);
+	} else {
+		cpufreq_update_policy(cpu);
+	}
 
 	return 0;
 }
@@ -745,6 +828,8 @@
 	.get_max_state = cpufreq_get_max_state,
 	.get_cur_state = cpufreq_get_cur_state,
 	.set_cur_state = cpufreq_set_cur_state,
+	.set_min_state = cpufreq_set_min_state,
+	.get_min_state = cpufreq_get_min_state,
 };
 
 static struct thermal_cooling_device_ops cpufreq_power_cooling_ops = {
@@ -783,6 +868,9 @@
  * @capacitance: dynamic power coefficient for these cpus
  * @plat_static_func: function to calculate the static power consumed by these
  *                    cpus (optional)
+ * @plat_mitig_func: function that does the mitigation by changing the
+ *                   frequencies (Optional). By default, cpufreq framweork will
+ *                   be notified of the new limits.
  *
  * This interface function registers the cpufreq cooling device with the name
  * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
@@ -795,7 +883,8 @@
 static struct thermal_cooling_device *
 __cpufreq_cooling_register(struct device_node *np,
 			const struct cpumask *clip_cpus, u32 capacitance,
-			get_static_t plat_static_func)
+			get_static_t plat_static_func,
+			struct cpu_cooling_ops *plat_ops)
 {
 	struct cpufreq_policy *policy;
 	struct thermal_cooling_device *cool_dev;
@@ -848,7 +937,9 @@
 	cpufreq_for_each_valid_entry(pos, table)
 		cpufreq_dev->max_level++;
 
-	cpufreq_dev->freq_table = kmalloc(sizeof(*cpufreq_dev->freq_table) *
+	/* Last level will indicate the core will be isolated. */
+	cpufreq_dev->max_level++;
+	cpufreq_dev->freq_table = kzalloc(sizeof(*cpufreq_dev->freq_table) *
 					  cpufreq_dev->max_level, GFP_KERNEL);
 	if (!cpufreq_dev->freq_table) {
 		cool_dev = ERR_PTR(-ENOMEM);
@@ -874,6 +965,8 @@
 		cooling_ops = &cpufreq_cooling_ops;
 	}
 
+	cpufreq_dev->plat_ops = plat_ops;
+
 	ret = get_idr(&cpufreq_idr, &cpufreq_dev->id);
 	if (ret) {
 		cool_dev = ERR_PTR(ret);
@@ -881,7 +974,7 @@
 	}
 
 	/* Fill freq-table in descending order of frequencies */
-	for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) {
+	for (i = 0, freq = -1; i < cpufreq_dev->max_level; i++) {
 		freq = find_next_max(table, freq);
 		cpufreq_dev->freq_table[i] = freq;
 
@@ -901,6 +994,9 @@
 		goto remove_idr;
 
 	cpufreq_dev->clipped_freq = cpufreq_dev->freq_table[0];
+	cpufreq_dev->floor_freq =
+		cpufreq_dev->freq_table[cpufreq_dev->max_level];
+	cpufreq_dev->cpufreq_floor_state = cpufreq_dev->max_level;
 	cpufreq_dev->cool_dev = cool_dev;
 
 	mutex_lock(&cooling_cpufreq_lock);
@@ -949,7 +1045,7 @@
 struct thermal_cooling_device *
 cpufreq_cooling_register(const struct cpumask *clip_cpus)
 {
-	return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL);
+	return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL, NULL);
 }
 EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
 
@@ -973,7 +1069,7 @@
 	if (!np)
 		return ERR_PTR(-EINVAL);
 
-	return __cpufreq_cooling_register(np, clip_cpus, 0, NULL);
+	return __cpufreq_cooling_register(np, clip_cpus, 0, NULL, NULL);
 }
 EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);
 
@@ -1003,11 +1099,34 @@
 			       get_static_t plat_static_func)
 {
 	return __cpufreq_cooling_register(NULL, clip_cpus, capacitance,
-				plat_static_func);
+				plat_static_func, NULL);
 }
 EXPORT_SYMBOL(cpufreq_power_cooling_register);
 
 /**
+ * cpufreq_platform_cooling_register() - create cpufreq cooling device with
+ * additional platform specific mitigation function.
+ *
+ * @clip_cpus: cpumask of cpus where the frequency constraints will happen
+ * @plat_ops: the platform mitigation functions that will be called insted of
+ * cpufreq, if provided.
+ *
+ * Return: a valid struct thermal_cooling_device pointer on success,
+ * on failure, it returns a corresponding ERR_PTR().
+ */
+struct thermal_cooling_device *
+cpufreq_platform_cooling_register(const struct cpumask *clip_cpus,
+				struct cpu_cooling_ops *plat_ops)
+{
+	struct device_node *cpu_node;
+
+	cpu_node = of_cpu_device_node_get(cpumask_first(clip_cpus));
+	return __cpufreq_cooling_register(cpu_node, clip_cpus, 0, NULL,
+						plat_ops);
+}
+EXPORT_SYMBOL(cpufreq_platform_cooling_register);
+
+/**
  * of_cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions
  * @np:	a valid struct device_node to the cooling device device tree node
  * @clip_cpus:	cpumask of cpus where the frequency constraints will happen
@@ -1040,7 +1159,7 @@
 		return ERR_PTR(-EINVAL);
 
 	return __cpufreq_cooling_register(np, clip_cpus, capacitance,
-				plat_static_func);
+				plat_static_func, NULL);
 }
 EXPORT_SYMBOL(of_cpufreq_power_cooling_register);
 
diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c
index 81631b1..b2990c1 100644
--- a/drivers/thermal/devfreq_cooling.c
+++ b/drivers/thermal/devfreq_cooling.c
@@ -51,6 +51,7 @@
 	struct thermal_cooling_device *cdev;
 	struct devfreq *devfreq;
 	unsigned long cooling_state;
+	unsigned long cooling_min_state;
 	u32 *power_table;
 	u32 *freq_table;
 	size_t freq_table_size;
@@ -96,13 +97,15 @@
 /**
  * partition_enable_opps() - disable all opps above a given state
  * @dfc:	Pointer to devfreq we are operating on
- * @cdev_state:	cooling device state we're setting
+ * @cdev_max_state: Max cooling device state we're setting
+ * @cdev_min_state: Min cooling device state we're setting
  *
  * Go through the OPPs of the device, enabling all OPPs until
  * @cdev_state and disabling those frequencies above it.
  */
 static int partition_enable_opps(struct devfreq_cooling_device *dfc,
-				 unsigned long cdev_state)
+				 unsigned long cdev_max_state,
+				 unsigned long cdev_min_state)
 {
 	int i;
 	struct device *dev = dfc->devfreq->dev.parent;
@@ -111,7 +114,8 @@
 		struct dev_pm_opp *opp;
 		int ret = 0;
 		unsigned int freq = dfc->freq_table[i];
-		bool want_enable = i >= cdev_state ? true : false;
+		bool want_enable = (i >= cdev_max_state) &&
+				      (i <= cdev_min_state) ? true : false;
 
 		rcu_read_lock();
 		opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable);
@@ -144,6 +148,41 @@
 	return 0;
 }
 
+static int devfreq_cooling_get_min_state(struct thermal_cooling_device *cdev,
+					 unsigned long *state)
+{
+	struct devfreq_cooling_device *dfc = cdev->devdata;
+
+	*state = dfc->cooling_min_state;
+
+	return 0;
+}
+
+static int devfreq_cooling_set_min_state(struct thermal_cooling_device *cdev,
+					 unsigned long state)
+{
+	struct devfreq_cooling_device *dfc = cdev->devdata;
+	struct devfreq *df = dfc->devfreq;
+	struct device *dev = df->dev.parent;
+	int ret;
+
+	if (state == dfc->cooling_min_state)
+		return 0;
+
+	dev_dbg(dev, "Setting cooling min state %lu\n", state);
+
+	if (state >= dfc->freq_table_size)
+		state = dfc->freq_table_size - 1;
+
+	ret = partition_enable_opps(dfc, dfc->cooling_state, state);
+	if (ret)
+		return ret;
+
+	dfc->cooling_min_state = state;
+
+	return 0;
+}
+
 static int devfreq_cooling_get_cur_state(struct thermal_cooling_device *cdev,
 					 unsigned long *state)
 {
@@ -170,7 +209,7 @@
 	if (state >= dfc->freq_table_size)
 		return -EINVAL;
 
-	ret = partition_enable_opps(dfc, state);
+	ret = partition_enable_opps(dfc, state, dfc->cooling_min_state);
 	if (ret)
 		return ret;
 
@@ -361,6 +400,8 @@
 	.get_max_state = devfreq_cooling_get_max_state,
 	.get_cur_state = devfreq_cooling_get_cur_state,
 	.set_cur_state = devfreq_cooling_set_cur_state,
+	.get_min_state = devfreq_cooling_get_min_state,
+	.set_min_state = devfreq_cooling_set_min_state,
 };
 
 /**
@@ -499,6 +540,7 @@
 	if (err)
 		goto free_tables;
 
+	dfc->cooling_min_state = dfc->freq_table_size - 1;
 	snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id);
 
 	cdev = thermal_of_cooling_device_register(np, dev_name, dfc,
diff --git a/drivers/thermal/gov_low_limits.c b/drivers/thermal/gov_low_limits.c
new file mode 100644
index 0000000..cf2dbc4
--- /dev/null
+++ b/drivers/thermal/gov_low_limits.c
@@ -0,0 +1,130 @@
+/*
+ *  Copyright (C) 2012 Intel Corp
+ *  Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
+ *  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 as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  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/thermal.h>
+#include <trace/events/thermal.h>
+
+#include "thermal_core.h"
+
+static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
+{
+	int trip_temp, trip_hyst;
+	enum thermal_trip_type trip_type;
+	struct thermal_instance *instance;
+	bool throttle;
+	int old_target;
+
+	tz->ops->get_trip_temp(tz, trip, &trip_temp);
+	tz->ops->get_trip_type(tz, trip, &trip_type);
+	if (tz->ops->get_trip_hyst) {
+		tz->ops->get_trip_hyst(tz, trip, &trip_hyst);
+		trip_hyst = trip_temp + trip_hyst;
+	} else {
+		trip_hyst = trip_temp;
+	}
+
+	mutex_lock(&tz->lock);
+
+	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
+		if (instance->trip != trip)
+			continue;
+
+		if ((tz->temperature <= trip_temp) ||
+			(instance->target != THERMAL_NO_TARGET
+				&& tz->temperature <= trip_hyst))
+			throttle = true;
+		else
+			throttle = false;
+
+		dev_dbg(&tz->device,
+			"Trip%d[type=%d,temp=%d,hyst=%d],throttle=%d\n",
+			trip, trip_type, trip_temp, trip_hyst, throttle);
+
+		old_target = instance->target;
+		instance->target = (throttle) ? instance->upper
+					: THERMAL_NO_TARGET;
+		dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n",
+					old_target, (int)instance->target);
+
+		if (old_target == instance->target)
+			continue;
+
+		if (old_target == THERMAL_NO_TARGET &&
+				instance->target != THERMAL_NO_TARGET) {
+			trace_thermal_zone_trip(tz, trip, trip_type);
+			tz->passive += 1;
+		} else if (old_target != THERMAL_NO_TARGET &&
+				instance->target == THERMAL_NO_TARGET) {
+			tz->passive -= 1;
+		}
+
+		instance->cdev->updated = false; /* cdev needs update */
+	}
+
+	mutex_unlock(&tz->lock);
+}
+
+/**
+ * low_limits_throttle - throttles devices associated with the given zone
+ * @tz - thermal_zone_device
+ * @trip - the trip point
+ *
+ * Throttling Logic: If the sensor reading goes below a trip point, the
+ * pre-defined mitigation will be applied for the cooling device.
+ * If the sensor reading goes above the trip hysteresis, the
+ * mitigation will be removed.
+ */
+static int low_limits_throttle(struct thermal_zone_device *tz, int trip)
+{
+	struct thermal_instance *instance;
+
+	thermal_zone_trip_update(tz, trip);
+
+	mutex_lock(&tz->lock);
+
+	list_for_each_entry(instance, &tz->thermal_instances, tz_node)
+		thermal_cdev_update(instance->cdev);
+
+	mutex_unlock(&tz->lock);
+
+	return 0;
+}
+
+static struct thermal_governor thermal_gov_low_limits_floor = {
+	.name		= "low_limits_floor",
+	.throttle	= low_limits_throttle,
+	.min_state_throttle = 1,
+};
+
+static struct thermal_governor thermal_gov_low_limits_cap = {
+	.name		= "low_limits_cap",
+	.throttle	= low_limits_throttle,
+};
+
+int thermal_gov_low_limits_register(void)
+{
+	thermal_register_governor(&thermal_gov_low_limits_cap);
+	return thermal_register_governor(&thermal_gov_low_limits_floor);
+}
+
+void thermal_gov_low_limits_unregister(void)
+{
+	thermal_unregister_governor(&thermal_gov_low_limits_cap);
+	thermal_unregister_governor(&thermal_gov_low_limits_floor);
+}
diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c
new file mode 100644
index 0000000..5b4bb7a
--- /dev/null
+++ b/drivers/thermal/msm-tsens.c
@@ -0,0 +1,288 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the term_tm 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/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/thermal.h>
+#include "tsens.h"
+
+LIST_HEAD(tsens_device_list);
+
+static int tsens_get_temp(struct tsens_sensor *s, int *temp)
+{
+	struct tsens_device *tmdev = s->tmdev;
+
+	return tmdev->ops->get_temp(s, temp);
+}
+
+static int tsens_set_trip_temp(struct tsens_sensor *s, int trip, int temp)
+{
+	struct tsens_device *tmdev = s->tmdev;
+
+	if (tmdev->ops->set_trip_temp)
+		return tmdev->ops->set_trip_temp(s, trip, temp);
+
+	return 0;
+}
+
+static int tsens_init(struct tsens_device *tmdev)
+{
+	if (tmdev->ops->hw_init)
+		return tmdev->ops->hw_init(tmdev);
+
+	return 0;
+}
+
+static int tsens_register_interrupts(struct tsens_device *tmdev)
+{
+	if (tmdev->ops->interrupts_reg)
+		return tmdev->ops->interrupts_reg(tmdev);
+
+	return 0;
+}
+
+static const struct of_device_id tsens_table[] = {
+	{	.compatible = "qcom,msm8996-tsens",
+		.data = &data_tsens2xxx,
+	},
+	{	.compatible = "qcom,msm8953-tsens",
+		.data = &data_tsens2xxx,
+	},
+	{	.compatible = "qcom,msm8998-tsens",
+		.data = &data_tsens2xxx,
+	},
+	{	.compatible = "qcom,msmhamster-tsens",
+		.data = &data_tsens2xxx,
+	},
+	{	.compatible = "qcom,sdm660-tsens",
+		.data = &data_tsens23xx,
+	},
+	{	.compatible = "qcom,sdm630-tsens",
+		.data = &data_tsens23xx,
+	},
+	{	.compatible = "qcom,sdm845-tsens",
+		.data = &data_tsens24xx,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, tsens_table);
+
+static struct thermal_zone_of_device_ops tsens_tm_thermal_zone_ops = {
+	.get_temp = tsens_get_temp,
+	.set_trip_temp = tsens_set_trip_temp,
+};
+
+static int get_device_tree_data(struct platform_device *pdev,
+				struct tsens_device *tmdev)
+{
+	struct device_node *of_node = pdev->dev.of_node;
+	u32 *hw_id, *client_id;
+	u32 rc = 0, i, tsens_num_sensors = 0;
+	int tsens_len;
+	const struct of_device_id *id;
+	const struct tsens_data *data;
+	struct resource *res_tsens_mem, *res_mem = NULL;
+
+	if (!of_match_node(tsens_table, of_node)) {
+		pr_err("Need to read SoC specific fuse map\n");
+		return -ENODEV;
+	}
+
+	id = of_match_node(tsens_table, of_node);
+	if (id == NULL) {
+		pr_err("can not find tsens_table of_node\n");
+		return -ENODEV;
+	}
+
+	data = id->data;
+	hw_id = devm_kzalloc(&pdev->dev,
+		tsens_num_sensors * sizeof(u32), GFP_KERNEL);
+	if (!hw_id)
+		return -ENOMEM;
+
+	client_id = devm_kzalloc(&pdev->dev,
+		tsens_num_sensors * sizeof(u32), GFP_KERNEL);
+	if (!client_id)
+		return -ENOMEM;
+
+	tmdev->ops = data->ops;
+	tmdev->ctrl_data = data;
+	tmdev->pdev = pdev;
+
+	if (!tmdev->ops || !tmdev->ops->hw_init || !tmdev->ops->get_temp) {
+		pr_err("Invalid ops\n");
+		return -EINVAL;
+	}
+
+	/* TSENS register region */
+	res_tsens_mem = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "tsens_physical");
+	if (!res_tsens_mem) {
+		pr_err("Could not get tsens physical address resource\n");
+		return -EINVAL;
+	}
+
+	tsens_len = res_tsens_mem->end - res_tsens_mem->start + 1;
+
+	res_mem = request_mem_region(res_tsens_mem->start,
+				tsens_len, res_tsens_mem->name);
+	if (!res_mem) {
+		pr_err("Request tsens physical memory region failed\n");
+		return -EINVAL;
+	}
+
+	tmdev->tsens_addr = ioremap(res_mem->start, tsens_len);
+	if (!tmdev->tsens_addr) {
+		pr_err("Failed to IO map TSENS registers.\n");
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32_array(of_node,
+		"qcom,sensor-id", hw_id, tsens_num_sensors);
+	if (rc) {
+		pr_err("Default sensor id mapping\n");
+		for (i = 0; i < tsens_num_sensors; i++)
+			tmdev->sensor[i].hw_id = i;
+	} else {
+		pr_err("Use specified sensor id mapping\n");
+		for (i = 0; i < tsens_num_sensors; i++)
+			tmdev->sensor[i].hw_id = hw_id[i];
+	}
+
+	rc = of_property_read_u32_array(of_node,
+		"qcom,client-id", client_id, tsens_num_sensors);
+	if (rc) {
+		for (i = 0; i < tsens_num_sensors; i++)
+			tmdev->sensor[i].id = i;
+		pr_debug("Default client id mapping\n");
+	} else {
+		for (i = 0; i < tsens_num_sensors; i++)
+			tmdev->sensor[i].id = client_id[i];
+		pr_debug("Use specified client id mapping\n");
+	}
+
+	return 0;
+}
+
+static int tsens_thermal_zone_register(struct tsens_device *tmdev)
+{
+	int rc = 0, i = 0;
+
+	for (i = 0; i < tmdev->num_sensors; i++) {
+		tmdev->sensor[i].tmdev = tmdev;
+		tmdev->sensor[i].tzd = devm_thermal_zone_of_sensor_register(
+					&tmdev->pdev->dev, i, &tmdev->sensor[i],
+					&tsens_tm_thermal_zone_ops);
+		if (IS_ERR(tmdev->sensor[i].tzd)) {
+			pr_err("Error registering sensor:%d\n", i);
+			continue;
+		}
+	}
+
+	return rc;
+}
+
+static int tsens_tm_remove(struct platform_device *pdev)
+{
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+int tsens_tm_probe(struct platform_device *pdev)
+{
+	struct device_node *of_node = pdev->dev.of_node;
+	struct tsens_device *tmdev = NULL;
+	u32 tsens_num_sensors = 0;
+	int rc;
+
+	if (!(pdev->dev.of_node))
+		return -ENODEV;
+
+	rc = of_property_read_u32(of_node,
+			"qcom,sensors", &tsens_num_sensors);
+	if (rc || (!tsens_num_sensors)) {
+		dev_err(&pdev->dev, "missing sensors\n");
+		return -ENODEV;
+	}
+
+	tmdev = devm_kzalloc(&pdev->dev,
+			sizeof(struct tsens_device) +
+			tsens_num_sensors *
+			sizeof(struct tsens_sensor),
+			GFP_KERNEL);
+	if (tmdev == NULL) {
+		pr_err("%s: kzalloc() failed.\n", __func__);
+		return -ENOMEM;
+	}
+
+	tmdev->num_sensors = tsens_num_sensors;
+
+	rc = get_device_tree_data(pdev, tmdev);
+	if (rc) {
+		pr_err("Error reading TSENS DT\n");
+		return rc;
+	}
+
+	rc = tsens_init(tmdev);
+	if (rc)
+		return rc;
+
+	rc = tsens_thermal_zone_register(tmdev);
+	if (rc) {
+		pr_err("Error registering the thermal zone\n");
+		return rc;
+	}
+
+	rc = tsens_register_interrupts(tmdev);
+	if (rc < 0) {
+		pr_err("TSENS interrupt register failed:%d\n", rc);
+		return rc;
+	}
+
+	list_add_tail(&tmdev->list, &tsens_device_list);
+	platform_set_drvdata(pdev, tmdev);
+
+	return rc;
+}
+
+static struct platform_driver tsens_tm_driver = {
+	.probe = tsens_tm_probe,
+	.remove = tsens_tm_remove,
+	.driver = {
+		.name = "msm-tsens",
+		.owner = THIS_MODULE,
+		.of_match_table = tsens_table,
+	},
+};
+
+int __init tsens_tm_init_driver(void)
+{
+	return platform_driver_register(&tsens_tm_driver);
+}
+subsys_initcall(tsens_tm_init_driver);
+
+static void __exit tsens_tm_deinit(void)
+{
+	platform_driver_unregister(&tsens_tm_driver);
+}
+module_exit(tsens_tm_deinit);
+
+MODULE_ALIAS("platform:" TSENS_DRIVER_NAME);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index d04ec3b..b337ad7 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -31,11 +31,16 @@
 #include <linux/export.h>
 #include <linux/string.h>
 #include <linux/thermal.h>
+#include <linux/list.h>
 
 #include "thermal_core.h"
 
-/***   Private data structures to represent thermal device tree data ***/
+#define for_each_tz_sibling(pos, head)                                         \
+	for (pos = list_first_entry((head), struct __thermal_zone, list);\
+		&(pos->list) != (head);                                  \
+		pos = list_next_entry(pos, list))                        \
 
+/***   Private data structures to represent thermal device tree data ***/
 /**
  * struct __thermal_bind_param - a match between trip and cooling device
  * @cooling_device: a pointer to identify the referred cooling device
@@ -54,18 +59,36 @@
 };
 
 /**
+ * struct __sensor_param - Holds individual sensor data
+ * @sensor_data: sensor driver private data passed as input argument
+ * @ops: sensor driver ops
+ * @trip_high: last trip high value programmed in the sensor driver
+ * @trip_low: last trip low value programmed in the sensor driver
+ * @lock: mutex lock acquired before updating the trip temperatures
+ * @first_tz: list head pointing the first thermal zone
+ */
+struct __sensor_param {
+	void *sensor_data;
+	const struct thermal_zone_of_device_ops *ops;
+	int trip_high, trip_low;
+	struct mutex lock;
+	struct list_head first_tz;
+};
+
+/**
  * struct __thermal_zone - internal representation of a thermal zone
  * @mode: current thermal zone device mode (enabled/disabled)
  * @passive_delay: polling interval while passive cooling is activated
  * @polling_delay: zone polling interval
  * @slope: slope of the temperature adjustment curve
  * @offset: offset of the temperature adjustment curve
+ * @tzd: thermal zone device pointer for this sensor
  * @ntrips: number of trip points
  * @trips: an array of trip points (0..ntrips - 1)
  * @num_tbps: number of thermal bind params
  * @tbps: an array of thermal bind params (0..num_tbps - 1)
- * @sensor_data: sensor private data used while reading temperature and trend
- * @ops: set of callbacks to handle the thermal zone based on DT
+ * @list: sibling thermal zone pointer
+ * @senps: sensor related parameters
  */
 
 struct __thermal_zone {
@@ -74,6 +97,7 @@
 	int polling_delay;
 	int slope;
 	int offset;
+	struct thermal_zone_device *tzd;
 
 	/* trip data */
 	int ntrips;
@@ -83,11 +107,14 @@
 	int num_tbps;
 	struct __thermal_bind_params *tbps;
 
+	struct list_head list;
 	/* sensor interface */
-	void *sensor_data;
-	const struct thermal_zone_of_device_ops *ops;
+	struct __sensor_param *senps;
 };
 
+static int of_thermal_aggregate_trip_types(struct thermal_zone_device *tz,
+		unsigned int trip_type_mask, int *low, int *high);
+
 /***   DT thermal zone device callbacks   ***/
 
 static int of_thermal_get_temp(struct thermal_zone_device *tz,
@@ -95,21 +122,36 @@
 {
 	struct __thermal_zone *data = tz->devdata;
 
-	if (!data->ops->get_temp)
+	if (!data->senps || !data->senps->ops->get_temp)
 		return -EINVAL;
 
-	return data->ops->get_temp(data->sensor_data, temp);
+	return data->senps->ops->get_temp(data->senps->sensor_data, temp);
 }
 
 static int of_thermal_set_trips(struct thermal_zone_device *tz,
-				int low, int high)
+				int inp_low, int inp_high)
 {
 	struct __thermal_zone *data = tz->devdata;
+	int high = INT_MAX, low = INT_MIN, ret = 0;
 
-	if (!data->ops || !data->ops->set_trips)
+	if (!data->senps || !data->senps->ops->set_trips)
 		return -EINVAL;
 
-	return data->ops->set_trips(data->sensor_data, low, high);
+	mutex_lock(&data->senps->lock);
+	of_thermal_aggregate_trip_types(tz, GENMASK(THERMAL_TRIP_CRITICAL, 0),
+					&low, &high);
+	if (low == data->senps->trip_low
+		&& high == data->senps->trip_high)
+		goto set_trips_exit;
+
+	data->senps->trip_low = low;
+	data->senps->trip_high = high;
+	ret = data->senps->ops->set_trips(data->senps->sensor_data,
+					  low, high);
+
+set_trips_exit:
+	mutex_unlock(&data->senps->lock);
+	return ret;
 }
 
 /**
@@ -192,7 +234,10 @@
 {
 	struct __thermal_zone *data = tz->devdata;
 
-	return data->ops->set_emul_temp(data->sensor_data, temp);
+	if (!data->senps || !data->senps->ops->set_emul_temp)
+		return -EINVAL;
+
+	return data->senps->ops->set_emul_temp(data->senps->sensor_data, temp);
 }
 
 static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
@@ -200,10 +245,11 @@
 {
 	struct __thermal_zone *data = tz->devdata;
 
-	if (!data->ops->get_trend)
+	if (!data->senps || !data->senps->ops->get_trend)
 		return -EINVAL;
 
-	return data->ops->get_trend(data->sensor_data, trip, trend);
+	return data->senps->ops->get_trend(data->senps->sensor_data,
+					   trip, trend);
 }
 
 static int of_thermal_bind(struct thermal_zone_device *thermal,
@@ -325,10 +371,11 @@
 	if (trip >= data->ntrips || trip < 0)
 		return -EDOM;
 
-	if (data->ops->set_trip_temp) {
+	if (data->senps && data->senps->ops->set_trip_temp) {
 		int ret;
 
-		ret = data->ops->set_trip_temp(data->sensor_data, trip, temp);
+		ret = data->senps->ops->set_trip_temp(data->senps->sensor_data,
+						      trip, temp);
 		if (ret)
 			return ret;
 	}
@@ -381,6 +428,89 @@
 	return -EINVAL;
 }
 
+static int of_thermal_aggregate_trip_types(struct thermal_zone_device *tz,
+		unsigned int trip_type_mask, int *low, int *high)
+{
+	int min = INT_MIN;
+	int max = INT_MAX;
+	int tt, th, trip;
+	int temp = tz->temperature;
+	struct thermal_zone_device *zone = NULL;
+	struct __thermal_zone *data = tz->devdata;
+	struct list_head *head;
+	enum thermal_trip_type type = 0;
+
+	head = &data->senps->first_tz;
+	for_each_tz_sibling(data, head) {
+		zone = data->tzd;
+		for (trip = 0; trip < data->ntrips; trip++) {
+			of_thermal_get_trip_type(zone, trip, &type);
+			if (!(BIT(type) & trip_type_mask))
+				continue;
+
+			if (!zone->tzp->tracks_low) {
+				tt = data->trips[trip].temperature;
+				if (tt > temp && tt < max)
+					max = tt;
+				th = tt - data->trips[trip].hysteresis;
+				if (th < temp && th > min)
+					min = th;
+			} else {
+				tt = data->trips[trip].temperature;
+				if (tt < temp && tt > min)
+					min = tt;
+				th = tt + data->trips[trip].hysteresis;
+				if (th > temp && th < max)
+					max = th;
+			}
+		}
+	}
+
+	*high = max;
+	*low = min;
+
+	return 0;
+}
+
+/*
+ * of_thermal_aggregate_trip - aggregate trip temperatures across sibling
+ *				thermal zones.
+ * @tz: pointer to the primary thermal zone.
+ * @type: the thermal trip type to be aggregated upon
+ * @low: the low trip threshold which the most lesser than the @temp
+ * @high: the high trip threshold which is the least greater than the @temp
+ */
+int of_thermal_aggregate_trip(struct thermal_zone_device *tz,
+				enum thermal_trip_type type,
+				int *low, int *high)
+{
+	if (type <= THERMAL_TRIP_CRITICAL)
+		return of_thermal_aggregate_trip_types(tz, BIT(type), low,
+						       high);
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(of_thermal_aggregate_trip);
+
+/*
+ * of_thermal_handle_trip - Handle thermal trip from sensors
+ *
+ * @tz: pointer to the primary thermal zone.
+ */
+void of_thermal_handle_trip(struct thermal_zone_device *tz)
+{
+	struct thermal_zone_device *zone;
+	struct __thermal_zone *data = tz->devdata;
+	struct list_head *head;
+
+	head = &data->senps->first_tz;
+	for_each_tz_sibling(data, head) {
+		zone = data->tzd;
+		thermal_zone_device_update(zone, THERMAL_EVENT_UNSPECIFIED);
+	}
+}
+EXPORT_SYMBOL(of_thermal_handle_trip);
+
 static struct thermal_zone_device_ops of_thermal_ops = {
 	.get_mode = of_thermal_get_mode,
 	.set_mode = of_thermal_set_mode,
@@ -400,8 +530,8 @@
 
 static struct thermal_zone_device *
 thermal_zone_of_add_sensor(struct device_node *zone,
-			   struct device_node *sensor, void *data,
-			   const struct thermal_zone_of_device_ops *ops)
+			   struct device_node *sensor,
+			   struct __sensor_param *sens_param)
 {
 	struct thermal_zone_device *tzd;
 	struct __thermal_zone *tz;
@@ -412,12 +542,11 @@
 
 	tz = tzd->devdata;
 
-	if (!ops)
+	if (!sens_param->ops)
 		return ERR_PTR(-EINVAL);
 
 	mutex_lock(&tzd->lock);
-	tz->ops = ops;
-	tz->sensor_data = data;
+	tz->senps = sens_param;
 
 	tzd->ops->get_temp = of_thermal_get_temp;
 	tzd->ops->get_trend = of_thermal_get_trend;
@@ -426,12 +555,13 @@
 	 * The thermal zone core will calculate the window if they have set the
 	 * optional set_trips pointer.
 	 */
-	if (ops->set_trips)
+	if (sens_param->ops->set_trips)
 		tzd->ops->set_trips = of_thermal_set_trips;
 
-	if (ops->set_emul_temp)
+	if (sens_param->ops->set_emul_temp)
 		tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
 
+	list_add_tail(&tz->list, &sens_param->first_tz);
 	mutex_unlock(&tzd->lock);
 
 	return tzd;
@@ -462,11 +592,10 @@
  * 01 - This function must enqueue the new sensor instead of using
  * it as the only source of temperature values.
  *
- * 02 - There must be a way to match the sensor with all thermal zones
- * that refer to it.
- *
  * Return: On success returns a valid struct thermal_zone_device,
- * otherwise, it returns a corresponding ERR_PTR(). Caller must
+ * otherwise, it returns a corresponding ERR_PTR(). Incase there are multiple
+ * thermal zones referencing the same sensor, the return value will be
+ * thermal_zone_device pointer of the first thermal zone. Caller must
  * check the return value with help of IS_ERR() helper.
  */
 struct thermal_zone_device *
@@ -475,6 +604,8 @@
 {
 	struct device_node *np, *child, *sensor_np;
 	struct thermal_zone_device *tzd = ERR_PTR(-ENODEV);
+	struct thermal_zone_device *first_tzd = NULL;
+	struct __sensor_param *sens_param = NULL;
 
 	np = of_find_node_by_name(NULL, "thermal-zones");
 	if (!np)
@@ -485,6 +616,17 @@
 		return ERR_PTR(-EINVAL);
 	}
 
+	sens_param = kzalloc(sizeof(*sens_param), GFP_KERNEL);
+	if (!sens_param) {
+		of_node_put(np);
+		return ERR_PTR(-ENOMEM);
+	}
+	sens_param->sensor_data = data;
+	sens_param->ops = ops;
+	INIT_LIST_HEAD(&sens_param->first_tz);
+	sens_param->trip_high = INT_MAX;
+	sens_param->trip_low = INT_MIN;
+	mutex_init(&sens_param->lock);
 	sensor_np = of_node_get(dev->of_node);
 
 	for_each_available_child_of_node(np, child) {
@@ -509,21 +651,23 @@
 
 		if (sensor_specs.np == sensor_np && id == sensor_id) {
 			tzd = thermal_zone_of_add_sensor(child, sensor_np,
-							 data, ops);
-			if (!IS_ERR(tzd))
+							 sens_param);
+			if (!IS_ERR(tzd)) {
+				if (!first_tzd)
+					first_tzd = tzd;
 				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
-
-			of_node_put(sensor_specs.np);
-			of_node_put(child);
-			goto exit;
+			}
 		}
 		of_node_put(sensor_specs.np);
 	}
-exit:
 	of_node_put(sensor_np);
 	of_node_put(np);
 
-	return tzd;
+	if (!first_tzd) {
+		first_tzd = ERR_PTR(-ENODEV);
+		kfree(sens_param);
+	}
+	return first_tzd;
 }
 EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_register);
 
@@ -546,6 +690,8 @@
 				       struct thermal_zone_device *tzd)
 {
 	struct __thermal_zone *tz;
+	struct thermal_zone_device *pos;
+	struct list_head *head;
 
 	if (!dev || !tzd || !tzd->devdata)
 		return;
@@ -556,14 +702,20 @@
 	if (!tz)
 		return;
 
-	mutex_lock(&tzd->lock);
-	tzd->ops->get_temp = NULL;
-	tzd->ops->get_trend = NULL;
-	tzd->ops->set_emul_temp = NULL;
+	head = &tz->senps->first_tz;
+	for_each_tz_sibling(tz, head) {
+		pos = tz->tzd;
+		mutex_lock(&pos->lock);
+		pos->ops->get_temp = NULL;
+		pos->ops->get_trend = NULL;
+		pos->ops->set_emul_temp = NULL;
 
-	tz->ops = NULL;
-	tz->sensor_data = NULL;
-	mutex_unlock(&tzd->lock);
+		list_del(&tz->list);
+		if (list_empty(&tz->senps->first_tz))
+			kfree(tz->senps);
+		tz->senps = NULL;
+		mutex_unlock(&pos->lock);
+	}
 }
 EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister);
 
@@ -832,6 +984,7 @@
 	if (!tz)
 		return ERR_PTR(-ENOMEM);
 
+	INIT_LIST_HEAD(&tz->list);
 	ret = of_property_read_u32(np, "polling-delay-passive", &prop);
 	if (ret < 0) {
 		pr_err("missing polling-delay-passive property\n");
@@ -975,6 +1128,7 @@
 		struct thermal_zone_params *tzp;
 		int i, mask = 0;
 		u32 prop;
+		const char *governor_name;
 
 		tz = thermal_of_build_thermal_zone(child);
 		if (IS_ERR(tz)) {
@@ -997,6 +1151,11 @@
 		/* No hwmon because there might be hwmon drivers registering */
 		tzp->no_hwmon = true;
 
+		if (!of_property_read_string(child, "thermal-governor",
+						&governor_name))
+			strlcpy(tzp->governor_name, governor_name,
+					THERMAL_NAME_LENGTH);
+
 		if (!of_property_read_u32(child, "sustainable-power", &prop))
 			tzp->sustainable_power = prop;
 
@@ -1007,6 +1166,9 @@
 		tzp->slope = tz->slope;
 		tzp->offset = tz->offset;
 
+		if (of_property_read_bool(child, "tracks-low"))
+			tzp->tracks_low = true;
+
 		zone = thermal_zone_device_register(child->name, tz->ntrips,
 						    mask, tz,
 						    ops, tzp,
@@ -1019,7 +1181,9 @@
 			kfree(ops);
 			of_thermal_free_zone(tz);
 			/* attempting to build remaining zones still */
+			continue;
 		}
+		tz->tzd = zone;
 	}
 	of_node_put(np);
 
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
index bcef2e7..4fa7f82 100644
--- a/drivers/thermal/step_wise.c
+++ b/drivers/thermal/step_wise.c
@@ -37,7 +37,7 @@
  *       for this trip point
  *    d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit
  *       for this trip point
- * If the temperature is lower than a trip point,
+ * If the temperature is lower than a hysteresis temperature,
  *    a. if the trend is THERMAL_TREND_RAISING, do nothing
  *    b. if the trend is THERMAL_TREND_DROPPING, use lower cooling
  *       state for this trip point, if the cooling state already
@@ -126,7 +126,7 @@
 
 static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
 {
-	int trip_temp;
+	int trip_temp, hyst_temp;
 	enum thermal_trip_type trip_type;
 	enum thermal_trend trend;
 	struct thermal_instance *instance;
@@ -134,22 +134,24 @@
 	int old_target;
 
 	if (trip == THERMAL_TRIPS_NONE) {
-		trip_temp = tz->forced_passive;
+		hyst_temp = trip_temp = tz->forced_passive;
 		trip_type = THERMAL_TRIPS_NONE;
 	} else {
 		tz->ops->get_trip_temp(tz, trip, &trip_temp);
+		if (tz->ops->get_trip_hyst) {
+			tz->ops->get_trip_hyst(tz, trip, &hyst_temp);
+			hyst_temp = trip_temp - hyst_temp;
+		} else {
+			hyst_temp = trip_temp;
+		}
 		tz->ops->get_trip_type(tz, trip, &trip_type);
 	}
 
 	trend = get_tz_trend(tz, trip);
 
-	if (tz->temperature >= trip_temp) {
-		throttle = true;
-		trace_thermal_zone_trip(tz, trip, trip_type);
-	}
-
-	dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n",
-				trip, trip_type, trip_temp, trend, throttle);
+	dev_dbg(&tz->device,
+		"Trip%d[type=%d,temp=%d,hyst=%d]:trend=%d,throttle=%d\n",
+		trip, trip_type, trip_temp, hyst_temp, trend, throttle);
 
 	mutex_lock(&tz->lock);
 
@@ -158,6 +160,22 @@
 			continue;
 
 		old_target = instance->target;
+		/*
+		 * Step wise has to lower the mitigation only if the
+		 * temperature goes below the hysteresis temperature.
+		 * Atleast, it has to hold on to mitigation device lower
+		 * limit if the temperature is above the hysteresis
+		 * temperature.
+		 */
+		if (tz->temperature >= trip_temp ||
+			(tz->temperature >= hyst_temp &&
+			 old_target != THERMAL_NO_TARGET)) {
+			throttle = true;
+			trace_thermal_zone_trip(tz, trip, trip_type);
+		} else {
+			throttle = false;
+		}
+
 		instance->target = get_target_state(instance, trend, throttle);
 		dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n",
 					old_target, (int)instance->target);
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 226b0b4ac..7b45b9a 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -49,6 +49,8 @@
 MODULE_DESCRIPTION("Generic thermal management sysfs support");
 MODULE_LICENSE("GPL v2");
 
+#define THERMAL_MAX_ACTIVE	16
+
 static DEFINE_IDR(thermal_tz_idr);
 static DEFINE_IDR(thermal_cdev_idr);
 static DEFINE_MUTEX(thermal_idr_lock);
@@ -64,6 +66,8 @@
 
 static struct thermal_governor *def_governor;
 
+static struct workqueue_struct *thermal_passive_wq;
+
 static struct thermal_governor *__find_governor(const char *name)
 {
 	struct thermal_governor *pos;
@@ -392,14 +396,15 @@
 	mutex_unlock(&thermal_list_lock);
 }
 
-static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
+static void thermal_zone_device_set_polling(struct workqueue_struct *queue,
+					    struct thermal_zone_device *tz,
 					    int delay)
 {
 	if (delay > 1000)
-		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
+		mod_delayed_work(queue, &tz->poll_queue,
 				 round_jiffies(msecs_to_jiffies(delay)));
 	else if (delay)
-		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
+		mod_delayed_work(queue, &tz->poll_queue,
 				 msecs_to_jiffies(delay));
 	else
 		cancel_delayed_work(&tz->poll_queue);
@@ -410,11 +415,13 @@
 	mutex_lock(&tz->lock);
 
 	if (tz->passive)
-		thermal_zone_device_set_polling(tz, tz->passive_delay);
+		thermal_zone_device_set_polling(thermal_passive_wq,
+						tz, tz->passive_delay);
 	else if (tz->polling_delay)
-		thermal_zone_device_set_polling(tz, tz->polling_delay);
+		thermal_zone_device_set_polling(system_freezable_wq,
+						tz, tz->polling_delay);
 	else
-		thermal_zone_device_set_polling(tz, 0);
+		thermal_zone_device_set_polling(NULL, tz, 0);
 
 	mutex_unlock(&tz->lock);
 }
@@ -450,7 +457,7 @@
 	}
 }
 
-static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
+void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
 {
 	enum thermal_trip_type type;
 
@@ -513,7 +520,6 @@
 		if (!ret && *temp < crit_temp)
 			*temp = tz->emul_temperature;
 	}
- 
 	mutex_unlock(&tz->lock);
 exit:
 	return ret;
@@ -1194,6 +1200,25 @@
 }
 
 static ssize_t
+thermal_cooling_device_min_state_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct thermal_cooling_device *cdev = to_cooling_device(dev);
+	unsigned long state;
+	int ret;
+
+	if (cdev->ops->get_min_state)
+		ret = cdev->ops->get_min_state(cdev, &state);
+	else
+		ret = -EPERM;
+
+	if (ret)
+		return ret;
+
+	return snprintf(buf, PAGE_SIZE, "%lu\n", state);
+}
+
+static ssize_t
 thermal_cooling_device_cur_state_show(struct device *dev,
 				      struct device_attribute *attr, char *buf)
 {
@@ -1213,8 +1238,7 @@
 				       const char *buf, size_t count)
 {
 	struct thermal_cooling_device *cdev = to_cooling_device(dev);
-	unsigned long state;
-	int result;
+	long state;
 
 	if (!sscanf(buf, "%ld\n", &state))
 		return -EINVAL;
@@ -1222,9 +1246,35 @@
 	if ((long)state < 0)
 		return -EINVAL;
 
-	result = cdev->ops->set_cur_state(cdev, state);
-	if (result)
-		return result;
+	cdev->sysfs_cur_state_req = state;
+
+	cdev->updated = false;
+	thermal_cdev_update(cdev);
+
+	return count;
+}
+
+static ssize_t
+thermal_cooling_device_min_state_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
+{
+	struct thermal_cooling_device *cdev = to_cooling_device(dev);
+	long state;
+	int ret = 0;
+
+	ret = sscanf(buf, "%ld\n", &state);
+	if (ret <= 0)
+		return (ret < 0) ? ret : -EINVAL;
+
+	if ((long)state < 0)
+		return -EINVAL;
+
+	cdev->sysfs_min_state_req = state;
+
+	cdev->updated = false;
+	thermal_cdev_update(cdev);
+
 	return count;
 }
 
@@ -1235,6 +1285,9 @@
 static DEVICE_ATTR(cur_state, 0644,
 		   thermal_cooling_device_cur_state_show,
 		   thermal_cooling_device_cur_state_store);
+static DEVICE_ATTR(min_state, 0644,
+		   thermal_cooling_device_min_state_show,
+		   thermal_cooling_device_min_state_store);
 
 static ssize_t
 thermal_cooling_device_trip_point_show(struct device *dev,
@@ -1255,6 +1308,7 @@
 	&dev_attr_cdev_type.attr,
 	&dev_attr_max_state.attr,
 	&dev_attr_cur_state.attr,
+	&dev_attr_min_state.attr,
 	NULL,
 };
 
@@ -1548,6 +1602,8 @@
 	cdev->device.class = &thermal_class;
 	cdev->device.groups = cooling_device_attr_groups;
 	cdev->devdata = devdata;
+	cdev->sysfs_cur_state_req = 0;
+	cdev->sysfs_min_state_req = ULONG_MAX;
 	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
 	result = device_register(&cdev->device);
 	if (result) {
@@ -1682,7 +1738,7 @@
 void thermal_cdev_update(struct thermal_cooling_device *cdev)
 {
 	struct thermal_instance *instance;
-	unsigned long target = 0;
+	unsigned long current_target = 0, min_target = ULONG_MAX;
 
 	mutex_lock(&cdev->lock);
 	/* cooling device is updated*/
@@ -1692,19 +1748,29 @@
 	}
 
 	/* Make sure cdev enters the deepest cooling state */
+	current_target = cdev->sysfs_cur_state_req;
+	min_target = cdev->sysfs_min_state_req;
 	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
 		dev_dbg(&cdev->device, "zone%d->target=%lu\n",
 				instance->tz->id, instance->target);
 		if (instance->target == THERMAL_NO_TARGET)
 			continue;
-		if (instance->target > target)
-			target = instance->target;
+		if (instance->tz->governor->min_state_throttle) {
+			if (instance->target < min_target)
+				min_target = instance->target;
+		} else {
+			if (instance->target > current_target)
+				current_target = instance->target;
+		}
 	}
-	cdev->ops->set_cur_state(cdev, target);
+	cdev->ops->set_cur_state(cdev, current_target);
+	if (cdev->ops->set_min_state)
+		cdev->ops->set_min_state(cdev, min_target);
 	cdev->updated = true;
 	mutex_unlock(&cdev->lock);
-	trace_cdev_update(cdev, target);
-	dev_dbg(&cdev->device, "set to state %lu\n", target);
+	trace_cdev_update(cdev, current_target);
+	dev_dbg(&cdev->device, "set to state %lu min state %lu\n",
+				current_target, min_target);
 }
 EXPORT_SYMBOL(thermal_cdev_update);
 
@@ -2069,7 +2135,7 @@
 
 	mutex_unlock(&thermal_list_lock);
 
-	thermal_zone_device_set_polling(tz, 0);
+	thermal_zone_device_set_polling(NULL, tz, 0);
 
 	if (tz->type[0])
 		device_remove_file(&tz->device, &dev_attr_type);
@@ -2172,6 +2238,8 @@
 	.n_mcgrps = ARRAY_SIZE(thermal_event_mcgrps),
 };
 
+static int allow_netlink_events;
+
 int thermal_generate_netlink_event(struct thermal_zone_device *tz,
 					enum events event)
 {
@@ -2186,6 +2254,9 @@
 	if (!tz)
 		return -EINVAL;
 
+	if (!allow_netlink_events)
+		return -ENODEV;
+
 	/* allocate memory */
 	size = nla_total_size(sizeof(struct thermal_genl_event)) +
 	       nla_total_size(0);
@@ -2237,7 +2308,13 @@
 
 static int genetlink_init(void)
 {
-	return genl_register_family(&thermal_event_genl_family);
+	int ret;
+
+	ret = genl_register_family(&thermal_event_genl_family);
+	if (!ret)
+		allow_netlink_events = true;
+
+	return ret;
 }
 
 static void genetlink_exit(void)
@@ -2247,6 +2324,8 @@
 #else /* !CONFIG_NET */
 static inline int genetlink_init(void) { return 0; }
 static inline void genetlink_exit(void) {}
+static inline int thermal_generate_netlink_event(struct thermal_zone_device *tz,
+		enum events event) { return -ENODEV; }
 #endif /* !CONFIG_NET */
 
 static int __init thermal_register_governors(void)
@@ -2269,6 +2348,10 @@
 	if (result)
 		return result;
 
+	result = thermal_gov_low_limits_register();
+	if (result)
+		return result;
+
 	return thermal_gov_power_allocator_register();
 }
 
@@ -2278,6 +2361,7 @@
 	thermal_gov_fair_share_unregister();
 	thermal_gov_bang_bang_unregister();
 	thermal_gov_user_space_unregister();
+	thermal_gov_low_limits_unregister();
 	thermal_gov_power_allocator_unregister();
 }
 
@@ -2316,21 +2400,26 @@
 {
 	int result;
 
+	thermal_passive_wq = alloc_workqueue("thermal_passive_wq",
+						WQ_HIGHPRI | WQ_UNBOUND
+						| WQ_FREEZABLE,
+						THERMAL_MAX_ACTIVE);
+	if (!thermal_passive_wq) {
+		result = -ENOMEM;
+		goto init_exit;
+	}
+
 	result = thermal_register_governors();
 	if (result)
-		goto error;
+		goto destroy_wq;
 
 	result = class_register(&thermal_class);
 	if (result)
 		goto unregister_governors;
 
-	result = genetlink_init();
-	if (result)
-		goto unregister_class;
-
 	result = of_parse_thermal_zones();
 	if (result)
-		goto exit_netlink;
+		goto exit_zone_parse;
 
 	result = register_pm_notifier(&thermal_pm_nb);
 	if (result)
@@ -2339,13 +2428,13 @@
 
 	return 0;
 
-exit_netlink:
-	genetlink_exit();
-unregister_class:
+exit_zone_parse:
 	class_unregister(&thermal_class);
 unregister_governors:
 	thermal_unregister_governors();
-error:
+destroy_wq:
+	destroy_workqueue(thermal_passive_wq);
+init_exit:
 	idr_destroy(&thermal_tz_idr);
 	idr_destroy(&thermal_cdev_idr);
 	mutex_destroy(&thermal_idr_lock);
@@ -2358,6 +2447,7 @@
 {
 	unregister_pm_notifier(&thermal_pm_nb);
 	of_thermal_destroy_zones();
+	destroy_workqueue(thermal_passive_wq);
 	genetlink_exit();
 	class_unregister(&thermal_class);
 	thermal_unregister_governors();
@@ -2368,5 +2458,19 @@
 	mutex_destroy(&thermal_governor_lock);
 }
 
-fs_initcall(thermal_init);
+static int __init thermal_netlink_init(void)
+{
+	int ret = 0;
+
+	ret = genetlink_init();
+	if (!ret)
+		goto exit_netlink;
+
+	thermal_exit();
+exit_netlink:
+	return ret;
+}
+
+subsys_initcall(thermal_init);
+fs_initcall(thermal_netlink_init);
 module_exit(thermal_exit);
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index 749d41a..eca8c3c 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -56,6 +56,7 @@
 
 int thermal_register_governor(struct thermal_governor *);
 void thermal_unregister_governor(struct thermal_governor *);
+void handle_thermal_trip(struct thermal_zone_device *tz, int trip);
 
 #ifdef CONFIG_THERMAL_GOV_STEP_WISE
 int thermal_gov_step_wise_register(void);
@@ -97,6 +98,14 @@
 static inline void thermal_gov_power_allocator_unregister(void) {}
 #endif /* CONFIG_THERMAL_GOV_POWER_ALLOCATOR */
 
+#ifdef CONFIG_THERMAL_GOV_LOW_LIMITS
+int thermal_gov_low_limits_register(void);
+void thermal_gov_low_limits_unregister(void);
+#else
+static inline int thermal_gov_low_limits_register(void) { return 0; }
+static inline void thermal_gov_low_limits_unregister(void) {}
+#endif /* CONFIG_THERMAL_GOV_LOW_LIMITS */
+
 /* device tree support */
 #ifdef CONFIG_THERMAL_OF
 int of_parse_thermal_zones(void);
@@ -105,6 +114,10 @@
 bool of_thermal_is_trip_valid(struct thermal_zone_device *, int);
 const struct thermal_trip *
 of_thermal_get_trip_points(struct thermal_zone_device *);
+int of_thermal_aggregate_trip(struct thermal_zone_device *tz,
+			      enum thermal_trip_type type,
+			      int *low, int *high);
+void of_thermal_handle_trip(struct thermal_zone_device *tz);
 #else
 static inline int of_parse_thermal_zones(void) { return 0; }
 static inline void of_thermal_destroy_zones(void) { }
@@ -122,6 +135,15 @@
 {
 	return NULL;
 }
+static inline int of_thermal_aggregate_trip(struct thermal_zone_device *tz,
+					    enum thermal_trip_type type,
+					    int *low, int *high)
+{
+	return -ENODEV;
+}
+static inline
+void of_thermal_handle_trip(struct thermal_zone_device *tz)
+{ }
 #endif
 
 #endif /* __THERMAL_CORE_H__ */
diff --git a/drivers/thermal/tsens-dbg.c b/drivers/thermal/tsens-dbg.c
new file mode 100644
index 0000000..d965a5c
--- /dev/null
+++ b/drivers/thermal/tsens-dbg.c
@@ -0,0 +1,104 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the term_tm 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 <asm/arch_timer.h>
+#include "tsens.h"
+
+/* debug defines */
+#define	TSENS_DBG_BUS_ID_0			0
+#define	TSENS_DBG_BUS_ID_1			1
+#define	TSENS_DBG_BUS_ID_2			2
+#define	TSENS_DBG_BUS_ID_15			15
+#define	TSENS_DEBUG_LOOP_COUNT_ID_0		2
+#define	TSENS_DEBUG_LOOP_COUNT			5
+#define	TSENS_DEBUG_STATUS_REG_START		10
+#define	TSENS_DEBUG_OFFSET_RANGE		16
+#define	TSENS_DEBUG_OFFSET_WORD1		0x4
+#define	TSENS_DEBUG_OFFSET_WORD2		0x8
+#define	TSENS_DEBUG_OFFSET_WORD3		0xc
+#define	TSENS_DEBUG_OFFSET_ROW			0x10
+#define	TSENS_DEBUG_DECIDEGC			-950
+#define	TSENS_DEBUG_CYCLE_MS			64
+#define	TSENS_DEBUG_POLL_MS			200
+#define	TSENS_DEBUG_BUS_ID2_MIN_CYCLE		50
+#define	TSENS_DEBUG_BUS_ID2_MAX_CYCLE		51
+#define	TSENS_DEBUG_ID_MASK_1_4			0xffffffe1
+#define	DEBUG_SIZE				10
+
+#define TSENS_DEBUG_CONTROL(n)			((n) + 0x1130)
+#define TSENS_DEBUG_DATA(n)			((n) + 0x1134)
+
+struct tsens_dbg_func {
+	int (*dbg_func)(struct tsens_device *, u32, u32, int *);
+};
+
+static int tsens_dbg_log_temp_reads(struct tsens_device *data, u32 id,
+					u32 dbg_type, int *temp)
+{
+	struct tsens_sensor *sensor;
+	struct tsens_device *tmdev = NULL;
+	u32 idx = 0;
+
+	if (!data)
+		return -EINVAL;
+
+	pr_debug("%d %d\n", id, dbg_type);
+	tmdev = data;
+	sensor = &tmdev->sensor[id];
+	idx = tmdev->tsens_dbg.sensor_dbg_info[sensor->hw_id].idx;
+	tmdev->tsens_dbg.sensor_dbg_info[sensor->hw_id].temp[idx%10] = *temp;
+	tmdev->tsens_dbg.sensor_dbg_info[sensor->hw_id].time_stmp[idx%10] =
+					sched_clock();
+	idx++;
+	tmdev->tsens_dbg.sensor_dbg_info[sensor->hw_id].idx = idx;
+
+	return 0;
+}
+
+static int tsens_dbg_log_interrupt_timestamp(struct tsens_device *data,
+						u32 id, u32 dbg_type, int *val)
+{
+	struct tsens_device *tmdev = NULL;
+	u32 idx = 0;
+
+	if (!data)
+		return -EINVAL;
+
+	pr_debug("%d %d\n", id, dbg_type);
+	tmdev = data;
+	/* debug */
+	idx = tmdev->tsens_dbg.tsens_thread_iq_dbg.idx;
+	tmdev->tsens_dbg.tsens_thread_iq_dbg.dbg_count[idx%10]++;
+	tmdev->tsens_dbg.tsens_thread_iq_dbg.time_stmp[idx%10] =
+							sched_clock();
+	tmdev->tsens_dbg.tsens_thread_iq_dbg.idx++;
+
+	return 0;
+}
+
+static struct tsens_dbg_func dbg_arr[] = {
+	[TSENS_DBG_LOG_TEMP_READS] = {tsens_dbg_log_temp_reads},
+	[TSENS_DBG_LOG_INTERRUPT_TIMESTAMP] = {
+			tsens_dbg_log_interrupt_timestamp},
+};
+
+int tsens2xxx_dbg(struct tsens_device *data, u32 id, u32 dbg_type, int *val)
+{
+	if (dbg_type >= TSENS_DBG_LOG_MAX)
+		return -EINVAL;
+
+	dbg_arr[dbg_type].dbg_func(data, id, dbg_type, val);
+
+	return 0;
+}
+EXPORT_SYMBOL(tsens2xxx_dbg);
diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h
new file mode 100644
index 0000000..45d244e
--- /dev/null
+++ b/drivers/thermal/tsens.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __QCOM_TSENS_H__
+#define __QCOM_TSENS_H__
+
+#include <linux/kernel.h>
+#include <linux/thermal.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#define DEBUG_SIZE				10
+#define TSENS_MAX_SENSORS			16
+#define TSENS_CONTROLLER_ID(n)			((n) + 0x1000)
+#define TSENS_CTRL_ADDR(n)			(n)
+#define TSENS_TM_SN_STATUS(n)			((n) + 0x10a0)
+
+enum tsens_dbg_type {
+	TSENS_DBG_POLL,
+	TSENS_DBG_LOG_TEMP_READS,
+	TSENS_DBG_LOG_INTERRUPT_TIMESTAMP,
+	TSENS_DBG_LOG_MAX
+};
+
+#define tsens_sec_to_msec_value		1000
+
+struct tsens_device;
+
+#if defined(CONFIG_THERMAL_TSENS)
+int tsens2xxx_dbg(struct tsens_device *data, u32 id, u32 dbg_type, int *temp);
+#else
+static inline int tsens2xxx_dbg(struct tsens_device *data, u32 id,
+						u32 dbg_type, int *temp)
+{ return -ENXIO; }
+#endif
+
+struct tsens_dbg {
+	u32				dbg_count[DEBUG_SIZE];
+	u32				idx;
+	unsigned long long		time_stmp[DEBUG_SIZE];
+	unsigned long			temp[DEBUG_SIZE];
+};
+
+struct tsens_dbg_context {
+	struct tsens_device		*tmdev;
+	struct tsens_dbg		tsens_thread_iq_dbg;
+	struct tsens_dbg		sensor_dbg_info[TSENS_MAX_SENSORS];
+	int				tsens_critical_wd_cnt;
+	struct delayed_work		tsens_critical_poll_test;
+};
+
+struct tsens_context {
+	enum thermal_device_mode	high_th_state;
+	enum thermal_device_mode	low_th_state;
+	enum thermal_device_mode	crit_th_state;
+	int				high_temp;
+	int				low_temp;
+	int				crit_temp;
+};
+
+struct tsens_sensor {
+	struct tsens_device		*tmdev;
+	struct thermal_zone_device	*tzd;
+	u32				hw_id;
+	u32				id;
+	const char			*sensor_name;
+	struct tsens_context		thr_state;
+};
+
+/**
+ * struct tsens_ops - operations as supported by the tsens device
+ * @init: Function to initialize the tsens device
+ * @get_temp: Function which returns the temp in millidegC
+ */
+struct tsens_ops {
+	int (*hw_init)(struct tsens_device *);
+	int (*get_temp)(struct tsens_sensor *, int *);
+	int (*set_trip_temp)(struct tsens_sensor *, int, int);
+	int (*interrupts_reg)(struct tsens_device *);
+	int (*dbg)(struct tsens_device *, u32, u32, int *);
+};
+
+struct tsens_irqs {
+	const char			*name;
+	irqreturn_t (*handler)(int, void *);
+};
+
+/**
+ * struct tsens_data - tsens instance specific data
+ * @num_sensors: Max number of sensors supported by platform
+ * @ops: operations the tsens instance supports
+ * @hw_ids: Subset of sensors ids supported by platform, if not the first n
+ */
+struct tsens_data {
+	const u32			num_sensors;
+	const struct tsens_ops		*ops;
+	unsigned int			*hw_ids;
+	u32				temp_factor;
+	bool				cycle_monitor;
+	u32				cycle_compltn_monitor_val;
+	bool				wd_bark;
+	u32				wd_bark_val;
+};
+
+struct tsens_device {
+	struct device			*dev;
+	struct platform_device		*pdev;
+	struct list_head		list;
+	u32				num_sensors;
+	struct regmap			*map;
+	struct regmap_field		*status_field;
+	void				*tsens_addr;
+	const struct tsens_ops		*ops;
+	struct tsens_dbg_context	tsens_dbg;
+	spinlock_t			tsens_crit_lock;
+	spinlock_t			tsens_upp_low_lock;
+	const struct tsens_data		*ctrl_data;
+	struct tsens_sensor		sensor[0];
+};
+
+extern const struct tsens_data data_tsens2xxx, data_tsens23xx, data_tsens24xx;
+
+#endif /* __QCOM_TSENS_H__ */
diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c
new file mode 100644
index 0000000..0f59dc5
--- /dev/null
+++ b/drivers/thermal/tsens2xxx.c
@@ -0,0 +1,543 @@
+/* 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 term_tm of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/vmalloc.h>
+#include "tsens.h"
+
+#define TSENS_DRIVER_NAME			"msm-tsens"
+
+#define TSENS_TM_INT_EN(n)			((n) + 0x1004)
+#define TSENS_TM_CRITICAL_INT_STATUS(n)		((n) + 0x1014)
+#define TSENS_TM_CRITICAL_INT_CLEAR(n)		((n) + 0x1018)
+#define TSENS_TM_CRITICAL_INT_MASK(n)		((n) + 0x101c)
+#define TSENS_TM_CRITICAL_WD_BARK		BIT(31)
+#define TSENS_TM_CRITICAL_CYCLE_MONITOR		BIT(30)
+#define TSENS_TM_CRITICAL_INT_EN		BIT(2)
+#define TSENS_TM_UPPER_INT_EN			BIT(1)
+#define TSENS_TM_LOWER_INT_EN			BIT(0)
+#define TSENS_TM_SN_UPPER_LOWER_THRESHOLD(n)	((n) + 0x1020)
+#define TSENS_TM_SN_ADDR_OFFSET			0x4
+#define TSENS_TM_UPPER_THRESHOLD_SET(n)		((n) << 12)
+#define TSENS_TM_UPPER_THRESHOLD_VALUE_SHIFT(n)	((n) >> 12)
+#define TSENS_TM_LOWER_THRESHOLD_VALUE(n)	((n) & 0xfff)
+#define TSENS_TM_UPPER_THRESHOLD_VALUE(n)	(((n) & 0xfff000) >> 12)
+#define TSENS_TM_UPPER_THRESHOLD_MASK		0xfff000
+#define TSENS_TM_LOWER_THRESHOLD_MASK		0xfff
+#define TSENS_TM_UPPER_THRESHOLD_SHIFT		12
+#define TSENS_TM_SN_CRITICAL_THRESHOLD(n)	((n) + 0x1060)
+#define TSENS_STATUS_ADDR_OFFSET		2
+#define TSENS_TM_UPPER_INT_MASK(n)		(((n) & 0xffff0000) >> 16)
+#define TSENS_TM_LOWER_INT_MASK(n)		((n) & 0xffff)
+#define TSENS_TM_UPPER_LOWER_INT_STATUS(n)	((n) + 0x1008)
+#define TSENS_TM_UPPER_LOWER_INT_CLEAR(n)	((n) + 0x100c)
+#define TSENS_TM_UPPER_LOWER_INT_MASK(n)	((n) + 0x1010)
+#define TSENS_TM_UPPER_INT_SET(n)		(1 << (n + 16))
+#define TSENS_TM_SN_CRITICAL_THRESHOLD_MASK	0xfff
+#define TSENS_TM_SN_STATUS_VALID_BIT		BIT(21)
+#define TSENS_TM_SN_STATUS_CRITICAL_STATUS	BIT(19)
+#define TSENS_TM_SN_STATUS_UPPER_STATUS		BIT(18)
+#define TSENS_TM_SN_STATUS_LOWER_STATUS		BIT(17)
+#define TSENS_TM_SN_LAST_TEMP_MASK		0xfff
+#define TSENS_TM_CODE_BIT_MASK			0xfff
+#define TSENS_TM_CODE_SIGN_BIT			0x800
+
+#define TSENS_EN				BIT(0)
+
+static void msm_tsens_convert_temp(int last_temp, int *temp)
+{
+	int code_mask = ~TSENS_TM_CODE_BIT_MASK;
+
+	if (last_temp & TSENS_TM_CODE_SIGN_BIT) {
+		/* Sign extension for negative value */
+		last_temp |= code_mask;
+	}
+
+	*temp = last_temp * 100;
+}
+
+static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp)
+{
+	struct tsens_device *tmdev = NULL;
+	unsigned int code;
+	void __iomem *sensor_addr;
+	int last_temp = 0, last_temp2 = 0, last_temp3 = 0;
+
+	if (!sensor)
+		return -EINVAL;
+
+	tmdev = sensor->tmdev;
+	sensor_addr = TSENS_TM_SN_STATUS(tmdev->tsens_addr);
+
+	code = readl_relaxed_no_log(sensor_addr +
+			(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
+	last_temp = code & TSENS_TM_SN_LAST_TEMP_MASK;
+
+	if (code & TSENS_TM_SN_STATUS_VALID_BIT) {
+		msm_tsens_convert_temp(last_temp, temp);
+		return 0;
+	}
+
+	code = readl_relaxed_no_log(sensor_addr +
+		(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
+	last_temp2 = code & TSENS_TM_SN_LAST_TEMP_MASK;
+	if (code & TSENS_TM_SN_STATUS_VALID_BIT) {
+		last_temp = last_temp2;
+		msm_tsens_convert_temp(last_temp, temp);
+		return 0;
+	}
+
+	code = readl_relaxed_no_log(sensor_addr +
+			(sensor->hw_id <<
+			TSENS_STATUS_ADDR_OFFSET));
+	last_temp3 = code & TSENS_TM_SN_LAST_TEMP_MASK;
+	if (code & TSENS_TM_SN_STATUS_VALID_BIT) {
+		last_temp = last_temp3;
+		msm_tsens_convert_temp(last_temp, temp);
+		return 0;
+	}
+
+	if (last_temp == last_temp2)
+		last_temp = last_temp2;
+	else if (last_temp2 == last_temp3)
+		last_temp = last_temp3;
+
+	msm_tsens_convert_temp(last_temp, temp);
+
+	if (tmdev->ops->dbg)
+		tmdev->ops->dbg(tmdev, (u32) sensor->hw_id,
+					TSENS_DBG_LOG_TEMP_READS, temp);
+
+	return 0;
+}
+
+static int tsens_tm_activate_trip_type(struct tsens_sensor *tm_sensor,
+			int trip, enum thermal_trip_activation_mode mode)
+{
+	struct tsens_device *tmdev = NULL;
+	unsigned int reg_cntl, mask;
+	unsigned long flags;
+	int rc = 0;
+
+	/* clear the interrupt and unmask */
+	if (!tm_sensor || trip < 0)
+		return -EINVAL;
+
+	tmdev = tm_sensor->tmdev;
+	if (!tmdev)
+		return -EINVAL;
+
+	spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags);
+	mask = (tm_sensor->hw_id);
+	switch (trip) {
+	case THERMAL_TRIP_CRITICAL:
+		tmdev->sensor[tm_sensor->hw_id].
+			thr_state.crit_th_state = mode;
+		reg_cntl = readl_relaxed(TSENS_TM_CRITICAL_INT_MASK
+							(tmdev->tsens_addr));
+		if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
+			writel_relaxed(reg_cntl | (1 << mask),
+				(TSENS_TM_CRITICAL_INT_MASK
+				(tmdev->tsens_addr)));
+		else
+			writel_relaxed(reg_cntl & ~(1 << mask),
+				(TSENS_TM_CRITICAL_INT_MASK
+				(tmdev->tsens_addr)));
+		break;
+	case THERMAL_TRIP_ACTIVE:
+		tmdev->sensor[tm_sensor->hw_id].
+			thr_state.high_th_state = mode;
+		reg_cntl = readl_relaxed(TSENS_TM_UPPER_LOWER_INT_MASK
+						(tmdev->tsens_addr));
+		if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
+			writel_relaxed(reg_cntl |
+				(TSENS_TM_UPPER_INT_SET(mask)),
+				(TSENS_TM_UPPER_LOWER_INT_MASK
+				(tmdev->tsens_addr)));
+		else
+			writel_relaxed(reg_cntl &
+				~(TSENS_TM_UPPER_INT_SET(mask)),
+				(TSENS_TM_UPPER_LOWER_INT_MASK
+				(tmdev->tsens_addr)));
+		break;
+	case THERMAL_TRIP_PASSIVE:
+		tmdev->sensor[tm_sensor->hw_id].
+			thr_state.low_th_state = mode;
+		reg_cntl = readl_relaxed(TSENS_TM_UPPER_LOWER_INT_MASK
+						(tmdev->tsens_addr));
+		if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
+			writel_relaxed(reg_cntl | (1 << mask),
+			(TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_addr)));
+		else
+			writel_relaxed(reg_cntl & ~(1 << mask),
+			(TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_addr)));
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags);
+	/* Activate and enable the respective trip threshold setting */
+	mb();
+
+	return rc;
+}
+
+static int tsens2xxx_set_trip_temp(struct tsens_sensor *tm_sensor,
+							int trip, int temp)
+{
+	unsigned int reg_cntl;
+	unsigned long flags;
+	struct tsens_device *tmdev = NULL;
+	int rc = 0;
+
+	if (!tm_sensor || trip < 0)
+		return -EINVAL;
+
+	tmdev = tm_sensor->tmdev;
+	if (!tmdev)
+		return -EINVAL;
+
+	spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags);
+	switch (trip) {
+	case THERMAL_TRIP_CRITICAL:
+		tmdev->sensor[tm_sensor->hw_id].
+				thr_state.crit_temp = temp;
+		temp &= TSENS_TM_SN_CRITICAL_THRESHOLD_MASK;
+		writel_relaxed(temp,
+			(TSENS_TM_SN_CRITICAL_THRESHOLD(tmdev->tsens_addr) +
+			(tm_sensor->hw_id * TSENS_TM_SN_ADDR_OFFSET)));
+		break;
+	case THERMAL_TRIP_ACTIVE:
+		tmdev->sensor[tm_sensor->hw_id].
+				thr_state.high_temp = temp;
+		reg_cntl = readl_relaxed((TSENS_TM_SN_UPPER_LOWER_THRESHOLD
+				(tmdev->tsens_addr)) +
+				(tm_sensor->hw_id *
+				TSENS_TM_SN_ADDR_OFFSET));
+		temp = TSENS_TM_UPPER_THRESHOLD_SET(temp);
+		temp &= TSENS_TM_UPPER_THRESHOLD_MASK;
+		reg_cntl &= ~TSENS_TM_UPPER_THRESHOLD_MASK;
+		writel_relaxed(reg_cntl | temp,
+			(TSENS_TM_SN_UPPER_LOWER_THRESHOLD(tmdev->tsens_addr) +
+			(tm_sensor->hw_id * TSENS_TM_SN_ADDR_OFFSET)));
+		break;
+	case THERMAL_TRIP_PASSIVE:
+		tmdev->sensor[tm_sensor->hw_id].
+				thr_state.low_temp = temp;
+		reg_cntl = readl_relaxed((TSENS_TM_SN_UPPER_LOWER_THRESHOLD
+				(tmdev->tsens_addr)) +
+				(tm_sensor->hw_id *
+				TSENS_TM_SN_ADDR_OFFSET));
+		temp &= TSENS_TM_LOWER_THRESHOLD_MASK;
+		reg_cntl &= ~TSENS_TM_LOWER_THRESHOLD_MASK;
+		writel_relaxed(reg_cntl | temp,
+			(TSENS_TM_SN_UPPER_LOWER_THRESHOLD(tmdev->tsens_addr) +
+			(tm_sensor->hw_id * TSENS_TM_SN_ADDR_OFFSET)));
+		break;
+	default:
+		pr_err("Invalid trip to TSENS: %d\n", trip);
+		rc = -EINVAL;
+	}
+
+	spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags);
+	/* Set trip temperature thresholds */
+	mb();
+
+	rc = tsens_tm_activate_trip_type(tm_sensor, trip,
+				THERMAL_TRIP_ACTIVATION_ENABLED);
+	if (rc)
+		pr_err("Error during trip activation :%d\n", rc);
+
+	return rc;
+}
+
+static irqreturn_t tsens_tm_critical_irq_thread(int irq, void *data)
+{
+	struct tsens_device *tm = data;
+	unsigned int i, status;
+	unsigned long flags;
+	void __iomem *sensor_status_addr;
+	void __iomem *sensor_int_mask_addr;
+	void __iomem *sensor_critical_addr;
+	void __iomem *wd_critical_addr;
+	int wd_mask;
+
+	sensor_status_addr = TSENS_TM_SN_STATUS(tm->tsens_addr);
+	sensor_int_mask_addr =
+		TSENS_TM_CRITICAL_INT_MASK(tm->tsens_addr);
+	sensor_critical_addr =
+		TSENS_TM_SN_CRITICAL_THRESHOLD(tm->tsens_addr);
+	wd_critical_addr =
+		TSENS_TM_CRITICAL_INT_STATUS(tm->tsens_addr);
+
+	if (tm->ctrl_data->wd_bark) {
+		wd_mask = readl_relaxed(wd_critical_addr);
+		if (wd_mask & TSENS_TM_CRITICAL_WD_BARK) {
+			/*
+			 * Clear watchdog interrupt and
+			 * increment global wd count
+			 */
+			writel_relaxed(wd_mask | TSENS_TM_CRITICAL_WD_BARK,
+				(TSENS_TM_CRITICAL_INT_CLEAR
+				(tm->tsens_addr)));
+			writel_relaxed(wd_mask & ~(TSENS_TM_CRITICAL_WD_BARK),
+				(TSENS_TM_CRITICAL_INT_CLEAR
+				(tm->tsens_addr)));
+			tm->tsens_dbg.tsens_critical_wd_cnt++;
+			return IRQ_HANDLED;
+		}
+	}
+
+	for (i = 0; i < tm->num_sensors; i++) {
+		int int_mask, int_mask_val;
+		u32 addr_offset;
+
+		spin_lock_irqsave(&tm->tsens_crit_lock, flags);
+		addr_offset = tm->sensor[i].hw_id *
+						TSENS_TM_SN_ADDR_OFFSET;
+		status = readl_relaxed(sensor_status_addr + addr_offset);
+		int_mask = readl_relaxed(sensor_int_mask_addr);
+
+		if ((status & TSENS_TM_SN_STATUS_CRITICAL_STATUS) &&
+			!(int_mask & (1 << tm->sensor[i].hw_id))) {
+			int_mask = readl_relaxed(sensor_int_mask_addr);
+			int_mask_val = (1 << tm->sensor[i].hw_id);
+			/* Mask the corresponding interrupt for the sensors */
+			writel_relaxed(int_mask | int_mask_val,
+				TSENS_TM_CRITICAL_INT_MASK(
+					tm->tsens_addr));
+			/* Clear the corresponding sensors interrupt */
+			writel_relaxed(int_mask_val,
+				TSENS_TM_CRITICAL_INT_CLEAR(tm->tsens_addr));
+			writel_relaxed(0,
+				TSENS_TM_CRITICAL_INT_CLEAR(
+					tm->tsens_addr));
+			tm->sensor[i].thr_state.
+					crit_th_state = THERMAL_DEVICE_DISABLED;
+		}
+		spin_unlock_irqrestore(&tm->tsens_crit_lock, flags);
+	}
+
+	/* Mask critical interrupt */
+	mb();
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t tsens_tm_irq_thread(int irq, void *data)
+{
+	struct tsens_device *tm = data;
+	unsigned int i, status, threshold;
+	unsigned long flags;
+	void __iomem *sensor_status_addr;
+	void __iomem *sensor_int_mask_addr;
+	void __iomem *sensor_upper_lower_addr;
+	u32 addr_offset = 0;
+
+	sensor_status_addr = TSENS_TM_SN_STATUS(tm->tsens_addr);
+	sensor_int_mask_addr =
+		TSENS_TM_UPPER_LOWER_INT_MASK(tm->tsens_addr);
+	sensor_upper_lower_addr =
+		TSENS_TM_SN_UPPER_LOWER_THRESHOLD(tm->tsens_addr);
+
+	for (i = 0; i < tm->num_sensors; i++) {
+		bool upper_thr = false, lower_thr = false;
+		int int_mask, int_mask_val = 0;
+
+		spin_lock_irqsave(&tm->tsens_upp_low_lock, flags);
+		addr_offset = tm->sensor[i].hw_id *
+						TSENS_TM_SN_ADDR_OFFSET;
+		status = readl_relaxed(sensor_status_addr + addr_offset);
+		threshold = readl_relaxed(sensor_upper_lower_addr +
+								addr_offset);
+		int_mask = readl_relaxed(sensor_int_mask_addr);
+
+		if ((status & TSENS_TM_SN_STATUS_UPPER_STATUS) &&
+			!(int_mask &
+				(1 << (tm->sensor[i].hw_id + 16)))) {
+			int_mask = readl_relaxed(sensor_int_mask_addr);
+			int_mask_val = TSENS_TM_UPPER_INT_SET(
+					tm->sensor[i].hw_id);
+			/* Mask the corresponding interrupt for the sensors */
+			writel_relaxed(int_mask | int_mask_val,
+				TSENS_TM_UPPER_LOWER_INT_MASK(
+					tm->tsens_addr));
+			/* Clear the corresponding sensors interrupt */
+			writel_relaxed(int_mask_val,
+				TSENS_TM_UPPER_LOWER_INT_CLEAR(
+					tm->tsens_addr));
+			writel_relaxed(0,
+				TSENS_TM_UPPER_LOWER_INT_CLEAR(
+					tm->tsens_addr));
+			upper_thr = true;
+			tm->sensor[i].thr_state.
+					high_th_state = THERMAL_DEVICE_DISABLED;
+		}
+
+		if ((status & TSENS_TM_SN_STATUS_LOWER_STATUS) &&
+			!(int_mask &
+				(1 << tm->sensor[i].hw_id))) {
+			int_mask = readl_relaxed(sensor_int_mask_addr);
+			int_mask_val = (1 << tm->sensor[i].hw_id);
+			/* Mask the corresponding interrupt for the sensors */
+			writel_relaxed(int_mask | int_mask_val,
+				TSENS_TM_UPPER_LOWER_INT_MASK(
+					tm->tsens_addr));
+			/* Clear the corresponding sensors interrupt */
+			writel_relaxed(int_mask_val,
+				TSENS_TM_UPPER_LOWER_INT_CLEAR(
+					tm->tsens_addr));
+			writel_relaxed(0,
+				TSENS_TM_UPPER_LOWER_INT_CLEAR(
+					tm->tsens_addr));
+			lower_thr = true;
+			tm->sensor[i].thr_state.
+					low_th_state = THERMAL_DEVICE_DISABLED;
+		}
+		spin_unlock_irqrestore(&tm->tsens_upp_low_lock, flags);
+
+		if (upper_thr || lower_thr) {
+			int temp;
+			enum thermal_trip_type trip =
+					THERMAL_TRIP_CONFIGURABLE_LOW;
+
+			if (upper_thr)
+				trip = THERMAL_TRIP_CONFIGURABLE_HI;
+			tsens2xxx_get_temp(&tm->sensor[i], &temp);
+			/* Use id for multiple controllers */
+			pr_debug("sensor:%d trigger temp (%d degC)\n",
+				tm->sensor[i].hw_id,
+				(status & TSENS_TM_SN_LAST_TEMP_MASK));
+		}
+	}
+
+	/* Disable monitoring sensor trip threshold for triggered sensor */
+	mb();
+
+	if (tm->ops->dbg)
+		tm->ops->dbg(tm, 0, TSENS_DBG_LOG_INTERRUPT_TIMESTAMP, NULL);
+
+	return IRQ_HANDLED;
+}
+
+static int tsens2xxx_hw_init(struct tsens_device *tmdev)
+{
+	void __iomem *srot_addr;
+	void __iomem *sensor_int_mask_addr;
+	unsigned int srot_val;
+	int crit_mask;
+
+	srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_addr + 0x4);
+	srot_val = readl_relaxed(srot_addr);
+	if (!(srot_val & TSENS_EN)) {
+		pr_err("TSENS device is not enabled\n");
+		return -ENODEV;
+	}
+
+	if (tmdev->ctrl_data->cycle_monitor) {
+		sensor_int_mask_addr =
+			TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_addr);
+		crit_mask = readl_relaxed(sensor_int_mask_addr);
+		writel_relaxed(
+			crit_mask | tmdev->ctrl_data->cycle_compltn_monitor_val,
+			(TSENS_TM_CRITICAL_INT_MASK
+			(tmdev->tsens_addr)));
+		/*Update critical cycle monitoring*/
+		mb();
+	}
+	writel_relaxed(TSENS_TM_CRITICAL_INT_EN |
+		TSENS_TM_UPPER_INT_EN | TSENS_TM_LOWER_INT_EN,
+		TSENS_TM_INT_EN(tmdev->tsens_addr));
+
+	spin_lock_init(&tmdev->tsens_crit_lock);
+	spin_lock_init(&tmdev->tsens_upp_low_lock);
+
+	return 0;
+}
+
+static const struct tsens_irqs tsens2xxx_irqs[] = {
+	{ "tsens-upper-lower", tsens_tm_irq_thread},
+	{ "tsens-critical", tsens_tm_critical_irq_thread},
+};
+
+static int tsens2xxx_register_interrupts(struct tsens_device *tmdev)
+{
+	struct platform_device *pdev;
+	int i, rc;
+
+	if (!tmdev)
+		return -EINVAL;
+
+	pdev = tmdev->pdev;
+
+	for (i = 0; i < ARRAY_SIZE(tsens2xxx_irqs); i++) {
+		int irq;
+
+		irq = platform_get_irq_byname(pdev, tsens2xxx_irqs[i].name);
+		if (irq < 0) {
+			dev_err(&pdev->dev, "failed to get irq %s\n",
+					tsens2xxx_irqs[i].name);
+			return irq;
+		}
+
+		rc = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+				tsens2xxx_irqs[i].handler,
+				IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				tsens2xxx_irqs[i].name, tmdev);
+		if (rc) {
+			dev_err(&pdev->dev, "failed to get irq %s\n",
+					tsens2xxx_irqs[i].name);
+			return rc;
+		}
+		enable_irq_wake(irq);
+	}
+
+	return 0;
+}
+
+static const struct tsens_ops ops_tsens2xxx = {
+	.hw_init	= tsens2xxx_hw_init,
+	.get_temp	= tsens2xxx_get_temp,
+	.set_trip_temp	= tsens2xxx_set_trip_temp,
+	.interrupts_reg	= tsens2xxx_register_interrupts,
+	.dbg		= tsens2xxx_dbg,
+};
+
+const struct tsens_data data_tsens2xxx = {
+	.cycle_monitor			= false,
+	.cycle_compltn_monitor_val	= 0,
+	.wd_bark			= false,
+	.wd_bark_val			= 0,
+	.ops				= &ops_tsens2xxx,
+};
+
+const struct tsens_data data_tsens23xx = {
+	.cycle_monitor			= true,
+	.cycle_compltn_monitor_val	= 0,
+	.wd_bark			= true,
+	.wd_bark_val			= 0,
+	.ops				= &ops_tsens2xxx,
+};
+
+const struct tsens_data data_tsens24xx = {
+	.cycle_monitor			= true,
+	.cycle_compltn_monitor_val	= 0,
+	.wd_bark			= true,
+	.wd_bark_val			= 1,
+	.ops				= &ops_tsens2xxx,
+};
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index a9ded51..bac9975 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1079,6 +1079,12 @@
 	    hardware.
 	    The driver supports console and High speed UART functions.
 
+config SERIAL_MSM_GENI_CONSOLE
+	tristate "MSM on-chip GENI HW based console support"
+	depends on SERIAL_MSM_GENI=y
+	select SERIAL_CORE_CONSOLE
+	select SERIAL_EARLYCON
+
 config SERIAL_MSM_CONSOLE
 	bool "MSM serial console support"
 	depends on SERIAL_MSM=y
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index a115f58..7c4654c 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -313,6 +313,7 @@
 }
 #endif
 
+#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
 static void msm_geni_serial_wr_char(struct uart_port *uport, int ch)
 {
 	geni_write_reg(ch, uport->membase, SE_GENI_TX_FIFOn);
@@ -384,6 +385,53 @@
 	spin_unlock(&uport->lock);
 }
 
+static int handle_rx_console(struct uart_port *uport,
+			unsigned int rx_fifo_wc,
+			unsigned int rx_last_byte_valid,
+			unsigned int rx_last)
+{
+	int i, c;
+	unsigned char *rx_char;
+	struct tty_port *tport;
+	struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+
+	tport = &uport->state->port;
+
+	for (i = 0; i < rx_fifo_wc; i++) {
+		int bytes = 4;
+
+		*(msm_port->rx_fifo) =
+			geni_read_reg(uport->membase, SE_GENI_RX_FIFOn);
+		rx_char = (unsigned char *)msm_port->rx_fifo;
+
+		if (i == (rx_fifo_wc - 1)) {
+			if (rx_last && rx_last_byte_valid)
+				bytes = rx_last_byte_valid;
+		}
+		for (c = 0; c < bytes; c++) {
+			char flag = TTY_NORMAL;
+			int sysrq;
+
+			uport->icount.rx++;
+			sysrq = uart_handle_sysrq_char(uport, rx_char[c]);
+			if (!sysrq)
+				tty_insert_flip_char(tport, rx_char[c], flag);
+		}
+	}
+	tty_flip_buffer_push(tport);
+	return 0;
+}
+#else
+static int handle_rx_console(struct uart_port *uport,
+			unsigned int rx_fifo_wc,
+			unsigned int rx_last_byte_valid,
+			unsigned int rx_last)
+{
+	return -EPERM;
+}
+
+#endif /* (CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)) */
+
 static void msm_geni_serial_start_tx(struct uart_port *uport)
 {
 	unsigned int geni_m_irq_en;
@@ -476,43 +524,6 @@
 		WARN_ON(1);
 }
 
-static int handle_rx_console(struct uart_port *uport,
-			unsigned int rx_fifo_wc,
-			unsigned int rx_last_byte_valid,
-			unsigned int rx_last)
-{
-	int i, c;
-	unsigned char *rx_char;
-	struct tty_port *tport;
-	struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
-
-	tport = &uport->state->port;
-
-	for (i = 0; i < rx_fifo_wc; i++) {
-		int bytes = 4;
-
-		*(msm_port->rx_fifo) =
-			geni_read_reg(uport->membase, SE_GENI_RX_FIFOn);
-		rx_char = (unsigned char *)msm_port->rx_fifo;
-
-		if (i == (rx_fifo_wc - 1)) {
-			if (rx_last && rx_last_byte_valid)
-				bytes = rx_last_byte_valid;
-		}
-		for (c = 0; c < bytes; c++) {
-			char flag = TTY_NORMAL;
-			int sysrq;
-
-			uport->icount.rx++;
-			sysrq = uart_handle_sysrq_char(uport, rx_char[c]);
-			if (!sysrq)
-				tty_insert_flip_char(tport, rx_char[c], flag);
-		}
-	}
-	tty_flip_buffer_push(tport);
-	return 0;
-}
-
 static int handle_rx_hs(struct uart_port *uport,
 			unsigned int rx_fifo_wc,
 			unsigned int rx_last_byte_valid,
@@ -848,7 +859,7 @@
 	unsigned int stop_bit_len;
 	unsigned int rxstale;
 	unsigned int clk_div;
-	unsigned long ser_clk_cfg;
+	unsigned long ser_clk_cfg = 0;
 	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
 	unsigned long clk_rate;
 
@@ -943,6 +954,7 @@
 	return is_tx_empty;
 }
 
+#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
 static int __init msm_geni_console_setup(struct console *co, char *options)
 {
 	struct uart_port *uport;
@@ -985,13 +997,100 @@
 	return uart_set_options(uport, co, baud, parity, bits, flow);
 }
 
-static void msm_geni_serial_debug_init(struct uart_port *uport)
+static void
+msm_geni_serial_early_console_write(struct console *con, const char *s,
+			unsigned int n)
 {
-	struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+	struct earlycon_device *dev = con->data;
 
-	msm_port->dbg = debugfs_create_dir(dev_name(uport->dev), NULL);
-	if (IS_ERR_OR_NULL(msm_port->dbg))
-		dev_err(uport->dev, "Failed to create dbg dir\n");
+	__msm_geni_serial_console_write(&dev->port, s, n);
+}
+
+static int __init
+msm_geni_serial_earlycon_setup(struct earlycon_device *dev,
+		const char *opt)
+{
+	struct uart_port *uport = &dev->port;
+	int ret = 0;
+	struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+	u32 tx_trans_cfg = 0;
+	u32 tx_parity_cfg = 0;
+	u32 rx_trans_cfg = 0;
+	u32 rx_parity_cfg = 0;
+	u32 stop_bit = 0;
+	u32 rx_stale = 0;
+	u32 bits_per_char = 0;
+	u32 s_clk_cfg = 0;
+	u32 baud = 115200;
+	u32 clk_div;
+	unsigned long clk_rate;
+
+	if (!uport->membase) {
+		ret = -ENOMEM;
+		goto exit_geni_serial_earlyconsetup;
+	}
+
+	if (get_se_proto(uport->membase) != UART) {
+		ret = -ENXIO;
+		goto exit_geni_serial_earlyconsetup;
+	}
+
+	msm_port->xfer_mode = FIFO_MODE;
+	set_rfr_wm(msm_port);
+	msm_port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
+	msm_port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
+	msm_port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
+	geni_se_init(uport->membase, msm_port->xfer_mode, msm_port->rx_wm,
+							msm_port->rx_rfr);
+	/*
+	 * Ignore Flow control.
+	 * Disable Tx Parity.
+	 * Don't check Parity during Rx.
+	 * Disable Rx Parity.
+	 * n = 8.
+	 * Stop bit = 0.
+	 * Stale timeout in bit-time (3 chars worth).
+	 */
+	tx_trans_cfg |= UART_CTS_MASK;
+	tx_parity_cfg = 0;
+	rx_trans_cfg = 0;
+	rx_parity_cfg = 0;
+	bits_per_char = 0x8;
+	stop_bit = 0;
+	rx_stale = 0x18;
+	clk_div = get_clk_div_rate(baud, &clk_rate);
+	if (clk_div <= 0) {
+		ret = -EINVAL;
+		goto exit_geni_serial_earlyconsetup;
+	}
+
+	s_clk_cfg |= SER_CLK_EN;
+	s_clk_cfg |= (clk_div << CLK_DIV_SHFT);
+
+	geni_serial_write_term_regs(uport, 0, tx_trans_cfg,
+		tx_parity_cfg, rx_trans_cfg, rx_parity_cfg, bits_per_char,
+		stop_bit, rx_stale, s_clk_cfg);
+
+	dev->con->write = msm_geni_serial_early_console_write;
+	dev->con->setup = NULL;
+	/*
+	 * Ensure that the early console setup completes before
+	 * returning.
+	 */
+	mb();
+exit_geni_serial_earlyconsetup:
+	return ret;
+}
+OF_EARLYCON_DECLARE(msm_geni_serial, "qcom,msm-geni-uart",
+		msm_geni_serial_earlycon_setup);
+
+static int console_register(struct uart_driver *drv)
+{
+	return uart_register_driver(drv);
+}
+static void console_unregister(struct uart_driver *drv)
+{
+	uart_unregister_driver(drv);
 }
 
 static struct console cons_ops = {
@@ -1004,6 +1103,33 @@
 	.data = &msm_geni_console_driver,
 };
 
+static struct uart_driver msm_geni_console_driver = {
+	.owner = THIS_MODULE,
+	.driver_name = "msm_geni_console",
+	.dev_name = "ttyMSM",
+	.nr =  GENI_UART_NR_PORTS,
+	.cons = &cons_ops,
+};
+#else
+static int console_register(struct uart_driver *drv)
+{
+	return 0;
+}
+
+static void console_unregister(struct uart_driver *drv)
+{
+}
+#endif /* defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) */
+
+static void msm_geni_serial_debug_init(struct uart_port *uport)
+{
+	struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+
+	msm_port->dbg = debugfs_create_dir(dev_name(uport->dev), NULL);
+	if (IS_ERR_OR_NULL(msm_port->dbg))
+		dev_err(uport->dev, "Failed to create dbg dir\n");
+}
+
 static const struct uart_ops msm_geni_serial_pops = {
 	.tx_empty = msm_geni_serial_tx_empty,
 	.stop_tx = msm_geni_serial_stop_tx,
@@ -1022,8 +1148,10 @@
 };
 
 static const struct of_device_id msm_geni_device_tbl[] = {
+#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
 	{ .compatible = "qcom,msm-geni-console",
 			.data = (void *)&msm_geni_console_driver},
+#endif
 	{ .compatible = "qcom,msm-geni-serial-hs",
 			.data = (void *)&msm_geni_serial_hs_driver},
 	{},
@@ -1189,92 +1317,6 @@
 	return 0;
 }
 
-static void
-msm_geni_serial_early_console_write(struct console *con, const char *s,
-			unsigned int n)
-{
-	struct earlycon_device *dev = con->data;
-
-	__msm_geni_serial_console_write(&dev->port, s, n);
-}
-
-static int __init
-msm_geni_serial_earlycon_setup(struct earlycon_device *dev,
-		const char *opt)
-{
-	struct uart_port *uport = &dev->port;
-	int ret = 0;
-	struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
-	u32 tx_trans_cfg = 0;
-	u32 tx_parity_cfg = 0;
-	u32 rx_trans_cfg = 0;
-	u32 rx_parity_cfg = 0;
-	u32 stop_bit = 0;
-	u32 rx_stale = 0;
-	u32 bits_per_char = 0;
-	u32 s_clk_cfg = 0;
-	u32 baud = 115200;
-	u32 clk_div;
-	unsigned long clk_rate;
-
-	if (!uport->membase) {
-		ret = -ENOMEM;
-		goto exit_geni_serial_earlyconsetup;
-	}
-
-	if (get_se_proto(uport->membase) != UART) {
-		ret = -ENXIO;
-		goto exit_geni_serial_earlyconsetup;
-	}
-
-	msm_port->xfer_mode = FIFO_MODE;
-	set_rfr_wm(msm_port);
-	msm_port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
-	msm_port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
-	msm_port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
-	geni_se_init(uport->membase, msm_port->xfer_mode, msm_port->rx_wm,
-							msm_port->rx_rfr);
-	/*
-	 * Ignore Flow control.
-	 * Disable Tx Parity.
-	 * Don't check Parity during Rx.
-	 * Disable Rx Parity.
-	 * n = 8.
-	 * Stop bit = 0.
-	 * Stale timeout in bit-time (3 chars worth).
-	 */
-	tx_trans_cfg |= UART_CTS_MASK;
-	tx_parity_cfg = 0;
-	rx_trans_cfg = 0;
-	rx_parity_cfg = 0;
-	bits_per_char = 0x8;
-	stop_bit = 0;
-	rx_stale = 0x18;
-	clk_div = get_clk_div_rate(baud, &clk_rate);
-	if (clk_div <= 0) {
-		ret = -EINVAL;
-		goto exit_geni_serial_earlyconsetup;
-	}
-
-	s_clk_cfg |= SER_CLK_EN;
-	s_clk_cfg |= (clk_div << CLK_DIV_SHFT);
-
-	geni_serial_write_term_regs(uport, 0, tx_trans_cfg,
-		tx_parity_cfg, rx_trans_cfg, rx_parity_cfg, bits_per_char,
-		stop_bit, rx_stale, s_clk_cfg);
-
-	dev->con->write = msm_geni_serial_early_console_write;
-	dev->con->setup = NULL;
-	/*
-	 * Ensure that the early console setup completes before
-	 * returning.
-	 */
-	mb();
-exit_geni_serial_earlyconsetup:
-	return ret;
-}
-OF_EARLYCON_DECLARE(msm_geni_serial, "qcom,msm-geni-uart",
-		msm_geni_serial_earlycon_setup);
 
 #ifdef CONFIG_PM
 static int msm_geni_serial_runtime_suspend(struct device *dev)
@@ -1366,13 +1408,6 @@
 	},
 };
 
-static struct uart_driver msm_geni_console_driver = {
-	.owner = THIS_MODULE,
-	.driver_name = "msm_geni_console",
-	.dev_name = "ttyMSM",
-	.nr =  GENI_UART_NR_PORTS,
-	.cons = &cons_ops,
-};
 
 static struct uart_driver msm_geni_serial_hs_driver = {
 	.owner = THIS_MODULE,
@@ -1393,7 +1428,7 @@
 		msm_geni_serial_ports[i].uport.line = i;
 	}
 
-	ret = uart_register_driver(&msm_geni_console_driver);
+	ret = console_register(&msm_geni_console_driver);
 	if (ret)
 		return ret;
 
@@ -1405,7 +1440,7 @@
 
 	ret = platform_driver_register(&msm_geni_serial_platform_driver);
 	if (ret) {
-		uart_unregister_driver(&msm_geni_console_driver);
+		console_unregister(&msm_geni_console_driver);
 		uart_unregister_driver(&msm_geni_serial_hs_driver);
 		return ret;
 	}
@@ -1419,7 +1454,7 @@
 {
 	platform_driver_unregister(&msm_geni_serial_platform_driver);
 	uart_unregister_driver(&msm_geni_serial_hs_driver);
-	uart_unregister_driver(&msm_geni_console_driver);
+	console_unregister(&msm_geni_console_driver);
 }
 module_exit(msm_geni_serial_exit);
 
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index a6c1fae..a391b50 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1380,7 +1380,7 @@
 
 	dev_dbg(&intf->dev, "%s called\n", __func__);
 
-	data = kmalloc(sizeof(*data), GFP_KERNEL);
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -1443,6 +1443,13 @@
 			break;
 		}
 	}
+
+	if (!data->bulk_out || !data->bulk_in) {
+		dev_err(&intf->dev, "bulk endpoints not found\n");
+		retcode = -ENODEV;
+		goto err_put;
+	}
+
 	/* Find int endpoint */
 	for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
 		endpoint = &iface_desc->endpoint[n].desc;
@@ -1468,8 +1475,10 @@
 	if (data->iin_ep_present) {
 		/* allocate int urb */
 		data->iin_urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (!data->iin_urb)
+		if (!data->iin_urb) {
+			retcode = -ENOMEM;
 			goto error_register;
+		}
 
 		/* will reference data in int urb */
 		kref_get(&data->kref);
@@ -1477,8 +1486,10 @@
 		/* allocate buffer for interrupt in */
 		data->iin_buffer = kmalloc(data->iin_wMaxPacketSize,
 					GFP_KERNEL);
-		if (!data->iin_buffer)
+		if (!data->iin_buffer) {
+			retcode = -ENOMEM;
 			goto error_register;
+		}
 
 		/* fill interrupt urb */
 		usb_fill_int_urb(data->iin_urb, data->usb_dev,
@@ -1511,6 +1522,7 @@
 	sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
 	sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
 	usbtmc_free_int(data);
+err_put:
 	kref_put(&data->kref, usbtmc_delete);
 	return retcode;
 }
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 1f7036c..eef716b 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -275,6 +275,16 @@
 
 			/*
 			 * Adjust bInterval for quirked devices.
+			 */
+			/*
+			 * This quirk fixes bIntervals reported in ms.
+			 */
+			if (to_usb_device(ddev)->quirks &
+				USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL) {
+				n = clamp(fls(d->bInterval) + 3, i, j);
+				i = j = n;
+			}
+			/*
 			 * This quirk fixes bIntervals reported in
 			 * linear microframes.
 			 */
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 2c4bd54..cf25708 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1433,7 +1433,7 @@
 {
 	if (IS_ENABLED(CONFIG_HAS_DMA) &&
 	    (urb->transfer_flags & URB_SETUP_MAP_SINGLE))
-		dma_unmap_single(hcd->self.controller,
+		dma_unmap_single(hcd->self.sysdev,
 				urb->setup_dma,
 				sizeof(struct usb_ctrlrequest),
 				DMA_TO_DEVICE);
@@ -2540,6 +2540,7 @@
 	}
 	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
 	/* Make sure that the other roothub is also deallocated. */
+	usb_atomic_notify_dead_bus(&hcd->self);
 }
 EXPORT_SYMBOL_GPL (usb_hc_died);
 
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index ffa53d8..c3d249f 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -4279,7 +4279,7 @@
 	struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
 	int connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN;
 
-	if (!udev->usb2_hw_lpm_capable)
+	if (!udev->usb2_hw_lpm_capable || !udev->bos)
 		return;
 
 	if (hub)
diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c
index 7728c91..af91b1e 100644
--- a/drivers/usb/core/notify.c
+++ b/drivers/usb/core/notify.c
@@ -17,6 +17,7 @@
 #include "usb.h"
 
 static BLOCKING_NOTIFIER_HEAD(usb_notifier_list);
+static ATOMIC_NOTIFIER_HEAD(usb_atomic_notifier_list);
 
 /**
  * usb_register_notify - register a notifier callback whenever a usb change happens
@@ -67,3 +68,33 @@
 {
 	blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus);
 }
+
+/**
+ * usb_register_atomic_notify - register a atomic notifier callback whenever a
+ * HC dies
+ * @nb: pointer to the atomic notifier block for the callback events.
+ *
+ */
+void usb_register_atomic_notify(struct notifier_block *nb)
+{
+	atomic_notifier_chain_register(&usb_atomic_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(usb_register_atomic_notify);
+
+/**
+ * usb_unregister_atomic_notify - unregister a atomic notifier callback
+ * @nb: pointer to the notifier block for the callback events.
+ *
+ */
+void usb_unregister_atomic_notify(struct notifier_block *nb)
+{
+	atomic_notifier_chain_unregister(&usb_atomic_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(usb_unregister_atomic_notify);
+
+
+void usb_atomic_notify_dead_bus(struct usb_bus *ubus)
+{
+	atomic_notifier_call_chain(&usb_atomic_notifier_list, USB_BUS_DIED,
+					 ubus);
+}
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 24f9f98..96b21b0 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -170,6 +170,14 @@
 	/* M-Systems Flash Disk Pioneers */
 	{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* Baum Vario Ultra */
+	{ USB_DEVICE(0x0904, 0x6101), .driver_info =
+			USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
+	{ USB_DEVICE(0x0904, 0x6102), .driver_info =
+			USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
+	{ USB_DEVICE(0x0904, 0x6103), .driver_info =
+			USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
+
 	/* Keytouch QWERTY Panel keyboard */
 	{ USB_DEVICE(0x0926, 0x3333), .driver_info =
 			USB_QUIRK_CONFIG_INTF_STRINGS },
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 5331812..fbff25f 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -175,6 +175,7 @@
 extern void usb_notify_remove_device(struct usb_device *udev);
 extern void usb_notify_add_bus(struct usb_bus *ubus);
 extern void usb_notify_remove_bus(struct usb_bus *ubus);
+extern void usb_atomic_notify_dead_bus(struct usb_bus *ubus);
 extern void usb_hub_adjust_deviceremovable(struct usb_device *hdev,
 		struct usb_hub_descriptor *desc);
 
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 94f65e4..33e3d9f 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -740,6 +740,16 @@
 		}
 	}
 
+	/*
+	 * Workaround for STAR 9000961433 which affects only version
+	 * 3.00a of the DWC_usb3 core. This prevents the controller
+	 * interrupt from being masked while handling events. IMOD
+	 * allows us to work around this issue. Enable it for the
+	 * affected version.
+	 */
+	 if (!dwc->imod_interval && (dwc->revision == DWC3_REVISION_300A))
+		dwc->imod_interval = 1;
+
 	/* issue device SoftReset too */
 	ret = dwc3_core_reset(dwc);
 	if (ret)
@@ -1109,6 +1119,15 @@
 
 #define DWC3_ALIGN_MASK		(16 - 1)
 
+/* check whether the core supports IMOD */
+bool dwc3_has_imod(struct dwc3 *dwc)
+{
+	return ((dwc3_is_usb3(dwc) &&
+		dwc->revision >= DWC3_REVISION_300A) ||
+		(dwc3_is_usb31(dwc) &&
+		dwc->revision >= DWC3_USB31_REVISION_120A));
+}
+
 static int dwc3_probe(struct platform_device *pdev)
 {
 	struct device		*dev = &pdev->dev;
@@ -1154,8 +1173,8 @@
 
 	/* will be enabled in dwc3_msm_resume() */
 	irq_set_status_flags(irq, IRQ_NOAUTOEN);
-	ret = devm_request_threaded_irq(dev, irq, NULL, dwc3_interrupt,
-			IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
+	ret = devm_request_irq(dev, irq, dwc3_interrupt, IRQF_SHARED, "dwc3",
+			dwc);
 	if (ret) {
 		dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
 				irq, ret);
@@ -1295,6 +1314,14 @@
 
 	spin_lock_init(&dwc->lock);
 
+	dwc->dwc_wq = alloc_ordered_workqueue("dwc_wq", WQ_HIGHPRI);
+	if (!dwc->dwc_wq) {
+		pr_err("%s: Unable to create workqueue dwc_wq\n", __func__);
+		return -ENOMEM;
+	}
+
+	INIT_WORK(&dwc->bh_work, dwc3_bh_work);
+
 	pm_runtime_no_callbacks(dev);
 	pm_runtime_set_active(dev);
 	pm_runtime_enable(dev);
@@ -1366,6 +1393,7 @@
 	 * memory region the next time probe is called.
 	 */
 	res->start -= DWC3_GLOBALS_REGS_START;
+	destroy_workqueue(dwc->dwc_wq);
 
 	return ret;
 }
@@ -1389,6 +1417,8 @@
 	dwc3_core_exit(dwc);
 	dwc3_ulpi_exit(dwc);
 
+	destroy_workqueue(dwc->dwc_wq);
+
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_allow(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 7968901..009193c 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -68,6 +68,7 @@
 #define DWC3_DEVICE_EVENT_OVERFLOW		11
 
 #define DWC3_GEVNTCOUNT_MASK	0xfffc
+#define DWC3_GEVNTCOUNT_EHB	(1 << 31)
 #define DWC3_GSNPSID_MASK	0xffff0000
 #define DWC3_GSNPSREV_MASK	0xffff
 
@@ -150,6 +151,8 @@
 #define DWC3_DEPCMDPAR0		0x08
 #define DWC3_DEPCMD		0x0c
 
+#define DWC3_DEV_IMOD(n)	(0xca00 + (n * 0x4))
+
 /* OTG Registers */
 #define DWC3_OCFG		0xcc00
 #define DWC3_OCTL		0xcc04
@@ -485,6 +488,11 @@
 #define DWC3_DEPCMD_TYPE_BULK		2
 #define DWC3_DEPCMD_TYPE_INTR		3
 
+#define DWC3_DEV_IMOD_COUNT_SHIFT	16
+#define DWC3_DEV_IMOD_COUNT_MASK	(0xffff << 16)
+#define DWC3_DEV_IMOD_INTERVAL_SHIFT	0
+#define DWC3_DEV_IMOD_INTERVAL_MASK	(0xffff << 0)
+
 #define DWC_CTRL_COUNT	10
 #define NUM_LOG_PAGES	12
 
@@ -939,6 +947,8 @@
  * @vbus_draw: current to be drawn from USB
  * @index: dwc3 instance's number
  * @dwc_ipc_log_ctxt: dwc3 ipc log context
+ * @imod_interval: set the interrupt moderation interval in 250ns
+ *			increments or 0 to disable.
  */
 struct dwc3 {
 	struct usb_ctrlrequest	*ctrl_req;
@@ -1027,6 +1037,7 @@
  */
 #define DWC3_REVISION_IS_DWC31		0x80000000
 #define DWC3_USB31_REVISION_110A	(0x3131302a | DWC3_REVISION_IS_DWC31)
+#define DWC3_USB31_REVISION_120A	(0x3132302a | DWC3_REVISION_IS_DWC31)
 
 	enum dwc3_ep0_next	ep0_next_event;
 	enum dwc3_ep0_state	ep0state;
@@ -1108,6 +1119,11 @@
 	bool			b_suspend;
 	unsigned int		vbus_draw;
 
+	u16			imod_interval;
+
+	struct workqueue_struct	*dwc_wq;
+	struct work_struct	bh_work;
+
 	/* IRQ timing statistics */
 	int			irq;
 	unsigned long		ep_cmd_timeout_cnt;
@@ -1283,12 +1299,20 @@
 u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
 int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
 
+/* check whether we are on the DWC_usb3 core */
+static inline bool dwc3_is_usb3(struct dwc3 *dwc)
+{
+	return !(dwc->revision & DWC3_REVISION_IS_DWC31);
+}
+
 /* check whether we are on the DWC_usb31 core */
 static inline bool dwc3_is_usb31(struct dwc3 *dwc)
 {
 	return !!(dwc->revision & DWC3_REVISION_IS_DWC31);
 }
 
+bool dwc3_has_imod(struct dwc3 *dwc);
+
 #if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
 int dwc3_host_init(struct dwc3 *dwc);
 void dwc3_host_exit(struct dwc3 *dwc);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 8d2b429..96684f4 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -215,6 +215,8 @@
 
 	unsigned int		irq_to_affin;
 	struct notifier_block	dwc3_cpu_notifier;
+	struct notifier_block	usbdev_nb;
+	bool			hc_died;
 
 	struct extcon_dev	*extcon_vbus;
 	struct extcon_dev	*extcon_id;
@@ -1506,6 +1508,33 @@
 	flush_delayed_work(&mdwc->sm_work);
 }
 
+static int msm_dwc3_usbdev_notify(struct notifier_block *self,
+			unsigned long action, void *priv)
+{
+	struct dwc3_msm *mdwc = container_of(self, struct dwc3_msm, usbdev_nb);
+	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
+	struct usb_bus *bus = priv;
+
+	/* Interested only in recovery when HC dies */
+	if (action != USB_BUS_DIED)
+		return 0;
+
+	dev_dbg(mdwc->dev, "%s initiate recovery from hc_died\n", __func__);
+	/* Recovery already under process */
+	if (mdwc->hc_died)
+		return 0;
+
+	if (bus->controller != &dwc->xhci->dev) {
+		dev_dbg(mdwc->dev, "%s event for diff HCD\n", __func__);
+		return 0;
+	}
+
+	mdwc->hc_died = true;
+	schedule_delayed_work(&mdwc->sm_work, 0);
+	return 0;
+}
+
+
 /*
  * Check whether the DWC3 requires resetting the ep
  * after going to Low Power Mode (lpm)
@@ -2045,6 +2074,9 @@
 	if (dwc->irq)
 		disable_irq(dwc->irq);
 
+	if (work_busy(&dwc->bh_work))
+		dbg_event(0xFF, "pend evt", 0);
+
 	/* disable power event irq, hs and ss phy irq is used as wake up src */
 	disable_irq(mdwc->pwr_event_irq);
 
@@ -2095,8 +2127,10 @@
 		dwc3_msm_config_gdsc(mdwc, 0);
 		clk_disable_unprepare(mdwc->sleep_clk);
 
-		if (mdwc->iommu_map)
+		if (mdwc->iommu_map) {
 			arm_iommu_detach_device(mdwc->dev);
+			dev_dbg(mdwc->dev, "IOMMU detached\n");
+		}
 	}
 
 	/* Remove bus voting */
@@ -2230,6 +2264,16 @@
 	if (mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) {
 		u32 tmp;
 
+		if (mdwc->iommu_map) {
+			ret = arm_iommu_attach_device(mdwc->dev,
+					mdwc->iommu_map);
+			if (ret)
+				dev_err(mdwc->dev, "IOMMU attach failed (%d)\n",
+						ret);
+			else
+				dev_dbg(mdwc->dev, "attached to IOMMU\n");
+		}
+
 		dev_dbg(mdwc->dev, "%s: exit power collapse\n", __func__);
 
 		dwc3_msm_power_collapse_por(mdwc);
@@ -2242,16 +2286,6 @@
 					PWR_EVNT_POWERDOWN_IN_P3_MASK, 1);
 
 		mdwc->lpm_flags &= ~MDWC3_POWER_COLLAPSE;
-
-		if (mdwc->iommu_map) {
-			ret = arm_iommu_attach_device(mdwc->dev,
-					mdwc->iommu_map);
-			if (ret)
-				dev_err(mdwc->dev, "IOMMU attach failed (%d)\n",
-						ret);
-			else
-				dev_dbg(mdwc->dev, "attached to IOMMU\n");
-		}
 	}
 
 	atomic_set(&dwc->in_lpm, 0);
@@ -2788,7 +2822,7 @@
 static int dwc3_msm_init_iommu(struct dwc3_msm *mdwc)
 {
 	struct device_node *node = mdwc->dev->of_node;
-	int atomic_ctx = 1;
+	int atomic_ctx = 1, s1_bypass;
 	int ret;
 
 	if (!of_property_read_bool(node, "iommus"))
@@ -2809,12 +2843,31 @@
 	if (ret) {
 		dev_err(mdwc->dev, "IOMMU set atomic attribute failed (%d)\n",
 			ret);
-		arm_iommu_release_mapping(mdwc->iommu_map);
-		mdwc->iommu_map = NULL;
-		return ret;
+		goto release_mapping;
 	}
 
+	s1_bypass = of_property_read_bool(node, "qcom,smmu-s1-bypass");
+	ret = iommu_domain_set_attr(mdwc->iommu_map->domain,
+			DOMAIN_ATTR_S1_BYPASS, &s1_bypass);
+	if (ret) {
+		dev_err(mdwc->dev, "IOMMU set s1 bypass (%d) failed (%d)\n",
+			s1_bypass, ret);
+		goto release_mapping;
+	}
+
+	ret = arm_iommu_attach_device(mdwc->dev, mdwc->iommu_map);
+	if (ret) {
+		dev_err(mdwc->dev, "IOMMU attach failed (%d)\n", ret);
+		goto release_mapping;
+	}
+	dev_dbg(mdwc->dev, "attached to IOMMU\n");
+
 	return 0;
+
+release_mapping:
+	arm_iommu_release_mapping(mdwc->iommu_map);
+	mdwc->iommu_map = NULL;
+	return ret;
 }
 
 static ssize_t mode_show(struct device *dev, struct device_attribute *attr,
@@ -3184,6 +3237,10 @@
 	ret = of_property_read_u32(node, "qcom,num-gsi-evt-buffs",
 				&mdwc->num_gsi_event_buffers);
 
+	/* IOMMU will be reattached upon each resume/connect */
+	if (mdwc->iommu_map)
+		arm_iommu_detach_device(mdwc->dev);
+
 	/*
 	 * Clocks and regulators will not be turned on until the first time
 	 * runtime PM resume is called. This is to allow for booting up with
@@ -3250,8 +3307,10 @@
 	if (mdwc->bus_perf_client)
 		msm_bus_scale_unregister_client(mdwc->bus_perf_client);
 uninit_iommu:
-	if (mdwc->iommu_map)
+	if (mdwc->iommu_map) {
+		arm_iommu_detach_device(mdwc->dev);
 		arm_iommu_release_mapping(mdwc->iommu_map);
+	}
 err:
 	return ret;
 }
@@ -3509,6 +3568,8 @@
 		mdwc->host_nb.notifier_call = dwc3_msm_host_notifier;
 		usb_register_notify(&mdwc->host_nb);
 
+		mdwc->usbdev_nb.notifier_call = msm_dwc3_usbdev_notify;
+		usb_register_atomic_notify(&mdwc->usbdev_nb);
 		/*
 		 * FIXME If micro A cable is disconnected during system suspend,
 		 * xhci platform device will be removed before runtime pm is
@@ -3562,6 +3623,7 @@
 	} else {
 		dev_dbg(mdwc->dev, "%s: turn off host\n", __func__);
 
+		usb_unregister_atomic_notify(&mdwc->usbdev_nb);
 		if (!IS_ERR(mdwc->vbus_reg))
 			ret = regulator_disable(mdwc->vbus_reg);
 		if (ret) {
@@ -3884,11 +3946,12 @@
 		break;
 
 	case OTG_STATE_A_HOST:
-		if (test_bit(ID, &mdwc->inputs)) {
-			dev_dbg(mdwc->dev, "id\n");
+		if (test_bit(ID, &mdwc->inputs) || mdwc->hc_died) {
+			dev_dbg(mdwc->dev, "id || hc_died\n");
 			dwc3_otg_start_host(mdwc, 0);
 			mdwc->otg_state = OTG_STATE_B_IDLE;
 			mdwc->vbus_retry_count = 0;
+			mdwc->hc_died = false;
 			work = 1;
 		} else {
 			dev_dbg(mdwc->dev, "still in a_host state. Resuming root hub.\n");
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 264d9af..a5d3209f 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2099,6 +2099,18 @@
 	u32			reg;
 
 	dbg_event(0xFF, "__Gadgetstart", 0);
+
+	/*
+	 * Use IMOD if enabled via dwc->imod_interval. Otherwise, if
+	 * the core supports IMOD, disable it.
+	 */
+	if (dwc->imod_interval) {
+		dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
+	} else if (dwc3_has_imod(dwc)) {
+		dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), 0);
+	}
+
 	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
 	reg &= ~(DWC3_DCFG_SPEED_MASK);
 
@@ -3473,8 +3485,6 @@
 		 */
 		evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
 		left -= 4;
-
-		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 4);
 	}
 
 	dwc->bh_handled_evt_cnt[dwc->bh_dbg_index] += (evt->count / 4);
@@ -3487,9 +3497,22 @@
 	reg &= ~DWC3_GEVNTSIZ_INTMASK;
 	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg);
 
+	if (dwc->imod_interval)
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0),
+				DWC3_GEVNTCOUNT_EHB);
+
 	return ret;
 }
 
+void dwc3_bh_work(struct work_struct *w)
+{
+	struct dwc3 *dwc = container_of(w, struct dwc3, bh_work);
+
+	 pm_runtime_get_sync(dwc->dev);
+	 dwc3_thread_interrupt(dwc->irq, dwc);
+	 pm_runtime_put(dwc->dev);
+}
+
 static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
 {
 	struct dwc3 *dwc = _dwc;
@@ -3543,6 +3566,8 @@
 	reg |= DWC3_GEVNTSIZ_INTMASK;
 	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg);
 
+	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count);
+
 	return IRQ_WAKE_THREAD;
 }
 
@@ -3572,7 +3597,7 @@
 	dwc->irq_dbg_index = (dwc->irq_dbg_index + 1) % MAX_INTR_STATS;
 
 	if (ret == IRQ_WAKE_THREAD)
-		dwc3_thread_interrupt(dwc->irq, dwc);
+		queue_work(dwc->dwc_wq, &dwc->bh_work);
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index 990f423..e973ad3 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -97,6 +97,7 @@
 int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
 void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force);
 irqreturn_t dwc3_interrupt(int irq, void *_dwc);
+void dwc3_bh_work(struct work_struct *w);
 
 static inline dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
 		struct dwc3_trb *trb)
diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c
index daca68b..46df732 100644
--- a/drivers/usb/gadget/function/f_accessory.c
+++ b/drivers/usb/gadget/function/f_accessory.c
@@ -611,8 +611,7 @@
 {
 	struct acc_dev *dev = fp->private_data;
 	struct usb_request *req;
-	ssize_t r = count;
-	unsigned xfer;
+	ssize_t r = count, xfer, len;
 	int ret = 0;
 
 	pr_debug("acc_read(%zu)\n", count);
@@ -633,6 +632,8 @@
 		goto done;
 	}
 
+	len = ALIGN(count, dev->ep_out->maxpacket);
+
 	if (dev->rx_done) {
 		// last req cancelled. try to get it.
 		req = dev->rx_req[0];
@@ -642,7 +643,7 @@
 requeue_req:
 	/* queue a request */
 	req = dev->rx_req[0];
-	req->length = count;
+	req->length = len;
 	dev->rx_done = 0;
 	ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL);
 	if (ret < 0) {
@@ -941,6 +942,8 @@
 			memset(dev->serial, 0, sizeof(dev->serial));
 			dev->start_requested = 0;
 			dev->audio_mode = 0;
+			strlcpy(dev->manufacturer, "Android", ACC_STRING_SIZE);
+			strlcpy(dev->model, "Android", ACC_STRING_SIZE);
 		}
 	}
 
@@ -1251,13 +1254,13 @@
 	INIT_DELAYED_WORK(&dev->start_work, acc_start_work);
 	INIT_WORK(&dev->hid_work, acc_hid_work);
 
-	/* _acc_dev must be set before calling usb_gadget_register_driver */
-	_acc_dev = dev;
-
 	ret = misc_register(&acc_device);
 	if (ret)
 		goto err;
 
+	/* _acc_dev must be set before calling usb_gadget_register_driver */
+	_acc_dev = dev;
+
 	return 0;
 
 err:
diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c
index a30766c..5e3828d 100644
--- a/drivers/usb/gadget/function/f_acm.c
+++ b/drivers/usb/gadget/function/f_acm.c
@@ -535,13 +535,15 @@
 {
 	struct usb_composite_dev *cdev = acm->port.func.config->cdev;
 	int			status;
+	__le16			serial_state;
 
 	spin_lock(&acm->lock);
 	if (acm->notify_req) {
 		dev_dbg(&cdev->gadget->dev, "acm ttyGS%d serial state %04x\n",
 			acm->port_num, acm->serial_state);
+		serial_state = cpu_to_le16(acm->serial_state);
 		status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE,
-				0, &acm->serial_state, sizeof(acm->serial_state));
+				0, &serial_state, sizeof(acm->serial_state));
 	} else {
 		acm->pending = true;
 		status = 0;
diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c
index db7903d..a2a9185 100644
--- a/drivers/usb/gadget/function/f_audio_source.c
+++ b/drivers/usb/gadget/function/f_audio_source.c
@@ -989,6 +989,7 @@
 
 struct device *create_function_device(char *name);
 
+#define AUDIO_SOURCE_DEV_NAME_LENGTH 20
 static struct usb_function_instance *audio_source_alloc_inst(void)
 {
 	struct audio_source_instance *fi_audio;
@@ -997,6 +998,8 @@
 	struct device *dev;
 	void *err_ptr;
 	int err = 0;
+	char device_name[AUDIO_SOURCE_DEV_NAME_LENGTH];
+	static u8 count;
 
 	fi_audio = kzalloc(sizeof(*fi_audio), GFP_KERNEL);
 	if (!fi_audio)
@@ -1014,7 +1017,11 @@
 
 	config_group_init_type_name(&fi_audio->func_inst.group, "",
 						&audio_source_func_type);
-	dev = create_function_device("f_audio_source");
+
+	snprintf(device_name, AUDIO_SOURCE_DEV_NAME_LENGTH,
+					"f_audio_source%d", count++);
+
+	dev = create_function_device(device_name);
 
 	if (IS_ERR(dev)) {
 		err_ptr = dev;
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index c807b12..12e94d5 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -1562,13 +1562,6 @@
 			event->bNotificationType, req->status);
 		/* FALLTHROUGH */
 	case 0:
-		/*
-		 * handle multiple pending resp available
-		 * notifications by queuing same until we're done,
-		 * rest of the notification require queuing new
-		 * request.
-		 */
-		gsi_ctrl_send_notification(gsi);
 		break;
 	}
 }
@@ -1663,6 +1656,14 @@
 	gsi_ctrl_send_cpkt_tomodem(gsi, req->buf, 0);
 }
 
+static void gsi_ctrl_send_response_complete(struct usb_ep *ep,
+		struct usb_request *req)
+{
+	struct f_gsi *gsi = req->context;
+
+	gsi_ctrl_send_notification(gsi);
+}
+
 static int
 gsi_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
 {
@@ -1749,6 +1750,8 @@
 		memcpy(req->buf, cpkt->buf, value);
 		gsi_ctrl_pkt_free(cpkt);
 
+		req->complete = gsi_ctrl_send_response_complete;
+		req->context = gsi;
 		log_event_dbg("copied encap_resp %d bytes",
 			value);
 		break;
@@ -3047,6 +3050,9 @@
 {
 	struct gsi_opts *opts = container_of(f, struct gsi_opts, func_inst);
 
+	if (!opts->gsi)
+		return;
+
 	if (opts->gsi->c_port.ctrl_device.fops)
 		misc_deregister(&opts->gsi->c_port.ctrl_device);
 
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index a832d27..fbe6910 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -1284,7 +1284,7 @@
 	card = midi->card;
 	midi->card = NULL;
 	if (card)
-		snd_card_free(card);
+		snd_card_free_when_closed(card);
 
 	usb_free_all_descriptors(f);
 }
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index 4d8694a..c6aa884 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -1425,6 +1425,7 @@
 	struct usb_request *req;
 	int i;
 
+	mtp_string_defs[INTERFACE_STRING_INDEX].id = 0;
 	while ((req = mtp_req_get(dev, &dev->tx_idle)))
 		mtp_request_free(req, dev->ep_in);
 	for (i = 0; i < RX_REQ_MAX; i++)
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 29b41b5..c7689d0 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -625,7 +625,7 @@
 	uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst;
 	uvc_ss_streaming_comp.wBytesPerInterval =
 		cpu_to_le16(max_packet_size * max_packet_mult *
-			    opts->streaming_maxburst);
+			    (opts->streaming_maxburst + 1));
 
 	/* Allocate endpoints. */
 	ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 7558021..681b77a 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -407,11 +407,20 @@
 				return -ENOMEM;
 
 			}
-			xhci_queue_stop_endpoint(xhci, command, slot_id, i,
-						 suspend);
+
+			ret = xhci_queue_stop_endpoint(xhci, command, slot_id,
+					i, suspend);
+			if (ret) {
+				spin_unlock_irqrestore(&xhci->lock, flags);
+				goto err_cmd_queue;
+			}
 		}
 	}
-	xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend);
+	ret = xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend);
+	if (ret) {
+		spin_unlock_irqrestore(&xhci->lock, flags);
+		goto err_cmd_queue;
+	}
 	xhci_ring_cmd_db(xhci);
 	spin_unlock_irqrestore(&xhci->lock, flags);
 
@@ -422,6 +431,8 @@
 		xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n");
 		ret = -ETIME;
 	}
+
+err_cmd_queue:
 	xhci_free_command(xhci, cmd);
 	return ret;
 }
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index f33f972..6d5f01a 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -136,6 +136,59 @@
 MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
 #endif
 
+static ssize_t config_imod_store(struct device *pdev,
+		struct device_attribute *attr, const char *buff, size_t size)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(pdev);
+	struct xhci_hcd *xhci;
+	u32 temp;
+	u32 imod;
+	unsigned long flags;
+
+	if (kstrtouint(buff, 10, &imod) != 1)
+		return 0;
+
+	imod &= ER_IRQ_INTERVAL_MASK;
+	xhci = hcd_to_xhci(hcd);
+
+	if (xhci->shared_hcd->state == HC_STATE_SUSPENDED
+		&& hcd->state == HC_STATE_SUSPENDED)
+		return -EACCES;
+
+	spin_lock_irqsave(&xhci->lock, flags);
+	temp = readl_relaxed(&xhci->ir_set->irq_control);
+	temp &= ~ER_IRQ_INTERVAL_MASK;
+	temp |= imod;
+	writel_relaxed(temp, &xhci->ir_set->irq_control);
+	spin_unlock_irqrestore(&xhci->lock, flags);
+
+	return size;
+}
+
+static ssize_t config_imod_show(struct device *pdev,
+		struct device_attribute *attr, char *buff)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(pdev);
+	struct xhci_hcd *xhci;
+	u32 temp;
+	unsigned long flags;
+
+	xhci = hcd_to_xhci(hcd);
+
+	if (xhci->shared_hcd->state == HC_STATE_SUSPENDED
+		&& hcd->state == HC_STATE_SUSPENDED)
+		return -EACCES;
+
+	spin_lock_irqsave(&xhci->lock, flags);
+	temp = readl_relaxed(&xhci->ir_set->irq_control) &
+			ER_IRQ_INTERVAL_MASK;
+	spin_unlock_irqrestore(&xhci->lock, flags);
+
+	return snprintf(buff, PAGE_SIZE, "%08u\n", temp);
+}
+
+static DEVICE_ATTR(config_imod, 0644, config_imod_show, config_imod_store);
+
 static int xhci_plat_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *match;
@@ -267,17 +320,22 @@
 			goto put_usb3_hcd;
 	}
 
-	ret = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_ONESHOT);
+	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (ret)
 		goto disable_usb_phy;
 
 	if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
 		xhci->shared_hcd->can_do_streams = 1;
 
-	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED | IRQF_ONESHOT);
+	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
 	if (ret)
 		goto dealloc_usb2_hcd;
 
+	ret = device_create_file(&pdev->dev, &dev_attr_config_imod);
+	if (ret)
+		dev_err(&pdev->dev, "%s: unable to create imod sysfs entry\n",
+					__func__);
+
 	pm_runtime_mark_last_busy(&pdev->dev);
 	pm_runtime_put_autosuspend(&pdev->dev);
 
@@ -312,6 +370,7 @@
 	pm_runtime_disable(&dev->dev);
 	xhci->xhc_state |= XHCI_STATE_REMOVING;
 
+	device_remove_file(&dev->dev, &dev_attr_config_imod);
 	usb_remove_hcd(xhci->shared_hcd);
 	usb_phy_shutdown(hcd->usb_phy);
 
@@ -352,7 +411,7 @@
 
 	dev_dbg(dev, "xhci-plat runtime suspend\n");
 
-	return xhci_suspend(xhci, true);
+	return 0;
 }
 
 static int xhci_plat_runtime_resume(struct device *dev)
@@ -366,7 +425,7 @@
 
 	dev_dbg(dev, "xhci-plat runtime resume\n");
 
-	ret = xhci_resume(xhci, false);
+	ret = 0;
 	pm_runtime_mark_last_busy(dev);
 
 	return ret;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index e7e9c07..5d434e0 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -675,7 +675,7 @@
 void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, struct xhci_ring *ring,
 				 struct xhci_td *td)
 {
-	struct device *dev = xhci_to_hcd(xhci)->self.controller;
+	struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
 	struct xhci_segment *seg = td->bounce_seg;
 	struct urb *urb = td->urb;
 
@@ -3153,7 +3153,7 @@
 static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len,
 			 u32 *trb_buff_len, struct xhci_segment *seg)
 {
-	struct device *dev = xhci_to_hcd(xhci)->self.controller;
+	struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
 	unsigned int unalign;
 	unsigned int max_pkt;
 	u32 new_buff_len;
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index 2975e80..9a67ae3 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -346,6 +346,9 @@
 	if (iface_desc->desc.bInterfaceClass != 0x0A)
 		return -ENODEV;
 
+	if (iface_desc->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	/* allocate memory for our device state and initialize it */
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (dev == NULL)
diff --git a/drivers/usb/misc/lvstest.c b/drivers/usb/misc/lvstest.c
index 7717651..d3d1247 100644
--- a/drivers/usb/misc/lvstest.c
+++ b/drivers/usb/misc/lvstest.c
@@ -366,6 +366,10 @@
 
 	hdev = interface_to_usbdev(intf);
 	desc = intf->cur_altsetting;
+
+	if (desc->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	endpoint = &desc->endpoint[0].desc;
 
 	/* valid only for SS root hub */
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 356d312..9ff6652 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -708,6 +708,11 @@
 
 	interface = intf->cur_altsetting;
 
+	if (interface->desc.bNumEndpoints < 3) {
+		usb_put_dev(usbdev);
+		return -ENODEV;
+	}
+
 	/*
 	 * Allocate parport interface 
 	 */
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 338575f..358feca 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -2467,8 +2467,8 @@
 	pm_runtime_get_sync(musb->controller);
 	musb_host_cleanup(musb);
 	musb_gadget_cleanup(musb);
-	spin_lock_irqsave(&musb->lock, flags);
 	musb_platform_disable(musb);
+	spin_lock_irqsave(&musb->lock, flags);
 	musb_generic_disable(musb);
 	spin_unlock_irqrestore(&musb->lock, flags);
 	musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c
index d4d7c56..cb443df 100644
--- a/drivers/usb/musb/musb_cppi41.c
+++ b/drivers/usb/musb/musb_cppi41.c
@@ -232,8 +232,27 @@
 			transferred < cppi41_channel->packet_sz)
 		cppi41_channel->prog_len = 0;
 
-	if (cppi41_channel->is_tx)
-		empty = musb_is_tx_fifo_empty(hw_ep);
+	if (cppi41_channel->is_tx) {
+		u8 type;
+
+		if (is_host_active(musb))
+			type = hw_ep->out_qh->type;
+		else
+			type = hw_ep->ep_in.type;
+
+		if (type == USB_ENDPOINT_XFER_ISOC)
+			/*
+			 * Don't use the early-TX-interrupt workaround below
+			 * for Isoch transfter. Since Isoch are periodic
+			 * transfer, by the time the next transfer is
+			 * scheduled, the current one should be done already.
+			 *
+			 * This avoids audio playback underrun issue.
+			 */
+			empty = true;
+		else
+			empty = musb_is_tx_fifo_empty(hw_ep);
+	}
 
 	if (!cppi41_channel->is_tx || empty) {
 		cppi41_trans_done(cppi41_channel);
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 42cc72e..af67a0d 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -233,6 +233,14 @@
 #define BANDRICH_PRODUCT_1012			0x1012
 
 #define QUALCOMM_VENDOR_ID			0x05C6
+/* These Quectel products use Qualcomm's vendor ID */
+#define QUECTEL_PRODUCT_UC20			0x9003
+#define QUECTEL_PRODUCT_UC15			0x9090
+
+#define QUECTEL_VENDOR_ID			0x2c7c
+/* These Quectel products use Quectel's vendor ID */
+#define QUECTEL_PRODUCT_EC21			0x0121
+#define QUECTEL_PRODUCT_EC25			0x0125
 
 #define CMOTECH_VENDOR_ID			0x16d8
 #define CMOTECH_PRODUCT_6001			0x6001
@@ -1161,7 +1169,14 @@
 	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
 	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */
 	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
-	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9003), /* Quectel UC20 */
+	/* Quectel products using Qualcomm vendor ID */
+	{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)},
+	{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20),
+	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	/* Quectel products using Quectel vendor ID */
+	{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC21),
+	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC25),
 	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 696458d..38b3f0d 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -169,6 +169,8 @@
 	{DEVICE_SWI(0x413c, 0x81a9)},	/* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
 	{DEVICE_SWI(0x413c, 0x81b1)},	/* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
 	{DEVICE_SWI(0x413c, 0x81b3)},	/* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
+	{DEVICE_SWI(0x413c, 0x81b5)},	/* Dell Wireless 5811e QDL */
+	{DEVICE_SWI(0x413c, 0x81b6)},	/* Dell Wireless 5811e QDL */
 
 	/* Huawei devices */
 	{DEVICE_HWI(0x03f0, 0x581d)},	/* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */
diff --git a/drivers/usb/wusbcore/wa-hc.c b/drivers/usb/wusbcore/wa-hc.c
index 252c7bd..d01496f 100644
--- a/drivers/usb/wusbcore/wa-hc.c
+++ b/drivers/usb/wusbcore/wa-hc.c
@@ -39,6 +39,9 @@
 	int result;
 	struct device *dev = &iface->dev;
 
+	if (iface->cur_altsetting->desc.bNumEndpoints < 3)
+		return -ENODEV;
+
 	result = wa_rpipes_create(wa);
 	if (result < 0)
 		goto error_rpipes_create;
diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c
index 0aa6c3c..35a1e77 100644
--- a/drivers/uwb/hwa-rc.c
+++ b/drivers/uwb/hwa-rc.c
@@ -823,6 +823,9 @@
 	struct hwarc *hwarc;
 	struct device *dev = &iface->dev;
 
+	if (iface->cur_altsetting->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	result = -ENOMEM;
 	uwb_rc = uwb_rc_alloc();
 	if (uwb_rc == NULL) {
diff --git a/drivers/uwb/i1480/dfu/usb.c b/drivers/uwb/i1480/dfu/usb.c
index 2bfc846..6345e85 100644
--- a/drivers/uwb/i1480/dfu/usb.c
+++ b/drivers/uwb/i1480/dfu/usb.c
@@ -362,6 +362,9 @@
 				 result);
 	}
 
+	if (iface->cur_altsetting->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	result = -ENOMEM;
 	i1480_usb = kzalloc(sizeof(*i1480_usb), GFP_KERNEL);
 	if (i1480_usb == NULL) {
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 288318a..16c8fcf 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -199,6 +199,11 @@
 	if (rc)
 		return rc;
 
+	bd->usr_brightness_req = brightness;
+	brightness = (brightness <= bd->thermal_brightness_limit) ?
+				bd->usr_brightness_req :
+				bd->thermal_brightness_limit;
+
 	rc = backlight_device_set_brightness(bd, brightness);
 
 	return rc ? rc : count;
@@ -310,6 +315,63 @@
 }
 EXPORT_SYMBOL(backlight_force_update);
 
+static int bd_cdev_get_max_brightness(struct thermal_cooling_device *cdev,
+					unsigned long *state)
+{
+	struct backlight_device *bd = (struct backlight_device *)cdev->devdata;
+
+	*state = bd->props.max_brightness;
+
+	return 0;
+}
+
+static int bd_cdev_get_cur_brightness(struct thermal_cooling_device *cdev,
+					unsigned long *state)
+{
+	struct backlight_device *bd = (struct backlight_device *)cdev->devdata;
+
+	*state = bd->props.max_brightness - bd->thermal_brightness_limit;
+
+	return 0;
+}
+
+static int bd_cdev_set_cur_brightness(struct thermal_cooling_device *cdev,
+					unsigned long state)
+{
+	struct backlight_device *bd = (struct backlight_device *)cdev->devdata;
+	int brightness_lvl;
+
+	brightness_lvl = bd->props.max_brightness - state;
+	if (brightness_lvl == bd->thermal_brightness_limit)
+		return 0;
+
+	bd->thermal_brightness_limit = brightness_lvl;
+	brightness_lvl = (bd->usr_brightness_req
+				<= bd->thermal_brightness_limit) ?
+				bd->usr_brightness_req :
+				bd->thermal_brightness_limit;
+	backlight_device_set_brightness(bd, brightness_lvl);
+
+	return 0;
+}
+
+static struct thermal_cooling_device_ops bd_cdev_ops = {
+	.get_max_state = bd_cdev_get_max_brightness,
+	.get_cur_state = bd_cdev_get_cur_brightness,
+	.set_cur_state = bd_cdev_set_cur_brightness,
+};
+
+static void backlight_cdev_register(struct device *parent,
+				    struct backlight_device *bd)
+{
+	if (of_find_property(parent->of_node, "#cooling-cells", NULL)) {
+		bd->cdev = thermal_of_cooling_device_register(parent->of_node,
+				(char *)dev_name(&bd->dev), bd, &bd_cdev_ops);
+		if (!bd->cdev)
+			pr_err("Cooling device register failed\n");
+	}
+}
+
 /**
  * backlight_device_register - create and register a new object of
  *   backlight_device class.
@@ -353,6 +415,8 @@
 			WARN(1, "%s: invalid backlight type", name);
 			new_bd->props.type = BACKLIGHT_RAW;
 		}
+		new_bd->thermal_brightness_limit = props->max_brightness;
+		new_bd->usr_brightness_req = props->brightness;
 	} else {
 		new_bd->props.type = BACKLIGHT_RAW;
 	}
@@ -369,6 +433,7 @@
 		return ERR_PTR(rc);
 	}
 
+	backlight_cdev_register(parent, new_bd);
 	new_bd->ops = ops;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index b87f5cf..4db10d7 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -1167,6 +1167,8 @@
 	p->userfont = 0;
 }
 
+static void set_vc_hi_font(struct vc_data *vc, bool set);
+
 static void fbcon_deinit(struct vc_data *vc)
 {
 	struct display *p = &fb_display[vc->vc_num];
@@ -1202,6 +1204,9 @@
 	if (free_font)
 		vc->vc_font.data = NULL;
 
+	if (vc->vc_hi_font_mask)
+		set_vc_hi_font(vc, false);
+
 	if (!con_is_bound(&fb_con))
 		fbcon_exit();
 
@@ -2438,32 +2443,10 @@
 	return 0;
 }
 
-static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
-			     const u8 * data, int userfont)
+/* set/clear vc_hi_font_mask and update vc attrs accordingly */
+static void set_vc_hi_font(struct vc_data *vc, bool set)
 {
-	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
-	struct fbcon_ops *ops = info->fbcon_par;
-	struct display *p = &fb_display[vc->vc_num];
-	int resize;
-	int cnt;
-	char *old_data = NULL;
-
-	if (con_is_visible(vc) && softback_lines)
-		fbcon_set_origin(vc);
-
-	resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
-	if (p->userfont)
-		old_data = vc->vc_font.data;
-	if (userfont)
-		cnt = FNTCHARCNT(data);
-	else
-		cnt = 256;
-	vc->vc_font.data = (void *)(p->fontdata = data);
-	if ((p->userfont = userfont))
-		REFCOUNT(data)++;
-	vc->vc_font.width = w;
-	vc->vc_font.height = h;
-	if (vc->vc_hi_font_mask && cnt == 256) {
+	if (!set) {
 		vc->vc_hi_font_mask = 0;
 		if (vc->vc_can_do_color) {
 			vc->vc_complement_mask >>= 1;
@@ -2486,7 +2469,7 @@
 			    ((c & 0xfe00) >> 1) | (c & 0xff);
 			vc->vc_attr >>= 1;
 		}
-	} else if (!vc->vc_hi_font_mask && cnt == 512) {
+	} else {
 		vc->vc_hi_font_mask = 0x100;
 		if (vc->vc_can_do_color) {
 			vc->vc_complement_mask <<= 1;
@@ -2518,8 +2501,38 @@
 			} else
 				vc->vc_video_erase_char = c & ~0x100;
 		}
-
 	}
+}
+
+static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
+			     const u8 * data, int userfont)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct fbcon_ops *ops = info->fbcon_par;
+	struct display *p = &fb_display[vc->vc_num];
+	int resize;
+	int cnt;
+	char *old_data = NULL;
+
+	if (con_is_visible(vc) && softback_lines)
+		fbcon_set_origin(vc);
+
+	resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
+	if (p->userfont)
+		old_data = vc->vc_font.data;
+	if (userfont)
+		cnt = FNTCHARCNT(data);
+	else
+		cnt = 256;
+	vc->vc_font.data = (void *)(p->fontdata = data);
+	if ((p->userfont = userfont))
+		REFCOUNT(data)++;
+	vc->vc_font.width = w;
+	vc->vc_font.height = h;
+	if (vc->vc_hi_font_mask && cnt == 256)
+		set_vc_hi_font(vc, false);
+	else if (!vc->vc_hi_font_mask && cnt == 512)
+		set_vc_hi_font(vc, true);
 
 	if (resize) {
 		int cols, rows;
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 9d2738e..2c2e679 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -427,6 +427,8 @@
 		 * Prime this virtqueue with one buffer so the hypervisor can
 		 * use it to signal us later (it can't be broken yet!).
 		 */
+		update_balloon_stats(vb);
+
 		sg_init_one(&sg, vb->stats, sizeof vb->stats);
 		if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
 		    < 0)
diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c
index 4ce10bc..4b85746 100644
--- a/drivers/xen/xen-acpi-processor.c
+++ b/drivers/xen/xen-acpi-processor.c
@@ -27,10 +27,10 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/syscore_ops.h>
 #include <linux/acpi.h>
 #include <acpi/processor.h>
 #include <xen/xen.h>
-#include <xen/xen-ops.h>
 #include <xen/interface/platform.h>
 #include <asm/xen/hypercall.h>
 
@@ -466,15 +466,33 @@
 	return rc;
 }
 
-static int xen_acpi_processor_resume(struct notifier_block *nb,
-				     unsigned long action, void *data)
+static void xen_acpi_processor_resume_worker(struct work_struct *dummy)
 {
+	int rc;
+
 	bitmap_zero(acpi_ids_done, nr_acpi_bits);
-	return xen_upload_processor_pm_data();
+
+	rc = xen_upload_processor_pm_data();
+	if (rc != 0)
+		pr_info("ACPI data upload failed, error = %d\n", rc);
 }
 
-struct notifier_block xen_acpi_processor_resume_nb = {
-	.notifier_call = xen_acpi_processor_resume,
+static void xen_acpi_processor_resume(void)
+{
+	static DECLARE_WORK(wq, xen_acpi_processor_resume_worker);
+
+	/*
+	 * xen_upload_processor_pm_data() calls non-atomic code.
+	 * However, the context for xen_acpi_processor_resume is syscore
+	 * with only the boot CPU online and in an atomic context.
+	 *
+	 * So defer the upload for some point safer.
+	 */
+	schedule_work(&wq);
+}
+
+static struct syscore_ops xap_syscore_ops = {
+	.resume	= xen_acpi_processor_resume,
 };
 
 static int __init xen_acpi_processor_init(void)
@@ -527,7 +545,7 @@
 	if (rc)
 		goto err_unregister;
 
-	xen_resume_notifier_register(&xen_acpi_processor_resume_nb);
+	register_syscore_ops(&xap_syscore_ops);
 
 	return 0;
 err_unregister:
@@ -544,7 +562,7 @@
 {
 	int i;
 
-	xen_resume_notifier_unregister(&xen_acpi_processor_resume_nb);
+	unregister_syscore_ops(&xap_syscore_ops);
 	kfree(acpi_ids_done);
 	kfree(acpi_id_present);
 	kfree(acpi_id_cst_present);
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 98f87fe..61cfcce 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -352,7 +352,6 @@
 static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	struct dentry *dir;
-	struct fscrypt_info *ci;
 	int dir_has_key, cached_with_key;
 
 	if (flags & LOOKUP_RCU)
@@ -364,18 +363,11 @@
 		return 0;
 	}
 
-	ci = d_inode(dir)->i_crypt_info;
-	if (ci && ci->ci_keyring_key &&
-	    (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) |
-					  (1 << KEY_FLAG_REVOKED) |
-					  (1 << KEY_FLAG_DEAD))))
-		ci = NULL;
-
 	/* this should eventually be an flag in d_flags */
 	spin_lock(&dentry->d_lock);
 	cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY;
 	spin_unlock(&dentry->d_lock);
-	dir_has_key = (ci != NULL);
+	dir_has_key = (d_inode(dir)->i_crypt_info != NULL);
 	dput(dir);
 
 	/*
diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
index 9b774f4..80bb956 100644
--- a/fs/crypto/fname.c
+++ b/fs/crypto/fname.c
@@ -350,7 +350,7 @@
 		fname->disk_name.len = iname->len;
 		return 0;
 	}
-	ret = get_crypt_info(dir);
+	ret = fscrypt_get_encryption_info(dir);
 	if (ret && ret != -EOPNOTSUPP)
 		return ret;
 
diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c
index 67fb6d8..bb46063 100644
--- a/fs/crypto/keyinfo.c
+++ b/fs/crypto/keyinfo.c
@@ -99,6 +99,7 @@
 	kfree(full_key_descriptor);
 	if (IS_ERR(keyring_key))
 		return PTR_ERR(keyring_key);
+	down_read(&keyring_key->sem);
 
 	if (keyring_key->type != &key_type_logon) {
 		printk_once(KERN_WARNING
@@ -106,11 +107,9 @@
 		res = -ENOKEY;
 		goto out;
 	}
-	down_read(&keyring_key->sem);
 	ukp = user_key_payload(keyring_key);
 	if (ukp->datalen != sizeof(struct fscrypt_key)) {
 		res = -EINVAL;
-		up_read(&keyring_key->sem);
 		goto out;
 	}
 	master_key = (struct fscrypt_key *)ukp->data;
@@ -121,17 +120,11 @@
 				"%s: key size incorrect: %d\n",
 				__func__, master_key->size);
 		res = -ENOKEY;
-		up_read(&keyring_key->sem);
 		goto out;
 	}
 	res = derive_key_aes(ctx->nonce, master_key->raw, raw_key);
-	up_read(&keyring_key->sem);
-	if (res)
-		goto out;
-
-	crypt_info->ci_keyring_key = keyring_key;
-	return 0;
 out:
+	up_read(&keyring_key->sem);
 	key_put(keyring_key);
 	return res;
 }
@@ -173,12 +166,11 @@
 	if (!ci)
 		return;
 
-	key_put(ci->ci_keyring_key);
 	crypto_free_skcipher(ci->ci_ctfm);
 	kmem_cache_free(fscrypt_info_cachep, ci);
 }
 
-int get_crypt_info(struct inode *inode)
+int fscrypt_get_encryption_info(struct inode *inode)
 {
 	struct fscrypt_info *crypt_info;
 	struct fscrypt_context ctx;
@@ -188,21 +180,15 @@
 	u8 *raw_key = NULL;
 	int res;
 
+	if (inode->i_crypt_info)
+		return 0;
+
 	res = fscrypt_initialize();
 	if (res)
 		return res;
 
 	if (!inode->i_sb->s_cop->get_context)
 		return -EOPNOTSUPP;
-retry:
-	crypt_info = ACCESS_ONCE(inode->i_crypt_info);
-	if (crypt_info) {
-		if (!crypt_info->ci_keyring_key ||
-				key_validate(crypt_info->ci_keyring_key) == 0)
-			return 0;
-		fscrypt_put_encryption_info(inode, crypt_info);
-		goto retry;
-	}
 
 	res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
 	if (res < 0) {
@@ -230,7 +216,6 @@
 	crypt_info->ci_data_mode = ctx.contents_encryption_mode;
 	crypt_info->ci_filename_mode = ctx.filenames_encryption_mode;
 	crypt_info->ci_ctfm = NULL;
-	crypt_info->ci_keyring_key = NULL;
 	memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
 				sizeof(crypt_info->ci_master_key));
 
@@ -285,14 +270,8 @@
 	if (res)
 		goto out;
 
-	kzfree(raw_key);
-	raw_key = NULL;
-	if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) {
-		put_crypt_info(crypt_info);
-		goto retry;
-	}
-	return 0;
-
+	if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL)
+		crypt_info = NULL;
 out:
 	if (res == -ENOKEY)
 		res = 0;
@@ -300,6 +279,7 @@
 	kzfree(raw_key);
 	return res;
 }
+EXPORT_SYMBOL(fscrypt_get_encryption_info);
 
 void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci)
 {
@@ -317,17 +297,3 @@
 	put_crypt_info(ci);
 }
 EXPORT_SYMBOL(fscrypt_put_encryption_info);
-
-int fscrypt_get_encryption_info(struct inode *inode)
-{
-	struct fscrypt_info *ci = inode->i_crypt_info;
-
-	if (!ci ||
-		(ci->ci_keyring_key &&
-		 (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) |
-					       (1 << KEY_FLAG_REVOKED) |
-					       (1 << KEY_FLAG_DEAD)))))
-		return get_crypt_info(inode);
-	return 0;
-}
-EXPORT_SYMBOL(fscrypt_get_encryption_info);
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 004eebb..a5807fd 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -1171,10 +1171,9 @@
 	set_buffer_uptodate(dir_block);
 	err = ext4_handle_dirty_dirent_node(handle, inode, dir_block);
 	if (err)
-		goto out;
+		return err;
 	set_buffer_verified(dir_block);
-out:
-	return err;
+	return ext4_mark_inode_dirty(handle, inode);
 }
 
 static int ext4_convert_inline_data_nolock(handle_t *handle,
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 4448ed3..3eeed8f 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -131,31 +131,26 @@
 }
 
 static int ext4_xattr_block_csum_verify(struct inode *inode,
-					sector_t block_nr,
-					struct ext4_xattr_header *hdr)
+					struct buffer_head *bh)
 {
-	if (ext4_has_metadata_csum(inode->i_sb) &&
-	    (hdr->h_checksum != ext4_xattr_block_csum(inode, block_nr, hdr)))
-		return 0;
-	return 1;
+	struct ext4_xattr_header *hdr = BHDR(bh);
+	int ret = 1;
+
+	if (ext4_has_metadata_csum(inode->i_sb)) {
+		lock_buffer(bh);
+		ret = (hdr->h_checksum == ext4_xattr_block_csum(inode,
+							bh->b_blocknr, hdr));
+		unlock_buffer(bh);
+	}
+	return ret;
 }
 
 static void ext4_xattr_block_csum_set(struct inode *inode,
-				      sector_t block_nr,
-				      struct ext4_xattr_header *hdr)
+				      struct buffer_head *bh)
 {
-	if (!ext4_has_metadata_csum(inode->i_sb))
-		return;
-
-	hdr->h_checksum = ext4_xattr_block_csum(inode, block_nr, hdr);
-}
-
-static inline int ext4_handle_dirty_xattr_block(handle_t *handle,
-						struct inode *inode,
-						struct buffer_head *bh)
-{
-	ext4_xattr_block_csum_set(inode, bh->b_blocknr, BHDR(bh));
-	return ext4_handle_dirty_metadata(handle, inode, bh);
+	if (ext4_has_metadata_csum(inode->i_sb))
+		BHDR(bh)->h_checksum = ext4_xattr_block_csum(inode,
+						bh->b_blocknr, BHDR(bh));
 }
 
 static inline const struct xattr_handler *
@@ -218,7 +213,7 @@
 	if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
 	    BHDR(bh)->h_blocks != cpu_to_le32(1))
 		return -EFSCORRUPTED;
-	if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh)))
+	if (!ext4_xattr_block_csum_verify(inode, bh))
 		return -EFSBADCRC;
 	error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size,
 				       bh->b_data);
@@ -601,23 +596,22 @@
 			}
 		}
 
+		ext4_xattr_block_csum_set(inode, bh);
 		/*
 		 * Beware of this ugliness: Releasing of xattr block references
 		 * from different inodes can race and so we have to protect
 		 * from a race where someone else frees the block (and releases
 		 * its journal_head) before we are done dirtying the buffer. In
 		 * nojournal mode this race is harmless and we actually cannot
-		 * call ext4_handle_dirty_xattr_block() with locked buffer as
+		 * call ext4_handle_dirty_metadata() with locked buffer as
 		 * that function can call sync_dirty_buffer() so for that case
 		 * we handle the dirtying after unlocking the buffer.
 		 */
 		if (ext4_handle_valid(handle))
-			error = ext4_handle_dirty_xattr_block(handle, inode,
-							      bh);
+			error = ext4_handle_dirty_metadata(handle, inode, bh);
 		unlock_buffer(bh);
 		if (!ext4_handle_valid(handle))
-			error = ext4_handle_dirty_xattr_block(handle, inode,
-							      bh);
+			error = ext4_handle_dirty_metadata(handle, inode, bh);
 		if (IS_SYNC(inode))
 			ext4_handle_sync(handle);
 		dquot_free_block(inode, EXT4_C2B(EXT4_SB(inode->i_sb), 1));
@@ -846,13 +840,14 @@
 				ext4_xattr_cache_insert(ext4_mb_cache,
 					bs->bh);
 			}
+			ext4_xattr_block_csum_set(inode, bs->bh);
 			unlock_buffer(bs->bh);
 			if (error == -EFSCORRUPTED)
 				goto bad_block;
 			if (!error)
-				error = ext4_handle_dirty_xattr_block(handle,
-								      inode,
-								      bs->bh);
+				error = ext4_handle_dirty_metadata(handle,
+								   inode,
+								   bs->bh);
 			if (error)
 				goto cleanup;
 			goto inserted;
@@ -950,10 +945,11 @@
 					ce->e_reusable = 0;
 				ea_bdebug(new_bh, "reusing; refcount now=%d",
 					  ref);
+				ext4_xattr_block_csum_set(inode, new_bh);
 				unlock_buffer(new_bh);
-				error = ext4_handle_dirty_xattr_block(handle,
-								      inode,
-								      new_bh);
+				error = ext4_handle_dirty_metadata(handle,
+								   inode,
+								   new_bh);
 				if (error)
 					goto cleanup_dquot;
 			}
@@ -1003,11 +999,12 @@
 				goto getblk_failed;
 			}
 			memcpy(new_bh->b_data, s->base, new_bh->b_size);
+			ext4_xattr_block_csum_set(inode, new_bh);
 			set_buffer_uptodate(new_bh);
 			unlock_buffer(new_bh);
 			ext4_xattr_cache_insert(ext4_mb_cache, new_bh);
-			error = ext4_handle_dirty_xattr_block(handle,
-							      inode, new_bh);
+			error = ext4_handle_dirty_metadata(handle, inode,
+							   new_bh);
 			if (error)
 				goto cleanup;
 		}
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 927da49..7d4b557 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -1125,10 +1125,8 @@
 
 	/* Set up a default-sized revoke table for the new mount. */
 	err = jbd2_journal_init_revoke(journal, JOURNAL_REVOKE_DEFAULT_HASH);
-	if (err) {
-		kfree(journal);
-		return NULL;
-	}
+	if (err)
+		goto err_cleanup;
 
 	spin_lock_init(&journal->j_history_lock);
 
@@ -1145,23 +1143,25 @@
 	journal->j_wbufsize = n;
 	journal->j_wbuf = kmalloc_array(n, sizeof(struct buffer_head *),
 					GFP_KERNEL);
-	if (!journal->j_wbuf) {
-		kfree(journal);
-		return NULL;
-	}
+	if (!journal->j_wbuf)
+		goto err_cleanup;
 
 	bh = getblk_unmovable(journal->j_dev, start, journal->j_blocksize);
 	if (!bh) {
 		pr_err("%s: Cannot get buffer for journal superblock\n",
 			__func__);
-		kfree(journal->j_wbuf);
-		kfree(journal);
-		return NULL;
+		goto err_cleanup;
 	}
 	journal->j_sb_buffer = bh;
 	journal->j_superblock = (journal_superblock_t *)bh->b_data;
 
 	return journal;
+
+err_cleanup:
+	kfree(journal->j_wbuf);
+	jbd2_journal_destroy_revoke(journal);
+	kfree(journal);
+	return NULL;
 }
 
 /* jbd2_journal_init_dev and jbd2_journal_init_inode:
diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c
index 91171dc..3cd7305 100644
--- a/fs/jbd2/revoke.c
+++ b/fs/jbd2/revoke.c
@@ -280,6 +280,7 @@
 
 fail1:
 	jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]);
+	journal->j_revoke_table[0] = NULL;
 fail0:
 	return -ENOMEM;
 }
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 6726440..e9fb2e8 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -361,6 +361,7 @@
 /* Event queued up for userspace to read */
 struct drm_pending_event {
 	struct completion *completion;
+	void (*completion_release)(struct completion *completion);
 	struct drm_event *event;
 	struct fence *fence;
 	struct list_head link;
diff --git a/include/dt-bindings/clock/qcom,gpucc-sdm845.h b/include/dt-bindings/clock/qcom,gpucc-sdm845.h
index 41eb823..13de1e1 100644
--- a/include/dt-bindings/clock/qcom,gpucc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,gpucc-sdm845.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -14,42 +14,42 @@
 #ifndef _DT_BINDINGS_CLK_MSM_GPU_CC_SDM845_H
 #define _DT_BINDINGS_CLK_MSM_GPU_CC_SDM845_H
 
+/* GPUCC clock registers */
 #define GPU_CC_ACD_AHB_CLK					0
 #define GPU_CC_ACD_CXO_CLK					1
-#define GPU_CC_AHB_CLK						2
+#define GPU_CC_AHB_CLK					2
 #define GPU_CC_CRC_AHB_CLK					3
 #define GPU_CC_CX_APB_CLK					4
-#define GPU_CC_CX_GFX3D_CLK					5
-#define GPU_CC_CX_GFX3D_SLV_CLK					6
-#define GPU_CC_CX_GMU_CLK					7
-#define GPU_CC_CX_QDSS_AT_CLK					8
-#define GPU_CC_CX_QDSS_TRIG_CLK					9
-#define GPU_CC_CX_QDSS_TSCTR_CLK				10
-#define GPU_CC_CX_SNOC_DVM_CLK					11
-#define GPU_CC_CXO_AON_CLK					12
-#define GPU_CC_CXO_CLK						13
-#define GPU_CC_DEBUG_CLK					14
-#define GPU_CC_GX_CXO_CLK					15
-#define GPU_CC_GX_GMU_CLK					16
-#define GPU_CC_GX_QDSS_TSCTR_CLK				17
-#define GPU_CC_GX_VSENSE_CLK					18
-#define GPU_CC_PLL0						19
-#define GPU_CC_PLL0_OUT_EVEN					20
-#define GPU_CC_PLL0_OUT_MAIN					21
-#define GPU_CC_PLL0_OUT_ODD					22
-#define GPU_CC_PLL0_OUT_TEST					23
-#define GPU_CC_PLL1						24
-#define GPU_CC_PLL1_OUT_EVEN					25
-#define GPU_CC_PLL1_OUT_MAIN					26
-#define GPU_CC_PLL1_OUT_ODD					27
-#define GPU_CC_PLL1_OUT_TEST					28
-#define GPU_CC_PLL_TEST_CLK					29
-#define GPU_CC_RBCPR_AHB_CLK					30
-#define GPU_CC_RBCPR_CLK					31
-#define GPU_CC_RBCPR_CLK_SRC					32
-#define GPU_CC_SLEEP_CLK					33
-#define GPU_CC_SPDM_GX_GFX3D_DIV_CLK				34
+#define GPU_CC_CX_GMU_CLK					5
+#define GPU_CC_CX_QDSS_AT_CLK					6
+#define GPU_CC_CX_QDSS_TRIG_CLK					7
+#define GPU_CC_CX_QDSS_TSCTR_CLK					8
+#define GPU_CC_CX_SNOC_DVM_CLK						9
+#define GPU_CC_CXO_AON_CLK					10
+#define GPU_CC_CXO_CLK					11
+#define GPU_CC_DEBUG_CLK					12
+#define GPU_CC_GX_CXO_CLK					13
+#define GPU_CC_GX_GMU_CLK					14
+#define GPU_CC_GX_QDSS_TSCTR_CLK					15
+#define GPU_CC_GX_VSENSE_CLK					16
+#define GPU_CC_PLL0_OUT_MAIN					 17
+#define GPU_CC_PLL0_OUT_ODD						18
+#define GPU_CC_PLL0_OUT_TEST					19
+#define GPU_CC_PLL1						20
+#define GPU_CC_PLL1_OUT_EVEN					21
+#define GPU_CC_PLL1_OUT_MAIN					22
+#define GPU_CC_PLL1_OUT_ODD					23
+#define GPU_CC_PLL1_OUT_TEST					24
+#define GPU_CC_PLL_TEST_CLK					25
+#define GPU_CC_RBCPR_AHB_CLK					26
+#define GPU_CC_RBCPR_CLK					27
+#define GPU_CC_RBCPR_CLK_SRC					28
+#define GPU_CC_SLEEP_CLK					29
+#define GPU_CC_GMU_CLK_SRC					30
+#define GPU_CC_CX_GFX3D_CLK					31
+#define GPU_CC_CX_GFX3D_SLV_CLK					32
 
+/* GPUCC reset clock registers */
 #define GPUCC_GPU_CC_ACD_BCR					0
 #define GPUCC_GPU_CC_CX_BCR					1
 #define GPUCC_GPU_CC_GFX3D_AON_BCR				2
@@ -59,4 +59,9 @@
 #define GPUCC_GPU_CC_SPDM_BCR					6
 #define GPUCC_GPU_CC_XO_BCR					7
 
+/* GFX3D clock registers */
+#define GPU_CC_PLL0						0
+#define GPU_CC_PLL0_OUT_EVEN					1
+#define GPU_CC_GX_GFX3D_CLK_SRC					2
+#define GPU_CC_GX_GFX3D_CLK						3
 #endif
diff --git a/include/dt-bindings/msm/msm-bus-ids.h b/include/dt-bindings/msm/msm-bus-ids.h
index 900f268..8135da9 100644
--- a/include/dt-bindings/msm/msm-bus-ids.h
+++ b/include/dt-bindings/msm/msm-bus-ids.h
@@ -42,6 +42,7 @@
 #define	MSM_BUS_FAB_DC_NOC 6150
 #define	MSM_BUS_FAB_MC_VIRT 6151
 #define	MSM_BUS_FAB_MEM_NOC 6152
+#define	MSM_BUS_FAB_IPA_VIRT 6153
 
 #define MSM_BUS_FAB_MC_VIRT_DISPLAY 26000
 #define MSM_BUS_FAB_MEM_NOC_DISPLAY 26001
@@ -86,6 +87,7 @@
 #define	MSM_BUS_BCM_CN0 7036
 #define	MSM_BUS_BCM_ACV 7037
 #define	MSM_BUS_BCM_ALC 7038
+#define	MSM_BUS_BCM_QUP0 7039
 
 #define	MSM_BUS_RSC_APPS 8000
 #define	MSM_BUS_RSC_DISP 8001
@@ -241,7 +243,8 @@
 #define	MSM_BUS_MASTER_ANOC_PCIE_SNOC 140
 #define	MSM_BUS_MASTER_PIMEM 141
 #define	MSM_BUS_MASTER_MEM_NOC_SNOC 142
-#define	MSM_BUS_MASTER_MASTER_LAST 143
+#define	MSM_BUS_MASTER_IPA_CORE 143
+#define	MSM_BUS_MASTER_MASTER_LAST 144
 
 #define MSM_BUS_MASTER_LLCC_DISPLAY 20000
 #define MSM_BUS_MASTER_MNOC_HF_MEM_NOC_DISPLAY 20001
@@ -579,7 +582,8 @@
 #define	MSM_BUS_SLAVE_SNOC_MEM_NOC_GC 774
 #define	MSM_BUS_SLAVE_SNOC_MEM_NOC_SF 775
 #define	MSM_BUS_SLAVE_MEM_NOC_SNOC 776
-#define	MSM_BUS_SLAVE_LAST 777
+#define	MSM_BUS_SLAVE_IPA 777
+#define	MSM_BUS_SLAVE_LAST 778
 
 #define	MSM_BUS_SLAVE_EBI_CH0_DISPLAY 20512
 #define	MSM_BUS_SLAVE_LLCC_DISPLAY 20513
diff --git a/include/linux/backlight.h b/include/linux/backlight.h
index 5f2fd61..d5ff4c30 100644
--- a/include/linux/backlight.h
+++ b/include/linux/backlight.h
@@ -12,6 +12,7 @@
 #include <linux/fb.h>
 #include <linux/mutex.h>
 #include <linux/notifier.h>
+#include <linux/thermal.h>
 
 /* Notes on locking:
  *
@@ -110,6 +111,12 @@
 	struct list_head entry;
 
 	struct device dev;
+	/* Backlight cooling device */
+	struct thermal_cooling_device *cdev;
+	/* Thermally limited max brightness */
+	int thermal_brightness_limit;
+	/* User brightness request */
+	int usr_brightness_req;
 
 	/* Multiple framebuffers may share one backlight device */
 	bool fb_bl_on[FB_MAX];
diff --git a/include/linux/bug.h b/include/linux/bug.h
index 292d6a1..6f3da08 100644
--- a/include/linux/bug.h
+++ b/include/linux/bug.h
@@ -121,4 +121,10 @@
 }
 
 #endif	/* CONFIG_GENERIC_BUG */
+
+#ifdef CONFIG_PANIC_ON_DATA_CORRUPTION
+#define PANIC_CORRUPTION 1
+#else
+#define PANIC_CORRUPTION 0
+#endif  /* CONFIG_PANIC_ON_DATA_CORRUPTION */
 #endif	/* _LINUX_BUG_H */
diff --git a/include/linux/ccp.h b/include/linux/ccp.h
index a765333..edc5d04 100644
--- a/include/linux/ccp.h
+++ b/include/linux/ccp.h
@@ -556,7 +556,7 @@
  * struct ccp_cmd - CPP operation request
  * @entry: list element (ccp driver use only)
  * @work: work element used for callbacks (ccp driver use only)
- * @ccp: CCP device to be run on (ccp driver use only)
+ * @ccp: CCP device to be run on
  * @ret: operation return code (ccp driver use only)
  * @flags: cmd processing flags
  * @engine: CCP operation to perform
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 31a7f91..8fd5fba 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -36,6 +36,8 @@
 #define CLK_IS_CRITICAL		BIT(11) /* do not gate, ever */
 /* parents need enable during gate/ungate, set rate and re-parent */
 #define CLK_OPS_PARENT_ENABLE	BIT(12)
+				/* unused */
+#define CLK_IS_MEASURE          BIT(14) /* measure clock */
 
 struct clk;
 struct clk_hw;
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
index c156f50..4fa2623 100644
--- a/include/linux/cpu_cooling.h
+++ b/include/linux/cpu_cooling.h
@@ -30,6 +30,11 @@
 
 typedef int (*get_static_t)(cpumask_t *cpumask, int interval,
 			    unsigned long voltage, u32 *power);
+typedef int (*plat_mitig_t)(int cpu, u32 clip_freq);
+
+struct cpu_cooling_ops {
+	plat_mitig_t ceil_limit, floor_limit;
+};
 
 #ifdef CONFIG_CPU_THERMAL
 /**
@@ -43,6 +48,10 @@
 cpufreq_power_cooling_register(const struct cpumask *clip_cpus,
 			       u32 capacitance, get_static_t plat_static_func);
 
+struct thermal_cooling_device *
+cpufreq_platform_cooling_register(const struct cpumask *clip_cpus,
+					struct cpu_cooling_ops *ops);
+
 /**
  * of_cpufreq_cooling_register - create cpufreq cooling device based on DT.
  * @np: a valid struct device_node to the cooling device device tree node.
@@ -112,6 +121,13 @@
 	return NULL;
 }
 
+static inline struct thermal_cooling_device *
+cpufreq_platform_cooling_register(const struct cpumask *clip_cpus,
+					struct cpu_cooling_ops *ops)
+{
+	return NULL;
+}
+
 static inline
 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
 {
diff --git a/include/linux/devfreq_cooling.h b/include/linux/devfreq_cooling.h
index 7adf6cc..374eb79 100644
--- a/include/linux/devfreq_cooling.h
+++ b/include/linux/devfreq_cooling.h
@@ -20,8 +20,6 @@
 #include <linux/devfreq.h>
 #include <linux/thermal.h>
 
-#ifdef CONFIG_DEVFREQ_THERMAL
-
 /**
  * struct devfreq_cooling_power - Devfreq cooling power ops
  * @get_static_power:	Take voltage, in mV, and return the static power
@@ -43,6 +41,8 @@
 	unsigned long dyn_power_coeff;
 };
 
+#ifdef CONFIG_DEVFREQ_THERMAL
+
 struct thermal_cooling_device *
 of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
 				  struct devfreq_cooling_power *dfc_power);
diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h
index ff8b11b..f6dfc29 100644
--- a/include/linux/fscrypto.h
+++ b/include/linux/fscrypto.h
@@ -79,7 +79,6 @@
 	u8 ci_filename_mode;
 	u8 ci_flags;
 	struct crypto_skcipher *ci_ctfm;
-	struct key *ci_keyring_key;
 	u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE];
 };
 
@@ -256,7 +255,6 @@
 extern int fscrypt_inherit_context(struct inode *, struct inode *,
 					void *, bool);
 /* keyinfo.c */
-extern int get_crypt_info(struct inode *);
 extern int fscrypt_get_encryption_info(struct inode *);
 extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *);
 
diff --git a/include/linux/iio/sw_device.h b/include/linux/iio/sw_device.h
index 23ca415..fa79319 100644
--- a/include/linux/iio/sw_device.h
+++ b/include/linux/iio/sw_device.h
@@ -62,7 +62,7 @@
 				  const char *name,
 				  struct config_item_type *type)
 {
-#ifdef CONFIG_CONFIGFS_FS
+#if IS_ENABLED(CONFIG_CONFIGFS_FS)
 	config_group_init_type_name(&d->group, name, type);
 #endif
 }
diff --git a/include/linux/ipa.h b/include/linux/ipa.h
index 16d3d26..0668534 100644
--- a/include/linux/ipa.h
+++ b/include/linux/ipa.h
@@ -98,7 +98,7 @@
 };
 
 /**
- * enum hdr_total_len_or_pad_type - type vof value held by TOTAL_LEN_OR_PAD
+ * enum hdr_total_len_or_pad_type - type of value held by TOTAL_LEN_OR_PAD
  * field in header configuration register.
  * @IPA_HDR_PAD: field is used as padding length
  * @IPA_HDR_TOTAL_LEN: field is used as total length
@@ -433,6 +433,55 @@
 		       unsigned long data);
 
 /**
+ * enum ipa_wdi_meter_evt_type - type of event client callback is
+ * for AP+STA mode metering
+ * @IPA_GET_WDI_SAP_STATS: get IPA_stats betwen SAP and STA -
+ *			use ipa_get_wdi_sap_stats structure
+ * @IPA_SET_WIFI_QUOTA: set quota limit on STA -
+ *			use ipa_set_wifi_quota structure
+ */
+enum ipa_wdi_meter_evt_type {
+	IPA_GET_WDI_SAP_STATS,
+	IPA_SET_WIFI_QUOTA,
+};
+
+struct ipa_get_wdi_sap_stats {
+	/* indicate to reset stats after query */
+	uint8_t reset_stats;
+	/* indicate valid stats from wlan-fw */
+	uint8_t stats_valid;
+	/* Tx: SAP->STA */
+	uint64_t ipv4_tx_packets;
+	uint64_t ipv4_tx_bytes;
+	/* Rx: STA->SAP */
+	uint64_t ipv4_rx_packets;
+	uint64_t ipv4_rx_bytes;
+	uint64_t ipv6_tx_packets;
+	uint64_t ipv6_tx_bytes;
+	uint64_t ipv6_rx_packets;
+	uint64_t ipv6_rx_bytes;
+};
+
+/**
+ * struct ipa_set_wifi_quota - structure used for
+ *                                   IPA_SET_WIFI_QUOTA.
+ *
+ * @quota_bytes:    Quota (in bytes) for the STA interface.
+ * @set_quota:       Indicate whether to set the quota (use 1) or
+ *                   unset the quota.
+ *
+ */
+struct ipa_set_wifi_quota {
+	uint64_t quota_bytes;
+	uint8_t  set_quota;
+	/* indicate valid quota set from wlan-fw */
+	uint8_t set_valid;
+};
+
+typedef void (*ipa_wdi_meter_notifier_cb)(enum ipa_wdi_meter_evt_type evt,
+		       void *data);
+
+/**
  * struct ipa_connect_params - low-level client connect input parameters. Either
  * client allocates the data and desc FIFO and specifies that in data+desc OR
  * specifies sizes and pipe_mem pref and IPA does the allocation.
@@ -1003,6 +1052,7 @@
  * @ul_smmu: WDI_RX configuration info when WLAN uses SMMU
  * @dl_smmu: WDI_TX configuration info when WLAN uses SMMU
  * @smmu_enabled: true if WLAN uses SMMU
+ * @ipa_wdi_meter_notifier_cb: Get WDI stats and quato info
  */
 struct ipa_wdi_in_params {
 	struct ipa_sys_connect_params sys;
@@ -1013,6 +1063,9 @@
 		struct ipa_wdi_dl_params_smmu dl_smmu;
 	} u;
 	bool smmu_enabled;
+#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
+	ipa_wdi_meter_notifier_cb wdi_notify;
+#endif
 };
 
 enum ipa_upstream_type {
@@ -1273,6 +1326,9 @@
 int ipa_suspend_wdi_pipe(u32 clnt_hdl);
 int ipa_get_wdi_stats(struct IpaHwStatsWDIInfoData_t *stats);
 u16 ipa_get_smem_restr_bytes(void);
+int ipa_broadcast_wdi_quota_reach_ind(uint32_t fid,
+		uint64_t num_bytes);
+
 /*
  * To retrieve doorbell physical address of
  * wlan pipes
@@ -1853,6 +1909,12 @@
 	return -EPERM;
 }
 
+static inline int ipa_broadcast_wdi_quota_reach_ind(uint32_t fid,
+		uint64_t num_bytes)
+{
+	return -EPERM;
+}
+
 static inline int ipa_uc_wdi_get_dbpa(
 	struct ipa_wdi_db_params *out)
 {
diff --git a/include/linux/mailbox/qmp.h b/include/linux/mailbox/qmp.h
new file mode 100644
index 0000000..df3565b
--- /dev/null
+++ b/include/linux/mailbox/qmp.h
@@ -0,0 +1,28 @@
+/* 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.
+ */
+
+#ifndef _QMP_H_
+#define _QMP_H_
+
+#include <linux/types.h>
+
+/**
+ * struct qmp_pkt - Packet structure to be used for TX and RX with QMP
+ * @size	size of data
+ * @data	Buffer holding data of this packet
+ */
+struct qmp_pkt {
+	u32 size;
+	void *data;
+};
+
+#endif /* _QMP_H_ */
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 8a507d2..c6c8d24 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -334,6 +334,7 @@
 	struct slim_device *slim_slave;
 	struct mutex io_lock;
 	struct mutex xfer_lock;
+	struct mutex reset_lock;
 	u8 version;
 
 	int reset_gpio;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 510a73a..d265f60 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -273,6 +273,7 @@
 						/* for byte mode */
 #define MMC_QUIRK_NONSTD_SDIO	(1<<2)		/* non-standard SDIO card attached */
 						/* (missing CIA registers) */
+#define MMC_QUIRK_BROKEN_CLK_GATING (1<<3)	/* clock gating the sdio bus will make card fail */
 #define MMC_QUIRK_NONSTD_FUNC_IF (1<<4)		/* SDIO card has nonstd function interfaces */
 #define MMC_QUIRK_DISABLE_CD	(1<<5)		/* disconnect CD/DAT[3] resistor */
 #define MMC_QUIRK_INAND_CMD38	(1<<6)		/* iNAND devices have broken CMD38 */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index fac3b5c..6dd1547 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -85,6 +85,12 @@
 
 struct mmc_host_ops {
 	/*
+	 * 'enable' is called when the host is claimed and 'disable' is called
+	 * when the host is released. 'enable' and 'disable' are deprecated.
+	 */
+	int (*enable)(struct mmc_host *host);
+	int (*disable)(struct mmc_host *host);
+	/*
 	 * It is optional for the host to implement pre_req and post_req in
 	 * order to support double buffering of requests (prepare one
 	 * request while another request is active).
@@ -313,9 +319,22 @@
 #define MMC_CAP2_HS400_ES	(1 << 20)	/* Host supports enhanced strobe */
 #define MMC_CAP2_NO_SD		(1 << 21)	/* Do not send SD commands during initialization */
 #define MMC_CAP2_NO_MMC		(1 << 22)	/* Do not send (e)MMC commands during initialization */
+#define MMC_CAP2_PACKED_WR_CONTROL (1 << 23)	/* Allow write packing control */
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
+#ifdef CONFIG_MMC_CLKGATE
+	int			clk_requests;	/* internal reference counter */
+	unsigned int		clk_delay;	/* number of MCI clk hold cycles */
+	bool			clk_gated;	/* clock gated */
+	struct delayed_work	clk_gate_work; /* delayed clock gate */
+	unsigned int		clk_old;	/* old clock value cache */
+	spinlock_t		clk_lock;	/* lock for clk fields */
+	struct mutex		clk_gate_mutex;	/* mutex for clock gating */
+	struct device_attribute clkgate_delay_attr;
+	unsigned long           clkgate_delay;
+#endif
+
 	/* host specific block data */
 	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
 	unsigned short		max_segs;	/* see blk_queue_max_segments */
@@ -523,6 +542,26 @@
 	return host->caps2 & MMC_CAP2_PACKED_WR;
 }
 
+#ifdef CONFIG_MMC_CLKGATE
+void mmc_host_clk_hold(struct mmc_host *host);
+void mmc_host_clk_release(struct mmc_host *host);
+unsigned int mmc_host_clk_rate(struct mmc_host *host);
+
+#else
+static inline void mmc_host_clk_hold(struct mmc_host *host)
+{
+}
+
+static inline void mmc_host_clk_release(struct mmc_host *host)
+{
+}
+
+static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
+{
+	return host->ios.clock;
+}
+#endif
+
 static inline int mmc_card_hs(struct mmc_card *card)
 {
 	return card->host->ios.timing == MMC_TIMING_SD_HS ||
diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h
index 541b10e..f5d2f72 100644
--- a/include/linux/msm_gsi.h
+++ b/include/linux/msm_gsi.h
@@ -367,6 +367,7 @@
 enum gsi_xfer_elem_type {
 	GSI_XFER_ELEM_DATA,
 	GSI_XFER_ELEM_IMME_CMD,
+	GSI_XFER_ELEM_NOP,
 };
 
 /**
@@ -409,6 +410,7 @@
  *
  *		    GSI_XFER_ELEM_DATA: for all data transfers
  *		    GSI_XFER_ELEM_IMME_CMD: for IPA immediate commands
+ *		    GSI_XFER_ELEM_NOP: for event generation only
  *
  * @xfer_user_data: cookie used in xfer_cb
  *
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
index 8462da2..2251428 100644
--- a/include/linux/perf/arm_pmu.h
+++ b/include/linux/perf/arm_pmu.h
@@ -84,6 +84,12 @@
 	ARMPMU_NR_ATTR_GROUPS
 };
 
+enum armpmu_pmu_states {
+	ARM_PMU_STATE_OFF,
+	ARM_PMU_STATE_RUNNING,
+	ARM_PMU_STATE_GOING_DOWN,
+};
+
 struct arm_pmu {
 	struct pmu	pmu;
 	cpumask_t	active_irqs;
@@ -108,6 +114,8 @@
 	void		(*free_irq)(struct arm_pmu *);
 	int		(*map_event)(struct perf_event *event);
 	int		num_events;
+	int		pmu_state;
+	int		percpu_irq;
 	atomic_t	active_events;
 	struct mutex	reserve_mutex;
 	u64		max_period;
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 531b8b1..3c80583 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -270,6 +270,8 @@
 	atomic_t			exclusive_cnt; /* < 0: cpu; > 0: tsk */
 	int				task_ctx_nr;
 	int				hrtimer_interval_ms;
+	u32				events_across_hotplug:1,
+					reserved:31;
 
 	/* number of address filters this PMU can do */
 	unsigned int			nr_addr_filters;
diff --git a/include/linux/phy/phy-qcom-ufs.h b/include/linux/phy/phy-qcom-ufs.h
index 7945fea..25e7a5f 100644
--- a/include/linux/phy/phy-qcom-ufs.h
+++ b/include/linux/phy/phy-qcom-ufs.h
@@ -58,5 +58,6 @@
 			u8 major, u16 minor, u16 step);
 const char *ufs_qcom_phy_name(struct phy *phy);
 int ufs_qcom_phy_configure_lpm(struct phy *generic_phy, bool enable);
+void ufs_qcom_phy_dbg_register_dump(struct phy *generic_phy);
 
 #endif /* PHY_QCOM_UFS_H_ */
diff --git a/include/linux/qdsp6v2/apr_tal.h b/include/linux/qdsp6v2/apr_tal.h
index 32c977f..bac5e90 100644
--- a/include/linux/qdsp6v2/apr_tal.h
+++ b/include/linux/qdsp6v2/apr_tal.h
@@ -32,7 +32,6 @@
 #if defined(CONFIG_MSM_QDSP6_APRV2_GLINK) || \
 	defined(CONFIG_MSM_QDSP6_APRV3_GLINK)
 #define APR_MAX_BUF			512
-#define APR_NUM_OF_TX_BUF		30
 #else
 #define APR_MAX_BUF			8092
 #endif
diff --git a/include/linux/qdsp6v2/rtac.h b/include/linux/qdsp6v2/rtac.h
index 3e5433b..eeea0eb 100644
--- a/include/linux/qdsp6v2/rtac.h
+++ b/include/linux/qdsp6v2/rtac.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2011, 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011, 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
@@ -95,4 +96,5 @@
 bool rtac_make_afe_callback(uint32_t *payload, u32 payload_size);
 void rtac_set_afe_handle(void *handle);
 void get_rtac_adm_data(struct rtac_adm *adm_data);
+void rtac_update_afe_topology(u32 port_id);
 #endif
diff --git a/include/linux/qpnp/qpnp-misc.h b/include/linux/qpnp/qpnp-misc.h
new file mode 100644
index 0000000..7d95bf2
--- /dev/null
+++ b/include/linux/qpnp/qpnp-misc.h
@@ -0,0 +1,56 @@
+/* Copyright (c) 2013-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.
+ */
+
+#ifndef __QPNP_MISC_H
+#define __QPNP_MISC_H
+
+#include <linux/errno.h>
+
+#ifdef CONFIG_QPNP_MISC
+/**
+ * qpnp_misc_irqs_available - check if IRQs are available
+ *
+ * @consumer_dev: device struct
+ *
+ * This function returns true if the MISC interrupts are available
+ * based on a check in the MISC peripheral revision registers.
+ *
+ * Any consumer of this function needs to reference a MISC device phandle
+ * using the "qcom,misc-ref" property in their device tree node.
+ */
+
+int qpnp_misc_irqs_available(struct device *consumer_dev);
+
+/**
+ * qpnp_misc_read_reg - read register from misc device
+ *
+ * @node: device node pointer
+ * @address: address offset in misc peripheral to be read
+ * @val: data read from register
+ *
+ * This function returns zero if reading the MISC register succeeds.
+ *
+ */
+
+int qpnp_misc_read_reg(struct device_node *node, u16 addr, u8 *val);
+#else
+static inline int qpnp_misc_irqs_available(struct device *consumer_dev)
+{
+	return 0;
+}
+static inline int qpnp_misc_read_reg(struct device_node *node, u16 addr,
+					u8 *val)
+{
+	return 0;
+}
+#endif
+#endif
diff --git a/include/linux/qpnp/qpnp-pbs.h b/include/linux/qpnp/qpnp-pbs.h
new file mode 100644
index 0000000..39497ac
--- /dev/null
+++ b/include/linux/qpnp/qpnp-pbs.h
@@ -0,0 +1,25 @@
+/* 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.
+ */
+
+#ifndef _QPNP_PBS_H
+#define _QPNP_PBS_H
+
+#ifdef CONFIG_QPNP_PBS
+int qpnp_pbs_trigger_event(struct device_node *dev_node, u8 bitmap);
+#else
+static inline int qpnp_pbs_trigger_event(struct device_node *dev_node,
+						 u8 bitmap) {
+	return -ENODEV;
+}
+#endif
+
+#endif
diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h
index 4023e3a..a0e2283 100644
--- a/include/linux/qpnp/qpnp-revid.h
+++ b/include/linux/qpnp/qpnp-revid.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
@@ -181,6 +181,7 @@
 #define PM660L_SUBTYPE	0x1A
 #define PM660_SUBTYPE	0x1B
 
+/* PMI8998 REV_ID */
 #define PMI8998_V1P0_REV1	0x00
 #define PMI8998_V1P0_REV2	0x00
 #define PMI8998_V1P0_REV3	0x00
@@ -196,6 +197,26 @@
 #define PMI8998_V2P0_REV3	0x00
 #define PMI8998_V2P0_REV4	0x02
 
+/* PM660 REV_ID */
+#define PM660_V1P0_REV1		0x00
+#define PM660_V1P0_REV2		0x00
+#define PM660_V1P0_REV3		0x00
+#define PM660_V1P0_REV4		0x01
+
+#define PM660_V1P1_REV1		0x00
+#define PM660_V1P1_REV2		0x00
+#define PM660_V1P1_REV3		0x01
+#define PM660_V1P1_REV4		0x01
+
+/* PMI8998 FAB_ID */
+#define PMI8998_FAB_ID_SMIC	0x11
+#define PMI8998_FAB_ID_GF	0x30
+
+/* PM660 FAB_ID */
+#define PM660_FAB_ID_GF		0x0
+#define PM660_FAB_ID_TSMC	0x2
+#define PM660_FAB_ID_MX		0x3
+
 /* PM8005 */
 #define PM8005_SUBTYPE		0x18
 
diff --git a/include/linux/regulator/qpnp-labibb-regulator.h b/include/linux/regulator/qpnp-labibb-regulator.h
new file mode 100644
index 0000000..2470695
--- /dev/null
+++ b/include/linux/regulator/qpnp-labibb-regulator.h
@@ -0,0 +1,23 @@
+/* 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.
+ */
+
+#ifndef _QPNP_LABIBB_REGULATOR_H
+#define _QPNP_LABIBB_REGULATOR_H
+
+enum labibb_notify_event {
+	LAB_VREG_OK = 1,
+};
+
+int qpnp_labibb_notifier_register(struct notifier_block *nb);
+int qpnp_labibb_notifier_unregister(struct notifier_block *nb);
+
+#endif
diff --git a/include/linux/sde_rsc.h b/include/linux/sde_rsc.h
new file mode 100644
index 0000000..60cc768
--- /dev/null
+++ b/include/linux/sde_rsc.h
@@ -0,0 +1,245 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _SDE_RSC_H_
+#define _SDE_RSC_H_
+
+#include <linux/kernel.h>
+
+/* primary display rsc index */
+#define SDE_RSC_INDEX		0
+
+#define MAX_RSC_CLIENT_NAME_LEN 128
+
+/**
+ * event will be triggered before sde core power collapse,
+ * mdss gdsc is still on
+ */
+#define SDE_RSC_EVENT_PRE_CORE_PC 0x1
+/**
+ * event will be triggered after sde core collapse complete,
+ * mdss gdsc is off now
+ */
+#define SDE_RSC_EVENT_POST_CORE_PC 0x2
+/**
+ * event will be triggered before restoring the sde core from power collapse,
+ * mdss gdsc is still off
+ */
+#define SDE_RSC_EVENT_PRE_CORE_RESTORE 0x4
+/**
+ * event will be triggered after restoring the sde core from power collapse,
+ * mdss gdsc is on now
+ */
+#define SDE_RSC_EVENT_POST_CORE_RESTORE 0x8
+/**
+ * event attached with solver state enabled
+ * all clients in clk_state or cmd_state
+ */
+#define SDE_RSC_EVENT_SOLVER_ENABLED 0x10
+/**
+ * event attached with solver state disabled
+ * one of the client requested for vid state
+ */
+#define SDE_RSC_EVENT_SOLVER_DISABLED 0x20
+
+/**
+ * sde_rsc_state: sde rsc state information
+ * SDE_RSC_IDLE_STATE: A client requests for idle state when there is no
+ *                    pixel or cmd transfer expected. An idle vote from
+ *                    all clients lead to power collapse state.
+ * SDE_RSC_CLK_STATE:  A client requests for clk state when it wants to
+ *                    only avoid mode-2 entry/exit. For ex: V4L2 driver,
+ *                    sde power handle, etc.
+ * SDE_RSC_CMD_STATE:  A client requests for cmd state when it wants to
+ *                    enable the solver mode.
+ * SDE_RSC_VID_STATE:  A client requests for vid state it wants to avoid
+ *                    solver enable because client is fetching data from
+ *                    continuously.
+ */
+enum sde_rsc_state {
+	SDE_RSC_IDLE_STATE,
+	SDE_RSC_CLK_STATE,
+	SDE_RSC_CMD_STATE,
+	SDE_RSC_VID_STATE,
+};
+
+/**
+ * struct sde_rsc_client: stores the rsc client for sde driver
+ * @name:	name of the client
+ * @current_state:   current client state
+ * @crtc_id:		crtc_id associated with this rsc client.
+ * @rsc_index:	rsc index of a client - only index "0" valid.
+ * @list:	list to attach client master list
+ */
+struct sde_rsc_client {
+	char name[MAX_RSC_CLIENT_NAME_LEN];
+	short current_state;
+	int crtc_id;
+	u32 rsc_index;
+	struct list_head list;
+};
+
+/**
+ * struct sde_rsc_event: local event registration entry structure
+ * @cb_func:	Pointer to desired callback function
+ * @usr:	User pointer to pass to callback on event trigger
+ * @rsc_index:	rsc index of a client - only index "0" valid.
+ * @event_type:	refer comments in event_register
+ * @list:	list to attach event master list
+ */
+struct sde_rsc_event {
+	void (*cb_func)(uint32_t event_type, void *usr);
+	void *usr;
+	u32 rsc_index;
+	uint32_t event_type;
+	struct list_head list;
+};
+
+/**
+ * struct sde_rsc_cmd_config: provides panel configuration to rsc
+ * when client is command mode. It is not required to set it during
+ * video mode.
+ *
+ * @fps:	panel te interval
+ * @vtotal:	current vertical total (height + vbp + vfp)
+ * @jitter:	panel can set the jitter to wake up rsc/solver early
+ *              This value causes mdp core to exit certain mode
+ *              early. Default is 10% jitter
+ * @prefill_lines:	max prefill lines based on panel
+ */
+struct sde_rsc_cmd_config {
+	u32 fps;
+	u32 vtotal;
+	u32 jitter;
+	u32 prefill_lines;
+};
+
+#ifdef CONFIG_DRM_SDE_RSC
+/**
+ * sde_rsc_client_create() - create the client for sde rsc.
+ * Different displays like DSI, HDMI, DP, WB, etc should call this
+ * api to register their vote for rpmh. They still need to vote for
+ * power handle to get the clocks.
+
+ * @rsc_index:   A client will be created on this RSC. As of now only
+ *               SDE_RSC_INDEX is valid rsc index.
+ * @name:	 Caller needs to provide some valid string to identify
+ *               the client. "primary", "dp", "hdmi" are suggested name.
+ * @is_primary:	 Caller needs to provide information if client is primary
+ *               or not. Primary client votes will be redirected to
+ *               display rsc.
+ * @config:	 fps, vtotal, porches, etc configuration for command mode
+ *               panel
+ *
+ * Return: client node pointer.
+ */
+struct sde_rsc_client *sde_rsc_client_create(u32 rsc_index, char *name,
+		bool is_primary_display);
+
+/**
+ * sde_rsc_client_destroy() - Destroy the sde rsc client.
+ *
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: none
+ */
+void sde_rsc_client_destroy(struct sde_rsc_client *client);
+
+/**
+ * sde_rsc_client_state_update() - rsc client state update
+ * Video mode, cmd mode and clk state are supported as modes. A client need to
+ * set this property during panel time. A switching client can set the
+ * property to change the state
+ *
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ * @state:	 Client state - video/cmd
+ * @config:	 fps, vtotal, porches, etc configuration for command mode
+ *               panel
+ * @crtc_id:	 current client's crtc id
+ *
+ * Return: error code.
+ */
+int sde_rsc_client_state_update(struct sde_rsc_client *client,
+	enum sde_rsc_state state,
+	struct sde_rsc_cmd_config *config, int crtc_id);
+
+/**
+ * sde_rsc_client_vote() - ab/ib vote from rsc client
+ *
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ * @ab:		 aggregated bandwidth vote from client.
+ * @ib:		 instant bandwidth vote from client.
+ *
+ * Return: error code.
+ */
+int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
+	u64 ab_vote, u64 ib_vote);
+
+/**
+ * sde_rsc_register_event - register a callback function for an event
+ * @rsc_index:   A client will be created on this RSC. As of now only
+ *               SDE_RSC_INDEX is valid rsc index.
+ * @event_type:  event type to register; client sets 0x3 if it wants
+ *               to register for CORE_PC and CORE_RESTORE - both events.
+ * @cb_func:     Pointer to desired callback function
+ * @usr:         User pointer to pass to callback on event trigger
+ * Returns: sde_rsc_event pointer on success
+ */
+struct sde_rsc_event *sde_rsc_register_event(int rsc_index, uint32_t event_type,
+		void (*cb_func)(uint32_t event_type, void *usr), void *usr);
+
+/**
+ * sde_rsc_unregister_event - unregister callback for an event
+ * @sde_rsc_event: event returned by sde_rsc_register_event
+ */
+void sde_rsc_unregister_event(struct sde_rsc_event *event);
+
+#else
+
+static inline struct sde_rsc_client *sde_rsc_client_create(u32 rsc_index,
+		char *name, bool is_primary_display)
+{
+	return NULL;
+}
+
+static inline void sde_rsc_client_destroy(struct sde_rsc_client *client)
+{
+}
+
+static inline int sde_rsc_client_state_update(struct sde_rsc_client *client,
+	enum sde_rsc_state state,
+	struct sde_rsc_cmd_config *config, int crtc_id)
+{
+	return 0;
+}
+
+static inline int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
+	u64 ab_vote, u64 ib_vote)
+{
+	return 0;
+}
+
+static inline struct sde_rsc_event *sde_rsc_register_event(int rsc_index,
+		uint32_t event_type,
+		void (*cb_func)(uint32_t event_type, void *usr), void *usr)
+{
+	return NULL;
+}
+
+static inline void sde_rsc_unregister_event(struct sde_rsc_event *event)
+{
+}
+
+#endif /* CONFIG_DRM_SDE_RSC */
+
+#endif /* _SDE_RSC_H_ */
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 8d0210e..8491bdc 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -142,6 +142,8 @@
 	int (*get_max_state) (struct thermal_cooling_device *, unsigned long *);
 	int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *);
 	int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
+	int (*set_min_state)(struct thermal_cooling_device *, unsigned long);
+	int (*get_min_state)(struct thermal_cooling_device *, unsigned long *);
 	int (*get_requested_power)(struct thermal_cooling_device *,
 				   struct thermal_zone_device *, u32 *);
 	int (*state2power)(struct thermal_cooling_device *,
@@ -161,6 +163,8 @@
 	struct mutex lock; /* protect thermal_instances list */
 	struct list_head thermal_instances;
 	struct list_head node;
+	unsigned long sysfs_cur_state_req;
+	unsigned long sysfs_min_state_req;
 };
 
 struct thermal_attr {
@@ -260,6 +264,7 @@
 	void (*unbind_from_tz)(struct thermal_zone_device *tz);
 	int (*throttle)(struct thermal_zone_device *tz, int trip);
 	struct list_head	governor_list;
+	int min_state_throttle;
 };
 
 /* Structure that holds binding parameters for a zone */
@@ -348,6 +353,12 @@
 	 * 		Used by thermal zone drivers (default 0).
 	 */
 	int offset;
+
+	/*
+	 * @tracks_low:	Indicates that the thermal zone params are for
+	 *		temperatures falling below the thresholds.
+	 */
+	bool tracks_low;
 };
 
 struct thermal_genl_event {
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 93094ba..1f39661 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1905,8 +1905,11 @@
 #define USB_DEVICE_REMOVE	0x0002
 #define USB_BUS_ADD		0x0003
 #define USB_BUS_REMOVE		0x0004
+#define USB_BUS_DIED		0x0005
 extern void usb_register_notify(struct notifier_block *nb);
 extern void usb_unregister_notify(struct notifier_block *nb);
+extern void usb_register_atomic_notify(struct notifier_block *nb);
+extern void usb_unregister_atomic_notify(struct notifier_block *nb);
 
 /* debugfs stuff */
 extern struct dentry *usb_debug_root;
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
index 1d0043d..de2a722 100644
--- a/include/linux/usb/quirks.h
+++ b/include/linux/usb/quirks.h
@@ -50,4 +50,10 @@
 /* device can't handle Link Power Management */
 #define USB_QUIRK_NO_LPM			BIT(10)
 
+/*
+ * Device reports its bInterval as linear frames instead of the
+ * USB 2.0 calculation.
+ */
+#define USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL	BIT(11)
+
 #endif /* __LINUX_USB_QUIRKS_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 677a047..6d27dae 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4245,6 +4245,32 @@
 					struct ieee80211_regdomain *rd);
 
 /**
+ * regulatory_hint_user - hint to the wireless core a regulatory domain
+ * which the driver has received from an application
+ * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain
+ *	should be in. If @rd is set this should be NULL. Note that if you
+ *	set this to NULL you should still set rd->alpha2 to some accepted
+ *	alpha2.
+ * @user_reg_hint_type: the type of user regulatory hint.
+ *
+ * Wireless drivers can use this function to hint to the wireless core
+ * the current regulatory domain as specified by trusted applications,
+ * it is the driver's responsibilty to estbalish which applications it
+ * trusts.
+ *
+ * The wiphy should be registered to cfg80211 prior to this call.
+ * For cfg80211 drivers this means you must first use wiphy_register(),
+ * for mac80211 drivers you must first use ieee80211_register_hw().
+ *
+ * Drivers should check the return value, its possible you can get
+ * an -ENOMEM or an -EINVAL.
+ *
+ * Return: 0 on success. -ENOMEM, -EINVAL.
+ */
+int regulatory_hint_user(const char *alpha2,
+			 enum nl80211_user_reg_hint_type user_reg_hint_type);
+
+/**
  * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
  * @wiphy: the wireless device we want to process the regulatory domain on
  * @regd: the custom regulatory domain to use for this wiphy
diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h
index 6b567d7..7ef984a 100644
--- a/include/soc/qcom/icnss.h
+++ b/include/soc/qcom/icnss.h
@@ -17,6 +17,21 @@
 #define ICNSS_MAX_IRQ_REGISTRATIONS    12
 #define ICNSS_MAX_TIMESTAMP_LEN        32
 
+enum icnss_uevent {
+	ICNSS_UEVENT_FW_READY,
+	ICNSS_UEVENT_FW_CRASHED,
+	ICNSS_UEVENT_FW_DOWN,
+};
+
+struct icnss_uevent_fw_down_data {
+	bool crashed;
+};
+
+struct icnss_uevent_data {
+	enum icnss_uevent uevent;
+	void *data;
+};
+
 struct icnss_driver_ops {
 	char *name;
 	int (*probe)(struct device *dev);
@@ -28,6 +43,7 @@
 	int (*pm_resume)(struct device *dev);
 	int (*suspend_noirq)(struct device *dev);
 	int (*resume_noirq)(struct device *dev);
+	int (*uevent)(struct device *dev, struct icnss_uevent_data *uevent);
 };
 
 
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 6de9dfa..7a09cb1 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -42,6 +42,8 @@
 #define ADM_MATRIX_ID_AUDIO_TX              1
 
 #define ADM_MATRIX_ID_COMPRESSED_AUDIO_RX   2
+
+#define ADM_MATRIX_ID_LISTEN_TX             4
 /* Enumeration for an audio Tx matrix ID.*/
 #define ADM_MATRIX_ID_AUDIOX              1
 
@@ -96,6 +98,16 @@
  */
 #define ADM_CMD_DEVICE_OPEN_V5                          0x00010326
 
+/* This command allows a client to open a COPP/Voice Proc the
+ *	way as ADM_CMD_DEVICE_OPEN_V5 but supports multiple endpoint2
+ *	channels.
+ *
+ *	@return
+ *	#ADM_CMDRSP_DEVICE_OPEN_V6 with the resulting status and
+ *	COPP ID.
+ */
+#define ADM_CMD_DEVICE_OPEN_V6                      0x00010356
+
 /* Definition for a low latency stream session. */
 #define ADM_LOW_LATENCY_DEVICE_SESSION			0x2000
 
@@ -251,6 +263,129 @@
  */
 } __packed;
 
+/*  ADM device open command payload of the
+ *  #ADM_CMD_DEVICE_OPEN_V6 command.
+ */
+struct adm_cmd_device_open_v6 {
+	struct apr_hdr		hdr;
+	u16                  flags;
+/* Reserved for future use. Clients must set this field
+ * to zero.
+ */
+
+	u16                  mode_of_operation;
+/* Specifies whether the COPP must be opened on the Tx or Rx
+ * path. Use the ADM_CMD_COPP_OPEN_MODE_OF_OPERATION_* macros for
+ * supported values and interpretation.
+ * Supported values:
+ * - 0x1 -- Rx path COPP
+ * - 0x2 -- Tx path live COPP
+ * - 0x3 -- Tx path nonlive COPP
+ * Live connections cause sample discarding in the Tx device
+ * matrix if the destination output ports do not pull them
+ * fast enough. Nonlive connections queue the samples
+ * indefinitely.
+ */
+
+	u16                  endpoint_id_1;
+/* Logical and physical endpoint ID of the audio path.
+ * If the ID is a voice processor Tx block, it receives near
+ * samples.	Supported values: Any pseudoport, AFE Rx port,
+ * or AFE Tx port For a list of valid IDs, refer to
+ * @xhyperref{Q4,[Q4]}.
+ * Q4 = Hexagon Multimedia: AFE Interface Specification
+ */
+
+	u16                  endpoint_id_2;
+/* Logical and physical endpoint ID 2 for a voice processor
+ * Tx block.
+ * This is not applicable to audio COPP.
+ * Supported values:
+ * - AFE Rx port
+ * - 0xFFFF -- Endpoint 2 is unavailable and the voice
+ * processor Tx
+ * block ignores this endpoint
+ * When the voice processor Tx block is created on the audio
+ * record path,
+ * it can receive far-end samples from an AFE Rx port if the
+ * voice call
+ * is active. The ID of the AFE port is provided in this
+ * field.
+ * For a list of valid IDs, refer @xhyperref{Q4,[Q4]}.
+ */
+
+	u32                  topology_id;
+/* Audio COPP topology ID; 32-bit GUID. */
+
+	u16                  dev_num_channel;
+/* Number of channels the audio COPP sends to/receives from
+ * the endpoint.
+ * Supported values: 1 to 8.
+ * The value is ignored for the voice processor Tx block,
+ * where channel
+ * configuration is derived from the topology ID.
+ */
+
+	u16                  bit_width;
+/* Bit width (in bits) that the audio COPP sends to/receives
+ * from the
+ * endpoint. The value is ignored for the voice processing
+ * Tx block,
+ * where the PCM width is 16 bits.
+ */
+
+	u32                  sample_rate;
+/* Sampling rate at which the audio COPP/voice processor
+ * Tx block
+ * interfaces with the endpoint.
+ * Supported values for voice processor Tx: 8000, 16000,
+ * 48000 Hz
+ * Supported values for audio COPP: >0 and <=192 kHz
+ */
+
+	u8                   dev_channel_mapping[8];
+/* Array of channel mapping of buffers that the audio COPP
+ * sends to the endpoint. Channel[i] mapping describes channel
+ * I inside the buffer, where 0 < i < dev_num_channel.
+ * This value is relevant only for an audio Rx COPP.
+ * For the voice processor block and Tx audio block, this field
+ * is set to zero and is ignored.
+ */
+
+	u16                  dev_num_channel_eid2;
+/* Number of channels the voice processor block sends
+ * to/receives from the endpoint2.
+ * Supported values: 1 to 8.
+ * The value is ignored for audio COPP or if endpoint_id_2 is
+ * set to 0xFFFF.
+ */
+
+	u16                  bit_width_eid2;
+/* Bit width (in bits) that the voice processor sends
+ * to/receives from the endpoint2.
+ * Supported values: 16 and 24.
+ * The value is ignored for audio COPP or if endpoint_id_2 is
+ * set to 0xFFFF.
+ */
+
+	u32                  sample_rate_eid2;
+/* Sampling rate at which the voice processor Tx block
+ * interfaces with the endpoint2.
+ * Supported values for Tx voice processor: >0 and <=384 kHz
+ * The value is ignored for audio COPP or if endpoint_id_2 is
+ * set to 0xFFFF.
+ */
+
+	u8                   dev_channel_mapping_eid2[8];
+/* Array of channel mapping of buffers that the voice processor
+ * sends to the endpoint. Channel[i] mapping describes channel
+ * I inside the buffer, where 0 < i < dev_num_channel.
+ * This value is relevant only for the Tx voice processor.
+ * The values are ignored for audio COPP or if endpoint_id_2 is
+ * set to 0xFFFF.
+ */
+} __packed;
+
 /*
  *	This command allows the client to close a COPP and disconnect
  *	the device session.
@@ -369,6 +504,15 @@
 	/* Reserved. This field must be set to zero.*/
 } __packed;
 
+/* Returns the status and COPP ID to an #ADM_CMD_DEVICE_OPEN_V6 command. */
+#define ADM_CMDRSP_DEVICE_OPEN_V6                      0x00010357
+
+/*  Payload of the #ADM_CMDRSP_DEVICE_OPEN_V6 message,
+ *	which returns the
+ *	status and COPP ID to an #ADM_CMD_DEVICE_OPEN_V6 command
+ *	is the exact same as ADM_CMDRSP_DEVICE_OPEN_V5.
+ */
+
 /* This command allows a query of one COPP parameter. */
 #define ADM_CMD_GET_PP_PARAMS_V5                                0x0001032A
 
@@ -1204,6 +1348,8 @@
  * #AFE_MODULE_SIDETONE_IIR_FILTER module.
  */
 #define AFE_PARAM_ID_SIDETONE_IIR_FILTER_CONFIG	0x00010204
+#define MAX_SIDETONE_IIR_DATA_SIZE 224
+#define MAX_NO_IIR_FILTER_STAGE    10
 
 struct afe_sidetone_iir_filter_config_params {
 	u16                  num_biquad_stages;
@@ -1215,6 +1361,7 @@
 /* Pregain for the compensating filter response.
  * Supported values: Any number in Q13 format
  */
+	uint8_t   iir_config[MAX_SIDETONE_IIR_DATA_SIZE];
 } __packed;
 
 #define AFE_MODULE_LOOPBACK	0x00010205
@@ -1365,6 +1512,55 @@
 
 } __packed;
 
+struct afe_loopback_sidetone_gain {
+	u16                  rx_port_id;
+	u16                  gain;
+} __packed;
+
+struct loopback_cfg_data {
+	u32                  loopback_cfg_minor_version;
+/* Minor version used for tracking the version of the RMC module
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_LOOPBACK_CONFIG
+ */
+	u16                  dst_port_id;
+	/* Destination Port Id. */
+	u16                  routing_mode;
+/* Specifies data path type from src to dest port.
+ * Supported values:
+ * #LB_MODE_DEFAULT
+ * #LB_MODE_SIDETONE
+ * #LB_MODE_EC_REF_VOICE_AUDIO
+ * #LB_MODE_EC_REF_VOICE_A
+ * #LB_MODE_EC_REF_VOICE
+ */
+
+	u16                  enable;
+/* Specifies whether to enable (1) or
+ * disable (0) an AFE loopback.
+ */
+	u16                  reserved;
+/* Reserved for 32-bit alignment. This field must be set to 0.
+ */
+} __packed;
+
+struct afe_st_loopback_cfg_v1 {
+	struct apr_hdr                    hdr;
+	struct afe_port_cmd_set_param_v2  param;
+	struct afe_port_param_data_v2     gain_pdata;
+	struct afe_loopback_sidetone_gain gain_data;
+	struct afe_port_param_data_v2     cfg_pdata;
+	struct loopback_cfg_data          cfg_data;
+} __packed;
+
+struct afe_loopback_iir_cfg_v2 {
+	struct apr_hdr                          hdr;
+	struct afe_port_cmd_set_param_v2        param;
+	struct afe_port_param_data_v2           st_iir_enable_pdata;
+	struct afe_mod_enable_param             st_iir_mode_enable_data;
+	struct afe_port_param_data_v2           st_iir_filter_config_pdata;
+	struct afe_sidetone_iir_filter_config_params st_iir_filter_config_data;
+} __packed;
 #define AFE_MODULE_SPEAKER_PROTECTION	0x00010209
 #define AFE_PARAM_ID_SPKR_PROT_CONFIG	0x0001020a
 #define AFE_API_VERSION_SPKR_PROT_CONFIG	0x1
@@ -1619,11 +1815,14 @@
 #define AFE_PORT_SAMPLE_RATE_16K          16000
 #define AFE_PORT_SAMPLE_RATE_48K          48000
 #define AFE_PORT_SAMPLE_RATE_96K          96000
+#define AFE_PORT_SAMPLE_RATE_176P4K       176400
 #define AFE_PORT_SAMPLE_RATE_192K         192000
+#define AFE_PORT_SAMPLE_RATE_352P8K       352800
 #define AFE_LINEAR_PCM_DATA				0x0
 #define AFE_NON_LINEAR_DATA				0x1
 #define AFE_LINEAR_PCM_DATA_PACKED_60958 0x2
 #define AFE_NON_LINEAR_DATA_PACKED_60958 0x3
+#define AFE_GENERIC_COMPRESSED           0x8
 
 /* This param id is used to configure I2S interface */
 #define AFE_PARAM_ID_I2S_CONFIG	0x0001020D
@@ -2265,6 +2464,13 @@
  */
 #define AFE_PARAM_ID_USB_AUDIO_DEV_PARAMS    0x000102A5
 
+
+/* ID of the parameter used to set the endianness value for the
+ * USB audio device. It should be used with
+ * AFE_MODULE_AUDIO_DEV_INTERFACE
+ */
+#define AFE_PARAM_ID_USB_AUDIO_DEV_LPCM_FMT 0x000102AA
+
 /* Minor version used for tracking USB audio  configuration */
 #define AFE_API_MINIOR_VERSION_USB_AUDIO_CONFIG 0x1
 
@@ -2280,6 +2486,15 @@
 	u32                  dev_token;
 } __packed;
 
+struct afe_param_id_usb_audio_dev_lpcm_fmt {
+/* Minor version used for tracking USB audio device parameter.
+ * Supported values: AFE_API_MINIOR_VERSION_USB_AUDIO_CONFIG
+ */
+	u32                  cfg_minor_version;
+/* Endianness of actual end USB audio device */
+	u32                  endian;
+} __packed;
+
 /* ID of the parameter used by AFE_PARAM_ID_USB_AUDIO_CONFIG to configure
  * USB audio interface. It should be used with AFE_MODULE_AUDIO_DEV_INTERFACE
  */
@@ -2324,13 +2539,18 @@
 	u16                  reserved;
 /* device token of actual end USB aduio device */
 	u32                  dev_token;
+/* endianness of this interface */
+	u32                   endian;
 } __packed;
 
 struct afe_usb_audio_dev_param_command {
 	struct apr_hdr hdr;
 	struct afe_port_cmd_set_param_v2 param;
 	struct afe_port_param_data_v2    pdata;
-	struct afe_param_id_usb_audio_dev_params usb_dev;
+	union {
+		struct afe_param_id_usb_audio_dev_params usb_dev;
+		struct afe_param_id_usb_audio_dev_lpcm_fmt lpcm_fmt;
+	};
 } __packed;
 
 /* This param id is used to configure Real Time Proxy interface. */
@@ -2528,7 +2748,9 @@
 	 * - #AFE_PORT_SAMPLE_RATE_16K
 	 * - #AFE_PORT_SAMPLE_RATE_24K
 	 * - #AFE_PORT_SAMPLE_RATE_32K
-	 * - #AFE_PORT_SAMPLE_RATE_48K @tablebulletend
+	 * - #AFE_PORT_SAMPLE_RATE_48K
+	 * - #AFE_PORT_SAMPLE_RATE_176P4K
+	 * - #AFE_PORT_SAMPLE_RATE_352P8K @tablebulletend
 	 */
 
 	u32	bit_width;
@@ -2537,10 +2759,11 @@
 	 */
 
 	u16	data_format;
-	/* < Data format: linear and compressed
+	/* < Data format: linear ,compressed, generic compresssed
 	 * @values
 	 * - #AFE_LINEAR_PCM_DATA
-	 * - #AFE_NON_LINEAR_DATA @tablebulletend
+	 * - #AFE_NON_LINEAR_DATA
+	 * - #AFE_GENERIC_COMPRESSED
 	 */
 
 	u16	sync_mode;
@@ -3419,7 +3642,7 @@
 #define DEFAULT_COPP_TOPOLOGY				0x00010314
 #define DEFAULT_POPP_TOPOLOGY				0x00010BE4
 #define COMPRESSED_PASSTHROUGH_DEFAULT_TOPOLOGY         0x0001076B
-#define COMPRESS_PASSTHROUGH_NONE_TOPOLOGY      0x00010774
+#define COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY            0x00010774
 #define VPM_TX_SM_ECNS_COPP_TOPOLOGY			0x00010F71
 #define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY			0x00010F72
 #define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY		0x00010F75
@@ -3725,6 +3948,8 @@
 
 #define ASM_MEDIA_FMT_EVRCWB_FS 0x00010BF0
 
+#define ASM_MEDIA_FMT_GENERIC_COMPRESSED  0x00013212
+
 #define ASM_MAX_EQ_BANDS 12
 
 #define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2 0x00010D98
@@ -3734,6 +3959,40 @@
 	/* Media format block size in bytes.*/
 }  __packed;
 
+struct asm_generic_compressed_fmt_blk_t {
+	struct apr_hdr hdr;
+	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
+
+	/*
+	 * Channel mapping array of bitstream output.
+	 * Channel[i] mapping describes channel i inside the buffer, where
+	 * i < num_channels. All valid used channels must be
+	 * present at the beginning of the array.
+	 */
+	uint8_t channel_mapping[8];
+
+	/*
+	 * Number of channels of the incoming bitstream.
+	 * Supported values: 1,2,3,4,5,6,7,8
+	 */
+	uint16_t num_channels;
+
+	/*
+	 * Nominal bits per sample value of the incoming bitstream.
+	 * Supported values: 16, 32
+	 */
+	uint16_t bits_per_sample;
+
+	/*
+	 * Nominal sampling rate of the incoming bitstream.
+	 * Supported values: 8000, 11025, 16000, 22050, 24000, 32000,
+	 *                   44100, 48000, 88200, 96000, 176400, 192000,
+	 *                   352800, 384000
+	 */
+	uint32_t sampling_rate;
+
+} __packed;
+
 struct asm_multi_channel_pcm_fmt_blk_v2 {
 	struct apr_hdr hdr;
 	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
@@ -4128,6 +4387,9 @@
 /* Enumeration for the raw AAC format. */
 #define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_RAW    3
 
+/* Enumeration for the AAC LATM format. */
+#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_LATM   4
+
 #define ASM_MEDIA_FMT_AAC_AOT_LC             2
 #define ASM_MEDIA_FMT_AAC_AOT_SBR            5
 #define ASM_MEDIA_FMT_AAC_AOT_PS             29
@@ -4783,8 +5045,8 @@
 
 } __packed;
 
-#define ASM_MEDIA_FMT_AC3			0x00010DEE
-#define ASM_MEDIA_FMT_EAC3			0x00010DEF
+#define ASM_MEDIA_FMT_AC3                    0x00010DEE
+#define ASM_MEDIA_FMT_EAC3                   0x00010DEF
 #define ASM_MEDIA_FMT_DTS                    0x00010D88
 #define ASM_MEDIA_FMT_MP2                    0x00010DE9
 #define ASM_MEDIA_FMT_FLAC                   0x00010C16
@@ -4793,7 +5055,6 @@
 #define ASM_MEDIA_FMT_APE                    0x00012F32
 #define ASM_MEDIA_FMT_DSD                    0x00012F3E
 
-
 /* Media format ID for adaptive transform acoustic coding. This
  * ID is used by the #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED command
  * only.
@@ -5816,6 +6077,138 @@
 /* Reserved for future use. This field must be set to zero. */
 } __packed;
 
+
+#define ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK    0x00010DBA
+
+/* Bitmask for the stream's Performance mode. */
+#define ASM_BIT_MASK_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK \
+	(0x70000000UL)
+
+/* Bit shift for the stream's Performance mode. */
+#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK    28
+
+/* Bitmask for the decoder converter enable flag. */
+#define ASM_BIT_MASK_DECODER_CONVERTER_FLAG    (0x00000078UL)
+
+/* Shift value for the decoder converter enable flag. */
+#define ASM_SHIFT_DECODER_CONVERTER_FLAG                              3
+
+/* Converter mode is None (Default). */
+#define ASM_CONVERTER_MODE_NONE                                       0
+
+/* Converter mode is DDP-to-DD. */
+#define ASM_DDP_DD_CONVERTER_MODE                                     1
+
+/*  Identifies a special converter mode where source and sink formats
+ *  are the same but postprocessing must applied. Therefore, Decode
+ *  @rarrow Re-encode is necessary.
+ */
+#define ASM_POST_PROCESS_CONVERTER_MODE                               2
+
+
+struct asm_stream_cmd_open_transcode_loopback_t {
+	struct apr_hdr         hdr;
+	u32                    mode_flags;
+/* Mode Flags specifies the performance mode in which this stream
+ * is to be opened.
+ * Supported values{for bits 30 to 28}(stream_perf_mode flag)
+ *
+ * #ASM_LEGACY_STREAM_SESSION -- This mode ensures backward
+ *       compatibility to the original behavior
+ *       of ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK
+ *
+ * #ASM_LOW_LATENCY_STREAM_SESSION -- Opens a loopback session by using
+ *  shortened buffers in low latency POPP
+ *  - Recommendation: Do not enable high latency algorithms. They might
+ *    negate the benefits of opening a low latency stream, and they
+ *    might also suffer quality degradation from unexpected jitter.
+ *  - This Low Latency mode is supported only for PCM In and PCM Out
+ *    loopbacks. An error is returned if Low Latency mode is opened for
+ *    other transcode loopback modes.
+ *  - To configure this subfield, use
+ *     ASM_BIT_MASK_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK and
+ *     ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK.
+ *
+ * Supported values{for bits 6 to 3} (decoder-converter compatibility)
+ * #ASM_CONVERTER_MODE_NONE (0x0) -- Default
+ * #ASM_DDP_DD_CONVERTER_MODE (0x1)
+ * #ASM_POST_PROCESS_CONVERTER_MODE (0x2)
+ * 0x3-0xF -- Reserved for future use
+ * - Use #ASM_BIT_MASK_DECODER_CONVERTER_FLAG and
+ *        ASM_SHIFT_DECODER_CONVERTER_FLAG to set this bit
+ * All other bits are reserved; clients must set them to 0.
+ */
+
+	u32                    src_format_id;
+/* Specifies the media format of the input audio stream.
+ *
+ * Supported values
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3
+ * - #ASM_MEDIA_FMT_DTS
+ * - #ASM_MEDIA_FMT_EAC3_DEC
+ * - #ASM_MEDIA_FMT_EAC3
+ * - #ASM_MEDIA_FMT_AC3_DEC
+ * - #ASM_MEDIA_FMT_AC3
+ */
+	u32                    sink_format_id;
+/* Specifies the media format of the output stream.
+ *
+ * Supported values
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3
+ * - #ASM_MEDIA_FMT_DTS (not supported in Low Latency mode)
+ * - #ASM_MEDIA_FMT_EAC3_DEC (not supported in Low Latency mode)
+ * - #ASM_MEDIA_FMT_EAC3 (not supported in Low Latency mode)
+ * - #ASM_MEDIA_FMT_AC3_DEC (not supported in Low Latency mode)
+ * - #ASM_MEDIA_FMT_AC3 (not supported in Low Latency mode)
+ */
+
+	u32                    audproc_topo_id;
+/* Postprocessing topology ID, which specifies the topology (order of
+ *        processing) of postprocessing algorithms.
+ *
+ * Supported values
+ *    - #ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT
+ *    - #ASM_STREAM_POSTPROC_TOPO_ID_PEAKMETER
+ *    - #ASM_STREAM_POSTPROC_TOPO_ID_MCH_PEAK_VOL
+ *    - #ASM_STREAM_POSTPROC_TOPO_ID_NONE
+ *  Topologies can be added through #ASM_CMD_ADD_TOPOLOGIES.
+ *  This field is ignored for the Converter mode, in which no
+ *  postprocessing is performed.
+ */
+
+	u16                    src_endpoint_type;
+/* Specifies the source endpoint that provides the input samples.
+ *
+ * Supported values
+ *  - 0 -- Tx device matrix or stream router (gateway to the hardware
+ *    ports)
+ *  - All other values are reserved
+ *  Clients must set this field to 0. Otherwise, an error is returned.
+ */
+
+	u16                    sink_endpoint_type;
+/*  Specifies the sink endpoint type.
+ *
+ *  Supported values
+ *  - 0 -- Rx device matrix or stream router (gateway to the hardware
+ *    ports)
+ *  - All other values are reserved
+ *   Clients must set this field to 0. Otherwise, an error is returned.
+ */
+
+	u16                    bits_per_sample;
+/*   Number of bits per sample processed by the ASM modules.
+ *   Supported values 16, 24
+ */
+
+	u16                    reserved;
+/*   This field must be set to 0.
+ */
+} __packed;
+
+
 #define ASM_STREAM_CMD_CLOSE             0x00010BCD
 #define ASM_STREAM_CMD_FLUSH             0x00010BCE
 
@@ -6771,6 +7164,12 @@
 	/*< Clients must set this field to zero. */
 } __packed;
 
+struct adm_set_mic_gain_params {
+	struct adm_cmd_set_pp_params_v5 params;
+	struct adm_param_data_v5 data;
+	struct admx_mic_gain mic_gain_data;
+} __packed;
+
 /* end_addtogroup audio_pp_param_ids */
 
 /* @ingroup audio_pp_module_ids
@@ -8662,6 +9061,31 @@
 	struct asm_stream_cmd_get_pp_params_v2 param;
 } __packed;
 
+/* Opcode to set BT address and license for aptx decoder */
+#define APTX_DECODER_BT_ADDRESS 0x00013201
+#define APTX_CLASSIC_DEC_LICENSE_ID 0x00013202
+
+struct aptx_dec_bt_addr_cfg {
+	uint32_t lap;
+	uint32_t uap;
+	uint32_t nap;
+} __packed;
+
+struct aptx_dec_bt_dev_addr {
+	struct apr_hdr hdr;
+	struct asm_stream_cmd_set_encdec_param encdec;
+	struct aptx_dec_bt_addr_cfg bt_addr_cfg;
+} __packed;
+
+struct asm_aptx_dec_fmt_blk_v2 {
+	struct apr_hdr hdr;
+	struct asm_data_cmd_media_fmt_update_v2 fmtblk;
+	u32     sample_rate;
+/* Number of samples per second.
+ * Supported values: 44100 and 48000 Hz
+ */
+} __packed;
+
 /* LSM Specific */
 #define VW_FEAT_DIM					(39)
 
@@ -8689,6 +9113,7 @@
 #define LSM_SESSION_EVENT_DETECTION_STATUS_V2		(0x00012B01)
 #define LSM_DATA_EVENT_READ_DONE			(0x00012B02)
 #define LSM_DATA_EVENT_STATUS				(0x00012B03)
+#define LSM_SESSION_EVENT_DETECTION_STATUS_V3		(0x00012B04)
 
 #define LSM_MODULE_ID_VOICE_WAKEUP			(0x00012C00)
 #define LSM_PARAM_ID_ENDPOINT_DETECT_THRESHOLD		(0x00012C01)
@@ -8701,6 +9126,12 @@
 #define LSM_PARAM_ID_LAB_ENABLE				(0x00012C09)
 #define LSM_PARAM_ID_LAB_CONFIG				(0x00012C0A)
 #define LSM_MODULE_ID_FRAMEWORK				(0x00012C0E)
+#define LSM_PARAM_ID_SWMAD_CFG				(0x00012C18)
+#define LSM_PARAM_ID_SWMAD_MODEL			(0x00012C19)
+#define LSM_PARAM_ID_SWMAD_ENABLE			(0x00012C1A)
+#define LSM_PARAM_ID_POLLING_ENABLE			(0x00012C1B)
+#define LSM_PARAM_ID_MEDIA_FMT				(0x00012C1E)
+#define LSM_PARAM_ID_FWK_MODE_CONFIG			(0x00012C27)
 
 /* HW MAD specific */
 #define AFE_MODULE_HW_MAD				(0x00010230)
@@ -9616,6 +10047,108 @@
 	union afe_port_group_config data;
 } __packed;
 
+/* ID of the parameter used by #AFE_MODULE_AUDIO_DEV_INTERFACE to specify
+ * the timing statistics of the corresponding device interface.
+ * Client can periodically query for the device time statistics to help adjust
+ * the PLL based on the drift value. The get param command must be sent to
+ * AFE port ID corresponding to device interface
+
+ * This parameter ID supports following get param commands:
+ * #AFE_PORT_CMD_GET_PARAM_V2 and
+ * #AFE_PORT_CMD_GET_PARAM_V3.
+ */
+#define AFE_PARAM_ID_DEV_TIMING_STATS           0x000102AD
+
+/* Version information used to handle future additions to AFE device
+ * interface timing statistics (for backward compatibility).
+ */
+#define AFE_API_VERSION_DEV_TIMING_STATS        0x1
+
+/* Enumeration for specifying a sink(Rx) device */
+#define AFE_SINK_DEVICE                         0x0
+
+/* Enumeration for specifying a source(Tx) device */
+#define AFE_SOURCE_DEVICE                       0x1
+
+/* Enumeration for specifying the drift reference is of type AV Timer */
+#define AFE_REF_TIMER_TYPE_AVTIMER              0x0
+
+/* Message payload structure for the
+ * AFE_PARAM_ID_DEV_TIMING_STATS parameter.
+ */
+struct afe_param_id_dev_timing_stats {
+	/* Minor version used to track the version of device interface timing
+	 * statistics. Currently, the supported version is 1.
+	 * @values #AFE_API_VERSION_DEV_TIMING_STATS
+	 */
+	u32       minor_version;
+
+	/* Indicates the device interface direction as either
+	 * source (Tx) or sink (Rx).
+	 * @values
+	 * #AFE_SINK_DEVICE
+	 * #AFE_SOURCE_DEVICE
+	 */
+	u16        device_direction;
+
+	/* Reference timer for drift accumulation and time stamp information.
+	 * @values
+	 * #AFE_REF_TIMER_TYPE_AVTIMER @tablebulletend
+	 */
+	u16        reference_timer;
+
+	/*
+	 * Flag to indicate if resync is required on the client side for
+	 * drift correction. Flag is set to TRUE for the first get_param
+	 * response after device interface starts. This flag value can be
+	 * used by client to identify if device interface restart has
+	 * happened and if any re-sync is required at their end for drift
+	 * correction.
+	 * @values
+	 * 0: FALSE (Resync not required)
+	 * 1: TRUE (Resync required) @tablebulletend
+	 */
+	u32        resync_flag;
+
+	/* Accumulated drift value in microseconds. This value is updated
+	 * every 100th ms.
+	 * Positive drift value indicates AV timer is running faster than device
+	 * Negative drift value indicates AV timer is running slower than device
+	 * @values Any valid int32 number
+	 */
+	s32         acc_drift_value;
+
+	/* Lower 32 bits of the 64-bit absolute timestamp of reference
+	 * timer in microseconds.
+
+	 * This timestamp corresponds to the time when the drift values
+	 * are accumlated for every 100th ms.
+	 * @values Any valid uint32 number
+	 */
+	u32        ref_timer_abs_ts_lsw;
+
+	/* Upper 32 bits of the 64-bit absolute timestamp of reference
+	 * timer in microseconds.
+	 * This timestamp corresponds to the time when the drift values
+	 * are accumlated for every 100th ms.
+	 * @values Any valid uint32 number
+	 */
+	u32        ref_timer_abs_ts_msw;
+} __packed;
+
+struct afe_av_dev_drift_get_param {
+	struct apr_hdr hdr;
+	struct afe_port_cmd_get_param_v2 get_param;
+	struct afe_port_param_data_v2 pdata;
+	struct afe_param_id_dev_timing_stats timing_stats;
+} __packed;
+
+struct afe_av_dev_drift_get_param_resp {
+	uint32_t status;
+	struct afe_port_param_data_v2 pdata;
+	struct afe_param_id_dev_timing_stats timing_stats;
+} __packed;
+
 /* Command for Matrix or Stream Router */
 #define ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2    0x00010DCE
 /* Module for AVSYNC */
@@ -9701,12 +10234,108 @@
 	 */
 };
 
+/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC which allows the
+ * audio client choose the rendering decision that the audio DSP should use.
+ */
+#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_MODE_CMD  0x00012F0D
+
+/* Indicates that rendering decision will be based on default rate
+ * (session clock based rendering, device driven).
+ * 1. The default session clock based rendering is inherently driven
+ *    by the timing of the device.
+ * 2. After the initial decision is made (first buffer after a run
+ *    command), subsequent data rendering decisions are made with
+ *    respect to the rate at which the device is rendering, thus deriving
+ *    its timing from the device.
+ * 3. While this decision making is simple, it has some inherent limitations
+ *    (mentioned in the next section).
+ * 4. If this API is not set, the session clock based rendering will be assumed
+ *    and this will ensure that the DSP is backward compatible.
+ */
+#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT 0
+
+/* Indicates that rendering decision will be based on local clock rate.
+ * 1. In the DSP loopback/client loopback use cases (frame based
+ *    inputs), the incoming data into audio DSP is time-stamped at the
+ *    local clock rate (STC).
+ * 2. This TS rate may match the incoming data rate or maybe different
+ *    from the incoming data rate.
+ * 3. Regardless, the data will be time-stamped with local STC and
+ *    therefore, the client is recommended to set this mode for these
+ *    use cases. This method is inherently more robust to sequencing
+ *    (AFE Start/Stop) and device switches, among other benefits.
+ * 4. This API will inform the DSP to compare every incoming buffer TS
+ *    against local STC.
+ * 5. DSP will continue to honor render windows APIs, as before.
+ */
+#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC 1
+
+/* Structure for rendering decision parameter */
+struct asm_session_mtmx_strtr_param_render_mode_t {
+	/* Specifies the type of rendering decision the audio DSP should use.
+	 *
+	 * @values
+	 * - #ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT
+	 * - #ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC
+	 */
+	u32                  flags;
+} __packed;
+
+/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC which allows the
+ * audio client to specify the clock recovery mechanism that the audio DSP
+ * should use.
+ */
+
+#define ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_CMD 0x00012F0E
+
+/* Indicates that default clock recovery will be used (no clock recovery).
+ * If the client wishes that no clock recovery be done, the client can
+ * choose this. This means that no attempt will made by the DSP to try and
+ * match the rates of the input and output audio.
+ */
+#define ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE 0
+
+/* Indicates that independent clock recovery needs to be used.
+ * 1. In the DSP loopback/client loopback use cases (frame based inputs),
+ *    the client should choose the independent clock recovery option.
+ * 2. This basically de-couples the audio and video from knowing each others
+ *    clock sources and lets the audio DSP independently rate match the input
+ *    and output rates.
+ * 3. After drift detection, the drift correction is achieved by either pulling
+ *    the PLLs (if applicable) or by stream to device rate matching
+ *    (for PCM use cases) by comparing drift with respect to STC.
+ * 4. For passthrough use cases, since the PLL pulling is the only option,
+ *    a best effort will be made.
+ *    If PLL pulling is not possible / available, the rendering will be
+ *    done without rate matching.
+ */
+#define ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO 1
+
+/* Payload of the #ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC parameter.
+ */
+struct asm_session_mtmx_strtr_param_clk_rec_t {
+	/* Specifies the type of clock recovery that the audio DSP should
+	 * use for rate matching.
+	 */
+
+	/* @values
+	 * #ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_DEFAULT
+	 * #ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_INDEPENDENT
+	 */
+	u32                  flags;
+} __packed;
+
+union asm_session_mtmx_strtr_param_config {
+	struct asm_session_mtmx_strtr_param_window_v2_t window_param;
+	struct asm_session_mtmx_strtr_param_render_mode_t render_param;
+	struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param;
+} __packed;
+
 struct asm_mtmx_strtr_params {
 	struct apr_hdr  hdr;
 	struct asm_session_cmd_set_mtmx_strstr_params_v2 param;
 	struct asm_stream_param_data_v2 data;
-	u32 window_lsw;
-	u32 window_msw;
+	union asm_session_mtmx_strtr_param_config config;
 } __packed;
 
 #define ASM_SESSION_CMD_GET_MTMX_STRTR_PARAMS_V2 0x00010DCF
@@ -9826,6 +10455,8 @@
 	COMPRESSED_PASSTHROUGH,
 	COMPRESSED_PASSTHROUGH_CONVERT,
 	COMPRESSED_PASSTHROUGH_DSD,
+	LISTEN,
+	COMPRESSED_PASSTHROUGH_GEN,
 };
 
 #define AUDPROC_MODULE_ID_COMPRESSED_MUTE                0x00010770
@@ -9897,4 +10528,21 @@
 #define AUDPROC_PARAM_ID_AUDIOSPHERE_DESIGN_MULTICHANNEL_INPUT   0x0001091D
 
 #define AUDPROC_PARAM_ID_AUDIOSPHERE_OPERATING_INPUT_MEDIA_INFO  0x0001091E
+
+#define AUDPROC_MODULE_ID_VOICE_TX_SECNS   0x10027059
+#define AUDPROC_PARAM_IDX_SEC_PRIMARY_MIC_CH 0x10014444
+
+struct admx_sec_primary_mic_ch {
+	uint16_t version;
+	uint16_t reserved;
+	uint16_t sec_primary_mic_ch;
+	uint16_t reserved1;
+} __packed;
+
+
+struct adm_set_sec_primary_ch_params {
+	struct adm_cmd_set_pp_params_v5 params;
+	struct adm_param_data_v5 data;
+	struct admx_sec_primary_mic_ch sec_primary_mic_ch_data;
+} __packed;
 #endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/cpe_core.h b/include/sound/cpe_core.h
index f4af562..411c2ff 100644
--- a/include/sound/cpe_core.h
+++ b/include/sound/cpe_core.h
@@ -162,7 +162,7 @@
 	int (*lsm_set_one_param)(void *core_handle,
 			struct cpe_lsm_session *session,
 			struct lsm_params_info *p_info,
-			void *data, enum LSM_PARAM_TYPE param_type);
+			void *data, uint32_t param_type);
 	void (*lsm_get_snd_model_offset)
 		(void *core_handle, struct cpe_lsm_session *,
 		 size_t *offset);
diff --git a/include/sound/jack.h b/include/sound/jack.h
index c66e4e9..722a20e 100644
--- a/include/sound/jack.h
+++ b/include/sound/jack.h
@@ -66,12 +66,12 @@
 				  SND_JACK_MICROPHONE2,
 
 	/* Kept separate from switches to facilitate implementation */
-	SND_JACK_BTN_0		= 0x4000,
-	SND_JACK_BTN_1		= 0x2000,
-	SND_JACK_BTN_2		= 0x1000,
-	SND_JACK_BTN_3		= 0x0800,
-	SND_JACK_BTN_4		= 0x0400,
-	SND_JACK_BTN_5		= 0x0200,
+	SND_JACK_BTN_0		= 0x8000,
+	SND_JACK_BTN_1		= 0x4000,
+	SND_JACK_BTN_2		= 0x2000,
+	SND_JACK_BTN_3		= 0x1000,
+	SND_JACK_BTN_4		= 0x0800,
+	SND_JACK_BTN_5		= 0x0400,
 };
 
 struct snd_jack {
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index c9a429d..42d048f 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, 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
@@ -58,9 +58,9 @@
 struct route_payload {
 	unsigned int copp_idx[MAX_COPPS_PER_PORT];
 	unsigned int port_id[MAX_COPPS_PER_PORT];
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate;
+	int app_type[MAX_COPPS_PER_PORT];
+	int acdb_dev_id[MAX_COPPS_PER_PORT];
+	int sample_rate[MAX_COPPS_PER_PORT];
 	unsigned short num_copps;
 	unsigned int session_id;
 };
@@ -96,12 +96,18 @@
 int adm_close(int port, int topology, int perf_mode);
 
 int adm_matrix_map(int path, struct route_payload payload_map,
-		   int perf_mode);
+		   int perf_mode, uint32_t passthr_mode);
 
 int adm_connect_afe_port(int mode, int session_id, int port_id);
 
 void adm_ec_ref_rx_id(int  port_id);
 
+void adm_num_ec_ref_rx_chans(int num_chans);
+
+void adm_ec_ref_rx_bit_width(int bit_width);
+
+void adm_ec_ref_rx_sampling_rate(int sampling_rate);
+
 int adm_get_lowlatency_copp_id(int port_id);
 
 int adm_set_multi_ch_map(char *channel_map, int path);
@@ -130,6 +136,11 @@
 int adm_set_softvolume(int port_id, int copp_idx,
 		       struct audproc_softvolume_params *softvol_param);
 
+int adm_set_mic_gain(int port_id, int copp_idx, int volume);
+
+int adm_send_set_multichannel_ec_primary_mic_ch(int port_id, int copp_idx,
+				int primary_mic_ch);
+
 int adm_param_enable(int port_id, int copp_idx, int module_id,  int enable);
 
 int adm_send_calibration(int port_id, int copp_idx, int path, int perf_mode,
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 367e75d..8361175 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -42,6 +42,8 @@
 #define AFE_CLK_VERSION_V1    1
 #define AFE_CLK_VERSION_V2    2
 
+typedef int (*routing_cb)(int port);
+
 enum {
 	/* IDX 0->4 */
 	IDX_PRIMARY_I2S_RX,
@@ -265,7 +267,7 @@
 int afe_open(u16 port_id, union afe_port_config *afe_config, int rate);
 int afe_close(int port_id);
 int afe_loopback(u16 enable, u16 rx_port, u16 tx_port);
-int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain);
+int afe_sidetone_enable(u16 tx_port_id, u16 rx_port_id, bool enable);
 int afe_loopback_gain(u16 port_id, u16 volume);
 int afe_validate_port(u16 port_id);
 int afe_get_port_index(u16 port_id);
@@ -362,5 +364,8 @@
 	struct afe_param_id_custom_tdm_header_cfg *custom_tdm_header_cfg,
 	u16 port_id);
 int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port,
-		u32 rate);
+		       u32 rate, u16 num_groups);
+void afe_set_routing_callback(routing_cb cb);
+int afe_get_av_dev_drift(struct afe_param_id_dev_timing_stats *timing_stats,
+		u16 port);
 #endif /* __Q6AFE_V2_H__ */
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 7321481..6bc93f5 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -53,6 +53,8 @@
 #define FORMAT_G711_MLAW_FS 0x001b
 #define FORMAT_DTS          0x001c
 #define FORMAT_DSD          0x001d
+#define FORMAT_APTX         0x001e
+#define FORMAT_GEN_COMPR    0x001f
 
 #define ENCDEC_SBCBITRATE   0x0001
 #define ENCDEC_IMMEDIATE_DECODE 0x0002
@@ -270,7 +272,7 @@
 		       uint16_t bits_per_sample);
 
 int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
-		       uint16_t bits_per_sample);
+		       uint16_t bits_per_sample, bool ts_mode);
 
 int q6asm_open_write(struct audio_client *ac, uint32_t format
 		/*, uint16_t bits_per_sample*/);
@@ -499,6 +501,11 @@
 			uint32_t rate, uint32_t channels,
 			bool use_default_chmap, char *channel_map,
 			uint16_t bits_per_sample);
+int q6asm_media_format_block_gen_compr(
+			struct audio_client *ac,
+			uint32_t rate, uint32_t channels,
+			bool use_default_chmap, char *channel_map,
+			uint16_t bits_per_sample);
 
 int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
 					     uint32_t rate, uint32_t channels,
@@ -552,6 +559,9 @@
 int q6asm_media_format_block_dsd(struct audio_client *ac,
 			struct asm_dsd_cfg *cfg, int stream_id);
 
+int q6asm_stream_media_format_block_aptx_dec(struct audio_client *ac,
+						uint32_t sr, int stream_id);
+
 int q6asm_ds1_set_endp_params(struct audio_client *ac,
 				int param_id, int param_value);
 
@@ -574,6 +584,10 @@
 int q6asm_dts_eagle_get(struct audio_client *ac, int param_id, uint32_t size,
 			void *data, struct param_outband *po, int m_id);
 
+/* Send aptx decoder BT address */
+int q6asm_set_aptx_dec_bt_addr(struct audio_client *ac,
+				struct aptx_dec_bt_addr_cfg *cfg);
+
 /* Set SoftPause Params */
 int q6asm_set_softpause(struct audio_client *ac,
 			struct asm_softpause_params *param);
@@ -627,6 +641,14 @@
 		struct asm_session_mtmx_strtr_param_window_v2_t *window_param,
 		uint32_t param_id);
 
+/* Configure DSP render mode */
+int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac,
+		uint32_t render_mode);
+
+/* Configure DSP clock recovery mode */
+int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac,
+		uint32_t clk_rec_mode);
+
 /* Retrieve the current DSP path delay */
 int q6asm_get_path_delay(struct audio_client *ac);
 
diff --git a/include/sound/q6lsm.h b/include/sound/q6lsm.h
index 22a62da..26106a8 100644
--- a/include/sound/q6lsm.h
+++ b/include/sound/q6lsm.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-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,6 +21,10 @@
 
 #define MAX_NUM_CONFIDENCE 20
 
+#define ADM_LSM_PORT_ID 0xADCB
+
+#define LSM_MAX_NUM_CHANNELS 8
+
 typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token,
 		       uint32_t *payload, void *priv);
 
@@ -49,11 +53,12 @@
 	uint32_t mem_map_handle;
 };
 
-struct lsm_lab_hw_params {
+struct lsm_hw_params {
 	u16 sample_rate;
 	u16 sample_size;
 	u32 buf_sz;
 	u32 period_count;
+	u16 num_chs;
 };
 
 struct lsm_client {
@@ -79,8 +84,12 @@
 	bool		lab_enable;
 	bool		lab_started;
 	struct lsm_lab_buffer *lab_buffer;
-	struct lsm_lab_hw_params hw_params;
+	struct lsm_hw_params hw_params;
 	bool		use_topology;
+	int		session_state;
+	bool		poll_enable;
+	int		perf_mode;
+	uint32_t	event_mode;
 };
 
 struct lsm_stream_cmd_open_tx {
@@ -134,6 +143,27 @@
 	uint16_t	reserved;
 } __packed;
 
+struct lsm_param_poll_enable {
+	struct lsm_param_payload_common common;
+	uint32_t	minor_version;
+	/* indicates to voice wakeup that HW MAD/SW polling is enabled or not */
+	uint32_t	polling_enable;
+} __packed;
+
+struct lsm_param_fwk_mode_cfg {
+	struct lsm_param_payload_common common;
+	uint32_t	minor_version;
+	uint32_t	mode;
+} __packed;
+
+struct lsm_param_media_fmt {
+	struct lsm_param_payload_common common;
+	uint32_t	minor_version;
+	uint32_t	sample_rate;
+	uint16_t	num_channels;
+	uint16_t	bit_width;
+	uint8_t		channel_mapping[LSM_MAX_NUM_CHANNELS];
+} __packed;
 
 /*
  * This param cannot be sent in this format.
@@ -163,11 +193,22 @@
 	struct lsm_param_min_confidence_levels	conf_payload;
 } __packed;
 
-struct lsm_cmd_set_opmode_connectport {
+struct lsm_cmd_set_params_opmode {
 	struct apr_hdr  msg_hdr;
 	struct lsm_set_params_hdr params_hdr;
-	struct lsm_param_connect_to_port	connect_to_port;
-	struct lsm_param_op_mode		op_mode;
+	struct lsm_param_op_mode op_mode;
+} __packed;
+
+struct lsm_cmd_set_connectport {
+	struct apr_hdr msg_hdr;
+	struct lsm_set_params_hdr params_hdr;
+	struct lsm_param_connect_to_port connect_to_port;
+} __packed;
+
+struct lsm_cmd_poll_enable {
+	struct apr_hdr  msg_hdr;
+	struct lsm_set_params_hdr params_hdr;
+	struct lsm_param_poll_enable poll_enable;
 } __packed;
 
 struct lsm_param_epd_thres {
@@ -250,6 +291,19 @@
 	uint32_t flags;
 } __packed;
 
+struct lsm_cmd_set_fwk_mode_cfg {
+	struct apr_hdr  msg_hdr;
+	struct lsm_set_params_hdr params_hdr;
+	struct lsm_param_fwk_mode_cfg fwk_mode_cfg;
+} __packed;
+
+struct lsm_cmd_set_media_fmt {
+	struct apr_hdr  msg_hdr;
+	struct lsm_set_params_hdr params_hdr;
+	struct lsm_param_media_fmt media_fmt;
+} __packed;
+
+
 struct lsm_client *q6lsm_client_alloc(lsm_app_cb cb, void *priv);
 void q6lsm_client_free(struct lsm_client *client);
 int q6lsm_open(struct lsm_client *client, uint16_t app_id);
@@ -274,8 +328,11 @@
 int q6lsm_lab_buffer_alloc(struct lsm_client *client, bool alloc);
 int q6lsm_set_one_param(struct lsm_client *client,
 			struct lsm_params_info *p_info, void *data,
-			enum LSM_PARAM_TYPE param_type);
+			uint32_t param_type);
 void q6lsm_sm_set_param_data(struct lsm_client *client,
 		struct lsm_params_info *p_info,
 		size_t *offset);
+int q6lsm_set_port_connected(struct lsm_client *client);
+int q6lsm_set_fwk_mode_cfg(struct lsm_client *client, uint32_t event_mode);
+int q6lsm_set_media_fmt_params(struct lsm_client *client);
 #endif /* __Q6LSM_H__ */
diff --git a/include/trace/events/rpmh.h b/include/trace/events/rpmh.h
index 62e7216..919877d 100644
--- a/include/trace/events/rpmh.h
+++ b/include/trace/events/rpmh.h
@@ -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
@@ -20,86 +20,89 @@
 
 DECLARE_EVENT_CLASS(rpmh_ack_recvd,
 
-	TP_PROTO(int m, u32 addr, int errno),
+	TP_PROTO(const char *s, int m, u32 addr, int errno),
 
-	TP_ARGS(m, addr, errno),
+	TP_ARGS(s, m, addr, errno),
 
 	TP_STRUCT__entry(
+		__field(const char *, name)
 		__field(int, m)
 		__field(u32, addr)
 		__field(int, errno)
 	),
 
 	TP_fast_assign(
+		__entry->name = s;
 		__entry->m = m;
 		__entry->addr = addr;
 		__entry->errno = errno;
 	),
 
-	TP_printk("ack: tcs-m:%d addr: 0x%08x errno: %d",
-			__entry->m, __entry->addr, __entry->errno)
+	TP_printk("%s: ack: tcs-m:%d addr: 0x%08x errno: %d",
+			__entry->name, __entry->m, __entry->addr, __entry->errno)
 );
 
 DEFINE_EVENT(rpmh_ack_recvd, rpmh_notify_irq,
-	TP_PROTO(int m, u32 addr, int err),
-	TP_ARGS(m, addr, err)
+	TP_PROTO(const char *s, int m, u32 addr, int err),
+	TP_ARGS(s, m, addr, err)
 );
 
 DEFINE_EVENT(rpmh_ack_recvd, rpmh_notify,
-	TP_PROTO(int m, u32 addr, int err),
-	TP_ARGS(m, addr, err)
+	TP_PROTO(const char *s, int m, u32 addr, int err),
+	TP_ARGS(s, m, addr, err)
 );
 
 TRACE_EVENT(rpmh_send_msg,
 
-	TP_PROTO(void *b, int m, int n, u32 h, u32 a, u32 v, bool c),
+	TP_PROTO(const char *s, int m, int n, u32 h, u32 a, u32 v, bool c, bool t),
 
-	TP_ARGS(b, m, n, h, a, v, c),
+	TP_ARGS(s, m, n, h, a, v, c, t),
 
 	TP_STRUCT__entry(
-		__field(void *, base)
+		__field(const char*, name)
 		__field(int, m)
 		__field(int, n)
 		__field(u32, hdr)
 		__field(u32, addr)
 		__field(u32, data)
 		__field(bool, complete)
+		__field(bool, trigger)
 	),
 
 	TP_fast_assign(
-		__entry->base = b;
+		__entry->name = s;
 		__entry->m = m;
 		__entry->n = n;
 		__entry->hdr = h;
 		__entry->addr = a;
 		__entry->data = v;
 		__entry->complete = c;
+		__entry->trigger = t;
 	),
 
-	TP_printk("msg: base: 0x%p  tcs(m): %d cmd(n): %d msgid: 0x%08x addr: 0x%08x data: 0x%08x complete: %d",
-			__entry->base + (672 * __entry->m) + (20 * __entry->n),
-			__entry->m, __entry->n, __entry->hdr,
-			__entry->addr, __entry->data, __entry->complete)
+	TP_printk("%s: send-msg: tcs(m): %d cmd(n): %d msgid: 0x%08x addr: 0x%08x data: 0x%08x complete: %d trigger: %d",
+			__entry->name, __entry->m, __entry->n, __entry->hdr,
+			__entry->addr, __entry->data, __entry->complete, __entry->trigger)
 );
 
 TRACE_EVENT(rpmh_control_msg,
 
-	TP_PROTO(void *r, u32 v),
+	TP_PROTO(const char *s, u32 v),
 
-	TP_ARGS(r, v),
+	TP_ARGS(s, v),
 
 	TP_STRUCT__entry(
-		__field(void *, reg)
+		__field(const char *, name)
 		__field(u32, data)
 	),
 
 	TP_fast_assign(
-		__entry->reg = r;
+		__entry->name = s;
 		__entry->data = v;
 	),
 
-	TP_printk("ctrl-msg: reg: 0x%p data: 0x%08x",
-			__entry->reg, __entry->data)
+	TP_printk("%s: ctrl-msg: data: 0x%08x",
+			__entry->name, __entry->data)
 );
 
 #endif /* _TRACE_RPMH_H */
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index fb882f5..fda50e9 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -268,6 +268,39 @@
 	__u32 blackness_level;
 };
 
+/**
+ * struct drm_msm_event_req - Payload to event enable/disable ioctls.
+ * @object_id: DRM object id. e.g.: for crtc pass crtc id.
+ * @object_type: DRM object type. e.g.: for crtc set it to DRM_MODE_OBJECT_CRTC.
+ * @event: Event for which notification is being enabled/disabled.
+ *         e.g.: for Histogram set - DRM_EVENT_HISTOGRAM.
+ * @client_context: Opaque pointer that will be returned during event response
+ *                  notification.
+ * @index: Object index(e.g.: crtc index), optional for user-space to set.
+ *         Driver will override value based on object_id and object_type.
+ */
+struct drm_msm_event_req {
+	__u32 object_id;
+	__u32 object_type;
+	__u32 event;
+	__u64 client_context;
+	__u32 index;
+};
+
+/**
+ * struct drm_msm_event_resp - payload returned when read is called for
+ *                            custom notifications.
+ * @base: Event type and length of complete notification payload.
+ * @info: Contains information about DRM that which raised this event.
+ * @data: Custom payload that driver returns for event type.
+ *        size of data = base.length - (sizeof(base) + sizeof(info))
+ */
+struct drm_msm_event_resp {
+	struct drm_event base;
+	struct drm_msm_event_req info;
+	__u8 data[];
+};
+
 #define DRM_MSM_GET_PARAM              0x00
 /* placeholder:
 #define DRM_MSM_SET_PARAM              0x01
@@ -284,6 +317,10 @@
 #define DRM_MSM_REGISTER_EVENT         0x41
 #define DRM_MSM_DEREGISTER_EVENT       0x42
 
+/* sde custom events */
+#define DRM_EVENT_HISTOGRAM 0x80000000
+#define DRM_EVENT_AD_BACKLIGHT 0x80000001
+
 #define DRM_IOCTL_MSM_GET_PARAM        DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GET_PARAM, struct drm_msm_param)
 #define DRM_IOCTL_MSM_GEM_NEW          DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_NEW, struct drm_msm_gem_new)
 #define DRM_IOCTL_MSM_GEM_INFO         DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_INFO, struct drm_msm_gem_info)
@@ -294,6 +331,10 @@
 #define DRM_IOCTL_MSM_GEM_MADVISE      DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_MADVISE, struct drm_msm_gem_madvise)
 #define DRM_IOCTL_SDE_WB_CONFIG \
 	DRM_IOW((DRM_COMMAND_BASE + DRM_SDE_WB_CONFIG), struct sde_drm_wb_cfg)
+#define DRM_IOCTL_MSM_REGISTER_EVENT   DRM_IOW((DRM_COMMAND_BASE + \
+			DRM_MSM_REGISTER_EVENT), struct drm_msm_event_req)
+#define DRM_IOCTL_MSM_DEREGISTER_EVENT DRM_IOW((DRM_COMMAND_BASE + \
+			DRM_MSM_DEREGISTER_EVENT), struct drm_msm_event_req)
 
 #if defined(__cplusplus)
 }
diff --git a/include/uapi/linux/esoc_ctrl.h b/include/uapi/linux/esoc_ctrl.h
index 1b17e1c..4201c95 100644
--- a/include/uapi/linux/esoc_ctrl.h
+++ b/include/uapi/linux/esoc_ctrl.h
@@ -5,11 +5,11 @@
 
 #define ESOC_CODE		0xCC
 
-#define ESOC_CMD_EXE		_IOW(ESOC_CODE, 1, __u32)
-#define ESOC_WAIT_FOR_REQ	_IOR(ESOC_CODE, 2, __u32)
-#define ESOC_NOTIFY		_IOW(ESOC_CODE, 3, __u32)
-#define ESOC_GET_STATUS		_IOR(ESOC_CODE, 4, __u32)
-#define ESOC_WAIT_FOR_CRASH	_IOR(ESOC_CODE, 6, __u32)
+#define ESOC_CMD_EXE		_IOW(ESOC_CODE, 1, unsigned int)
+#define ESOC_WAIT_FOR_REQ	_IOR(ESOC_CODE, 2, unsigned int)
+#define ESOC_NOTIFY		_IOW(ESOC_CODE, 3, unsigned int)
+#define ESOC_GET_STATUS		_IOR(ESOC_CODE, 4, unsigned int)
+#define ESOC_WAIT_FOR_CRASH	_IOR(ESOC_CODE, 6, unsigned int)
 #define ESOC_REG_REQ_ENG	_IO(ESOC_CODE, 7)
 #define ESOC_REG_CMD_ENG	_IO(ESOC_CODE, 8)
 
diff --git a/include/uapi/linux/msm_audio_calibration.h b/include/uapi/linux/msm_audio_calibration.h
index 11af32e..5a0b860 100644
--- a/include/uapi/linux/msm_audio_calibration.h
+++ b/include/uapi/linux/msm_audio_calibration.h
@@ -98,12 +98,15 @@
 	ULP_LSM_TOPOLOGY_ID_CAL_TYPE,
 	AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE,
 	AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE,
+	AFE_SIDETONE_IIR_CAL_TYPE,
 	MAX_CAL_TYPES,
 };
 
 #define AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE
 #define AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE
 
+#define AFE_SIDETONE_IIR_CAL_TYPE AFE_SIDETONE_IIR_CAL_TYPE
+
 enum {
 	VERSION_0_0,
 };
@@ -346,6 +349,19 @@
 	int32_t		pid;
 };
 
+#define MAX_SIDETONE_IIR_DATA_SIZE   224
+#define MAX_NO_IIR_FILTER_STAGE      10
+
+struct audio_cal_info_sidetone_iir {
+	uint16_t	iir_enable;
+	uint16_t	num_biquad_stages;
+	uint16_t	pregain;
+	int32_t	        tx_acdb_id;
+	int32_t	        rx_acdb_id;
+	int32_t	        mid;
+	int32_t	        pid;
+	uint8_t	        iir_config[MAX_SIDETONE_IIR_DATA_SIZE];
+};
 struct audio_cal_info_lsm_top {
 	int32_t		topology;
 	int32_t		acdb_id;
@@ -580,6 +596,17 @@
 	struct audio_cal_type_sidetone		cal_type;
 };
 
+struct audio_cal_type_sidetone_iir {
+	struct audio_cal_type_header	   cal_hdr;
+	struct audio_cal_data		   cal_data;
+	struct audio_cal_info_sidetone_iir cal_info;
+};
+
+struct audio_cal_sidetone_iir {
+	struct audio_cal_header		   hdr;
+	struct audio_cal_type_sidetone_iir cal_type;
+};
+
 struct audio_cal_type_lsm_top {
 	struct audio_cal_type_header	cal_hdr;
 	struct audio_cal_data		cal_data;
diff --git a/include/uapi/linux/msm_kgsl.h b/include/uapi/linux/msm_kgsl.h
index 941a816..c190446 100644
--- a/include/uapi/linux/msm_kgsl.h
+++ b/include/uapi/linux/msm_kgsl.h
@@ -327,6 +327,7 @@
 #define KGSL_PROP_DEVICE_QDSS_STM	0x19
 #define KGSL_PROP_MIN_ACCESS_LENGTH	0x1A
 #define KGSL_PROP_UBWC_MODE		0x1B
+#define KGSL_PROP_DEVICE_QTIMER		0x20
 
 struct kgsl_shadowprop {
 	unsigned long gpuaddr;
@@ -339,6 +340,11 @@
 	uint64_t size;
 };
 
+struct kgsl_qtimer_prop {
+	uint64_t gpuaddr;
+	uint64_t size;
+};
+
 struct kgsl_version {
 	unsigned int drv_major;
 	unsigned int drv_minor;
diff --git a/include/uapi/media/Kbuild b/include/uapi/media/Kbuild
index d138beb..5f375c4 100644
--- a/include/uapi/media/Kbuild
+++ b/include/uapi/media/Kbuild
@@ -1,8 +1,8 @@
-header-y += cam_req_mgr.h
 header-y += cam_defs.h
 header-y += cam_isp.h
 header-y += cam_isp_vfe.h
 header-y += cam_isp_ife.h
+header-y += cam_req_mgr.h
 header-y += cam_sensor.h
 header-y += cam_sync.h
 header-y += msm_media_info.h
diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h
index 18bd04a..3e2b24c 100644
--- a/include/uapi/media/cam_req_mgr.h
+++ b/include/uapi/media/cam_req_mgr.h
@@ -9,16 +9,17 @@
 
 #define CAM_REQ_MGR_VNODE_NAME "cam-req-mgr-devnode"
 
-#define CAM_DEVICE_TYPE_BASE    (MEDIA_ENT_F_OLD_BASE)
-#define CAM_VNODE_DEVICE_TYPE   (CAM_DEVICE_TYPE_BASE)
-#define CAM_SENSOR_DEVICE_TYPE  (CAM_DEVICE_TYPE_BASE + 1)
-#define CAM_IFE_DEVICE_TYPE     (CAM_DEVICE_TYPE_BASE + 2)
-#define CAM_ICP_DEVICE_TYPE     (CAM_DEVICE_TYPE_BASE + 3)
-#define CAM_LRME_DEVICE_TYPE    (CAM_DEVICE_TYPE_BASE + 4)
-#define CAM_JPEG_DEVICE_TYPE    (CAM_DEVICE_TYPE_BASE + 5)
-#define CAM_FD_DEVICE_TYPE      (CAM_DEVICE_TYPE_BASE + 6)
-#define CAM_CPAS_DEVICE_TYPE    (CAM_DEVICE_TYPE_BASE + 7)
-#define CAM_CSIPHY_DEVICE_TYPE  (CAM_DEVICE_TYPE_BASE + 8)
+#define CAM_DEVICE_TYPE_BASE      (MEDIA_ENT_F_OLD_BASE)
+#define CAM_VNODE_DEVICE_TYPE     (CAM_DEVICE_TYPE_BASE)
+#define CAM_SENSOR_DEVICE_TYPE    (CAM_DEVICE_TYPE_BASE + 1)
+#define CAM_IFE_DEVICE_TYPE       (CAM_DEVICE_TYPE_BASE + 2)
+#define CAM_ICP_DEVICE_TYPE       (CAM_DEVICE_TYPE_BASE + 3)
+#define CAM_LRME_DEVICE_TYPE      (CAM_DEVICE_TYPE_BASE + 4)
+#define CAM_JPEG_DEVICE_TYPE      (CAM_DEVICE_TYPE_BASE + 5)
+#define CAM_FD_DEVICE_TYPE        (CAM_DEVICE_TYPE_BASE + 6)
+#define CAM_CPAS_DEVICE_TYPE      (CAM_DEVICE_TYPE_BASE + 7)
+#define CAM_CSIPHY_DEVICE_TYPE    (CAM_DEVICE_TYPE_BASE + 8)
+#define CAM_ACTUATOR_DEVICE_TYPE  (CAM_DEVICE_TYPE_BASE + 9)
 
 /* cam_req_mgr hdl info */
 #define CAM_REQ_MGR_HDL_IDX_POS           8
diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h
index e04ccf0..3048105 100644
--- a/include/uapi/sound/compress_offload.h
+++ b/include/uapi/sound/compress_offload.h
@@ -70,7 +70,7 @@
 	__u32 pcm_frames;
 	__u32 pcm_io_frames;
 	__u32 sampling_rate;
-	uint64_t timestamp;
+	__u64 timestamp;
 } __attribute__((packed, aligned(4)));
 
 /**
@@ -128,24 +128,46 @@
  * @reserved: reserved for furture use
  */
 struct snd_compr_audio_info {
-	uint32_t frame_size;
-	uint32_t reserved[15];
+	__u32 frame_size;
+	__u32 reserved[15];
 } __attribute__((packed, aligned(4)));
 
+#define SNDRV_COMPRESS_RENDER_MODE_AUDIO_MASTER 0
+#define SNDRV_COMPRESS_RENDER_MODE_STC_MASTER 1
+
+#define SNDRV_COMPRESS_CLK_REC_MODE_NONE 0
+#define SNDRV_COMPRESS_CLK_REC_MODE_AUTO 1
+
 /**
  * enum sndrv_compress_encoder
  * @SNDRV_COMPRESS_ENCODER_PADDING: no of samples appended by the encoder at the
  * end of the track
  * @SNDRV_COMPRESS_ENCODER_DELAY: no of samples inserted by the encoder at the
  * beginning of the track
+ * @SNDRV_COMPRESS_PATH_DELAY: dsp path delay in microseconds
+ * @SNDRV_COMPRESS_RENDER_MODE: dsp render mode (audio master or stc)
+ * @SNDRV_COMPRESS_CLK_REC_MODE: clock recovery mode ( none or auto)
+ * @SNDRV_COMPRESS_RENDER_WINDOW: render window
+ * @SNDRV_COMPRESS_START_DELAY: start delay
  */
 enum sndrv_compress_encoder {
 	SNDRV_COMPRESS_ENCODER_PADDING = 1,
 	SNDRV_COMPRESS_ENCODER_DELAY = 2,
 	SNDRV_COMPRESS_MIN_BLK_SIZE = 3,
 	SNDRV_COMPRESS_MAX_BLK_SIZE = 4,
+	SNDRV_COMPRESS_PATH_DELAY = 5,
+	SNDRV_COMPRESS_RENDER_MODE = 6,
+	SNDRV_COMPRESS_CLK_REC_MODE = 7,
+	SNDRV_COMPRESS_RENDER_WINDOW = 8,
+	SNDRV_COMPRESS_START_DELAY = 9,
 };
 
+#define SNDRV_COMPRESS_PATH_DELAY SNDRV_COMPRESS_PATH_DELAY
+#define SNDRV_COMPRESS_RENDER_MODE SNDRV_COMPRESS_RENDER_MODE
+#define SNDRV_COMPRESS_CLK_REC_MODE SNDRV_COMPRESS_CLK_REC_MODE
+#define SNDRV_COMPRESS_RENDER_WINDOW SNDRV_COMPRESS_RENDER_WINDOW
+#define SNDRV_COMPRESS_START_DELAY SNDRV_COMPRESS_START_DELAY
+
 /**
  * struct snd_compr_metadata - compressed stream metadata
  * @key: key id
diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h
index 75f61fb..09593e7 100644
--- a/include/uapi/sound/compress_params.h
+++ b/include/uapi/sound/compress_params.h
@@ -104,7 +104,8 @@
 #define SND_AUDIOCODEC_ALAC                  ((__u32) 0x00000020)
 #define SND_AUDIOCODEC_APE                   ((__u32) 0x00000021)
 #define SND_AUDIOCODEC_DSD                   ((__u32) 0x00000022)
-#define SND_AUDIOCODEC_MAX                   SND_AUDIOCODEC_DSD
+#define SND_AUDIOCODEC_APTX                  ((__u32) 0x00000023)
+#define SND_AUDIOCODEC_MAX                   SND_AUDIOCODEC_APTX
 
 /*
  * Profile and modes are listed with bit masks. This allows for a
@@ -398,6 +399,12 @@
 	__u32 seek_table_present;
 };
 
+struct snd_dec_aptx {
+	__u32 lap;
+	__u32 uap;
+	__u32 nap;
+};
+
 union snd_codec_options {
 	struct snd_enc_wma wma;
 	struct snd_enc_vorbis vorbis;
@@ -409,6 +416,7 @@
 	struct snd_dec_vorbis vorbis_dec;
 	struct snd_dec_alac alac;
 	struct snd_dec_ape ape;
+	struct snd_dec_aptx aptx_dec;
 };
 
 /** struct snd_codec_desc - description of codec capabilities
diff --git a/include/uapi/sound/lsm_params.h b/include/uapi/sound/lsm_params.h
index eafdc11..9ca5930 100644
--- a/include/uapi/sound/lsm_params.h
+++ b/include/uapi/sound/lsm_params.h
@@ -1,6 +1,9 @@
 #ifndef _UAPI_LSM_PARAMS_H__
 #define _UAPI_LSM_PARAMS_H__
 
+#define LSM_POLLING_ENABLE_SUPPORT
+#define LSM_EVENT_TIMESTAMP_MODE_SUPPORT
+
 #include <linux/types.h>
 #include <sound/asound.h>
 
@@ -18,6 +21,19 @@
 #define LSM_OUT_TRANSFER_MODE_RT (0)
 #define LSM_OUT_TRANSFER_MODE_FTRT (1)
 
+#define LSM_ENDPOINT_DETECT_THRESHOLD (0)
+#define LSM_OPERATION_MODE (1)
+#define LSM_GAIN (2)
+#define LSM_MIN_CONFIDENCE_LEVELS (3)
+#define LSM_REG_SND_MODEL (4)
+#define LSM_DEREG_SND_MODEL (5)
+#define LSM_CUSTOM_PARAMS (6)
+#define LSM_POLLING_ENABLE (7)
+#define LSM_PARAMS_MAX (LSM_POLLING_ENABLE + 1)
+
+#define LSM_EVENT_NON_TIME_STAMP_MODE (0)
+#define LSM_EVENT_TIME_STAMP_MODE (1)
+
 enum lsm_app_id {
 	LSM_VOICE_WAKEUP_APP_ID = 1,
 	LSM_VOICE_WAKEUP_APP_ID_V2 = 2,
@@ -35,18 +51,6 @@
 	LSM_VOICE_WAKEUP_STATUS_REJECTED
 };
 
-enum LSM_PARAM_TYPE {
-	LSM_ENDPOINT_DETECT_THRESHOLD = 0,
-	LSM_OPERATION_MODE,
-	LSM_GAIN,
-	LSM_MIN_CONFIDENCE_LEVELS,
-	LSM_REG_SND_MODEL,
-	LSM_DEREG_SND_MODEL,
-	LSM_CUSTOM_PARAMS,
-	/* driver ioctl will parse only so many params */
-	LSM_PARAMS_MAX,
-};
-
 /*
  * Data for LSM_ENDPOINT_DETECT_THRESHOLD param_type
  * @epd_begin: Begin threshold
@@ -75,6 +79,14 @@
 	__u16 gain;
 };
 
+/*
+ * Data for LSM_POLLING_ENABLE param_type
+ * @poll_en: Polling enable or disable
+ */
+struct snd_lsm_poll_enable {
+	bool poll_en;
+};
+
 
 struct snd_lsm_sound_model_v2 {
 	__u8 __user *data;
@@ -95,11 +107,20 @@
 	__u8 payload[0];
 };
 
+struct snd_lsm_event_status_v3 {
+	__u32 timestamp_lsw;
+	__u32 timestamp_msw;
+	__u16 status;
+	__u16 payload_size;
+	__u8 payload[0];
+};
+
 struct snd_lsm_detection_params {
 	__u8 *conf_level;
 	enum lsm_detection_mode detect_mode;
 	__u8 num_confidence_levels;
 	bool detect_failure;
+	bool poll_enable;
 };
 
 /*
@@ -122,7 +143,7 @@
 	__u32 param_id;
 	__u32 param_size;
 	__u8 __user *param_data;
-	enum LSM_PARAM_TYPE param_type;
+	uint32_t param_type;
 };
 
 /*
@@ -171,5 +192,9 @@
 					struct snd_lsm_module_params)
 #define SNDRV_LSM_OUT_FORMAT_CFG _IOW('U', 0x0C, \
 				      struct snd_lsm_output_format_cfg)
+#define SNDRV_LSM_SET_PORT	_IO('U', 0x0D)
+#define SNDRV_LSM_SET_FWK_MODE_CONFIG	_IOW('U', 0x0E, uint32_t)
+#define SNDRV_LSM_EVENT_STATUS_V3	_IOW('U', 0x0F, \
+					struct snd_lsm_event_status_v3)
 
 #endif
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 24f0d77..113d325 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -372,6 +372,7 @@
 static DEFINE_PER_CPU(atomic_t, perf_cgroup_events);
 static DEFINE_PER_CPU(int, perf_sched_cb_usages);
 static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events);
+static DEFINE_PER_CPU(bool, is_idle);
 
 static atomic_t nr_mmap_events __read_mostly;
 static atomic_t nr_comm_events __read_mostly;
@@ -3605,23 +3606,31 @@
 static int perf_event_read(struct perf_event *event, bool group)
 {
 	int event_cpu, ret = 0;
+	bool active_event_skip_read = false;
 
 	/*
 	 * If event is enabled and currently active on a CPU, update the
 	 * value in the event structure:
 	 */
+	event_cpu = READ_ONCE(event->oncpu);
+
+	if (event->state == PERF_EVENT_STATE_ACTIVE) {
+		if ((unsigned int)event_cpu >= nr_cpu_ids)
+			return 0;
+		if (cpu_isolated(event_cpu) ||
+			(event->attr.exclude_idle &&
+				per_cpu(is_idle, event_cpu)))
+			active_event_skip_read = true;
+	}
+
 	if (event->state == PERF_EVENT_STATE_ACTIVE &&
-						!cpu_isolated(event->oncpu)) {
+		!active_event_skip_read) {
 		struct perf_read_data data = {
 			.event = event,
 			.group = group,
 			.ret = 0,
 		};
 
-		event_cpu = READ_ONCE(event->oncpu);
-		if ((unsigned)event_cpu >= nr_cpu_ids)
-			return 0;
-
 		preempt_disable();
 		event_cpu = __perf_event_read_cpu(event, event_cpu);
 
@@ -3635,10 +3644,12 @@
 		 * Therefore, either way, we'll have an up-to-date event count
 		 * after this.
 		 */
-		(void)smp_call_function_single(event_cpu, __perf_event_read, &data, 1);
+		(void)smp_call_function_single(event_cpu,
+				__perf_event_read, &data, 1);
 		preempt_enable();
 		ret = data.ret;
-	} else if (event->state == PERF_EVENT_STATE_INACTIVE) {
+	} else if (event->state == PERF_EVENT_STATE_INACTIVE ||
+			active_event_skip_read) {
 		struct perf_event_context *ctx = event->ctx;
 		unsigned long flags;
 
@@ -3731,7 +3742,8 @@
 
 	if (!task) {
 		/* Must be root to operate on a CPU event: */
-		if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN))
+		if (!is_kernel_event(event) && perf_paranoid_cpu() &&
+			!capable(CAP_SYS_ADMIN))
 			return ERR_PTR(-EACCES);
 
 		/*
@@ -7586,6 +7598,7 @@
 	.start		= perf_swevent_start,
 	.stop		= perf_swevent_stop,
 	.read		= perf_swevent_read,
+	.events_across_hotplug = 1,
 };
 
 #ifdef CONFIG_EVENT_TRACING
@@ -7730,6 +7743,7 @@
 	.start		= perf_swevent_start,
 	.stop		= perf_swevent_stop,
 	.read		= perf_swevent_read,
+	.events_across_hotplug = 1,
 };
 
 static inline void perf_tp_register(void)
@@ -8460,6 +8474,7 @@
 	.start		= cpu_clock_event_start,
 	.stop		= cpu_clock_event_stop,
 	.read		= cpu_clock_event_read,
+	.events_across_hotplug = 1,
 };
 
 /*
@@ -8541,6 +8556,7 @@
 	.start		= task_clock_event_start,
 	.stop		= task_clock_event_stop,
 	.read		= task_clock_event_read,
+	.events_across_hotplug = 1,
 };
 
 static void perf_pmu_nop_void(struct pmu *pmu)
@@ -10715,6 +10731,76 @@
 }
 
 #if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
+static void
+check_hotplug_start_event(struct perf_event *event)
+{
+	if (event->attr.type == PERF_TYPE_SOFTWARE) {
+		switch (event->attr.config) {
+		case PERF_COUNT_SW_CPU_CLOCK:
+			cpu_clock_event_start(event, 0);
+			break;
+		case PERF_COUNT_SW_TASK_CLOCK:
+			break;
+		default:
+			if (event->pmu->start)
+				event->pmu->start(event, 0);
+			break;
+		}
+	}
+}
+
+static int perf_event_start_swevents(unsigned int cpu)
+{
+	struct perf_event_context *ctx;
+	struct pmu *pmu;
+	struct perf_event *event;
+	int idx;
+
+	idx = srcu_read_lock(&pmus_srcu);
+	list_for_each_entry_rcu(pmu, &pmus, entry) {
+		ctx = &per_cpu_ptr(pmu->pmu_cpu_context, cpu)->ctx;
+		mutex_lock(&ctx->mutex);
+		raw_spin_lock(&ctx->lock);
+		list_for_each_entry(event, &ctx->event_list, event_entry)
+			check_hotplug_start_event(event);
+		raw_spin_unlock(&ctx->lock);
+		mutex_unlock(&ctx->mutex);
+	}
+	srcu_read_unlock(&pmus_srcu, idx);
+	return 0;
+}
+
+/*
+ * If keeping events across hotplugging is supported, do not
+ * remove the event list so event lives beyond CPU hotplug.
+ * The context is exited via an fd close path when userspace
+ * is done and the target CPU is online. If software clock
+ * event is active, then stop hrtimer associated with it.
+ * Start the timer when the CPU comes back online.
+ */
+static void
+check_hotplug_remove_from_context(struct perf_event *event,
+			   struct perf_cpu_context *cpuctx,
+			   struct perf_event_context *ctx)
+{
+	if (!event->pmu->events_across_hotplug) {
+		__perf_remove_from_context(event, cpuctx,
+			ctx, (void *)DETACH_GROUP);
+	} else if (event->attr.type == PERF_TYPE_SOFTWARE) {
+		switch (event->attr.config) {
+		case PERF_COUNT_SW_CPU_CLOCK:
+			cpu_clock_event_stop(event, 0);
+			break;
+		case PERF_COUNT_SW_TASK_CLOCK:
+			break;
+		default:
+			if (event->pmu->stop)
+				event->pmu->stop(event, 0);
+			break;
+		}
+	}
+}
+
 static void __perf_event_exit_context(void *__info)
 {
 	struct perf_event_context *ctx = __info;
@@ -10723,7 +10809,7 @@
 
 	raw_spin_lock(&ctx->lock);
 	list_for_each_entry(event, &ctx->event_list, event_entry)
-		__perf_remove_from_context(event, cpuctx, ctx, (void *)DETACH_GROUP);
+		check_hotplug_remove_from_context(event, cpuctx, ctx);
 	raw_spin_unlock(&ctx->lock);
 }
 
@@ -10775,6 +10861,26 @@
 	.priority = INT_MIN,
 };
 
+static int event_idle_notif(struct notifier_block *nb, unsigned long action,
+							void *data)
+{
+	switch (action) {
+	case IDLE_START:
+		__this_cpu_write(is_idle, true);
+		break;
+	case IDLE_END:
+		__this_cpu_write(is_idle, false);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block perf_event_idle_nb = {
+	.notifier_call = event_idle_notif,
+};
+
+
 void __init perf_event_init(void)
 {
 	int ret;
@@ -10788,6 +10894,7 @@
 	perf_pmu_register(&perf_task_clock, NULL, -1);
 	perf_tp_register();
 	perf_event_init_cpu(smp_processor_id());
+	idle_notifier_register(&perf_event_idle_nb);
 	register_reboot_notifier(&perf_reboot_notifier);
 
 	ret = init_hw_breakpoint();
@@ -10842,6 +10949,21 @@
 }
 device_initcall(perf_event_sysfs_init);
 
+static int perf_cpu_hp_init(void)
+{
+	int ret;
+
+	ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ONLINE,
+				"PERF/CORE/AP_PERF_ONLINE",
+				perf_event_start_swevents,
+				perf_event_exit_cpu);
+	if (ret)
+		pr_err("CPU hotplug notifier for perf core could not be registered: %d\n",
+		       ret);
+	return ret;
+}
+subsys_initcall(perf_cpu_hp_init);
+
 #ifdef CONFIG_CGROUP_PERF
 static struct cgroup_subsys_state *
 perf_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 22d67f0..0854263 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -703,12 +703,22 @@
 		/* silent return to keep pcm code cleaner */
 
 	if (!pm_qos_request_active(req)) {
-		WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n");
+		WARN(1, "pm_qos_remove_request() called for unknown object\n");
 		return;
 	}
 
 	cancel_delayed_work_sync(&req->work);
 
+#ifdef CONFIG_SMP
+	if (req->type == PM_QOS_REQ_AFFINE_IRQ) {
+		int ret = 0;
+		/* Get the current affinity */
+		ret = irq_set_affinity_notifier(req->irq, NULL);
+		if (ret)
+			WARN(1, "IRQ affinity notify set failed\n");
+	}
+#endif
+
 	trace_pm_qos_remove_request(req->pm_qos_class, PM_QOS_DEFAULT_VALUE);
 	pm_qos_update_target(pm_qos_array[req->pm_qos_class]->constraints,
 			     req, PM_QOS_REMOVE_REQ,
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 124eb6a..0085f66 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -1770,12 +1770,11 @@
 #ifdef CONFIG_SMP
 		if (tsk_nr_cpus_allowed(p) > 1 && rq->dl.overloaded)
 			queue_push_tasks(rq);
-#else
+#endif
 		if (dl_task(rq->curr))
 			check_preempt_curr_dl(rq, p, 0);
 		else
 			resched_curr(rq);
-#endif
 	}
 }
 
diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c
index e43344f..4de373f 100644
--- a/kernel/sched/hmp.c
+++ b/kernel/sched/hmp.c
@@ -3180,6 +3180,13 @@
 		update_task_ravg(rq->curr, rq, TASK_UPDATE, sched_ktime_clock(),
 				 0);
 
+		/*
+		 * Ensure that we don't report load for 'cpu' again via the
+		 * cpufreq_update_util path in the window that started at
+		 * rq->window_start
+		 */
+		rq->load_reported_window = rq->window_start;
+
 		account_load_subtractions(rq);
 		load[i] = rq->prev_runnable_sum;
 		nload[i] = rq->nt_prev_runnable_sum;
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index bcac711..709f719 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -2410,10 +2410,9 @@
 #ifdef CONFIG_SMP
 		if (tsk_nr_cpus_allowed(p) > 1 && rq->rt.overloaded)
 			queue_push_tasks(rq);
-#else
+#endif /* CONFIG_SMP */
 		if (p->prio < rq->curr->prio)
 			resched_curr(rq);
-#endif /* CONFIG_SMP */
 	}
 }
 
diff --git a/kernel/trace/ipc_logging.c b/kernel/trace/ipc_logging.c
index fa7fd14..6d310ab 100644
--- a/kernel/trace/ipc_logging.c
+++ b/kernel/trace/ipc_logging.c
@@ -515,8 +515,8 @@
 	tsv_qtimer_write(&ectxt);
 	avail_size = (MAX_MSG_SIZE - (ectxt.offset + hdr_size));
 	va_start(arg_list, fmt);
-	data_size = vsnprintf((ectxt.buff + ectxt.offset + hdr_size),
-			      avail_size, fmt, arg_list);
+	data_size = vscnprintf((ectxt.buff + ectxt.offset + hdr_size),
+				avail_size, fmt, arg_list);
 	va_end(arg_list);
 	tsv_write_header(&ectxt, TSV_TYPE_BYTE_ARRAY, data_size);
 	ectxt.offset += data_size;
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 84c5076..7ae9b24 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -2116,6 +2116,7 @@
 		       current->comm, preempt_count(), task_pid_nr(current),
 		       worker->current_func);
 		debug_show_held_locks(current);
+		BUG_ON(PANIC_CORRUPTION);
 		dump_stack();
 	}
 
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index fa9c7cd..64ec3fd 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -257,6 +257,17 @@
 
 	  If unsure, say N.
 
+config PAGE_OWNER_ENABLE_DEFAULT
+	bool "Enable Track page owner by default"
+	depends on PAGE_OWNER
+	---help---
+	  This keeps track of what call chain is the owner of a page, may
+	  help to find bare alloc_page(s) leaks. If you include this
+	  feature on your build, it is enabled by default. You should pass
+	  "page_owner=off" to boot parameter in order to disable it. Eats
+	  a fair amount of memory if enabled. See tools/vm/page_owner_sort.c
+	  for user-space helper.
+
 config DEBUG_FS
 	bool "Debug Filesystem"
 	select SRCU
@@ -2029,6 +2040,19 @@
 	        memtest=17, mean do 17 test patterns.
 	  If you are unsure how to answer this question, answer N.
 
+config MEMTEST_ENABLE_DEFAULT
+	int "Enable Memtest pattern test by default? (0-17)"
+	range 0 17
+	default "0"
+	depends on MEMTEST
+	help
+	  This option helps to select Memtest to be enabled through
+	  kernel defconfig options. Alternatively it can be enabled
+	  using memtest=<patterns> kernel command line.
+
+	  Default value is kept as "0" so that it is kept as disabled.
+	  To enable enter any value between 1-17 range.
+
 config TEST_STATIC_KEYS
 	tristate "Test static keys"
 	default n
@@ -2038,6 +2062,13 @@
 
 	  If unsure, say N.
 
+config PANIC_ON_DATA_CORRUPTION
+	bool "Cause a Kernel Panic When Data Corruption is detected"
+	help
+	 Select this option to upgrade warnings for potentially
+	 recoverable data corruption scenarios to system-halting panics,
+	 for easier detection and debug.
+
 source "samples/Kconfig"
 
 source "lib/Kconfig.kgdb"
diff --git a/lib/list_debug.c b/lib/list_debug.c
index 3859bf6..7a5c1c0 100644
--- a/lib/list_debug.c
+++ b/lib/list_debug.c
@@ -11,6 +11,7 @@
 #include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/rculist.h>
+#include <linux/bug.h>
 
 /*
  * Insert a new entry between two known consecutive entries.
@@ -34,6 +35,10 @@
 	WARN(new == prev || new == next,
 	     "list_add double add: new=%p, prev=%p, next=%p.\n",
 	     new, prev, next);
+
+	BUG_ON((prev->next != next || next->prev != prev ||
+		 new == prev || new == next) && PANIC_CORRUPTION);
+
 	next->prev = new;
 	new->next = next;
 	new->prev = prev;
@@ -58,9 +63,11 @@
 		"list_del corruption. prev->next should be %p, "
 		"but was %p\n", entry, prev->next) ||
 	    WARN(next->prev != entry,
-		"list_del corruption. next->prev should be %p, "
-		"but was %p\n", entry, next->prev))
+		"list_del corruption. next->prev should be %p, but was %p\n",
+		entry, next->prev)) {
+		BUG_ON(PANIC_CORRUPTION);
 		return;
+	}
 
 	__list_del(prev, next);
 }
diff --git a/mm/memtest.c b/mm/memtest.c
index 8eaa4c3..15a423e 100644
--- a/mm/memtest.c
+++ b/mm/memtest.c
@@ -80,8 +80,8 @@
 }
 
 /* default is disabled */
-static unsigned int memtest_pattern __initdata;
-
+static unsigned int memtest_pattern __initdata =
+		CONFIG_MEMTEST_ENABLE_DEFAULT;
 static int __init parse_memtest(char *arg)
 {
 	int ret = 0;
diff --git a/mm/page_owner.c b/mm/page_owner.c
index 60634dc..d2db436 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -25,7 +25,8 @@
 	depot_stack_handle_t handle;
 };
 
-static bool page_owner_disabled = true;
+static bool page_owner_disabled =
+	!IS_ENABLED(CONFIG_PAGE_OWNER_ENABLE_DEFAULT);
 DEFINE_STATIC_KEY_FALSE(page_owner_inited);
 
 static depot_stack_handle_t dummy_handle;
@@ -41,6 +42,9 @@
 	if (strcmp(buf, "on") == 0)
 		page_owner_disabled = false;
 
+	if (strcmp(buf, "off") == 0)
+		page_owner_disabled = true;
+
 	return 0;
 }
 early_param("page_owner", early_page_owner_param);
diff --git a/mm/page_poison.c b/mm/page_poison.c
index 2e647c6..0abd75e 100644
--- a/mm/page_poison.c
+++ b/mm/page_poison.c
@@ -106,7 +106,8 @@
 	return error && !(error & (error - 1));
 }
 
-static void check_poison_mem(unsigned char *mem, size_t bytes)
+static void check_poison_mem(struct page *page,
+			     unsigned char *mem, size_t bytes)
 {
 	static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 10);
 	unsigned char *start;
@@ -127,12 +128,15 @@
 	if (!__ratelimit(&ratelimit))
 		return;
 	else if (start == end && single_bit_flip(*start, PAGE_POISON))
-		pr_err("pagealloc: single bit error\n");
+		pr_err("pagealloc: single bit error on page with phys start 0x%lx\n",
+			(unsigned long)page_to_phys(page));
 	else
-		pr_err("pagealloc: memory corruption\n");
+		pr_err("pagealloc: memory corruption on page with phys start 0x%lx\n",
+			(unsigned long)page_to_phys(page));
 
 	print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, start,
 			end - start + 1, 1);
+	BUG_ON(PANIC_CORRUPTION);
 	dump_stack();
 }
 
@@ -144,7 +148,7 @@
 		return;
 
 	addr = kmap_atomic(page);
-	check_poison_mem(addr, PAGE_SIZE);
+	check_poison_mem(page, addr, PAGE_SIZE);
 	clear_page_poison(page);
 	kunmap_atomic(addr);
 }
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index d243688..d3f6c26 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -1334,7 +1334,6 @@
 		if ((map->osd_state[osd] & CEPH_OSD_EXISTS) &&
 		    (xorstate & CEPH_OSD_EXISTS)) {
 			pr_info("osd%d does not exist\n", osd);
-			map->osd_weight[osd] = CEPH_OSD_IN;
 			ret = set_primary_affinity(map, osd,
 						   CEPH_OSD_DEFAULT_PRIMARY_AFFINITY);
 			if (ret)
diff --git a/net/core/netclassid_cgroup.c b/net/core/netclassid_cgroup.c
index 11fce17..46e8830 100644
--- a/net/core/netclassid_cgroup.c
+++ b/net/core/netclassid_cgroup.c
@@ -69,27 +69,17 @@
 	return 0;
 }
 
-static void update_classid(struct cgroup_subsys_state *css, void *v)
-{
-	struct css_task_iter it;
-	struct task_struct *p;
-
-	css_task_iter_start(css, &it);
-	while ((p = css_task_iter_next(&it))) {
-		task_lock(p);
-		iterate_fd(p->files, 0, update_classid_sock, v);
-		task_unlock(p);
-	}
-	css_task_iter_end(&it);
-}
-
 static void cgrp_attach(struct cgroup_taskset *tset)
 {
 	struct cgroup_subsys_state *css;
+	struct task_struct *p;
 
-	cgroup_taskset_first(tset, &css);
-	update_classid(css,
-		       (void *)(unsigned long)css_cls_state(css)->classid);
+	cgroup_taskset_for_each(p, css, tset) {
+		task_lock(p);
+		iterate_fd(p->files, 0, update_classid_sock,
+			   (void *)(unsigned long)css_cls_state(css)->classid);
+		task_unlock(p);
+	}
 }
 
 static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft)
@@ -101,12 +91,22 @@
 			 u64 value)
 {
 	struct cgroup_cls_state *cs = css_cls_state(css);
+	struct css_task_iter it;
+	struct task_struct *p;
 
 	cgroup_sk_alloc_disable();
 
 	cs->classid = (u32)value;
 
-	update_classid(css, (void *)(unsigned long)cs->classid);
+	css_task_iter_start(css, &it);
+	while ((p = css_task_iter_next(&it))) {
+		task_lock(p);
+		iterate_fd(p->files, 0, update_classid_sock,
+			   (void *)(unsigned long)cs->classid);
+		task_unlock(p);
+	}
+	css_task_iter_end(&it);
+
 	return 0;
 }
 
diff --git a/net/core/sock.c b/net/core/sock.c
index 87a740b..19562f7 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1437,6 +1437,11 @@
 		pr_debug("%s: optmem leakage (%d bytes) detected\n",
 			 __func__, atomic_read(&sk->sk_omem_alloc));
 
+	if (sk->sk_frag.page) {
+		put_page(sk->sk_frag.page);
+		sk->sk_frag.page = NULL;
+	}
+
 	if (sk->sk_peer_cred)
 		put_cred(sk->sk_peer_cred);
 	put_pid(sk->sk_peer_pid);
@@ -1533,6 +1538,12 @@
 			is_charged = sk_filter_charge(newsk, filter);
 
 		if (unlikely(!is_charged || xfrm_sk_clone_policy(newsk, sk))) {
+			/* We need to make sure that we don't uncharge the new
+			 * socket if we couldn't charge it in the first place
+			 * as otherwise we uncharge the parent's filter.
+			 */
+			if (!is_charged)
+				RCU_INIT_POINTER(newsk->sk_filter, NULL);
 			/* It is still raw copy of parent, so invalidate
 			 * destructor and make plain sk_free() */
 			newsk->sk_destruct = NULL;
@@ -2741,11 +2752,6 @@
 
 	sk_refcnt_debug_release(sk);
 
-	if (sk->sk_frag.page) {
-		put_page(sk->sk_frag.page);
-		sk->sk_frag.page = NULL;
-	}
-
 	sock_put(sk);
 }
 EXPORT_SYMBOL(sk_common_release);
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 18412f9..98fd2f7 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -1082,7 +1082,8 @@
 
 	net = sock_net(skb->sk);
 	nlh = nlmsg_hdr(skb);
-	if (skb->len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len ||
+	if (skb->len < nlmsg_total_size(sizeof(*frn)) ||
+	    skb->len < nlh->nlmsg_len ||
 	    nlmsg_len(nlh) < sizeof(*frn))
 		return;
 
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 723059a..e074816 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5572,6 +5572,7 @@
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
 	tcp_set_state(sk, TCP_ESTABLISHED);
+	icsk->icsk_ack.lrcvtime = tcp_time_stamp;
 
 	if (skb) {
 		icsk->icsk_af_ops->sk_rx_dst_set(sk, skb);
@@ -5790,7 +5791,6 @@
 			 * to stand against the temptation 8)     --ANK
 			 */
 			inet_csk_schedule_ack(sk);
-			icsk->icsk_ack.lrcvtime = tcp_time_stamp;
 			tcp_enter_quickack_mode(sk);
 			inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
 						  TCP_DELACK_MAX, TCP_RTO_MAX);
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 6234eba..8615a6b 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -466,6 +466,7 @@
 		newtp->mdev_us = jiffies_to_usecs(TCP_TIMEOUT_INIT);
 		minmax_reset(&newtp->rtt_min, tcp_time_stamp, ~0U);
 		newicsk->icsk_rto = TCP_TIMEOUT_INIT;
+		newicsk->icsk_ack.lrcvtime = tcp_time_stamp;
 
 		newtp->packets_out = 0;
 		newtp->retrans_out = 0;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index f6fbd25..26d5718 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1037,6 +1037,7 @@
 	ipc6.hlimit = -1;
 	ipc6.tclass = -1;
 	ipc6.dontfrag = -1;
+	sockc.tsflags = sk->sk_tsflags;
 
 	/* destination address check */
 	if (sin6) {
@@ -1157,7 +1158,6 @@
 
 	fl6.flowi6_mark = sk->sk_mark;
 	fl6.flowi6_uid = sk->sk_uid;
-	sockc.tsflags = sk->sk_tsflags;
 
 	if (msg->msg_controllen) {
 		opt = &opt_space;
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index ae25ded..0792541 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -588,7 +588,7 @@
 			ipv4 = true;
 			break;
 		case OVS_TUNNEL_KEY_ATTR_IPV6_SRC:
-			SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.dst,
+			SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.src,
 					nla_get_in6_addr(a), is_mask);
 			ipv6 = true;
 			break;
@@ -649,6 +649,8 @@
 			tun_flags |= TUNNEL_VXLAN_OPT;
 			opts_type = type;
 			break;
+		case OVS_TUNNEL_KEY_ATTR_PAD:
+			break;
 		default:
 			OVS_NLERR(log, "Unknown IP tunnel attribute %d",
 				  type);
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index 6a0d485..c36757e 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -146,6 +146,7 @@
 	if (s) {
 		struct unix_sock *u = unix_sk(s);
 
+		BUG_ON(!atomic_long_read(&u->inflight));
 		BUG_ON(list_empty(&u->link));
 
 		if (atomic_long_dec_and_test(&u->inflight))
@@ -341,6 +342,14 @@
 	}
 	list_del(&cursor);
 
+	/* Now gc_candidates contains only garbage.  Restore original
+	 * inflight counters for these as well, and remove the skbuffs
+	 * which are creating the cycle(s).
+	 */
+	skb_queue_head_init(&hitlist);
+	list_for_each_entry(u, &gc_candidates, link)
+		scan_children(&u->sk, inc_inflight, &hitlist);
+
 	/* not_cycle_list contains those sockets which do not make up a
 	 * cycle.  Restore these to the inflight list.
 	 */
@@ -350,14 +359,6 @@
 		list_move_tail(&u->link, &gc_inflight_list);
 	}
 
-	/* Now gc_candidates contains only garbage.  Restore original
-	 * inflight counters for these as well, and remove the skbuffs
-	 * which are creating the cycle(s).
-	 */
-	skb_queue_head_init(&hitlist);
-	list_for_each_entry(u, &gc_candidates, link)
-	scan_children(&u->sk, inc_inflight, &hitlist);
-
 	spin_unlock(&unix_gc_lock);
 
 	/* Here we are. Hitlist is filled. Die. */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 034f70c..9ed6b0f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -548,21 +548,17 @@
 {
 	int err;
 
-	rtnl_lock();
-
 	if (!cb->args[0]) {
 		err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
 				  nl80211_fam.attrbuf, nl80211_fam.maxattr,
 				  nl80211_policy);
 		if (err)
-			goto out_unlock;
+			return err;
 
 		*wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
 						   nl80211_fam.attrbuf);
-		if (IS_ERR(*wdev)) {
-			err = PTR_ERR(*wdev);
-			goto out_unlock;
-		}
+		if (IS_ERR(*wdev))
+			return PTR_ERR(*wdev);
 		*rdev = wiphy_to_rdev((*wdev)->wiphy);
 		/* 0 is the first index - add 1 to parse only once */
 		cb->args[0] = (*rdev)->wiphy_idx + 1;
@@ -572,10 +568,8 @@
 		struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
 		struct wireless_dev *tmp;
 
-		if (!wiphy) {
-			err = -ENODEV;
-			goto out_unlock;
-		}
+		if (!wiphy)
+			return -ENODEV;
 		*rdev = wiphy_to_rdev(wiphy);
 		*wdev = NULL;
 
@@ -586,21 +580,11 @@
 			}
 		}
 
-		if (!*wdev) {
-			err = -ENODEV;
-			goto out_unlock;
-		}
+		if (!*wdev)
+			return -ENODEV;
 	}
 
 	return 0;
- out_unlock:
-	rtnl_unlock();
-	return err;
-}
-
-static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev)
-{
-	rtnl_unlock();
 }
 
 /* IE validation */
@@ -2584,17 +2568,17 @@
 	int filter_wiphy = -1;
 	struct cfg80211_registered_device *rdev;
 	struct wireless_dev *wdev;
+	int ret;
 
 	rtnl_lock();
 	if (!cb->args[2]) {
 		struct nl80211_dump_wiphy_state state = {
 			.filter_wiphy = -1,
 		};
-		int ret;
 
 		ret = nl80211_dump_wiphy_parse(skb, cb, &state);
 		if (ret)
-			return ret;
+			goto out_unlock;
 
 		filter_wiphy = state.filter_wiphy;
 
@@ -2639,12 +2623,14 @@
 		wp_idx++;
 	}
  out:
-	rtnl_unlock();
-
 	cb->args[0] = wp_idx;
 	cb->args[1] = if_idx;
 
-	return skb->len;
+	ret = skb->len;
+ out_unlock:
+	rtnl_unlock();
+
+	return ret;
 }
 
 static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
@@ -4371,9 +4357,10 @@
 	int sta_idx = cb->args[2];
 	int err;
 
+	rtnl_lock();
 	err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
 	if (err)
-		return err;
+		goto out_err;
 
 	if (!wdev->netdev) {
 		err = -EINVAL;
@@ -4408,7 +4395,7 @@
 	cb->args[2] = sta_idx;
 	err = skb->len;
  out_err:
-	nl80211_finish_wdev_dump(rdev);
+	rtnl_unlock();
 
 	return err;
 }
@@ -5179,9 +5166,10 @@
 	int path_idx = cb->args[2];
 	int err;
 
+	rtnl_lock();
 	err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
 	if (err)
-		return err;
+		goto out_err;
 
 	if (!rdev->ops->dump_mpath) {
 		err = -EOPNOTSUPP;
@@ -5214,7 +5202,7 @@
 	cb->args[2] = path_idx;
 	err = skb->len;
  out_err:
-	nl80211_finish_wdev_dump(rdev);
+	rtnl_unlock();
 	return err;
 }
 
@@ -5374,9 +5362,10 @@
 	int path_idx = cb->args[2];
 	int err;
 
+	rtnl_lock();
 	err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
 	if (err)
-		return err;
+		goto out_err;
 
 	if (!rdev->ops->dump_mpp) {
 		err = -EOPNOTSUPP;
@@ -5409,7 +5398,7 @@
 	cb->args[2] = path_idx;
 	err = skb->len;
  out_err:
-	nl80211_finish_wdev_dump(rdev);
+	rtnl_unlock();
 	return err;
 }
 
@@ -7559,9 +7548,12 @@
 	int start = cb->args[2], idx = 0;
 	int err;
 
+	rtnl_lock();
 	err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
-	if (err)
+	if (err) {
+		rtnl_unlock();
 		return err;
+	}
 
 	wdev_lock(wdev);
 	spin_lock_bh(&rdev->bss_lock);
@@ -7584,7 +7576,7 @@
 	wdev_unlock(wdev);
 
 	cb->args[2] = idx;
-	nl80211_finish_wdev_dump(rdev);
+	rtnl_unlock();
 
 	return skb->len;
 }
@@ -7668,9 +7660,10 @@
 	int res;
 	bool radio_stats;
 
+	rtnl_lock();
 	res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
 	if (res)
-		return res;
+		goto out_err;
 
 	/* prepare_wdev_dump parsed the attributes */
 	radio_stats = nl80211_fam.attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
@@ -7711,7 +7704,7 @@
 	cb->args[2] = survey_idx;
 	res = skb->len;
  out_err:
-	nl80211_finish_wdev_dump(rdev);
+	rtnl_unlock();
 	return res;
 }
 
@@ -11302,17 +11295,13 @@
 	void *data = NULL;
 	unsigned int data_len = 0;
 
-	rtnl_lock();
-
 	if (cb->args[0]) {
 		/* subtract the 1 again here */
 		struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
 		struct wireless_dev *tmp;
 
-		if (!wiphy) {
-			err = -ENODEV;
-			goto out_unlock;
-		}
+		if (!wiphy)
+			return -ENODEV;
 		*rdev = wiphy_to_rdev(wiphy);
 		*wdev = NULL;
 
@@ -11333,13 +11322,11 @@
 			  nl80211_fam.attrbuf, nl80211_fam.maxattr,
 			  nl80211_policy);
 	if (err)
-		goto out_unlock;
+		return err;
 
 	if (!nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID] ||
-	    !nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
-		err = -EINVAL;
-		goto out_unlock;
-	}
+	    !nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD])
+		return -EINVAL;
 
 	*wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
 					   nl80211_fam.attrbuf);
@@ -11348,10 +11335,8 @@
 
 	*rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk),
 					   nl80211_fam.attrbuf);
-	if (IS_ERR(*rdev)) {
-		err = PTR_ERR(*rdev);
-		goto out_unlock;
-	}
+	if (IS_ERR(*rdev))
+		return PTR_ERR(*rdev);
 
 	vid = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID]);
 	subcmd = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
@@ -11364,19 +11349,15 @@
 		if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
 			continue;
 
-		if (!vcmd->dumpit) {
-			err = -EOPNOTSUPP;
-			goto out_unlock;
-		}
+		if (!vcmd->dumpit)
+			return -EOPNOTSUPP;
 
 		vcmd_idx = i;
 		break;
 	}
 
-	if (vcmd_idx < 0) {
-		err = -EOPNOTSUPP;
-		goto out_unlock;
-	}
+	if (vcmd_idx < 0)
+		return -EOPNOTSUPP;
 
 	if (nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]) {
 		data = nla_data(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]);
@@ -11393,9 +11374,6 @@
 
 	/* keep rtnl locked in successful case */
 	return 0;
- out_unlock:
-	rtnl_unlock();
-	return err;
 }
 
 static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
@@ -11410,9 +11388,10 @@
 	int err;
 	struct nlattr *vendor_data;
 
+	rtnl_lock();
 	err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
 	if (err)
-		return err;
+		goto out;
 
 	vcmd_idx = cb->args[2];
 	data = (void *)cb->args[3];
@@ -11421,18 +11400,26 @@
 
 	if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
 			   WIPHY_VENDOR_CMD_NEED_NETDEV)) {
-		if (!wdev)
-			return -EINVAL;
+		if (!wdev) {
+			err = -EINVAL;
+			goto out;
+		}
 		if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
-		    !wdev->netdev)
-			return -EINVAL;
+		    !wdev->netdev) {
+			err = -EINVAL;
+			goto out;
+		}
 
 		if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
 			if (wdev->netdev &&
-			    !netif_running(wdev->netdev))
-				return -ENETDOWN;
-			if (!wdev->netdev && !wdev->p2p_started)
-				return -ENETDOWN;
+			    !netif_running(wdev->netdev)) {
+				err = -ENETDOWN;
+				goto out;
+			}
+			if (!wdev->netdev && !wdev->p2p_started) {
+				err = -ENETDOWN;
+				goto out;
+			}
 		}
 	}
 
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index eeb23d2..bc0ebd4 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2340,6 +2340,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(regulatory_hint_user);
 
 int regulatory_hint_indoor(bool is_indoor, u32 portid)
 {
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index f6ced31..822ac90 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -28,9 +28,6 @@
 bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region);
 enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy);
 
-int regulatory_hint_user(const char *alpha2,
-			 enum nl80211_user_reg_hint_type user_reg_hint_type);
-
 /**
  * regulatory_hint_indoor - hint operation in indoor env. or not
  * @is_indoor: if true indicates that user space thinks that the
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 5bf7e1bf..e0437a7 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -3062,6 +3062,11 @@
 {
 	int rv;
 
+	/* Initialize the per-net locks here */
+	spin_lock_init(&net->xfrm.xfrm_state_lock);
+	spin_lock_init(&net->xfrm.xfrm_policy_lock);
+	mutex_init(&net->xfrm.xfrm_cfg_mutex);
+
 	rv = xfrm_statistics_init(net);
 	if (rv < 0)
 		goto out_statistics;
@@ -3078,11 +3083,6 @@
 	if (rv < 0)
 		goto out;
 
-	/* Initialize the per-net locks here */
-	spin_lock_init(&net->xfrm.xfrm_state_lock);
-	spin_lock_init(&net->xfrm.xfrm_policy_lock);
-	mutex_init(&net->xfrm.xfrm_cfg_mutex);
-
 	return 0;
 
 out:
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 671a1d0..a7e27e1 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -412,7 +412,14 @@
 	up = nla_data(rp);
 	ulen = xfrm_replay_state_esn_len(up);
 
-	if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen)
+	/* Check the overall length and the internal bitmap length to avoid
+	 * potential overflow. */
+	if (nla_len(rp) < ulen ||
+	    xfrm_replay_state_esn_len(replay_esn) != ulen ||
+	    replay_esn->bmp_len != up->bmp_len)
+		return -EINVAL;
+
+	if (up->replay_window > up->bmp_len * sizeof(__u32) * 8)
 		return -EINVAL;
 
 	return 0;
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 8dd39fe..bbba7be 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -375,7 +375,8 @@
 		 * the elapsed time to detect xruns.
 		 */
 		jdelta = curr_jiffies - runtime->hw_ptr_jiffies;
-		if (jdelta < runtime->hw_ptr_buffer_jiffies / 2)
+		if ((jdelta < runtime->hw_ptr_buffer_jiffies / 2) ||
+		    (runtime->hw_ptr_buffer_jiffies <= 0))
 			goto no_delta_check;
 		hdelta = jdelta - delta * HZ / runtime->rate;
 		xrun_threshold = runtime->hw_ptr_buffer_jiffies / 2 + 1;
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 4c93520..f3b1d7f 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1832,6 +1832,7 @@
 	     info->output_pool != client->pool->size)) {
 		if (snd_seq_write_pool_allocated(client)) {
 			/* remove all existing cells */
+			snd_seq_pool_mark_closing(client->pool);
 			snd_seq_queue_client_leave_cells(client->number);
 			snd_seq_pool_done(client->pool);
 		}
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
index 86240d0..3f4efcb 100644
--- a/sound/core/seq/seq_fifo.c
+++ b/sound/core/seq/seq_fifo.c
@@ -70,6 +70,9 @@
 		return;
 	*fifo = NULL;
 
+	if (f->pool)
+		snd_seq_pool_mark_closing(f->pool);
+
 	snd_seq_fifo_clear(f);
 
 	/* wake up clients if any */
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index dfa5156..5847c44 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -414,6 +414,18 @@
 	return 0;
 }
 
+/* refuse the further insertion to the pool */
+void snd_seq_pool_mark_closing(struct snd_seq_pool *pool)
+{
+	unsigned long flags;
+
+	if (snd_BUG_ON(!pool))
+		return;
+	spin_lock_irqsave(&pool->lock, flags);
+	pool->closing = 1;
+	spin_unlock_irqrestore(&pool->lock, flags);
+}
+
 /* remove events */
 int snd_seq_pool_done(struct snd_seq_pool *pool)
 {
@@ -424,10 +436,6 @@
 		return -EINVAL;
 
 	/* wait for closing all threads */
-	spin_lock_irqsave(&pool->lock, flags);
-	pool->closing = 1;
-	spin_unlock_irqrestore(&pool->lock, flags);
-
 	if (waitqueue_active(&pool->output_sleep))
 		wake_up(&pool->output_sleep);
 
@@ -484,6 +492,7 @@
 	*ppool = NULL;
 	if (pool == NULL)
 		return 0;
+	snd_seq_pool_mark_closing(pool);
 	snd_seq_pool_done(pool);
 	kfree(pool);
 	return 0;
diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h
index 4a2ec77..32f959c 100644
--- a/sound/core/seq/seq_memory.h
+++ b/sound/core/seq/seq_memory.h
@@ -84,6 +84,7 @@
 int snd_seq_pool_init(struct snd_seq_pool *pool);
 
 /* done pool - free events */
+void snd_seq_pool_mark_closing(struct snd_seq_pool *pool);
 int snd_seq_pool_done(struct snd_seq_pool *pool);
 
 /* create pool */
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index ab4cdab..79edd88 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -1905,7 +1905,7 @@
 		return err;
 
 	/* Set DMA transfer mask */
-	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
+	if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
 		dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
 	} else {
 		dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 0c62b1d..112caa2 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -6058,6 +6058,8 @@
 		ALC295_STANDARD_PINS,
 		{0x17, 0x21014040},
 		{0x18, 0x21a19050}),
+	SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+		ALC295_STANDARD_PINS),
 	SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
 		ALC298_STANDARD_PINS,
 		{0x17, 0x90170110}),
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 9685b02..fe135b4 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -927,11 +927,11 @@
 
 config AUDIO_EXT_CLK
 	tristate
-	default y if SND_SOC_WCD9335=y || SND_SOC_WCD9330=y || SND_SOC_MSM8X16_WCD=y
+	default y if SND_SOC_WCD9335=y || SND_SOC_WCD9330=y || SND_SOC_SDM660_CDC=y
 
 config SND_SOC_WCD_MBHC
 	tristate
-	default y if (SND_SOC_MSM8909_WCD=y || SND_SOC_MSM8X16_WCD=y || SND_SOC_WCD9335=y) && SND_SOC_MDMCALIFORNIUM!=y
+	default y if (SND_SOC_MSM8909_WCD=y || SND_SOC_SDM660_CDC=y || SND_SOC_WCD9335=y) && SND_SOC_MDMCALIFORNIUM!=y
 
 config SND_SOC_WCD_DSP_MGR
 	tristate
@@ -1159,11 +1159,12 @@
 
 config SND_SOC_MSM_HDMI_CODEC_RX
 	bool "HDMI Audio Playback"
-	depends on FB_MSM_MDSS_HDMI_PANEL && (SND_SOC_APQ8084 || SND_SOC_MSM8994 || SND_SOC_MSM8996 || SND_SOC_MSM8998)
+	depends on FB_MSM_MDSS_HDMI_PANEL && (SND_SOC_APQ8084 || SND_SOC_MSM8994 || SND_SOC_MSM8996 || SND_SOC_MSM8998 || SND_SOC_SDM660_COMMON)
 	help
 	HDMI audio drivers should be built only if the platform
         supports hdmi panel.
 
-source "sound/soc/codecs/msm8x16/Kconfig"
+source "sound/soc/codecs/sdm660_cdc/Kconfig"
+source "sound/soc/codecs/msm_sdw/Kconfig"
 
 endmenu
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 78db388..20ae32e 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -482,4 +482,5 @@
 obj-$(CONFIG_SND_SOC_MAX9877)	+= snd-soc-max9877.o
 obj-$(CONFIG_SND_SOC_MAX98504)	+= snd-soc-max98504.o
 obj-$(CONFIG_SND_SOC_TPA6130A2)	+= snd-soc-tpa6130a2.o
-obj-y += msm8x16/
+obj-y += sdm660_cdc/
+obj-y += msm_sdw/
diff --git a/sound/soc/codecs/msm8x16/Makefile b/sound/soc/codecs/msm8x16/Makefile
deleted file mode 100644
index 1e4522f..0000000
--- a/sound/soc/codecs/msm8x16/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-snd-soc-msm8952-wcd-objs := msm8x16-wcd.o msm8x16-wcd-tables.o msm89xx-regmap.o
-obj-$(CONFIG_SND_SOC_MSM8X16_WCD)      += snd-soc-msm8952-wcd.o msm8916-wcd-irq.o
diff --git a/sound/soc/codecs/msm8x16/msm8x16-wcd-tables.c b/sound/soc/codecs/msm8x16/msm8x16-wcd-tables.c
deleted file mode 100644
index b969639..0000000
--- a/sound/soc/codecs/msm8x16/msm8x16-wcd-tables.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/* Copyright (c) 2015-2016, 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 "msm8x16-wcd.h"
-
-const u8 msm89xx_pmic_cdc_reg_readable[MSM89XX_PMIC_CDC_CACHE_SIZE] = {
-		[MSM89XX_PMIC_DIGITAL_REVISION1] = 1,
-		[MSM89XX_PMIC_DIGITAL_REVISION2] = 1,
-		[MSM89XX_PMIC_DIGITAL_PERPH_TYPE] = 1,
-		[MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE] = 1,
-		[MSM89XX_PMIC_DIGITAL_INT_RT_STS] = 1,
-		[MSM89XX_PMIC_DIGITAL_INT_SET_TYPE] = 1,
-		[MSM89XX_PMIC_DIGITAL_INT_POLARITY_HIGH] = 1,
-		[MSM89XX_PMIC_DIGITAL_INT_POLARITY_LOW] = 1,
-		[MSM89XX_PMIC_DIGITAL_INT_EN_SET] = 1,
-		[MSM89XX_PMIC_DIGITAL_INT_EN_CLR] = 1,
-		[MSM89XX_PMIC_DIGITAL_INT_LATCHED_STS] = 1,
-		[MSM89XX_PMIC_DIGITAL_INT_PENDING_STS] = 1,
-		[MSM89XX_PMIC_DIGITAL_INT_MID_SEL] = 1,
-		[MSM89XX_PMIC_DIGITAL_INT_PRIORITY] = 1,
-		[MSM89XX_PMIC_DIGITAL_GPIO_MODE] = 1,
-		[MSM89XX_PMIC_DIGITAL_PIN_CTL_OE] = 1,
-		[MSM89XX_PMIC_DIGITAL_PIN_CTL_DATA] = 1,
-		[MSM89XX_PMIC_DIGITAL_PIN_STATUS] = 1,
-		[MSM89XX_PMIC_DIGITAL_HDRIVE_CTL] = 1,
-		[MSM89XX_PMIC_DIGITAL_CDC_RST_CTL] = 1,
-		[MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL] = 1,
-		[MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL] = 1,
-		[MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL] = 1,
-		[MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL] = 1,
-		[MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL] = 1,
-		[MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL] = 1,
-		[MSM89XX_PMIC_DIGITAL_CDC_CONN_RX1_CTL] = 1,
-		[MSM89XX_PMIC_DIGITAL_CDC_CONN_RX2_CTL] = 1,
-		[MSM89XX_PMIC_DIGITAL_CDC_CONN_RX3_CTL] = 1,
-		[MSM89XX_PMIC_DIGITAL_CDC_CONN_RX_LB_CTL] = 1,
-		[MSM89XX_PMIC_DIGITAL_CDC_RX_CTL1] = 1,
-		[MSM89XX_PMIC_DIGITAL_CDC_RX_CTL2] = 1,
-		[MSM89XX_PMIC_DIGITAL_CDC_RX_CTL3] = 1,
-		[MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA0] = 1,
-		[MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA1] = 1,
-		[MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA2] = 1,
-		[MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA3] = 1,
-		[MSM89XX_PMIC_DIGITAL_DIG_DEBUG_CTL] = 1,
-		[MSM89XX_PMIC_DIGITAL_SPARE_0] = 1,
-		[MSM89XX_PMIC_DIGITAL_SPARE_1] = 1,
-		[MSM89XX_PMIC_DIGITAL_SPARE_2] = 1,
-		[MSM89XX_PMIC_ANALOG_REVISION1] = 1,
-		[MSM89XX_PMIC_ANALOG_REVISION2] = 1,
-		[MSM89XX_PMIC_ANALOG_REVISION3] = 1,
-		[MSM89XX_PMIC_ANALOG_REVISION4] = 1,
-		[MSM89XX_PMIC_ANALOG_PERPH_TYPE] = 1,
-		[MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE] = 1,
-		[MSM89XX_PMIC_ANALOG_INT_RT_STS] = 1,
-		[MSM89XX_PMIC_ANALOG_INT_SET_TYPE] = 1,
-		[MSM89XX_PMIC_ANALOG_INT_POLARITY_HIGH] = 1,
-		[MSM89XX_PMIC_ANALOG_INT_POLARITY_LOW] = 1,
-		[MSM89XX_PMIC_ANALOG_INT_EN_SET] = 1,
-		[MSM89XX_PMIC_ANALOG_INT_EN_CLR] = 1,
-		[MSM89XX_PMIC_ANALOG_INT_LATCHED_STS] = 1,
-		[MSM89XX_PMIC_ANALOG_INT_PENDING_STS] = 1,
-		[MSM89XX_PMIC_ANALOG_INT_MID_SEL] = 1,
-		[MSM89XX_PMIC_ANALOG_INT_PRIORITY] = 1,
-		[MSM89XX_PMIC_ANALOG_MICB_1_EN] = 1,
-		[MSM89XX_PMIC_ANALOG_MICB_1_VAL] = 1,
-		[MSM89XX_PMIC_ANALOG_MICB_1_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS] = 1,
-		[MSM89XX_PMIC_ANALOG_MICB_2_EN] = 1,
-		[MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2] = 1,
-		[MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1] = 1,
-		[MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2] = 1,
-		[MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER] = 1,
-		[MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_MBHC_BTN3_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_MBHC_BTN4_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT] = 1,
-		[MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT] = 1,
-		[MSM89XX_PMIC_ANALOG_TX_1_EN] = 1,
-		[MSM89XX_PMIC_ANALOG_TX_2_EN] = 1,
-		[MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_1] = 1,
-		[MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_2] = 1,
-		[MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS] = 1,
-		[MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV] = 1,
-		[MSM89XX_PMIC_ANALOG_TX_3_EN] = 1,
-		[MSM89XX_PMIC_ANALOG_NCP_EN] = 1,
-		[MSM89XX_PMIC_ANALOG_NCP_CLK] = 1,
-		[MSM89XX_PMIC_ANALOG_NCP_DEGLITCH] = 1,
-		[MSM89XX_PMIC_ANALOG_NCP_FBCTRL] = 1,
-		[MSM89XX_PMIC_ANALOG_NCP_BIAS] = 1,
-		[MSM89XX_PMIC_ANALOG_NCP_VCTRL] = 1,
-		[MSM89XX_PMIC_ANALOG_NCP_TEST] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_CLOCK_DIVIDER] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_COM_OCP_COUNT] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_LDO_OCP] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_EAR_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_ATEST] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_HPH_STATUS] = 1,
-		[MSM89XX_PMIC_ANALOG_RX_EAR_STATUS] = 1,
-		[MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_SPKR_DRV_CLIP_DET] = 1,
-		[MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET] = 1,
-		[MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_SPKR_DRV_MISC] = 1,
-		[MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG] = 1,
-		[MSM89XX_PMIC_ANALOG_CURRENT_LIMIT] = 1,
-		[MSM89XX_PMIC_ANALOG_OUTPUT_VOLTAGE] = 1,
-		[MSM89XX_PMIC_ANALOG_BYPASS_MODE] = 1,
-		[MSM89XX_PMIC_ANALOG_BOOST_EN_CTL] = 1,
-		[MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO] = 1,
-		[MSM89XX_PMIC_ANALOG_RDSON_MAX_DUTY_CYCLE] = 1,
-		[MSM89XX_PMIC_ANALOG_BOOST_TEST1_1] = 1,
-		[MSM89XX_PMIC_ANALOG_BOOST_TEST_2] = 1,
-		[MSM89XX_PMIC_ANALOG_SPKR_SAR_STATUS] = 1,
-		[MSM89XX_PMIC_ANALOG_SPKR_DRV_STATUS] = 1,
-		[MSM89XX_PMIC_ANALOG_PBUS_ADD_CSR] = 1,
-		[MSM89XX_PMIC_ANALOG_PBUS_ADD_SEL] = 1,
-		[MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL] = 1,
-		[MSM89XX_PMIC_DIGITAL_INT_LATCHED_CLR] = 1,
-		[MSM89XX_PMIC_ANALOG_INT_LATCHED_CLR] = 1,
-		[MSM89XX_PMIC_ANALOG_NCP_CLIM_ADDR] = 1,
-		[MSM89XX_PMIC_DIGITAL_SEC_ACCESS] = 1,
-		[MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3] = 1,
-		[MSM89XX_PMIC_ANALOG_SEC_ACCESS] = 1,
-};
-
-const u8 msm89xx_cdc_core_reg_readable[MSM89XX_CDC_CORE_CACHE_SIZE] = {
-		[MSM89XX_CDC_CORE_CLK_RX_RESET_CTL] = 1,
-		[MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_CLK_RX_I2S_CTL] = 1,
-		[MSM89XX_CDC_CORE_CLK_TX_I2S_CTL] = 1,
-		[MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_CLK_OTHR_CTL] = 1,
-		[MSM89XX_CDC_CORE_CLK_RX_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_CLK_MCLK_CTL] = 1,
-		[MSM89XX_CDC_CORE_CLK_PDM_CTL] = 1,
-		[MSM89XX_CDC_CORE_CLK_SD_CTL] = 1,
-		[MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX1_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX2_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX3_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX1_B2_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX2_B2_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX3_B2_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX1_B3_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX2_B3_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX3_B3_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX1_B4_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX2_B4_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX3_B4_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX1_B5_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX2_B5_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX3_B5_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX1_B6_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX2_B6_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX3_B6_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL] = 1,
-		[MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL] = 1,
-		[MSM89XX_CDC_CORE_TOP_GAIN_UPDATE] = 1,
-		[MSM89XX_CDC_CORE_TOP_CTL] = 1,
-		[MSM89XX_CDC_CORE_DEBUG_DESER1_CTL] = 1,
-		[MSM89XX_CDC_CORE_DEBUG_DESER2_CTL] = 1,
-		[MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG] = 1,
-		[MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG] = 1,
-		[MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG] = 1,
-		[MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR1_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR2_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL] = 1,
-		[MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_RX1_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_RX1_B2_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_RX1_B3_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_RX2_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_RX2_B2_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_RX2_B3_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_RX3_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_RX3_B2_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_TX_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL] = 1,
-		[MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL] = 1,
-		[MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER] = 1,
-		[MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER] = 1,
-		[MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER] = 1,
-		[MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER] = 1,
-		[MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN] = 1,
-		[MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN] = 1,
-		[MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN] = 1,
-		[MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN] = 1,
-		[MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG] = 1,
-		[MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG] = 1,
-		[MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG] = 1,
-		[MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG] = 1,
-		[MSM89XX_CDC_CORE_TX1_MUX_CTL] = 1,
-		[MSM89XX_CDC_CORE_TX2_MUX_CTL] = 1,
-		[MSM89XX_CDC_CORE_TX3_MUX_CTL] = 1,
-		[MSM89XX_CDC_CORE_TX4_MUX_CTL] = 1,
-		[MSM89XX_CDC_CORE_TX1_CLK_FS_CTL] = 1,
-		[MSM89XX_CDC_CORE_TX2_CLK_FS_CTL] = 1,
-		[MSM89XX_CDC_CORE_TX3_CLK_FS_CTL] = 1,
-		[MSM89XX_CDC_CORE_TX4_CLK_FS_CTL] = 1,
-		[MSM89XX_CDC_CORE_TX1_DMIC_CTL] = 1,
-		[MSM89XX_CDC_CORE_TX2_DMIC_CTL] = 1,
-		[MSM89XX_CDC_CORE_TX3_DMIC_CTL] = 1,
-		[MSM89XX_CDC_CORE_TX4_DMIC_CTL] = 1,
-};
diff --git a/sound/soc/codecs/msm8x16/msm8x16-wcd.c b/sound/soc/codecs/msm8x16/msm8x16-wcd.c
deleted file mode 100644
index f76dde7..0000000
--- a/sound/soc/codecs/msm8x16/msm8x16-wcd.c
+++ /dev/null
@@ -1,6022 +0,0 @@
-/* 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/device.h>
-#include <linux/printk.h>
-#include <linux/ratelimit.h>
-#include <linux/debugfs.h>
-#include <linux/io.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/pm_runtime.h>
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <linux/spmi.h>
-#include <linux/of_gpio.h>
-#include <linux/regulator/consumer.h>
-#include <linux/mfd/wcd9xxx/core.h>
-#include <linux/qdsp6v2/apr.h>
-#include <linux/timer.h>
-#include <linux/workqueue.h>
-#include <linux/sched.h>
-#include <sound/q6afe-v2.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/tlv.h>
-#include <sound/q6core.h>
-#include <soc/qcom/subsystem_notif.h>
-#include "../../msm/msmfalcon-common.h"
-#include "../wcd-mbhc-v2.h"
-#include "msm8916-wcd-irq.h"
-#include "msm8x16-wcd.h"
-
-#define DRV_NAME "msm-codec"
-#define MSM89XX_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
-			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
-#define MSM89XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
-		SNDRV_PCM_FMTBIT_S24_LE)
-
-#define NUM_INTERPOLATORS	3
-#define BITS_PER_REG		8
-#define MSM89XX_TX_PORT_NUMBER	4
-
-#define MSM89XX_I2S_MASTER_MODE_MASK	0x08
-#define MSM89XX_DIGITAL_CODEC_BASE_ADDR		0x771C000
-#define PMIC_SLAVE_ID_0		0
-#define PMIC_SLAVE_ID_1		1
-
-#define PMIC_MBG_OK		0x2C08
-#define PMIC_LDO7_EN_CTL	0x4646
-#define MASK_MSB_BIT		0x80
-
-#define CODEC_DT_MAX_PROP_SIZE			40
-#define MSM89XX_DIGITAL_CODEC_REG_SIZE		0x400
-#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH	64
-
-#define MCLK_RATE_9P6MHZ	9600000
-#define MCLK_RATE_12P288MHZ	12288000
-
-#define BUS_DOWN 1
-
-/*
- *50 Milliseconds sufficient for DSP bring up in the modem
- * after Sub System Restart
- */
-#define ADSP_STATE_READY_TIMEOUT_MS 50
-
-#define HPHL_PA_DISABLE (0x01 << 1)
-#define HPHR_PA_DISABLE (0x01 << 2)
-#define EAR_PA_DISABLE (0x01 << 3)
-#define SPKR_PA_DISABLE (0x01 << 4)
-
-enum {
-	BOOST_SWITCH = 0,
-	BOOST_ALWAYS,
-	BYPASS_ALWAYS,
-	BOOST_ON_FOREVER,
-};
-
-#define EAR_PMD 0
-#define EAR_PMU 1
-#define SPK_PMD 2
-#define SPK_PMU 3
-
-#define MICBIAS_DEFAULT_VAL 1800000
-#define MICBIAS_MIN_VAL 1600000
-#define MICBIAS_STEP_SIZE 50000
-
-#define DEFAULT_BOOST_VOLTAGE 5000
-#define MIN_BOOST_VOLTAGE 4000
-#define MAX_BOOST_VOLTAGE 5550
-#define BOOST_VOLTAGE_STEP 50
-
-#define MSM89XX_MBHC_BTN_COARSE_ADJ  100 /* in mV */
-#define MSM89XX_MBHC_BTN_FINE_ADJ 12 /* in mV */
-
-#define VOLTAGE_CONVERTER(value, min_value, step_size)\
-	((value - min_value)/step_size)
-
-enum {
-	AIF1_PB = 0,
-	AIF1_CAP,
-	AIF2_VIFEED,
-	NUM_CODEC_DAIS,
-};
-
-enum {
-	RX_MIX1_INP_SEL_ZERO = 0,
-	RX_MIX1_INP_SEL_IIR1,
-	RX_MIX1_INP_SEL_IIR2,
-	RX_MIX1_INP_SEL_RX1,
-	RX_MIX1_INP_SEL_RX2,
-	RX_MIX1_INP_SEL_RX3,
-};
-
-static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
-static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
-static struct snd_soc_dai_driver msm8x16_wcd_i2s_dai[];
-/* By default enable the internal speaker boost */
-static bool spkr_boost_en = true;
-
-#define MSM89XX_ACQUIRE_LOCK(x) \
-	mutex_lock_nested(&x, SINGLE_DEPTH_NESTING)
-
-#define MSM89XX_RELEASE_LOCK(x) mutex_unlock(&x)
-
-
-/* Codec supports 2 IIR filters */
-enum {
-	IIR1 = 0,
-	IIR2,
-	IIR_MAX,
-};
-
-/* Codec supports 5 bands */
-enum {
-	BAND1 = 0,
-	BAND2,
-	BAND3,
-	BAND4,
-	BAND5,
-	BAND_MAX,
-};
-
-struct hpf_work {
-	struct msm8x16_wcd_priv *msm8x16_wcd;
-	u32 decimator;
-	u8 tx_hpf_cut_of_freq;
-	struct delayed_work dwork;
-};
-
-static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
-
-static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = {
-	"cdc-vdd-mic-bias",
-};
-
-static unsigned long rx_digital_gain_reg[] = {
-	MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL,
-	MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL,
-	MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL,
-};
-
-static unsigned long tx_digital_gain_reg[] = {
-	MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN,
-	MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN,
-};
-
-enum {
-	MSM89XX_SPMI_DIGITAL = 0,
-	MSM89XX_SPMI_ANALOG,
-	MSM89XX_CODEC_CORE,
-	MAX_MSM89XX_DEVICE
-};
-
-static struct wcd_mbhc_register
-	wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = {
-
-	WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN",
-			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x80, 7, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN",
-			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x40, 6, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE",
-			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x20, 5, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL",
-			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x18, 3, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE",
-			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x01, 0, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL",
-			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0xC0, 6, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL",
-			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x20, 5, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE",
-			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x10, 4, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE",
-			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x08, 3, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND",
-			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x01, 0, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC",
-			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x06, 1, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN",
-			  MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, 0x80, 7, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC",
-			  MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, 0xF0, 4, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC",
-			  MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, 0x0C, 2, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF",
-			  MSM89XX_PMIC_ANALOG_MBHC_BTN3_CTL, 0x03, 0, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT",
-			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x01,
-			  0, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT",
-			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x02,
-			  1, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT",
-			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x08,
-			  3, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT",
-			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x04,
-			  2, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN",
-			  MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL, 0x10, 4, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT",
-			  MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT, 0xFF, 0, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL",
-			  MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, 0x70, 4, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT",
-			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0xFF,
-			  0, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL",
-			  MSM89XX_PMIC_ANALOG_MICB_2_EN, 0xC0, 6, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME",
-			  MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFC, 2, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN",
-			  MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x10, 4, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN",
-			  MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x20, 5, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN",
-			  MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x30, 4, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE",
-			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT,
-			  0x10, 4, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL",
-			  MSM89XX_PMIC_ANALOG_MICB_2_EN, 0x20, 5, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN",
-			  0, 0, 0, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS",
-			  0, 0, 0, 0),
-	WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL",
-			  0, 0, 0, 0),
-};
-
-struct msm8x16_wcd_spmi {
-	struct spmi_device *spmi;
-	int base;
-};
-
-/* Multiply gain_adj and offset by 1000 and 100 to avoid float arithmetic */
-static const struct wcd_imped_i_ref imped_i_ref[] = {
-	{I_h4_UA, 8, 800, 9000, 10000},
-	{I_pt5_UA, 10, 100, 990, 4600},
-	{I_14_UA, 17, 14, 1050, 700},
-	{I_l4_UA, 10, 4, 1165, 110},
-	{I_1_UA, 0, 1, 1200, 65},
-};
-
-static const struct wcd_mbhc_intr intr_ids = {
-	.mbhc_sw_intr =  MSM89XX_IRQ_MBHC_HS_DET,
-	.mbhc_btn_press_intr = MSM89XX_IRQ_MBHC_PRESS,
-	.mbhc_btn_release_intr = MSM89XX_IRQ_MBHC_RELEASE,
-	.mbhc_hs_ins_intr = MSM89XX_IRQ_MBHC_INSREM_DET1,
-	.mbhc_hs_rem_intr = MSM89XX_IRQ_MBHC_INSREM_DET,
-	.hph_left_ocp = MSM89XX_IRQ_HPHL_OCP,
-	.hph_right_ocp = MSM89XX_IRQ_HPHR_OCP,
-};
-
-static int msm_digcdc_clock_control(bool flag);
-static int msm8x16_wcd_dt_parse_vreg_info(struct device *dev,
-	struct msm8x16_wcd_regulator *vreg,
-	const char *vreg_name, bool ondemand);
-static struct msm8x16_wcd_pdata *msm8x16_wcd_populate_dt_pdata(
-	struct device *dev);
-static int msm8x16_wcd_enable_ext_mb_source(struct wcd_mbhc *mbhc,
-					    bool turn_on);
-static void msm8x16_trim_btn_reg(struct snd_soc_codec *codec);
-static void msm8x16_wcd_set_micb_v(struct snd_soc_codec *codec);
-static void msm8x16_wcd_set_boost_v(struct snd_soc_codec *codec);
-static void msm8x16_wcd_set_auto_zeroing(struct snd_soc_codec *codec,
-		bool enable);
-static void msm8x16_wcd_configure_cap(struct snd_soc_codec *codec,
-		bool micbias1, bool micbias2);
-static bool msm8x16_wcd_use_mb(struct snd_soc_codec *codec);
-
-struct msm8x16_wcd_spmi msm8x16_wcd_modules[MAX_MSM89XX_DEVICE];
-
-static void *adsp_state_notifier;
-
-static struct snd_soc_codec *registered_codec;
-static struct snd_soc_codec *registered_digcodec;
-
-static int get_codec_version(struct msm8x16_wcd_priv *msm8x16_wcd)
-{
-	if (msm8x16_wcd->codec_version == DIANGU)
-		return DIANGU;
-	else if (msm8x16_wcd->codec_version == CAJON_2_0)
-		return CAJON_2_0;
-	else if (msm8x16_wcd->codec_version == CAJON)
-		return CAJON;
-	else if (msm8x16_wcd->codec_version == CONGA)
-		return CONGA;
-	else if (msm8x16_wcd->pmic_rev == TOMBAK_2_0)
-		return TOMBAK_2_0;
-	else if (msm8x16_wcd->pmic_rev == TOMBAK_1_0)
-		return TOMBAK_1_0;
-
-	pr_err("%s: unsupported codec version\n", __func__);
-	return UNSUPPORTED;
-}
-
-static int msm_digcdc_clock_control(bool flag)
-{
-	int ret = -EINVAL;
-	struct msm_asoc_mach_data *pdata = NULL;
-
-	pdata = snd_soc_card_get_drvdata(registered_codec->component.card);
-
-	if (flag) {
-		mutex_lock(&pdata->cdc_int_mclk0_mutex);
-		if (atomic_read(&pdata->int_mclk0_enabled) == false) {
-			pdata->digital_cdc_core_clk.enable = 1;
-			ret = afe_set_lpass_clock_v2(
-					AFE_PORT_ID_INT0_MI2S_RX,
-					&pdata->digital_cdc_core_clk);
-			if (ret < 0) {
-				pr_err("failed to enable the INT_MCLK0\n");
-				goto err_mclk;
-			}
-			pr_err("enabled digital codec core clk\n");
-			atomic_set(&pdata->int_mclk0_enabled, true);
-			schedule_delayed_work(&pdata->disable_int_mclk0_work,
-					      50);
-		}
-err_mclk:
-		mutex_unlock(&pdata->cdc_int_mclk0_mutex);
-		return ret;
-	}
-	return 0;
-}
-
-void enable_digital_callback(void *flag)
-{
-	msm_digcdc_clock_control(true);
-}
-
-void disable_digital_callback(void *flag)
-{
-	msm_digcdc_clock_control(false);
-}
-
-static int snd_soc_read_wrapper(struct snd_soc_codec *codec, u16 reg)
-{
-	int ret = -EINVAL;
-	struct msm8x16_wcd *msm8x16_wcd = codec->control_data;
-
-	pr_err("%s reg = %x\n", __func__, reg);
-	mutex_lock(&msm8x16_wcd->io_lock);
-	if (MSM89XX_IS_PMIC_CDC_REG(reg))
-		ret = snd_soc_read(codec, reg);
-	else if (MSM89XX_IS_CDC_CORE_REG(reg))
-		ret = snd_soc_read(registered_digcodec, reg);
-	mutex_unlock(&msm8x16_wcd->io_lock);
-
-	return ret;
-}
-
-static int snd_soc_write_wrapper(struct snd_soc_codec *codec, u16 reg, u8 val)
-{
-	int ret = -EINVAL;
-	struct msm8x16_wcd *msm8x16_wcd = codec->control_data;
-
-	pr_err("%s reg = %x\n", __func__, reg);
-	mutex_lock(&msm8x16_wcd->io_lock);
-	if (MSM89XX_IS_PMIC_CDC_REG(reg))
-		ret = snd_soc_write(codec, reg, val);
-	else if (MSM89XX_IS_CDC_CORE_REG(reg))
-		ret = snd_soc_write(registered_digcodec, reg, val);
-	mutex_unlock(&msm8x16_wcd->io_lock);
-
-	return ret;
-}
-
-static int snd_soc_update_bits_wrapper(struct snd_soc_codec *codec,
-			u16 reg, u8 mask, u8 val)
-{
-	int ret = -EINVAL;
-	struct msm8x16_wcd *msm8x16_wcd = codec->control_data;
-
-	pr_err("%s reg = %x\n", __func__, reg);
-	mutex_lock(&msm8x16_wcd->io_lock);
-	if (MSM89XX_IS_PMIC_CDC_REG(reg))
-		ret = snd_soc_update_bits(codec, reg, mask, val);
-	else if (MSM89XX_IS_CDC_CORE_REG(reg))
-		ret = snd_soc_update_bits(registered_digcodec, reg, mask, val);
-	mutex_unlock(&msm8x16_wcd->io_lock);
-
-	return ret;
-}
-
-static void wcd_mbhc_meas_imped(struct snd_soc_codec *codec,
-				s16 *impedance_l, s16 *impedance_r)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	if ((msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_BOTH) ||
-		(msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHL)) {
-		/* Enable ZDET_L_MEAS_EN */
-		snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
-				0x08, 0x08);
-		/* Wait for 2ms for measurement to complete */
-		usleep_range(2000, 2100);
-		/* Read Left impedance value from Result1 */
-		*impedance_l = snd_soc_read_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
-		/* Enable ZDET_R_MEAS_EN */
-		snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
-				0x08, 0x00);
-	}
-	if ((msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_BOTH) ||
-		(msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHR)) {
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
-			0x04, 0x04);
-		/* Wait for 2ms for measurement to complete */
-		usleep_range(2000, 2100);
-		/* Read Right impedance value from Result1 */
-		*impedance_r = snd_soc_read_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
-		snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
-				0x04, 0x00);
-	}
-}
-
-static void msm8x16_set_ref_current(struct snd_soc_codec *codec,
-				enum wcd_curr_ref curr_ref)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	pr_err("%s: curr_ref: %d\n", __func__, curr_ref);
-
-	if (get_codec_version(msm8x16_wcd) < CAJON)
-		pr_err("%s: Setting ref current not required\n", __func__);
-
-	msm8x16_wcd->imped_i_ref = imped_i_ref[curr_ref];
-
-	switch (curr_ref) {
-	case I_h4_UA:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MICB_2_EN,
-			0x07, 0x01);
-		break;
-	case I_pt5_UA:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MICB_2_EN,
-			0x07, 0x04);
-		break;
-	case I_14_UA:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MICB_2_EN,
-			0x07, 0x03);
-		break;
-	case I_l4_UA:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MICB_2_EN,
-			0x07, 0x01);
-		break;
-	case I_1_UA:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MICB_2_EN,
-			0x07, 0x00);
-		break;
-	default:
-		pr_err("%s: No ref current set\n", __func__);
-		break;
-	}
-}
-
-static bool msm8x16_adj_ref_current(struct snd_soc_codec *codec,
-					s16 *impedance_l, s16 *impedance_r)
-{
-	int i = 2;
-	s16 compare_imp = 0;
-
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	if (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHR)
-		compare_imp = *impedance_r;
-	else
-		compare_imp = *impedance_l;
-
-	if (get_codec_version(msm8x16_wcd) < CAJON) {
-		pr_err("%s: Reference current adjustment not required\n",
-			 __func__);
-		return false;
-	}
-
-	while (compare_imp < imped_i_ref[i].min_val) {
-		msm8x16_set_ref_current(codec,
-					imped_i_ref[++i].curr_ref);
-		wcd_mbhc_meas_imped(codec,
-				impedance_l, impedance_r);
-		compare_imp = (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHR)
-				? *impedance_r : *impedance_l;
-	}
-
-	return true;
-}
-
-void msm8x16_wcd_spk_ext_pa_cb(
-		int (*codec_spk_ext_pa)(struct snd_soc_codec *codec,
-			int enable), struct snd_soc_codec *codec)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	pr_err("%s: Enter\n", __func__);
-	msm8x16_wcd->codec_spk_ext_pa_cb = codec_spk_ext_pa;
-}
-
-void msm8x16_wcd_hph_comp_cb(
-	int (*codec_hph_comp_gpio)(bool enable), struct snd_soc_codec *codec)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	pr_err("%s: Enter\n", __func__);
-	msm8x16_wcd->codec_hph_comp_gpio = codec_hph_comp_gpio;
-}
-
-static void msm8x16_wcd_compute_impedance(struct snd_soc_codec *codec, s16 l,
-				s16 r, uint32_t *zl, uint32_t *zr, bool high)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-	uint32_t rl = 0, rr = 0;
-	struct wcd_imped_i_ref R = msm8x16_wcd->imped_i_ref;
-	int codec_ver = get_codec_version(msm8x16_wcd);
-
-	switch (codec_ver) {
-	case TOMBAK_1_0:
-	case TOMBAK_2_0:
-	case CONGA:
-		if (high) {
-			pr_err("%s: This plug has high range impedance\n",
-				 __func__);
-			rl = (uint32_t)(((100 * (l * 400 - 200))/96) - 230);
-			rr = (uint32_t)(((100 * (r * 400 - 200))/96) - 230);
-		} else {
-			pr_err("%s: This plug has low range impedance\n",
-				 __func__);
-			rl = (uint32_t)(((1000 * (l * 2 - 1))/1165) - (13/10));
-			rr = (uint32_t)(((1000 * (r * 2 - 1))/1165) - (13/10));
-		}
-		break;
-	case CAJON:
-	case CAJON_2_0:
-	case DIANGU:
-		if (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHL) {
-			rr = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * r - 5)) -
-			   (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
-			rl = (uint32_t)(((10000 * (R.multiplier * (10 * l - 5)))
-			      - R.offset * R.gain_adj)/(R.gain_adj * 100));
-		} else if (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHR) {
-			rr = (uint32_t)(((10000 * (R.multiplier * (10 * r - 5)))
-			      - R.offset * R.gain_adj)/(R.gain_adj * 100));
-			rl = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * l - 5))-
-			   (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
-		} else if (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_NONE) {
-			rr = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * r - 5)) -
-			   (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
-			rl = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * l - 5))-
-			   (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
-		} else {
-			rr = (uint32_t)(((10000 * (R.multiplier * (10 * r - 5)))
-			      - R.offset * R.gain_adj)/(R.gain_adj * 100));
-			rl = (uint32_t)(((10000 * (R.multiplier * (10 * l - 5)))
-			      - R.offset * R.gain_adj)/(R.gain_adj * 100));
-		}
-		break;
-	default:
-		pr_err("%s: No codec mentioned\n", __func__);
-		break;
-	}
-	*zl = rl;
-	*zr = rr;
-}
-
-static struct firmware_cal *msm8x16_wcd_get_hwdep_fw_cal(
-		struct wcd_mbhc *mbhc,
-		enum wcd_cal_type type)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd;
-	struct firmware_cal *hwdep_cal;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	if (!codec) {
-		pr_err("%s: NULL codec pointer\n", __func__);
-		return NULL;
-	}
-	msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-	hwdep_cal = wcdcal_get_fw_cal(msm8x16_wcd->fw_data, type);
-	if (!hwdep_cal) {
-		dev_err(codec->dev, "%s: cal not sent by %d\n",
-				__func__, type);
-		return NULL;
-	}
-	return hwdep_cal;
-}
-
-static void wcd9xxx_spmi_irq_control(struct snd_soc_codec *codec,
-				     int irq, bool enable)
-{
-	if (enable)
-		wcd9xxx_spmi_enable_irq(irq);
-	else
-		wcd9xxx_spmi_disable_irq(irq);
-}
-
-static void msm8x16_mbhc_clk_setup(struct snd_soc_codec *codec,
-				   bool enable)
-{
-	if (enable)
-		snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-				0x08, 0x08);
-	else
-		snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-				0x08, 0x00);
-}
-
-static int msm8x16_mbhc_map_btn_code_to_num(struct snd_soc_codec *codec)
-{
-	int btn_code;
-	int btn;
-
-	btn_code = snd_soc_read_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
-
-	switch (btn_code) {
-	case 0:
-		btn = 0;
-		break;
-	case 1:
-		btn = 1;
-		break;
-	case 3:
-		btn = 2;
-		break;
-	case 7:
-		btn = 3;
-		break;
-	case 15:
-		btn = 4;
-		break;
-	default:
-		btn = -EINVAL;
-		break;
-	};
-
-	return btn;
-}
-
-static bool msm8x16_spmi_lock_sleep(struct wcd_mbhc *mbhc, bool lock)
-{
-	if (lock)
-		return wcd9xxx_spmi_lock_sleep();
-	wcd9xxx_spmi_unlock_sleep();
-	return 0;
-}
-
-static bool msm8x16_wcd_micb_en_status(struct wcd_mbhc *mbhc, int micb_num)
-{
-	if (micb_num == MIC_BIAS_1)
-		return (snd_soc_read_wrapper(mbhc->codec,
-				     MSM89XX_PMIC_ANALOG_MICB_1_EN) &
-			0x80);
-	if (micb_num == MIC_BIAS_2)
-		return (snd_soc_read_wrapper(mbhc->codec,
-				     MSM89XX_PMIC_ANALOG_MICB_2_EN) &
-			0x80);
-	return false;
-}
-
-static void msm8x16_wcd_enable_master_bias(struct snd_soc_codec *codec,
-					   bool enable)
-{
-	if (enable)
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL,
-			0x30, 0x30);
-	else
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL,
-			0x30, 0x00);
-}
-
-static void msm8x16_wcd_mbhc_common_micb_ctrl(struct snd_soc_codec *codec,
-					      int event, bool enable)
-{
-	u16 reg;
-	u8 mask;
-	u8 val;
-
-	switch (event) {
-	case MBHC_COMMON_MICB_PRECHARGE:
-		reg = MSM89XX_PMIC_ANALOG_MICB_1_CTL;
-		mask = 0x60;
-		val = (enable ? 0x60 : 0x00);
-		break;
-	case MBHC_COMMON_MICB_SET_VAL:
-		reg = MSM89XX_PMIC_ANALOG_MICB_1_VAL;
-		mask = 0xFF;
-		val = (enable ? 0xC0 : 0x00);
-		break;
-	case MBHC_COMMON_MICB_TAIL_CURR:
-		reg = MSM89XX_PMIC_ANALOG_MICB_1_EN;
-		mask = 0x04;
-		val = (enable ? 0x04 : 0x00);
-		break;
-	};
-	snd_soc_update_bits_wrapper(codec, reg, mask, val);
-}
-
-static void msm8x16_wcd_mbhc_internal_micbias_ctrl(struct snd_soc_codec *codec,
-						   int micbias_num, bool enable)
-{
-	if (micbias_num == 1) {
-		if (enable)
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS,
-				0x10, 0x10);
-		else
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS,
-				0x10, 0x00);
-	}
-}
-
-static bool msm8x16_wcd_mbhc_hph_pa_on_status(struct snd_soc_codec *codec)
-{
-	return (snd_soc_read_wrapper(codec, MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN) &
-		0x30) ? true : false;
-}
-
-static void msm8x16_wcd_mbhc_program_btn_thr(struct snd_soc_codec *codec,
-					     s16 *btn_low, s16 *btn_high,
-					     int num_btn, bool is_micbias)
-{
-	int i;
-	u32 course, fine, reg_val;
-	u16 reg_addr = MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL;
-	s16 *btn_voltage;
-
-	btn_voltage = ((is_micbias) ? btn_high : btn_low);
-
-	for (i = 0; i <  num_btn; i++) {
-		course = (btn_voltage[i] / MSM89XX_MBHC_BTN_COARSE_ADJ);
-		fine = ((btn_voltage[i] % MSM89XX_MBHC_BTN_COARSE_ADJ) /
-				MSM89XX_MBHC_BTN_FINE_ADJ);
-
-		reg_val = (course << 5) | (fine << 2);
-		snd_soc_update_bits_wrapper(codec, reg_addr, 0xFC, reg_val);
-		pr_err("%s: course: %d fine: %d reg_addr: %x reg_val: %x\n",
-			  __func__, course, fine, reg_addr, reg_val);
-		reg_addr++;
-	}
-}
-
-static void msm8x16_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
-					    uint32_t *zr)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-	s16 impedance_l, impedance_r;
-	s16 impedance_l_fixed;
-	s16 reg0, reg1, reg2, reg3, reg4;
-	bool high = false;
-	bool min_range_used =  false;
-
-	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
-	reg0 = snd_soc_read_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER);
-	reg1 = snd_soc_read_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL);
-	reg2 = snd_soc_read_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2);
-	reg3 = snd_soc_read_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MICB_2_EN);
-	reg4 = snd_soc_read_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL);
-
-	msm8x16_wcd->imped_det_pin = WCD_MBHC_DET_BOTH;
-	mbhc->hph_type = WCD_MBHC_HPH_NONE;
-
-	/* disable FSM and micbias and enable pullup*/
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
-			0x80, 0x00);
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MICB_2_EN,
-			0xA5, 0x25);
-	/*
-	 * Enable legacy electrical detection current sources
-	 * and disable fast ramp and enable manual switching
-	 * of extra capacitance
-	 */
-	pr_err("%s: Setup for impedance det\n", __func__);
-
-	msm8x16_set_ref_current(codec, I_h4_UA);
-
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2,
-			0x06, 0x02);
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER,
-			0x02, 0x02);
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL,
-			0x02, 0x00);
-
-	pr_err("%s: Start performing impedance detection\n",
-		 __func__);
-
-	wcd_mbhc_meas_imped(codec, &impedance_l, &impedance_r);
-
-	if (impedance_l > 2 || impedance_r > 2) {
-		high = true;
-		if (!mbhc->mbhc_cfg->mono_stero_detection) {
-			/* Set ZDET_CHG to 0  to discharge ramp */
-			snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
-					0x02, 0x00);
-			/* wait 40ms for the discharge ramp to complete */
-			usleep_range(40000, 40100);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
-				0x03, 0x00);
-			msm8x16_wcd->imped_det_pin = (impedance_l > 2 &&
-						      impedance_r > 2) ?
-						      WCD_MBHC_DET_NONE :
-						      ((impedance_l > 2) ?
-						      WCD_MBHC_DET_HPHR :
-						      WCD_MBHC_DET_HPHL);
-			if (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_NONE)
-				goto exit;
-		} else {
-			if (get_codec_version(msm8x16_wcd) >= CAJON) {
-				if (impedance_l == 63 && impedance_r == 63) {
-					pr_err("%s: HPHL and HPHR are floating\n",
-						 __func__);
-					msm8x16_wcd->imped_det_pin =
-							WCD_MBHC_DET_NONE;
-					mbhc->hph_type = WCD_MBHC_HPH_NONE;
-				} else if (impedance_l == 63
-					   && impedance_r < 63) {
-					pr_err("%s: Mono HS with HPHL floating\n",
-						 __func__);
-					msm8x16_wcd->imped_det_pin =
-							WCD_MBHC_DET_HPHR;
-					mbhc->hph_type = WCD_MBHC_HPH_MONO;
-				} else if (impedance_r == 63 &&
-					   impedance_l < 63) {
-					pr_err("%s: Mono HS with HPHR floating\n",
-						 __func__);
-					msm8x16_wcd->imped_det_pin =
-							WCD_MBHC_DET_HPHL;
-					mbhc->hph_type = WCD_MBHC_HPH_MONO;
-				} else if (impedance_l > 3 && impedance_r > 3 &&
-					(impedance_l == impedance_r)) {
-					snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2,
-					0x06, 0x06);
-					wcd_mbhc_meas_imped(codec, &impedance_l,
-							    &impedance_r);
-					if (impedance_r == impedance_l)
-						pr_err("%s: Mono Headset\n",
-							  __func__);
-						msm8x16_wcd->imped_det_pin =
-							WCD_MBHC_DET_NONE;
-						mbhc->hph_type =
-							WCD_MBHC_HPH_MONO;
-				} else {
-					pr_err("%s: STEREO headset is found\n",
-						 __func__);
-					msm8x16_wcd->imped_det_pin =
-							WCD_MBHC_DET_BOTH;
-					mbhc->hph_type = WCD_MBHC_HPH_STEREO;
-				}
-			}
-		}
-	}
-
-	msm8x16_set_ref_current(codec, I_pt5_UA);
-	msm8x16_set_ref_current(codec, I_14_UA);
-
-	/* Enable RAMP_L, RAMP_R & ZDET_CHG*/
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
-			0x03, 0x03);
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
-			0x02, 0x02);
-	/* wait for 50msec for the HW to apply ramp on HPHL and HPHR */
-	usleep_range(50000, 50100);
-	/* Enable ZDET_DISCHG_CAP_CTL  to add extra capacitance */
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
-			0x01, 0x01);
-	/* wait for 5msec for the voltage to get stable */
-	usleep_range(5000, 5100);
-
-
-	wcd_mbhc_meas_imped(codec, &impedance_l, &impedance_r);
-
-	min_range_used = msm8x16_adj_ref_current(codec,
-						&impedance_l, &impedance_r);
-	if (!mbhc->mbhc_cfg->mono_stero_detection) {
-		/* Set ZDET_CHG to 0  to discharge ramp */
-		snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
-				0x02, 0x00);
-		/* wait for 40msec for the capacitor to discharge */
-		usleep_range(40000, 40100);
-		snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
-				0x03, 0x00);
-		goto exit;
-	}
-
-	/* we are setting ref current to the minimun range or the measured
-	 * value larger than the minimum value, so min_range_used is true.
-	 * If the headset is mono headset with either HPHL or HPHR floating
-	 * then we have already done the mono stereo detection and do not
-	 * need to continue further.
-	 */
-
-	if (!min_range_used ||
-	    msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHL ||
-	    msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHR)
-		goto exit;
-
-
-	/* Disable Set ZDET_CONN_RAMP_L and enable ZDET_CONN_FIXED_L */
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
-			0x02, 0x00);
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL,
-			0x02, 0x02);
-	/* Set ZDET_CHG to 0  */
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
-			0x02, 0x00);
-	/* wait for 40msec for the capacitor to discharge */
-	usleep_range(40000, 40100);
-
-	/* Set ZDET_CONN_RAMP_R to 0  */
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
-			0x01, 0x00);
-	/* Enable ZDET_L_MEAS_EN */
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
-			0x08, 0x08);
-	/* wait for 2msec for the HW to compute left inpedance value */
-	usleep_range(2000, 2100);
-	/* Read Left impedance value from Result1 */
-	impedance_l_fixed = snd_soc_read_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
-	/* Disable ZDET_L_MEAS_EN */
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
-			0x08, 0x00);
-	/*
-	 * Assume impedance_l is L1, impedance_l_fixed is L2.
-	 * If the following condition is met, we can take this
-	 * headset as mono one with impedance of L2.
-	 * Otherwise, take it as stereo with impedance of L1.
-	 * Condition:
-	 * abs[(L2-0.5L1)/(L2+0.5L1)] < abs [(L2-L1)/(L2+L1)]
-	 */
-	if ((abs(impedance_l_fixed - impedance_l/2) *
-		(impedance_l_fixed + impedance_l)) >=
-		(abs(impedance_l_fixed - impedance_l) *
-		(impedance_l_fixed + impedance_l/2))) {
-		pr_err("%s: STEREO plug type detected\n",
-			 __func__);
-		mbhc->hph_type = WCD_MBHC_HPH_STEREO;
-	} else {
-		pr_err("%s: MONO plug type detected\n",
-			__func__);
-		mbhc->hph_type = WCD_MBHC_HPH_MONO;
-		impedance_l = impedance_l_fixed;
-	}
-	/* Enable ZDET_CHG  */
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
-			0x02, 0x02);
-	/* wait for 10msec for the capacitor to charge */
-	usleep_range(10000, 10100);
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
-			0x02, 0x02);
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL,
-			0x02, 0x00);
-	/* Set ZDET_CHG to 0  to discharge HPHL */
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
-			0x02, 0x00);
-	/* wait for 40msec for the capacitor to discharge */
-	usleep_range(40000, 40100);
-	snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
-			0x02, 0x00);
-
-exit:
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, reg4);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_MICB_2_EN, reg3);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL, reg1);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, reg0);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, reg2);
-	msm8x16_wcd_compute_impedance(codec, impedance_l, impedance_r,
-				      zl, zr, high);
-
-	pr_err("%s: RL %d ohm, RR %d ohm\n", __func__, *zl, *zr);
-	pr_err("%s: Impedance detection completed\n", __func__);
-}
-
-static int msm8x16_register_notifier(struct wcd_mbhc *mbhc,
-				     struct notifier_block *nblock,
-				     bool enable)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-	struct msm8x16_wcd_priv *msm8x16_wcd =
-		snd_soc_codec_get_drvdata(codec);
-
-	if (enable)
-		return blocking_notifier_chain_register(&msm8x16_wcd->notifier,
-							nblock);
-	return blocking_notifier_chain_unregister(
-			&msm8x16_wcd->notifier,	nblock);
-}
-
-static int msm8x16_wcd_request_irq(struct snd_soc_codec *codec,
-				   int irq, irq_handler_t handler,
-				   const char *name, void *data)
-{
-	return wcd9xxx_spmi_request_irq(irq, handler, name, data);
-}
-
-static int msm8x16_wcd_free_irq(struct snd_soc_codec *codec,
-				int irq, void *data)
-{
-	return wcd9xxx_spmi_free_irq(irq, data);
-}
-
-static const struct wcd_mbhc_cb mbhc_cb = {
-	.enable_mb_source = msm8x16_wcd_enable_ext_mb_source,
-	.trim_btn_reg = msm8x16_trim_btn_reg,
-	.compute_impedance = msm8x16_wcd_mbhc_calc_impedance,
-	.set_micbias_value = msm8x16_wcd_set_micb_v,
-	.set_auto_zeroing = msm8x16_wcd_set_auto_zeroing,
-	.get_hwdep_fw_cal = msm8x16_wcd_get_hwdep_fw_cal,
-	.set_cap_mode = msm8x16_wcd_configure_cap,
-	.register_notifier = msm8x16_register_notifier,
-	.request_irq = msm8x16_wcd_request_irq,
-	.irq_control = wcd9xxx_spmi_irq_control,
-	.free_irq = msm8x16_wcd_free_irq,
-	.clk_setup = msm8x16_mbhc_clk_setup,
-	.map_btn_code_to_num = msm8x16_mbhc_map_btn_code_to_num,
-	.lock_sleep = msm8x16_spmi_lock_sleep,
-	.micbias_enable_status = msm8x16_wcd_micb_en_status,
-	.mbhc_bias = msm8x16_wcd_enable_master_bias,
-	.mbhc_common_micb_ctrl = msm8x16_wcd_mbhc_common_micb_ctrl,
-	.micb_internal = msm8x16_wcd_mbhc_internal_micbias_ctrl,
-	.hph_pa_on_status = msm8x16_wcd_mbhc_hph_pa_on_status,
-	.set_btn_thr = msm8x16_wcd_mbhc_program_btn_thr,
-	.extn_use_mb = msm8x16_wcd_use_mb,
-};
-
-static const uint32_t wcd_imped_val[] = {4, 8, 12, 13, 16,
-					20, 24, 28, 32,
-					36, 40, 44, 48};
-
-void msm8x16_notifier_call(struct snd_soc_codec *codec,
-				  const enum wcd_notify_event event)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	pr_err("%s: notifier call event %d\n", __func__, event);
-	blocking_notifier_call_chain(&msm8x16_wcd->notifier, event,
-				     &msm8x16_wcd->mbhc);
-}
-
-static void msm8x16_wcd_boost_on(struct snd_soc_codec *codec)
-{
-	u8 dest = 0x00;
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-
-	if ((dest & MASK_MSB_BIT) == 0) {
-		pr_err("PMIC MBG not ON, enable codec hw_en MB bit again\n");
-		snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30);
-		/* Allow 1ms for PMIC MBG state to be updated */
-		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-	}
-	snd_soc_update_bits_wrapper(codec,
-		MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3,
-		0x0F, 0x0F);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_SEC_ACCESS,
-		0xA5);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3,
-		0x0F);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL,
-		0x30);
-	if (get_codec_version(msm8x16_wcd) < CAJON_2_0) {
-		snd_soc_write_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_CURRENT_LIMIT,
-			0x82);
-	} else {
-		snd_soc_write_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_CURRENT_LIMIT,
-			0xA2);
-	}
-	snd_soc_update_bits_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
-		0x69, 0x69);
-	snd_soc_update_bits_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG,
-		0x01, 0x01);
-	snd_soc_update_bits_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO,
-		0x88, 0x88);
-	snd_soc_update_bits_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
-		0x03, 0x03);
-	snd_soc_update_bits_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL,
-		0xE1, 0xE1);
-	if (get_codec_version(msm8x16_wcd) < CAJON_2_0) {
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-			0x20, 0x20);
-		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
-			0xDF, 0xDF);
-		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-	} else {
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
-			0x40, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-			0x20, 0x20);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
-			0x80, 0x80);
-		usleep_range(500, 510);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
-			0x40, 0x40);
-		usleep_range(500, 510);
-	}
-}
-
-static void msm8x16_wcd_boost_off(struct snd_soc_codec *codec)
-{
-	snd_soc_update_bits_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
-		0xDF, 0x5F);
-	snd_soc_update_bits_wrapper(codec,
-		MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-		0x20, 0x00);
-}
-
-static void msm8x16_wcd_bypass_on(struct snd_soc_codec *codec)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	if (get_codec_version(msm8x16_wcd) < CAJON_2_0) {
-		snd_soc_write_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_SEC_ACCESS,
-			0xA5);
-		snd_soc_write_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3,
-			0x07);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
-			0x02, 0x02);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
-			0x01, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
-			0x40, 0x40);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
-			0x80, 0x80);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
-			0xDF, 0xDF);
-	} else {
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-			0x20, 0x20);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
-			0x20, 0x20);
-	}
-}
-
-static void msm8x16_wcd_bypass_off(struct snd_soc_codec *codec)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	if (get_codec_version(msm8x16_wcd) < CAJON_2_0) {
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
-			0x80, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
-			0x80, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
-			0x02, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
-			0x40, 0x00);
-	} else {
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
-			0x20, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-			0x20, 0x00);
-	}
-}
-
-static void msm8x16_wcd_boost_mode_sequence(struct snd_soc_codec *codec,
-					int flag)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	if (flag == EAR_PMU) {
-		switch (msm8x16_wcd->boost_option) {
-		case BOOST_SWITCH:
-			if (msm8x16_wcd->ear_pa_boost_set) {
-				msm8x16_wcd_boost_off(codec);
-				msm8x16_wcd_bypass_on(codec);
-			}
-			break;
-		case BOOST_ALWAYS:
-			msm8x16_wcd_boost_on(codec);
-			break;
-		case BYPASS_ALWAYS:
-			msm8x16_wcd_bypass_on(codec);
-			break;
-		case BOOST_ON_FOREVER:
-			msm8x16_wcd_boost_on(codec);
-			break;
-		default:
-			pr_err("%s: invalid boost option: %d\n", __func__,
-						msm8x16_wcd->boost_option);
-			break;
-		}
-	} else if (flag == EAR_PMD) {
-		switch (msm8x16_wcd->boost_option) {
-		case BOOST_SWITCH:
-			if (msm8x16_wcd->ear_pa_boost_set)
-				msm8x16_wcd_bypass_off(codec);
-			break;
-		case BOOST_ALWAYS:
-			msm8x16_wcd_boost_off(codec);
-			/* 80ms for EAR boost to settle down */
-			msleep(80);
-			break;
-		case BYPASS_ALWAYS:
-			/* nothing to do as bypass on always */
-			break;
-		case BOOST_ON_FOREVER:
-			/* nothing to do as boost on forever */
-			break;
-		default:
-			pr_err("%s: invalid boost option: %d\n", __func__,
-						msm8x16_wcd->boost_option);
-			break;
-		}
-	} else if (flag == SPK_PMU) {
-		switch (msm8x16_wcd->boost_option) {
-		case BOOST_SWITCH:
-			if (msm8x16_wcd->spk_boost_set) {
-				msm8x16_wcd_bypass_off(codec);
-				msm8x16_wcd_boost_on(codec);
-			}
-			break;
-		case BOOST_ALWAYS:
-			msm8x16_wcd_boost_on(codec);
-			break;
-		case BYPASS_ALWAYS:
-			msm8x16_wcd_bypass_on(codec);
-			break;
-		case BOOST_ON_FOREVER:
-			msm8x16_wcd_boost_on(codec);
-			break;
-		default:
-			pr_err("%s: invalid boost option: %d\n", __func__,
-						msm8x16_wcd->boost_option);
-			break;
-		}
-	} else if (flag == SPK_PMD) {
-		switch (msm8x16_wcd->boost_option) {
-		case BOOST_SWITCH:
-			if (msm8x16_wcd->spk_boost_set) {
-				msm8x16_wcd_boost_off(codec);
-				/*
-				 * Add 40 ms sleep for the spk
-				 * boost to settle down
-				 */
-				msleep(40);
-			}
-			break;
-		case BOOST_ALWAYS:
-			msm8x16_wcd_boost_off(codec);
-			/*
-			 * Add 40 ms sleep for the spk
-			 * boost to settle down
-			 */
-			msleep(40);
-			break;
-		case BYPASS_ALWAYS:
-			/* nothing to do as bypass on always */
-			break;
-		case BOOST_ON_FOREVER:
-			/* nothing to do as boost on forever */
-			break;
-		default:
-			pr_err("%s: invalid boost option: %d\n", __func__,
-						msm8x16_wcd->boost_option);
-			break;
-		}
-	}
-}
-
-static int msm8x16_wcd_dt_parse_vreg_info(struct device *dev,
-	struct msm8x16_wcd_regulator *vreg, const char *vreg_name,
-	bool ondemand)
-{
-	int len, ret = 0;
-	const __be32 *prop;
-	char prop_name[CODEC_DT_MAX_PROP_SIZE];
-	struct device_node *regnode = NULL;
-	u32 prop_val;
-
-	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply",
-		vreg_name);
-	regnode = of_parse_phandle(dev->of_node, prop_name, 0);
-
-	if (!regnode) {
-		dev_err(dev, "Looking up %s property in node %s failed\n",
-			prop_name, dev->of_node->full_name);
-		return -ENODEV;
-	}
-
-	dev_err(dev, "Looking up %s property in node %s\n",
-		prop_name, dev->of_node->full_name);
-
-	vreg->name = vreg_name;
-	vreg->ondemand = ondemand;
-
-	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
-		"qcom,%s-voltage", vreg_name);
-	prop = of_get_property(dev->of_node, prop_name, &len);
-
-	if (!prop || (len != (2 * sizeof(__be32)))) {
-		dev_err(dev, "%s %s property\n",
-			prop ? "invalid format" : "no", prop_name);
-		return -EINVAL;
-	}
-	vreg->min_uv = be32_to_cpup(&prop[0]);
-	vreg->max_uv = be32_to_cpup(&prop[1]);
-
-	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
-		"qcom,%s-current", vreg_name);
-
-	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
-	if (ret) {
-		dev_err(dev, "Looking up %s property in node %s failed",
-			prop_name, dev->of_node->full_name);
-		return -EFAULT;
-	}
-	vreg->optimum_ua = prop_val;
-
-	dev_err(dev, "%s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n\n", vreg->name,
-		 vreg->min_uv, vreg->max_uv, vreg->optimum_ua, vreg->ondemand);
-	return 0;
-}
-
-static void msm8x16_wcd_dt_parse_boost_info(struct snd_soc_codec *codec)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd_priv =
-		snd_soc_codec_get_drvdata(codec);
-	const char *prop_name = "qcom,cdc-boost-voltage";
-	int boost_voltage, ret;
-
-	ret = of_property_read_u32(codec->dev->of_node, prop_name,
-			&boost_voltage);
-	if (ret) {
-		dev_err(codec->dev, "Looking up %s property in node %s failed\n",
-			prop_name, codec->dev->of_node->full_name);
-		boost_voltage = DEFAULT_BOOST_VOLTAGE;
-	}
-	if (boost_voltage < MIN_BOOST_VOLTAGE ||
-			boost_voltage > MAX_BOOST_VOLTAGE) {
-		dev_err(codec->dev,
-				"Incorrect boost voltage. Reverting to default\n");
-		boost_voltage = DEFAULT_BOOST_VOLTAGE;
-	}
-
-	msm8x16_wcd_priv->boost_voltage =
-		VOLTAGE_CONVERTER(boost_voltage, MIN_BOOST_VOLTAGE,
-				BOOST_VOLTAGE_STEP);
-	dev_err(codec->dev, "Boost voltage value is: %d\n",
-			boost_voltage);
-}
-
-static void msm8x16_wcd_dt_parse_micbias_info(struct device *dev,
-			struct wcd9xxx_micbias_setting *micbias)
-{
-	const char *prop_name = "qcom,cdc-micbias-cfilt-mv";
-	int ret;
-
-	ret = of_property_read_u32(dev->of_node, prop_name,
-			&micbias->cfilt1_mv);
-	if (ret) {
-		dev_err(dev, "Looking up %s property in node %s failed",
-			prop_name, dev->of_node->full_name);
-		micbias->cfilt1_mv = MICBIAS_DEFAULT_VAL;
-	}
-}
-
-static struct msm8x16_wcd_pdata *msm8x16_wcd_populate_dt_pdata(
-						struct device *dev)
-{
-	struct msm8x16_wcd_pdata *pdata;
-	int ret, static_cnt, ond_cnt, idx, i;
-	const char *name = NULL;
-	const char *static_prop_name = "qcom,cdc-static-supplies";
-	const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
-
-	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
-	if (!pdata)
-		return NULL;
-
-	static_cnt = of_property_count_strings(dev->of_node, static_prop_name);
-	if (static_cnt < 0) {
-		dev_err(dev, "%s: Failed to get static supplies %d\n", __func__,
-			static_cnt);
-		ret = -EINVAL;
-		goto err;
-	}
-
-	/* On-demand supply list is an optional property */
-	ond_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
-	if (ond_cnt < 0)
-		ond_cnt = 0;
-
-	WARN_ON(static_cnt <= 0 || ond_cnt < 0);
-	if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) {
-		dev_err(dev, "%s: Num of supplies %u > max supported %zd\n",
-				__func__, (static_cnt + ond_cnt),
-					ARRAY_SIZE(pdata->regulator));
-		ret = -EINVAL;
-		goto err;
-	}
-
-	for (idx = 0; idx < static_cnt; idx++) {
-		ret = of_property_read_string_index(dev->of_node,
-						    static_prop_name, idx,
-						    &name);
-		if (ret) {
-			dev_err(dev, "%s: of read string %s idx %d error %d\n",
-				__func__, static_prop_name, idx, ret);
-			goto err;
-		}
-
-		dev_err(dev, "%s: Found static cdc supply %s\n", __func__,
-			name);
-		ret = msm8x16_wcd_dt_parse_vreg_info(dev,
-						&pdata->regulator[idx],
-						name, false);
-		if (ret) {
-			dev_err(dev, "%s:err parsing vreg for %s idx %d\n",
-				__func__, name, idx);
-			goto err;
-		}
-	}
-
-	for (i = 0; i < ond_cnt; i++, idx++) {
-		ret = of_property_read_string_index(dev->of_node, ond_prop_name,
-						    i, &name);
-		if (ret) {
-			dev_err(dev, "%s: err parsing on_demand for %s idx %d\n",
-				__func__, ond_prop_name, i);
-			goto err;
-		}
-
-		dev_err(dev, "%s: Found on-demand cdc supply %s\n", __func__,
-			name);
-		ret = msm8x16_wcd_dt_parse_vreg_info(dev,
-						&pdata->regulator[idx],
-						name, true);
-		if (ret) {
-			dev_err(dev, "%s: err parsing vreg on_demand for %s idx %d\n",
-				__func__, name, idx);
-			goto err;
-		}
-	}
-	msm8x16_wcd_dt_parse_micbias_info(dev, &pdata->micbias);
-	return pdata;
-err:
-	devm_kfree(dev, pdata);
-	dev_err(dev, "%s: Failed to populate DT data ret = %d\n",
-		__func__, ret);
-	return NULL;
-}
-
-static int msm8x16_wcd_codec_enable_on_demand_supply(
-		struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-	int ret = 0;
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-	struct on_demand_supply *supply;
-
-	if (w->shift >= ON_DEMAND_SUPPLIES_MAX) {
-		dev_err(codec->dev, "%s: error index > MAX Demand supplies",
-			__func__);
-		ret = -EINVAL;
-		goto out;
-	}
-	dev_err(codec->dev, "%s: supply: %s event: %d ref: %d\n",
-		__func__, on_demand_supply_name[w->shift], event,
-		atomic_read(&msm8x16_wcd->on_demand_list[w->shift].ref));
-
-	supply = &msm8x16_wcd->on_demand_list[w->shift];
-	WARN_ONCE(!supply->supply, "%s isn't defined\n",
-		  on_demand_supply_name[w->shift]);
-	if (!supply->supply) {
-		dev_err(codec->dev, "%s: err supply not present ond for %d",
-			__func__, w->shift);
-		goto out;
-	}
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		if (atomic_inc_return(&supply->ref) == 1)
-			ret = regulator_enable(supply->supply);
-		if (ret)
-			dev_err(codec->dev, "%s: Failed to enable %s\n",
-				__func__,
-				on_demand_supply_name[w->shift]);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		if (atomic_read(&supply->ref) == 0) {
-			dev_err(codec->dev, "%s: %s supply has been disabled.\n",
-				 __func__, on_demand_supply_name[w->shift]);
-			goto out;
-		}
-		if (atomic_dec_return(&supply->ref) == 0)
-			ret = regulator_disable(supply->supply);
-			if (ret)
-				dev_err(codec->dev, "%s: Failed to disable %s\n",
-					__func__,
-					on_demand_supply_name[w->shift]);
-		break;
-	default:
-		break;
-	}
-out:
-	return ret;
-}
-
-static int msm8x16_wcd_codec_enable_clock_block(struct snd_soc_codec *codec,
-						int enable)
-{
-	struct msm_asoc_mach_data *pdata = NULL;
-
-	pdata = snd_soc_card_get_drvdata(codec->component.card);
-	if (enable) {
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x01, 0x01);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x03);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30, 0x30);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x0C);
-		if (pdata->mclk_freq == MCLK_RATE_12P288MHZ)
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_TOP_CTL, 0x01, 0x00);
-		else if (pdata->mclk_freq == MCLK_RATE_9P6MHZ)
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_TOP_CTL, 0x01, 0x01);
-	} else {
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x00);
-
-	}
-	return 0;
-}
-
-static int msm8x16_wcd_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	dev_err(codec->dev, "%s: event = %d\n", __func__, event);
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		msm8x16_wcd_codec_enable_clock_block(codec, 1);
-		if (!(strcmp(w->name, "EAR CP"))) {
-			snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-					0x80, 0x80);
-			msm8x16_wcd_boost_mode_sequence(codec, EAR_PMU);
-		} else if (get_codec_version(msm8x16_wcd) == DIANGU) {
-			snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-					0x80, 0x80);
-		} else {
-			snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-					0xC0, 0xC0);
-		}
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-		if (!(strcmp(w->name, "EAR CP"))) {
-			snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-					0x80, 0x00);
-			if (msm8x16_wcd->boost_option != BOOST_ALWAYS) {
-				dev_err(codec->dev,
-					"%s: boost_option:%d, tear down ear\n",
-					__func__, msm8x16_wcd->boost_option);
-				msm8x16_wcd_boost_mode_sequence(codec, EAR_PMD);
-			}
-			/*
-			 * Reset pa select bit from ear to hph after ear pa
-			 * is disabled and HPH DAC disable to reduce ear
-			 * turn off pop and avoid HPH pop in concurrency
-			 */
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x80, 0x00);
-		} else {
-			if (get_codec_version(msm8x16_wcd) < DIANGU)
-				snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-					0x40, 0x00);
-			if (msm8x16_wcd->rx_bias_count == 0)
-				snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-					0x80, 0x00);
-			dev_err(codec->dev, "%s: rx_bias_count = %d\n",
-					__func__, msm8x16_wcd->rx_bias_count);
-		}
-		break;
-	}
-	return 0;
-}
-
-static int msm8x16_wcd_ear_pa_boost_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	ucontrol->value.integer.value[0] =
-		(msm8x16_wcd->ear_pa_boost_set ? 1 : 0);
-	dev_err(codec->dev, "%s: msm8x16_wcd->ear_pa_boost_set = %d\n",
-			__func__, msm8x16_wcd->ear_pa_boost_set);
-	return 0;
-}
-
-static int msm8x16_wcd_ear_pa_boost_set(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct msm8x16_wcd_priv *msm8x16_wcd =
-			snd_soc_codec_get_drvdata(codec);
-
-	dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
-		__func__, ucontrol->value.integer.value[0]);
-	msm8x16_wcd->ear_pa_boost_set =
-		(ucontrol->value.integer.value[0] ? true : false);
-	return 0;
-}
-
-static int msm8x16_wcd_pa_gain_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	u8 ear_pa_gain;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-
-	ear_pa_gain = snd_soc_read_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_EAR_CTL);
-
-	ear_pa_gain = (ear_pa_gain >> 5) & 0x1;
-
-	if (ear_pa_gain == 0x00) {
-		ucontrol->value.integer.value[0] = 0;
-	} else if (ear_pa_gain == 0x01) {
-		ucontrol->value.integer.value[0] = 1;
-	} else  {
-		dev_err(codec->dev, "%s: ERROR: Unsupported Ear Gain = 0x%x\n",
-			__func__, ear_pa_gain);
-		return -EINVAL;
-	}
-
-	ucontrol->value.integer.value[0] = ear_pa_gain;
-	dev_err(codec->dev, "%s: ear_pa_gain = 0x%x\n",
-		__func__, ear_pa_gain);
-	return 0;
-}
-
-static int msm8x16_wcd_loopback_mode_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct msm_asoc_mach_data *pdata = NULL;
-
-	pdata = snd_soc_card_get_drvdata(codec->component.card);
-	dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
-		__func__, ucontrol->value.integer.value[0]);
-
-	return pdata->lb_mode;
-}
-
-static int msm8x16_wcd_loopback_mode_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct msm_asoc_mach_data *pdata = NULL;
-
-	pdata = snd_soc_card_get_drvdata(codec->component.card);
-	dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
-		__func__, ucontrol->value.integer.value[0]);
-
-	switch (ucontrol->value.integer.value[0]) {
-	case 0:
-		pdata->lb_mode = false;
-		break;
-	case 1:
-		pdata->lb_mode = true;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int msm8x16_wcd_pa_gain_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	u8 ear_pa_gain;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-
-	dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
-		__func__, ucontrol->value.integer.value[0]);
-
-	switch (ucontrol->value.integer.value[0]) {
-	case 0:
-		ear_pa_gain = 0x00;
-		break;
-	case 1:
-		ear_pa_gain = 0x20;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	snd_soc_update_bits_wrapper(codec, MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
-			    0x20, ear_pa_gain);
-	return 0;
-}
-
-static int msm8x16_wcd_hph_mode_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	if (msm8x16_wcd->hph_mode == NORMAL_MODE) {
-		ucontrol->value.integer.value[0] = 0;
-	} else if (msm8x16_wcd->hph_mode == HD2_MODE) {
-		ucontrol->value.integer.value[0] = 1;
-	} else  {
-		dev_err(codec->dev, "%s: ERROR: Default HPH Mode= %d\n",
-			__func__, msm8x16_wcd->hph_mode);
-	}
-
-	dev_err(codec->dev, "%s: msm8x16_wcd->hph_mode = %d\n", __func__,
-			msm8x16_wcd->hph_mode);
-	return 0;
-}
-
-static int msm8x16_wcd_hph_mode_set(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
-		__func__, ucontrol->value.integer.value[0]);
-
-	switch (ucontrol->value.integer.value[0]) {
-	case 0:
-		msm8x16_wcd->hph_mode = NORMAL_MODE;
-		break;
-	case 1:
-		if (get_codec_version(msm8x16_wcd) >= DIANGU)
-			msm8x16_wcd->hph_mode = HD2_MODE;
-		break;
-	default:
-		msm8x16_wcd->hph_mode = NORMAL_MODE;
-		break;
-	}
-	dev_err(codec->dev, "%s: msm8x16_wcd->hph_mode_set = %d\n",
-		__func__, msm8x16_wcd->hph_mode);
-	return 0;
-}
-
-static int msm8x16_wcd_boost_option_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	if (msm8x16_wcd->boost_option == BOOST_SWITCH) {
-		ucontrol->value.integer.value[0] = 0;
-	} else if (msm8x16_wcd->boost_option == BOOST_ALWAYS) {
-		ucontrol->value.integer.value[0] = 1;
-	} else if (msm8x16_wcd->boost_option == BYPASS_ALWAYS) {
-		ucontrol->value.integer.value[0] = 2;
-	} else if (msm8x16_wcd->boost_option == BOOST_ON_FOREVER) {
-		ucontrol->value.integer.value[0] = 3;
-	} else  {
-		dev_err(codec->dev, "%s: ERROR: Unsupported Boost option= %d\n",
-			__func__, msm8x16_wcd->boost_option);
-		return -EINVAL;
-	}
-
-	dev_err(codec->dev, "%s: msm8x16_wcd->boost_option = %d\n", __func__,
-			msm8x16_wcd->boost_option);
-	return 0;
-}
-
-static int msm8x16_wcd_boost_option_set(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
-		__func__, ucontrol->value.integer.value[0]);
-
-	switch (ucontrol->value.integer.value[0]) {
-	case 0:
-		msm8x16_wcd->boost_option = BOOST_SWITCH;
-		break;
-	case 1:
-		msm8x16_wcd->boost_option = BOOST_ALWAYS;
-		break;
-	case 2:
-		msm8x16_wcd->boost_option = BYPASS_ALWAYS;
-		msm8x16_wcd_bypass_on(codec);
-		break;
-	case 3:
-		msm8x16_wcd->boost_option = BOOST_ON_FOREVER;
-		msm8x16_wcd_boost_on(codec);
-		break;
-	default:
-		pr_err("%s: invalid boost option: %d\n", __func__,
-					msm8x16_wcd->boost_option);
-		return -EINVAL;
-	}
-	dev_err(codec->dev, "%s: msm8x16_wcd->boost_option_set = %d\n",
-		__func__, msm8x16_wcd->boost_option);
-	return 0;
-}
-
-static int msm8x16_wcd_ext_spk_boost_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	if (msm8x16_wcd->ext_spk_boost_set == false)
-		ucontrol->value.integer.value[0] = 0;
-	else
-		ucontrol->value.integer.value[0] = 1;
-
-	dev_err(codec->dev, "%s: msm8x16_wcd->ext_spk_boost_set = %d\n",
-				__func__, msm8x16_wcd->ext_spk_boost_set);
-	return 0;
-}
-
-static int msm8x16_wcd_ext_spk_boost_set(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
-		__func__, ucontrol->value.integer.value[0]);
-
-	switch (ucontrol->value.integer.value[0]) {
-	case 0:
-		msm8x16_wcd->ext_spk_boost_set = false;
-		break;
-	case 1:
-		msm8x16_wcd->ext_spk_boost_set = true;
-		break;
-	default:
-		return -EINVAL;
-	}
-	dev_err(codec->dev, "%s: msm8x16_wcd->spk_boost_set = %d\n",
-		__func__, msm8x16_wcd->spk_boost_set);
-	return 0;
-}
-static int msm8x16_wcd_get_iir_enable_audio_mixer(
-					struct snd_kcontrol *kcontrol,
-					struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	int iir_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->reg;
-	int band_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->shift;
-
-	ucontrol->value.integer.value[0] =
-		(snd_soc_read_wrapper(codec,
-			    (MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx)) &
-		(1 << band_idx)) != 0;
-
-	dev_err(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
-		iir_idx, band_idx,
-		(uint32_t)ucontrol->value.integer.value[0]);
-	return 0;
-}
-
-static int msm8x16_wcd_put_iir_enable_audio_mixer(
-					struct snd_kcontrol *kcontrol,
-					struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	int iir_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->reg;
-	int band_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->shift;
-	int value = ucontrol->value.integer.value[0];
-
-	/* Mask first 5 bits, 6-8 are reserved */
-	snd_soc_update_bits_wrapper(codec,
-		(MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx),
-			    (1 << band_idx), (value << band_idx));
-
-	dev_err(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
-	  iir_idx, band_idx,
-		((snd_soc_read_wrapper(codec,
-		(MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx)) &
-	  (1 << band_idx)) != 0));
-
-	return 0;
-}
-static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
-				   int iir_idx, int band_idx,
-				   int coeff_idx)
-{
-	uint32_t value = 0;
-
-	/* Address does not automatically update if reading */
-	snd_soc_write_wrapper(codec,
-		(MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
-		((band_idx * BAND_MAX + coeff_idx)
-		* sizeof(uint32_t)) & 0x7F);
-
-	value |= snd_soc_read_wrapper(codec,
-		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx));
-
-	snd_soc_write_wrapper(codec,
-		(MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
-		((band_idx * BAND_MAX + coeff_idx)
-		* sizeof(uint32_t) + 1) & 0x7F);
-
-	value |= (snd_soc_read_wrapper(codec,
-		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 8);
-
-	snd_soc_write_wrapper(codec,
-		(MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
-		((band_idx * BAND_MAX + coeff_idx)
-		* sizeof(uint32_t) + 2) & 0x7F);
-
-	value |= (snd_soc_read_wrapper(codec,
-		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 16);
-
-	snd_soc_write_wrapper(codec,
-		(MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
-		((band_idx * BAND_MAX + coeff_idx)
-		* sizeof(uint32_t) + 3) & 0x7F);
-
-	/* Mask bits top 2 bits since they are reserved */
-	value |= ((snd_soc_read_wrapper(codec,
-			(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL
-		+ 64 * iir_idx)) & 0x3f) << 24);
-
-	return value;
-
-}
-
-static int msm8x16_wcd_get_iir_band_audio_mixer(
-					struct snd_kcontrol *kcontrol,
-					struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	int iir_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->reg;
-	int band_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->shift;
-
-	ucontrol->value.integer.value[0] =
-		get_iir_band_coeff(codec, iir_idx, band_idx, 0);
-	ucontrol->value.integer.value[1] =
-		get_iir_band_coeff(codec, iir_idx, band_idx, 1);
-	ucontrol->value.integer.value[2] =
-		get_iir_band_coeff(codec, iir_idx, band_idx, 2);
-	ucontrol->value.integer.value[3] =
-		get_iir_band_coeff(codec, iir_idx, band_idx, 3);
-	ucontrol->value.integer.value[4] =
-		get_iir_band_coeff(codec, iir_idx, band_idx, 4);
-
-	dev_err(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
-		"%s: IIR #%d band #%d b1 = 0x%x\n"
-		"%s: IIR #%d band #%d b2 = 0x%x\n"
-		"%s: IIR #%d band #%d a1 = 0x%x\n"
-		"%s: IIR #%d band #%d a2 = 0x%x\n",
-		__func__, iir_idx, band_idx,
-		(uint32_t)ucontrol->value.integer.value[0],
-		__func__, iir_idx, band_idx,
-		(uint32_t)ucontrol->value.integer.value[1],
-		__func__, iir_idx, band_idx,
-		(uint32_t)ucontrol->value.integer.value[2],
-		__func__, iir_idx, band_idx,
-		(uint32_t)ucontrol->value.integer.value[3],
-		__func__, iir_idx, band_idx,
-		(uint32_t)ucontrol->value.integer.value[4]);
-	return 0;
-}
-
-static void set_iir_band_coeff(struct snd_soc_codec *codec,
-				int iir_idx, int band_idx,
-				uint32_t value)
-{
-	snd_soc_write_wrapper(codec,
-		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
-		(value & 0xFF));
-
-	snd_soc_write_wrapper(codec,
-		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
-		(value >> 8) & 0xFF);
-
-	snd_soc_write_wrapper(codec,
-		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
-		(value >> 16) & 0xFF);
-
-	/* Mask top 2 bits, 7-8 are reserved */
-	snd_soc_write_wrapper(codec,
-		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
-		(value >> 24) & 0x3F);
-
-}
-
-static int msm8x16_wcd_put_iir_band_audio_mixer(
-					struct snd_kcontrol *kcontrol,
-					struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	int iir_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->reg;
-	int band_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->shift;
-
-	/* Mask top bit it is reserved */
-	/* Updates addr automatically for each B2 write */
-	snd_soc_write_wrapper(codec,
-		(MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
-		(band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
-
-
-	set_iir_band_coeff(codec, iir_idx, band_idx,
-			   ucontrol->value.integer.value[0]);
-	set_iir_band_coeff(codec, iir_idx, band_idx,
-			   ucontrol->value.integer.value[1]);
-	set_iir_band_coeff(codec, iir_idx, band_idx,
-			   ucontrol->value.integer.value[2]);
-	set_iir_band_coeff(codec, iir_idx, band_idx,
-			   ucontrol->value.integer.value[3]);
-	set_iir_band_coeff(codec, iir_idx, band_idx,
-			   ucontrol->value.integer.value[4]);
-
-	dev_err(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
-		"%s: IIR #%d band #%d b1 = 0x%x\n"
-		"%s: IIR #%d band #%d b2 = 0x%x\n"
-		"%s: IIR #%d band #%d a1 = 0x%x\n"
-		"%s: IIR #%d band #%d a2 = 0x%x\n",
-		__func__, iir_idx, band_idx,
-		get_iir_band_coeff(codec, iir_idx, band_idx, 0),
-		__func__, iir_idx, band_idx,
-		get_iir_band_coeff(codec, iir_idx, band_idx, 1),
-		__func__, iir_idx, band_idx,
-		get_iir_band_coeff(codec, iir_idx, band_idx, 2),
-		__func__, iir_idx, band_idx,
-		get_iir_band_coeff(codec, iir_idx, band_idx, 3),
-		__func__, iir_idx, band_idx,
-		get_iir_band_coeff(codec, iir_idx, band_idx, 4));
-	return 0;
-}
-
-static int msm8x16_wcd_compander_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-	int comp_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->reg;
-	int rx_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->shift;
-
-	dev_err(codec->dev, "%s: msm8x16_wcd->comp[%d]_enabled[%d] = %d\n",
-			__func__, comp_idx, rx_idx,
-			msm8x16_wcd->comp_enabled[rx_idx]);
-
-	ucontrol->value.integer.value[0] = msm8x16_wcd->comp_enabled[rx_idx];
-
-	dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
-		__func__, ucontrol->value.integer.value[0]);
-
-	return 0;
-}
-
-static int msm8x16_wcd_compander_set(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-	int comp_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->reg;
-	int rx_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->shift;
-	int value = ucontrol->value.integer.value[0];
-
-	dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
-		__func__, ucontrol->value.integer.value[0]);
-
-	if (get_codec_version(msm8x16_wcd) >= DIANGU) {
-		if (!value)
-			msm8x16_wcd->comp_enabled[rx_idx] = 0;
-		else
-			msm8x16_wcd->comp_enabled[rx_idx] = comp_idx;
-	}
-
-	dev_err(codec->dev, "%s: msm8x16_wcd->comp[%d]_enabled[%d] = %d\n",
-		__func__, comp_idx, rx_idx,
-		msm8x16_wcd->comp_enabled[rx_idx]);
-
-	return 0;
-}
-
-static const char * const msm8x16_wcd_loopback_mode_ctrl_text[] = {
-		"DISABLE", "ENABLE"};
-static const struct soc_enum msm8x16_wcd_loopback_mode_ctl_enum[] = {
-		SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_loopback_mode_ctrl_text),
-};
-
-static const char * const msm8x16_wcd_ear_pa_boost_ctrl_text[] = {
-		"DISABLE", "ENABLE"};
-static const struct soc_enum msm8x16_wcd_ear_pa_boost_ctl_enum[] = {
-		SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_ear_pa_boost_ctrl_text),
-};
-
-static const char * const msm8x16_wcd_ear_pa_gain_text[] = {
-		"POS_1P5_DB", "POS_6_DB"};
-static const struct soc_enum msm8x16_wcd_ear_pa_gain_enum[] = {
-		SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_ear_pa_gain_text),
-};
-
-static const char * const msm8x16_wcd_boost_option_ctrl_text[] = {
-		"BOOST_SWITCH", "BOOST_ALWAYS", "BYPASS_ALWAYS",
-		"BOOST_ON_FOREVER"};
-static const struct soc_enum msm8x16_wcd_boost_option_ctl_enum[] = {
-		SOC_ENUM_SINGLE_EXT(4, msm8x16_wcd_boost_option_ctrl_text),
-};
-static const char * const msm8x16_wcd_spk_boost_ctrl_text[] = {
-		"DISABLE", "ENABLE"};
-static const struct soc_enum msm8x16_wcd_spk_boost_ctl_enum[] = {
-		SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_spk_boost_ctrl_text),
-};
-
-static const char * const msm8x16_wcd_ext_spk_boost_ctrl_text[] = {
-		"DISABLE", "ENABLE"};
-static const struct soc_enum msm8x16_wcd_ext_spk_boost_ctl_enum[] = {
-		SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_ext_spk_boost_ctrl_text),
-};
-
-static const char * const msm8x16_wcd_hph_mode_ctrl_text[] = {
-		"NORMAL", "HD2"};
-static const struct soc_enum msm8x16_wcd_hph_mode_ctl_enum[] = {
-		SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(msm8x16_wcd_hph_mode_ctrl_text),
-			msm8x16_wcd_hph_mode_ctrl_text),
-};
-
-/*cut of frequency for high pass filter*/
-static const char * const cf_text[] = {
-	"MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
-};
-
-static const struct soc_enum cf_dec1_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX1_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_dec2_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX2_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_rxmix1_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX1_B4_CTL, 0, 3, cf_text);
-
-static const struct soc_enum cf_rxmix2_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX2_B4_CTL, 0, 3, cf_text);
-
-static const struct soc_enum cf_rxmix3_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX3_B4_CTL, 0, 3, cf_text);
-
-static const struct snd_kcontrol_new msm8x16_wcd_snd_controls[] = {
-
-	SOC_ENUM_EXT("RX HPH Mode", msm8x16_wcd_hph_mode_ctl_enum[0],
-		msm8x16_wcd_hph_mode_get, msm8x16_wcd_hph_mode_set),
-
-	SOC_ENUM_EXT("Boost Option", msm8x16_wcd_boost_option_ctl_enum[0],
-		msm8x16_wcd_boost_option_get, msm8x16_wcd_boost_option_set),
-
-	SOC_ENUM_EXT("EAR PA Boost", msm8x16_wcd_ear_pa_boost_ctl_enum[0],
-		msm8x16_wcd_ear_pa_boost_get, msm8x16_wcd_ear_pa_boost_set),
-
-	SOC_ENUM_EXT("EAR PA Gain", msm8x16_wcd_ear_pa_gain_enum[0],
-		msm8x16_wcd_pa_gain_get, msm8x16_wcd_pa_gain_put),
-
-	SOC_ENUM_EXT("Ext Spk Boost", msm8x16_wcd_ext_spk_boost_ctl_enum[0],
-		msm8x16_wcd_ext_spk_boost_get, msm8x16_wcd_ext_spk_boost_set),
-
-	SOC_ENUM_EXT("LOOPBACK Mode", msm8x16_wcd_loopback_mode_ctl_enum[0],
-		msm8x16_wcd_loopback_mode_get, msm8x16_wcd_loopback_mode_put),
-
-	SOC_SINGLE_TLV("ADC1 Volume", MSM89XX_PMIC_ANALOG_TX_1_EN, 3,
-					8, 0, analog_gain),
-	SOC_SINGLE_TLV("ADC2 Volume", MSM89XX_PMIC_ANALOG_TX_2_EN, 3,
-					8, 0, analog_gain),
-	SOC_SINGLE_TLV("ADC3 Volume", MSM89XX_PMIC_ANALOG_TX_3_EN, 3,
-					8, 0, analog_gain),
-
-	SOC_SINGLE_SX_TLV("RX1 Digital Volume",
-			  MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL,
-			0,  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX2 Digital Volume",
-			  MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL,
-			0,  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX3 Digital Volume",
-			  MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL,
-			0,  -84, 40, digital_gain),
-
-	SOC_SINGLE_SX_TLV("DEC1 Volume",
-			  MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN,
-			0,  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC2 Volume",
-			  MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN,
-			0,  -84, 40, digital_gain),
-
-	SOC_SINGLE_SX_TLV("IIR1 INP1 Volume",
-			  MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL,
-			0,  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP2 Volume",
-			  MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL,
-			0,  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP3 Volume",
-			  MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL,
-			0,  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP4 Volume",
-			  MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL,
-			0,  -84,	40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR2 INP1 Volume",
-			  MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL,
-			0,  -84, 40, digital_gain),
-
-	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
-	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
-
-	SOC_SINGLE("TX1 HPF Switch",
-		MSM89XX_CDC_CORE_TX1_MUX_CTL, 3, 1, 0),
-	SOC_SINGLE("TX2 HPF Switch",
-		MSM89XX_CDC_CORE_TX2_MUX_CTL, 3, 1, 0),
-
-	SOC_SINGLE("RX1 HPF Switch",
-		MSM89XX_CDC_CORE_RX1_B5_CTL, 2, 1, 0),
-	SOC_SINGLE("RX2 HPF Switch",
-		MSM89XX_CDC_CORE_RX2_B5_CTL, 2, 1, 0),
-	SOC_SINGLE("RX3 HPF Switch",
-		MSM89XX_CDC_CORE_RX3_B5_CTL, 2, 1, 0),
-
-	SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
-	SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
-	SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
-
-	SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
-	msm8x16_wcd_get_iir_enable_audio_mixer,
-	msm8x16_wcd_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
-	msm8x16_wcd_get_iir_enable_audio_mixer,
-	msm8x16_wcd_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
-	msm8x16_wcd_get_iir_enable_audio_mixer,
-	msm8x16_wcd_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
-	msm8x16_wcd_get_iir_enable_audio_mixer,
-	msm8x16_wcd_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
-	msm8x16_wcd_get_iir_enable_audio_mixer,
-	msm8x16_wcd_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
-	msm8x16_wcd_get_iir_enable_audio_mixer,
-	msm8x16_wcd_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
-	msm8x16_wcd_get_iir_enable_audio_mixer,
-	msm8x16_wcd_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
-	msm8x16_wcd_get_iir_enable_audio_mixer,
-	msm8x16_wcd_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
-	msm8x16_wcd_get_iir_enable_audio_mixer,
-	msm8x16_wcd_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
-	msm8x16_wcd_get_iir_enable_audio_mixer,
-	msm8x16_wcd_put_iir_enable_audio_mixer),
-
-	SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
-	msm8x16_wcd_get_iir_band_audio_mixer,
-	msm8x16_wcd_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
-	msm8x16_wcd_get_iir_band_audio_mixer,
-	msm8x16_wcd_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
-	msm8x16_wcd_get_iir_band_audio_mixer,
-	msm8x16_wcd_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
-	msm8x16_wcd_get_iir_band_audio_mixer,
-	msm8x16_wcd_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
-	msm8x16_wcd_get_iir_band_audio_mixer,
-	msm8x16_wcd_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
-	msm8x16_wcd_get_iir_band_audio_mixer,
-	msm8x16_wcd_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
-	msm8x16_wcd_get_iir_band_audio_mixer,
-	msm8x16_wcd_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
-	msm8x16_wcd_get_iir_band_audio_mixer,
-	msm8x16_wcd_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
-	msm8x16_wcd_get_iir_band_audio_mixer,
-	msm8x16_wcd_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
-	msm8x16_wcd_get_iir_band_audio_mixer,
-	msm8x16_wcd_put_iir_band_audio_mixer),
-
-	SOC_SINGLE_EXT("COMP0 RX1", COMPANDER_1, MSM89XX_RX1, 1, 0,
-	msm8x16_wcd_compander_get, msm8x16_wcd_compander_set),
-
-	SOC_SINGLE_EXT("COMP0 RX2", COMPANDER_1, MSM89XX_RX2, 1, 0,
-	msm8x16_wcd_compander_get, msm8x16_wcd_compander_set),
-};
-
-static int tombak_hph_impedance_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	int ret;
-	uint32_t zl, zr;
-	bool hphr;
-	struct soc_multi_mixer_control *mc;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct msm8x16_wcd_priv *priv = snd_soc_codec_get_drvdata(codec);
-
-	mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
-
-	hphr = mc->shift;
-	ret = wcd_mbhc_get_impedance(&priv->mbhc, &zl, &zr);
-	if (ret)
-		pr_err("%s: Failed to get mbhc imped", __func__);
-	pr_err("%s: zl %u, zr %u\n", __func__, zl, zr);
-	ucontrol->value.integer.value[0] = hphr ? zr : zl;
-
-	return 0;
-}
-
-static const struct snd_kcontrol_new impedance_detect_controls[] = {
-	SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
-			tombak_hph_impedance_get, NULL),
-	SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
-			tombak_hph_impedance_get, NULL),
-};
-
-static int tombak_get_hph_type(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct msm8x16_wcd_priv *priv = snd_soc_codec_get_drvdata(codec);
-	struct wcd_mbhc *mbhc;
-
-	if (!priv) {
-		pr_err("%s: msm8x16-wcd private data is NULL\n",
-			 __func__);
-		return -EINVAL;
-	}
-
-	mbhc = &priv->mbhc;
-	if (!mbhc) {
-		pr_err("%s: mbhc not initialized\n", __func__);
-		return -EINVAL;
-	}
-
-	ucontrol->value.integer.value[0] = (u32) mbhc->hph_type;
-	pr_err("%s: hph_type = %u\n", __func__, mbhc->hph_type);
-
-	return 0;
-}
-
-static const struct snd_kcontrol_new hph_type_detect_controls[] = {
-	SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0,
-	tombak_get_hph_type, NULL),
-};
-
-static const char * const rx_mix1_text[] = {
-	"ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
-};
-
-static const char * const rx_mix2_text[] = {
-	"ZERO", "IIR1", "IIR2"
-};
-
-static const char * const dec_mux_text[] = {
-	"ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2"
-};
-
-static const char * const dec3_mux_text[] = {
-	"ZERO", "DMIC3"
-};
-
-static const char * const dec4_mux_text[] = {
-	"ZERO", "DMIC4"
-};
-
-static const char * const adc2_mux_text[] = {
-	"ZERO", "INP2", "INP3"
-};
-
-static const char * const ext_spk_text[] = {
-	"Off", "On"
-};
-
-static const char * const wsa_spk_text[] = {
-	"ZERO", "WSA"
-};
-
-static const char * const rdac2_mux_text[] = {
-	"ZERO", "RX2", "RX1"
-};
-
-static const char * const iir_inp1_text[] = {
-	"ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
-};
-
-static const struct soc_enum adc2_enum =
-	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
-		ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
-
-static const struct soc_enum ext_spk_enum =
-	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
-		ARRAY_SIZE(ext_spk_text), ext_spk_text);
-
-static const struct soc_enum wsa_spk_enum =
-	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
-		ARRAY_SIZE(wsa_spk_text), wsa_spk_text);
-
-/* RX1 MIX1 */
-static const struct soc_enum rx_mix1_inp1_chain_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B1_CTL,
-		0, 6, rx_mix1_text);
-
-static const struct soc_enum rx_mix1_inp2_chain_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B1_CTL,
-		3, 6, rx_mix1_text);
-
-static const struct soc_enum rx_mix1_inp3_chain_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B2_CTL,
-		0, 6, rx_mix1_text);
-
-/* RX1 MIX2 */
-static const struct soc_enum rx_mix2_inp1_chain_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B3_CTL,
-		0, 3, rx_mix2_text);
-
-/* RX2 MIX1 */
-static const struct soc_enum rx2_mix1_inp1_chain_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL,
-		0, 6, rx_mix1_text);
-
-static const struct soc_enum rx2_mix1_inp2_chain_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL,
-		3, 6, rx_mix1_text);
-
-static const struct soc_enum rx2_mix1_inp3_chain_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL,
-		0, 6, rx_mix1_text);
-
-/* RX2 MIX2 */
-static const struct soc_enum rx2_mix2_inp1_chain_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B3_CTL,
-		0, 3, rx_mix2_text);
-
-/* RX3 MIX1 */
-static const struct soc_enum rx3_mix1_inp1_chain_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL,
-		0, 6, rx_mix1_text);
-
-static const struct soc_enum rx3_mix1_inp2_chain_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL,
-		3, 6, rx_mix1_text);
-
-static const struct soc_enum rx3_mix1_inp3_chain_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL,
-		0, 6, rx_mix1_text);
-
-/* DEC */
-static const struct soc_enum dec1_mux_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B1_CTL,
-		0, 6, dec_mux_text);
-
-static const struct soc_enum dec2_mux_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B1_CTL,
-		3, 6, dec_mux_text);
-
-static const struct soc_enum dec3_mux_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX3_MUX_CTL, 0,
-				ARRAY_SIZE(dec3_mux_text), dec3_mux_text);
-
-static const struct soc_enum dec4_mux_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX4_MUX_CTL, 0,
-				ARRAY_SIZE(dec4_mux_text), dec4_mux_text);
-
-static const struct soc_enum rdac2_mux_enum =
-	SOC_ENUM_SINGLE(MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL,
-		0, 3, rdac2_mux_text);
-
-static const struct soc_enum iir1_inp1_mux_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL,
-		0, 6, iir_inp1_text);
-
-static const struct soc_enum iir2_inp1_mux_enum =
-	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL,
-		0, 6, iir_inp1_text);
-
-static const struct snd_kcontrol_new ext_spk_mux =
-	SOC_DAPM_ENUM("Ext Spk Switch Mux", ext_spk_enum);
-
-static const struct snd_kcontrol_new rx_mix1_inp1_mux =
-	SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx_mix1_inp2_mux =
-	SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx_mix1_inp3_mux =
-	SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
-	SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
-	SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix1_inp3_mux =
-	SOC_DAPM_ENUM("RX2 MIX1 INP3 Mux", rx2_mix1_inp3_chain_enum);
-
-static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
-	SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
-	SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx3_mix1_inp3_mux =
-	SOC_DAPM_ENUM("RX3 MIX1 INP3 Mux", rx3_mix1_inp3_chain_enum);
-
-static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
-	SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx_mix2_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
-	SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
-
-static const struct snd_kcontrol_new tx_adc2_mux =
-	SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
-
-static int msm8x16_wcd_put_dec_enum(struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_dapm_widget_list *wlist =
-			dapm_kcontrol_get_wlist(kcontrol);
-	struct snd_soc_dapm_widget *w = wlist->widgets[0];
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-	unsigned int dec_mux, decimator;
-	char *dec_name = NULL;
-	char *widget_name = NULL;
-	char *temp;
-	u16 tx_mux_ctl_reg;
-	u8 adc_dmic_sel = 0x0;
-	int ret = 0;
-	char *dec_num;
-
-	if (ucontrol->value.enumerated.item[0] > e->items) {
-		dev_err(codec->dev, "%s: Invalid enum value: %d\n",
-			__func__, ucontrol->value.enumerated.item[0]);
-		return -EINVAL;
-	}
-	dec_mux = ucontrol->value.enumerated.item[0];
-
-	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
-	if (!widget_name) {
-		dev_err(codec->dev, "%s: failed to copy string\n",
-			__func__);
-		return -ENOMEM;
-	}
-	temp = widget_name;
-
-	dec_name = strsep(&widget_name, " ");
-	widget_name = temp;
-	if (!dec_name) {
-		dev_err(codec->dev, "%s: Invalid decimator = %s\n",
-			__func__, w->name);
-		ret =  -EINVAL;
-		goto out;
-	}
-
-	dec_num = strpbrk(dec_name, "12");
-	if (dec_num == NULL) {
-		dev_err(codec->dev, "%s: Invalid DEC selected\n", __func__);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	ret = kstrtouint(dec_num, 10, &decimator);
-	if (ret < 0) {
-		dev_err(codec->dev, "%s: Invalid decimator = %s\n",
-			__func__, dec_name);
-		ret =  -EINVAL;
-		goto out;
-	}
-
-	dev_err(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
-		, __func__, w->name, decimator, dec_mux);
-
-	switch (decimator) {
-	case 1:
-	case 2:
-		if ((dec_mux == 4) || (dec_mux == 5))
-			adc_dmic_sel = 0x1;
-		else
-			adc_dmic_sel = 0x0;
-		break;
-	default:
-		dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
-			__func__, decimator);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	tx_mux_ctl_reg =
-		MSM89XX_CDC_CORE_TX1_MUX_CTL + 32 * (decimator - 1);
-
-	snd_soc_update_bits_wrapper(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
-
-	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
-
-out:
-	kfree(widget_name);
-	return ret;
-}
-
-#define MSM89XX_DEC_ENUM(xname, xenum) \
-{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-	.info = snd_soc_info_enum_double, \
-	.get = snd_soc_dapm_get_enum_double, \
-	.put = msm8x16_wcd_put_dec_enum, \
-	.private_value = (unsigned long)&xenum }
-
-static const struct snd_kcontrol_new dec1_mux =
-	MSM89XX_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
-
-static const struct snd_kcontrol_new dec2_mux =
-	MSM89XX_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
-
-static const struct snd_kcontrol_new dec3_mux =
-	SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
-
-static const struct snd_kcontrol_new dec4_mux =
-	SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
-
-static const struct snd_kcontrol_new rdac2_mux =
-	SOC_DAPM_ENUM("RDAC2 MUX Mux", rdac2_mux_enum);
-
-static const struct snd_kcontrol_new iir1_inp1_mux =
-	SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
-
-static const char * const ear_text[] = {
-	"ZERO", "Switch",
-};
-
-static const struct soc_enum ear_enum =
-	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(ear_text), ear_text);
-
-static const struct snd_kcontrol_new ear_pa_mux[] = {
-	SOC_DAPM_ENUM("EAR_S", ear_enum)
-};
-
-static const struct snd_kcontrol_new wsa_spk_mux[] = {
-	SOC_DAPM_ENUM("WSA Spk Switch", wsa_spk_enum)
-};
-
-static const struct snd_kcontrol_new iir2_inp1_mux =
-	SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
-
-static const char * const hph_text[] = {
-	"ZERO", "Switch",
-};
-
-static const struct soc_enum hph_enum =
-	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(hph_text), hph_text);
-
-static const struct snd_kcontrol_new hphl_mux[] = {
-	SOC_DAPM_ENUM("HPHL", hph_enum)
-};
-
-static const struct snd_kcontrol_new hphr_mux[] = {
-	SOC_DAPM_ENUM("HPHR", hph_enum)
-};
-
-static const struct snd_kcontrol_new spkr_mux[] = {
-	SOC_DAPM_ENUM("SPK", hph_enum)
-};
-
-static const char * const lo_text[] = {
-	"ZERO", "Switch",
-};
-
-static const struct soc_enum lo_enum =
-	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(hph_text), hph_text);
-
-static const struct snd_kcontrol_new lo_mux[] = {
-	SOC_DAPM_ENUM("LINE_OUT", lo_enum)
-};
-
-static void msm8x16_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
-					 int enable)
-{
-	struct msm8x16_wcd_priv *wcd8x16 = snd_soc_codec_get_drvdata(codec);
-
-	dev_err(codec->dev, "%s %d\n", __func__, enable);
-
-	if (enable) {
-		wcd8x16->adc_count++;
-		snd_soc_update_bits_wrapper(codec,
-				    MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL,
-				    0x20, 0x20);
-		snd_soc_update_bits_wrapper(codec,
-				    MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-				    0x10, 0x10);
-	} else {
-		wcd8x16->adc_count--;
-		if (!wcd8x16->adc_count) {
-			snd_soc_update_bits_wrapper(codec,
-				    MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-				    0x10, 0x00);
-			snd_soc_update_bits_wrapper(codec,
-				    MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL,
-					    0x20, 0x0);
-		}
-	}
-}
-
-static int msm8x16_wcd_codec_enable_adc(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	u16 adc_reg;
-	u8 init_bit_shift;
-
-	dev_err(codec->dev, "%s %d\n", __func__, event);
-
-	adc_reg = MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_2;
-
-	if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN)
-		init_bit_shift = 5;
-	else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) ||
-		 (w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN))
-		init_bit_shift = 4;
-	else {
-		dev_err(codec->dev, "%s: Error, invalid adc register\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		msm8x16_wcd_codec_enable_adc_block(codec, 1);
-		if (w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN)
-			snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MICB_1_CTL, 0x02, 0x02);
-		/*
-		 * Add delay of 10 ms to give sufficient time for the voltage
-		 * to shoot up and settle so that the txfe init does not
-		 * happen when the input voltage is changing too much.
-		 */
-		usleep_range(10000, 10010);
-		snd_soc_update_bits_wrapper(codec,
-			adc_reg, 1 << init_bit_shift,
-			1 << init_bit_shift);
-		if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN)
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL,
-				0x03, 0x00);
-		else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) ||
-			(w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN))
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL,
-				0x03, 0x00);
-		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		/*
-		 * Add delay of 12 ms before deasserting the init
-		 * to reduce the tx pop
-		 */
-	usleep_range(12000, 12010);
-		snd_soc_update_bits_wrapper(codec,
-			adc_reg, 1 << init_bit_shift, 0x00);
-		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		msm8x16_wcd_codec_enable_adc_block(codec, 0);
-		if (w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN)
-			snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_MICB_1_CTL, 0x02, 0x00);
-		if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN)
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL,
-				0x03, 0x02);
-		else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) ||
-			(w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN))
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL,
-				0x03, 0x02);
-
-		break;
-	}
-	return 0;
-}
-
-static int msm8x16_wcd_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
-				     struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	dev_err(codec->dev, "%s %d %s\n", __func__, event, w->name);
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0x01, 0x01);
-		switch (msm8x16_wcd->boost_option) {
-		case BOOST_SWITCH:
-			if (!msm8x16_wcd->spk_boost_set)
-				snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
-					0x10, 0x10);
-			break;
-		case BOOST_ALWAYS:
-		case BOOST_ON_FOREVER:
-			break;
-		case BYPASS_ALWAYS:
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
-				0x10, 0x10);
-			break;
-		default:
-			pr_err("%s: invalid boost option: %d\n", __func__,
-						msm8x16_wcd->boost_option);
-			break;
-		}
-		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0xE0, 0xE0);
-		if (get_codec_version(msm8x16_wcd) != TOMBAK_1_0)
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x01, 0x01);
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-		switch (msm8x16_wcd->boost_option) {
-		case BOOST_SWITCH:
-			if (msm8x16_wcd->spk_boost_set)
-				snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
-					0xEF, 0xEF);
-			else
-				snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
-					0x10, 0x00);
-			break;
-		case BOOST_ALWAYS:
-		case BOOST_ON_FOREVER:
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
-				0xEF, 0xEF);
-			break;
-		case BYPASS_ALWAYS:
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x00);
-			break;
-		default:
-			pr_err("%s: invalid boost option: %d\n", __func__,
-						msm8x16_wcd->boost_option);
-			break;
-		}
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00);
-		snd_soc_update_bits_wrapper(codec, w->reg, 0x80, 0x80);
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x01);
-		msm8x16_wcd->mute_mask |= SPKR_PA_DISABLE;
-		/*
-		 * Add 1 ms sleep for the mute to take effect
-		 */
-		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x10);
-		if (get_codec_version(msm8x16_wcd) < CAJON_2_0)
-			msm8x16_wcd_boost_mode_sequence(codec, SPK_PMD);
-		snd_soc_update_bits_wrapper(codec, w->reg, 0x80, 0x00);
-		switch (msm8x16_wcd->boost_option) {
-		case BOOST_SWITCH:
-			if (msm8x16_wcd->spk_boost_set)
-				snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
-					0xEF, 0x69);
-			break;
-		case BOOST_ALWAYS:
-		case BOOST_ON_FOREVER:
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
-				0xEF, 0x69);
-			break;
-		case BYPASS_ALWAYS:
-			break;
-		default:
-			pr_err("%s: invalid boost option: %d\n", __func__,
-						msm8x16_wcd->boost_option);
-			break;
-		}
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0xE0, 0x00);
-		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0x01, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x00);
-		if (get_codec_version(msm8x16_wcd) != TOMBAK_1_0)
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x01, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00);
-		if (get_codec_version(msm8x16_wcd) >= CAJON_2_0)
-			msm8x16_wcd_boost_mode_sequence(codec, SPK_PMD);
-		break;
-	}
-	return 0;
-}
-
-static int msm8x16_wcd_codec_enable_dig_clk(struct snd_soc_dapm_widget *w,
-				     struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-	struct msm_asoc_mach_data *pdata = NULL;
-
-	pdata = snd_soc_card_get_drvdata(codec->component.card);
-
-	dev_err(codec->dev, "%s event %d w->name %s\n", __func__,
-			event, w->name);
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		msm8x16_wcd_codec_enable_clock_block(codec, 1);
-		snd_soc_update_bits_wrapper(codec, w->reg, 0x80, 0x80);
-		msm8x16_wcd_boost_mode_sequence(codec, SPK_PMU);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		if (msm8x16_wcd->rx_bias_count == 0)
-			snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-					0x80, 0x00);
-	}
-	return 0;
-}
-
-static int msm8x16_wcd_codec_enable_dmic(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-	u8  dmic_clk_en;
-	u16 dmic_clk_reg;
-	s32 *dmic_clk_cnt;
-	unsigned int dmic;
-	int ret;
-	char *dec_num = strpbrk(w->name, "12");
-
-	if (dec_num == NULL) {
-		dev_err(codec->dev, "%s: Invalid DMIC\n", __func__);
-		return -EINVAL;
-	}
-
-	ret = kstrtouint(dec_num, 10, &dmic);
-	if (ret < 0) {
-		dev_err(codec->dev,
-			"%s: Invalid DMIC line on the codec\n", __func__);
-		return -EINVAL;
-	}
-
-	switch (dmic) {
-	case 1:
-	case 2:
-		dmic_clk_en = 0x01;
-		dmic_clk_cnt = &(msm8x16_wcd->dmic_1_2_clk_cnt);
-		dmic_clk_reg = MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL;
-		dev_err(codec->dev,
-			"%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
-			__func__, event,  dmic, *dmic_clk_cnt);
-		break;
-	default:
-		dev_err(codec->dev, "%s: Invalid DMIC Selection\n", __func__);
-		return -EINVAL;
-	}
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		(*dmic_clk_cnt)++;
-		if (*dmic_clk_cnt == 1) {
-			snd_soc_update_bits_wrapper(codec, dmic_clk_reg,
-					0x0E, 0x02);
-			snd_soc_update_bits_wrapper(codec, dmic_clk_reg,
-					dmic_clk_en, dmic_clk_en);
-		}
-		if (dmic == 1)
-			snd_soc_update_bits_wrapper(codec,
-			MSM89XX_CDC_CORE_TX1_DMIC_CTL, 0x07, 0x01);
-		if (dmic == 2)
-			snd_soc_update_bits_wrapper(codec,
-			MSM89XX_CDC_CORE_TX2_DMIC_CTL, 0x07, 0x01);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		(*dmic_clk_cnt)--;
-		if (*dmic_clk_cnt  == 0)
-			snd_soc_update_bits_wrapper(codec, dmic_clk_reg,
-					dmic_clk_en, 0);
-		break;
-	}
-	return 0;
-}
-
-static bool msm8x16_wcd_use_mb(struct snd_soc_codec *codec)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	if (get_codec_version(msm8x16_wcd) < CAJON)
-		return true;
-	else
-		return false;
-}
-
-static void msm8x16_wcd_set_auto_zeroing(struct snd_soc_codec *codec,
-					bool enable)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	if (get_codec_version(msm8x16_wcd) < CONGA) {
-		if (enable)
-			/*
-			 * Set autozeroing for special headset detection and
-			 * buttons to work.
-			 */
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MICB_2_EN,
-				0x18, 0x10);
-		else
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MICB_2_EN,
-				0x18, 0x00);
-
-	} else {
-		pr_err("%s: Auto Zeroing is not required from CONGA\n",
-				__func__);
-	}
-}
-
-static void msm8x16_trim_btn_reg(struct snd_soc_codec *codec)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	if (get_codec_version(msm8x16_wcd) == TOMBAK_1_0) {
-		pr_err("%s: This device needs to be trimmed\n", __func__);
-		/*
-		 * Calculate the trim value for each device used
-		 * till is comes in production by hardware team
-		 */
-		snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_SEC_ACCESS,
-				0xA5, 0xA5);
-		snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_TRIM_CTRL2,
-				0xFF, 0x30);
-	} else {
-		pr_err("%s: This device is trimmed at ATE\n", __func__);
-	}
-}
-static int msm8x16_wcd_enable_ext_mb_source(struct wcd_mbhc *mbhc,
-					    bool turn_on)
-{
-	int ret = 0;
-	static int count;
-	struct snd_soc_codec *codec = mbhc->codec;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-
-	dev_err(codec->dev, "%s turn_on: %d count: %d\n", __func__, turn_on,
-			count);
-	if (turn_on) {
-		if (!count) {
-			ret = snd_soc_dapm_force_enable_pin(dapm,
-				"MICBIAS_REGULATOR");
-			snd_soc_dapm_sync(dapm);
-		}
-		count++;
-	} else {
-		if (count > 0)
-			count--;
-		if (!count) {
-			ret = snd_soc_dapm_disable_pin(dapm,
-				"MICBIAS_REGULATOR");
-			snd_soc_dapm_sync(dapm);
-		}
-	}
-
-	if (ret)
-		dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
-			__func__, turn_on ? "enable" : "disabled");
-	else
-		dev_err(codec->dev, "%s: %s external micbias source\n",
-			 __func__, turn_on ? "Enabled" : "Disabled");
-
-	return ret;
-}
-
-static int msm8x16_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct msm8x16_wcd_priv *msm8x16_wcd =
-				snd_soc_codec_get_drvdata(codec);
-	u16 micb_int_reg;
-	char *internal1_text = "Internal1";
-	char *internal2_text = "Internal2";
-	char *internal3_text = "Internal3";
-	char *external2_text = "External2";
-	char *external_text = "External";
-	bool micbias2;
-
-	dev_err(codec->dev, "%s %d\n", __func__, event);
-	switch (w->reg) {
-	case MSM89XX_PMIC_ANALOG_MICB_1_EN:
-	case MSM89XX_PMIC_ANALOG_MICB_2_EN:
-		micb_int_reg = MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS;
-		break;
-	default:
-		dev_err(codec->dev,
-			"%s: Error, invalid micbias register 0x%x\n",
-			__func__, w->reg);
-		return -EINVAL;
-	}
-
-	micbias2 = (snd_soc_read_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_MICB_2_EN) & 0x80);
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		if (strnstr(w->name, internal1_text, strlen(w->name))) {
-			if (get_codec_version(msm8x16_wcd) >= CAJON)
-				snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2,
-					0x02, 0x02);
-			snd_soc_update_bits_wrapper(codec,
-				micb_int_reg, 0x80, 0x80);
-		} else if (strnstr(w->name, internal2_text, strlen(w->name))) {
-			snd_soc_update_bits_wrapper(codec,
-				micb_int_reg, 0x10, 0x10);
-			snd_soc_update_bits_wrapper(codec,
-				w->reg, 0x60, 0x00);
-		} else if (strnstr(w->name, internal3_text, strlen(w->name))) {
-			snd_soc_update_bits_wrapper(codec,
-				micb_int_reg, 0x2, 0x2);
-		/*
-		 * update MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2
-		 * for external bias only, not for external2.
-		 */
-		} else if (!strnstr(w->name, external2_text, strlen(w->name)) &&
-					strnstr(w->name, external_text,
-						strlen(w->name))) {
-			snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2,
-					0x02, 0x02);
-		}
-		if (!strnstr(w->name, external_text, strlen(w->name)))
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MICB_1_EN, 0x05, 0x04);
-		if (w->reg == MSM89XX_PMIC_ANALOG_MICB_1_EN)
-			msm8x16_wcd_configure_cap(codec, true, micbias2);
-
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		if (get_codec_version(msm8x16_wcd) <= TOMBAK_2_0)
-			usleep_range(20000, 20100);
-		if (strnstr(w->name, internal1_text, strlen(w->name))) {
-			snd_soc_update_bits_wrapper(codec,
-				micb_int_reg, 0x40, 0x40);
-		} else if (strnstr(w->name, internal2_text,  strlen(w->name))) {
-			snd_soc_update_bits_wrapper(codec,
-				 micb_int_reg, 0x08, 0x08);
-			msm8x16_notifier_call(codec,
-					WCD_EVENT_POST_MICBIAS_2_ON);
-		} else if (strnstr(w->name, internal3_text, 30)) {
-			snd_soc_update_bits_wrapper(codec,
-				 micb_int_reg, 0x01, 0x01);
-		} else if (strnstr(w->name, external2_text, strlen(w->name))) {
-			msm8x16_notifier_call(codec,
-					WCD_EVENT_POST_MICBIAS_2_ON);
-		}
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		if (strnstr(w->name, internal1_text, strlen(w->name))) {
-			snd_soc_update_bits_wrapper(codec,
-				micb_int_reg, 0xC0, 0x40);
-		} else if (strnstr(w->name, internal2_text, strlen(w->name))) {
-			msm8x16_notifier_call(codec,
-				WCD_EVENT_POST_MICBIAS_2_OFF);
-		} else if (strnstr(w->name, internal3_text, 30)) {
-			snd_soc_update_bits_wrapper(codec,
-				micb_int_reg, 0x2, 0x0);
-		} else if (strnstr(w->name, external2_text, strlen(w->name))) {
-			/*
-			 * send micbias turn off event to mbhc driver and then
-			 * break, as no need to set MICB_1_EN register.
-			 */
-			msm8x16_notifier_call(codec,
-					WCD_EVENT_POST_MICBIAS_2_OFF);
-			break;
-		}
-		if (w->reg == MSM89XX_PMIC_ANALOG_MICB_1_EN)
-			msm8x16_wcd_configure_cap(codec, false, micbias2);
-		break;
-	}
-	return 0;
-}
-
-static void tx_hpf_corner_freq_callback(struct work_struct *work)
-{
-	struct delayed_work *hpf_delayed_work;
-	struct hpf_work *hpf_work;
-	struct msm8x16_wcd_priv *msm8x16_wcd;
-	struct snd_soc_codec *codec;
-	u16 tx_mux_ctl_reg;
-	u8 hpf_cut_of_freq;
-
-	hpf_delayed_work = to_delayed_work(work);
-	hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
-	msm8x16_wcd = hpf_work->msm8x16_wcd;
-	codec = hpf_work->msm8x16_wcd->codec;
-	hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
-
-	tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX1_MUX_CTL +
-			(hpf_work->decimator - 1) * 32;
-
-	dev_err(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
-		 __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
-	snd_soc_update_bits_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV, 0xFF, 0x51);
-
-	snd_soc_update_bits_wrapper(codec,
-		tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
-}
-
-
-#define  TX_MUX_CTL_CUT_OFF_FREQ_MASK	0x30
-#define  CF_MIN_3DB_4HZ			0x0
-#define  CF_MIN_3DB_75HZ		0x1
-#define  CF_MIN_3DB_150HZ		0x2
-
-static int msm8x16_wcd_codec_set_iir_gain(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	int value = 0, reg;
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		if (w->shift == 0)
-			reg = MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL;
-		else if (w->shift == 1)
-			reg = MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL;
-		value = snd_soc_read_wrapper(codec, reg);
-		snd_soc_write_wrapper(codec, reg, value);
-		break;
-	default:
-		pr_err("%s: event = %d not expected\n", __func__, event);
-	}
-	return 0;
-}
-
-static int msm8x16_wcd_codec_enable_dec(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct msm_asoc_mach_data *pdata = NULL;
-	unsigned int decimator;
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-	char *dec_name = NULL;
-	char *widget_name = NULL;
-	char *temp;
-	int ret = 0, i;
-	u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
-	u8 dec_hpf_cut_of_freq;
-	int offset;
-	char *dec_num;
-
-	pdata = snd_soc_card_get_drvdata(codec->component.card);
-	dev_err(codec->dev, "%s %d\n", __func__, event);
-
-	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
-	if (!widget_name)
-		return -ENOMEM;
-	temp = widget_name;
-
-	dec_name = strsep(&widget_name, " ");
-	widget_name = temp;
-	if (!dec_name) {
-		dev_err(codec->dev,
-			"%s: Invalid decimator = %s\n", __func__, w->name);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	dec_num = strpbrk(dec_name, "1234");
-	if (dec_num == NULL) {
-		dev_err(codec->dev, "%s: Invalid Decimator\n", __func__);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	ret = kstrtouint(dec_num, 10, &decimator);
-	if (ret < 0) {
-		dev_err(codec->dev,
-			"%s: Invalid decimator = %s\n", __func__, dec_name);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	dev_err(codec->dev,
-		"%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
-		w->name, dec_name, decimator);
-
-	if (w->reg == MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL) {
-		dec_reset_reg = MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL;
-		offset = 0;
-	} else {
-		dev_err(codec->dev, "%s: Error, incorrect dec\n", __func__);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	tx_vol_ctl_reg = MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG +
-			 32 * (decimator - 1);
-	tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX1_MUX_CTL +
-			  32 * (decimator - 1);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		if (decimator == 3 || decimator == 4) {
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL,
-				0xFF, 0x5);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_TX1_DMIC_CTL +
-					(decimator - 1) * 0x20, 0x7, 0x2);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_TX1_DMIC_CTL +
-					(decimator - 1) * 0x20, 0x7, 0x2);
-		}
-		/* Enableable TX digital mute */
-		snd_soc_update_bits_wrapper(codec, tx_vol_ctl_reg, 0x01, 0x01);
-		for (i = 0; i < NUM_DECIMATORS; i++) {
-			if (decimator == i + 1)
-				msm8x16_wcd->dec_active[i] = true;
-		}
-
-		dec_hpf_cut_of_freq =
-			snd_soc_read_wrapper(codec, tx_mux_ctl_reg);
-
-		dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
-
-		tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
-			dec_hpf_cut_of_freq;
-
-		if (dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ) {
-
-			/* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
-			snd_soc_update_bits_wrapper(codec, tx_mux_ctl_reg, 0x30,
-					    CF_MIN_3DB_150HZ << 4);
-		}
-		snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV,
-				0xFF, 0x42);
-
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		/* enable HPF */
-		snd_soc_update_bits_wrapper(codec, tx_mux_ctl_reg, 0x08, 0x00);
-
-		if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
-				CF_MIN_3DB_150HZ) {
-
-			schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
-					msecs_to_jiffies(300));
-		}
-		/* apply the digital gain after the decimator is enabled*/
-		if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg))
-			snd_soc_write_wrapper(codec,
-				  tx_digital_gain_reg[w->shift + offset],
-				  snd_soc_read_wrapper(codec,
-				  tx_digital_gain_reg[w->shift + offset])
-				  );
-		if (pdata->lb_mode) {
-			pr_err("%s: loopback mode unmute the DEC\n",
-							__func__);
-			snd_soc_update_bits_wrapper(codec,
-				tx_vol_ctl_reg, 0x01, 0x00);
-		}
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits_wrapper(codec, tx_vol_ctl_reg, 0x01, 0x01);
-		msleep(20);
-		snd_soc_update_bits_wrapper(codec, tx_mux_ctl_reg, 0x08, 0x08);
-		cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits_wrapper(codec,
-			dec_reset_reg, 1 << w->shift, 1 << w->shift);
-		snd_soc_update_bits_wrapper(codec,
-			dec_reset_reg, 1 << w->shift, 0x0);
-		snd_soc_update_bits_wrapper(codec,
-			tx_mux_ctl_reg, 0x08, 0x08);
-		snd_soc_update_bits_wrapper(codec,
-			tx_mux_ctl_reg, 0x30,
-			(tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
-		snd_soc_update_bits_wrapper(codec,
-			tx_vol_ctl_reg, 0x01, 0x00);
-		for (i = 0; i < NUM_DECIMATORS; i++) {
-			if (decimator == i + 1)
-				msm8x16_wcd->dec_active[i] = false;
-		}
-		if (decimator == 3 || decimator == 4) {
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL,
-				0xFF, 0x0);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_TX1_DMIC_CTL +
-					(decimator - 1) * 0x20, 0x7, 0x0);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_TX1_DMIC_CTL +
-					(decimator - 1) * 0x20, 0x7, 0x0);
-		}
-		break;
-	}
-out:
-	kfree(widget_name);
-	return ret;
-}
-
-static int msm89xx_wcd_codec_enable_vdd_spkr(struct snd_soc_dapm_widget *w,
-				       struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-	int ret = 0;
-
-	if (!msm8x16_wcd->ext_spk_boost_set) {
-		dev_err(codec->dev, "%s: ext_boost not supported/disabled\n",
-								__func__);
-		return 0;
-	}
-	dev_err(codec->dev, "%s: %s %d\n", __func__, w->name, event);
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		if (msm8x16_wcd->spkdrv_reg) {
-			ret = regulator_enable(msm8x16_wcd->spkdrv_reg);
-			if (ret)
-				dev_err(codec->dev,
-					"%s Failed to enable spkdrv reg %s\n",
-					__func__, MSM89XX_VDD_SPKDRV_NAME);
-		}
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		if (msm8x16_wcd->spkdrv_reg) {
-			ret = regulator_disable(msm8x16_wcd->spkdrv_reg);
-			if (ret)
-				dev_err(codec->dev,
-					"%s: Failed to disable spkdrv_reg %s\n",
-					__func__, MSM89XX_VDD_SPKDRV_NAME);
-		}
-		break;
-	}
-	return 0;
-}
-
-static int msm8x16_wcd_codec_config_compander(struct snd_soc_codec *codec,
-					int interp_n, int event)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	dev_err(codec->dev, "%s: event %d shift %d, enabled %d\n",
-		__func__, event, interp_n,
-		msm8x16_wcd->comp_enabled[interp_n]);
-
-	/* compander is not enabled */
-	if (!msm8x16_wcd->comp_enabled[interp_n])
-		return 0;
-
-	switch (msm8x16_wcd->comp_enabled[interp_n]) {
-	case COMPANDER_1:
-		if (SND_SOC_DAPM_EVENT_ON(event)) {
-			/* Enable Compander Clock */
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x09);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x01);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_COMP0_B1_CTL,
-				1 << interp_n, 1 << interp_n);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x01);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0x50);
-			/* add sleep for compander to settle */
-			usleep_range(1000, 1100);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x28);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0xB0);
-
-			/* Enable Compander GPIO */
-			if (msm8x16_wcd->codec_hph_comp_gpio)
-				msm8x16_wcd->codec_hph_comp_gpio(1);
-		} else if (SND_SOC_DAPM_EVENT_OFF(event)) {
-			/* Disable Compander GPIO */
-			if (msm8x16_wcd->codec_hph_comp_gpio)
-				msm8x16_wcd->codec_hph_comp_gpio(0);
-
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x05);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_COMP0_B1_CTL,
-				1 << interp_n, 0);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x00);
-		}
-		break;
-	default:
-		dev_err(codec->dev, "%s: Invalid compander %d\n", __func__,
-				msm8x16_wcd->comp_enabled[interp_n]);
-		break;
-	};
-
-	return 0;
-}
-
-static int msm8x16_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
-						 struct snd_kcontrol *kcontrol,
-						 int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	dev_err(codec->dev, "%s %d %s\n", __func__, event, w->name);
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		msm8x16_wcd_codec_config_compander(codec, w->shift, event);
-		/* apply the digital gain after the interpolator is enabled*/
-		if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
-			snd_soc_write_wrapper(codec,
-				  rx_digital_gain_reg[w->shift],
-				  snd_soc_read_wrapper(codec,
-				  rx_digital_gain_reg[w->shift])
-				  );
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		msm8x16_wcd_codec_config_compander(codec, w->shift, event);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_CDC_CORE_CLK_RX_RESET_CTL,
-			1 << w->shift, 1 << w->shift);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_CDC_CORE_CLK_RX_RESET_CTL,
-			1 << w->shift, 0x0);
-		/*
-		 * disable the mute enabled during the PMD of this device
-		 */
-		if ((w->shift == 0) &&
-			(msm8x16_wcd->mute_mask & HPHL_PA_DISABLE)) {
-			pr_err("disabling HPHL mute\n");
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00);
-			if (get_codec_version(msm8x16_wcd) >= CAJON)
-				snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP,
-					0xF0, 0x20);
-			msm8x16_wcd->mute_mask &= ~(HPHL_PA_DISABLE);
-		} else if ((w->shift == 1) &&
-				(msm8x16_wcd->mute_mask & HPHR_PA_DISABLE)) {
-			pr_err("disabling HPHR mute\n");
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x00);
-			if (get_codec_version(msm8x16_wcd) >= CAJON)
-				snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP,
-					0xF0, 0x20);
-			msm8x16_wcd->mute_mask &= ~(HPHR_PA_DISABLE);
-		} else if ((w->shift == 2) &&
-				(msm8x16_wcd->mute_mask & SPKR_PA_DISABLE)) {
-			pr_err("disabling SPKR mute\n");
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00);
-			msm8x16_wcd->mute_mask &= ~(SPKR_PA_DISABLE);
-		} else if ((w->shift == 0) &&
-				(msm8x16_wcd->mute_mask & EAR_PA_DISABLE)) {
-			pr_err("disabling EAR mute\n");
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00);
-			msm8x16_wcd->mute_mask &= ~(EAR_PA_DISABLE);
-		}
-	}
-	return 0;
-}
-
-
-/* The register address is the same as other codec so it can use resmgr */
-static int msm8x16_wcd_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	dev_err(codec->dev, "%s %d\n", __func__, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		msm8x16_wcd->rx_bias_count++;
-		if (msm8x16_wcd->rx_bias_count == 1) {
-			snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
-					0x80, 0x80);
-			snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
-					0x01, 0x01);
-		}
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		msm8x16_wcd->rx_bias_count--;
-		if (msm8x16_wcd->rx_bias_count == 0) {
-			snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
-					0x01, 0x00);
-			snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
-					0x80, 0x00);
-		}
-		break;
-	}
-	dev_err(codec->dev, "%s rx_bias_count = %d\n",
-			__func__, msm8x16_wcd->rx_bias_count);
-	return 0;
-}
-
-static uint32_t wcd_get_impedance_value(uint32_t imped)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(wcd_imped_val) - 1; i++) {
-		if (imped >= wcd_imped_val[i] &&
-			imped < wcd_imped_val[i + 1])
-			break;
-	}
-
-	pr_err("%s: selected impedance value = %d\n",
-		 __func__, wcd_imped_val[i]);
-	return wcd_imped_val[i];
-}
-
-void wcd_imped_config(struct snd_soc_codec *codec,
-			uint32_t imped, bool set_gain)
-{
-	uint32_t value;
-	int codec_version;
-	struct msm8x16_wcd_priv *msm8x16_wcd =
-				snd_soc_codec_get_drvdata(codec);
-
-	value = wcd_get_impedance_value(imped);
-
-	if (value < wcd_imped_val[0]) {
-		pr_err("%s, detected impedance is less than 4 Ohm\n",
-			 __func__);
-		return;
-	}
-	if (value >= wcd_imped_val[ARRAY_SIZE(wcd_imped_val) - 1]) {
-		pr_err("%s, invalid imped, greater than 48 Ohm\n = %d\n",
-			__func__, value);
-		return;
-	}
-
-	codec_version = get_codec_version(msm8x16_wcd);
-
-	if (set_gain) {
-		switch (codec_version) {
-		case TOMBAK_1_0:
-		case TOMBAK_2_0:
-		case CONGA:
-			/*
-			 * For 32Ohm load and higher loads, Set 0x19E
-			 * bit 5 to 1 (POS_6_DB_DI). For loads lower
-			 * than 32Ohm (such as 16Ohm load), Set 0x19E
-			 * bit 5 to 0 (POS_1P5_DB_DI)
-			 */
-			if (value >= 32)
-				snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
-					0x20, 0x20);
-			else
-				snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
-					0x20, 0x00);
-			break;
-		case CAJON:
-		case CAJON_2_0:
-		case DIANGU:
-			if (value >= 13) {
-				snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
-					0x20, 0x20);
-				snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_NCP_VCTRL,
-					0x07, 0x07);
-			} else {
-				snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
-					0x20, 0x00);
-				snd_soc_update_bits_wrapper(codec,
-					MSM89XX_PMIC_ANALOG_NCP_VCTRL,
-					0x07, 0x04);
-			}
-			break;
-		}
-	} else {
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
-			0x20, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_NCP_VCTRL,
-			0x07, 0x04);
-	}
-
-	pr_err("%s: Exit\n", __func__);
-}
-
-static int msm8x16_wcd_hphl_dac_event(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	uint32_t impedl, impedr;
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-	int ret;
-
-	dev_err(codec->dev, "%s %s %d\n", __func__, w->name, event);
-	ret = wcd_mbhc_get_impedance(&msm8x16_wcd->mbhc,
-			&impedl, &impedr);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		if (get_codec_version(msm8x16_wcd) > CAJON)
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
-				0x08, 0x08);
-		if (get_codec_version(msm8x16_wcd) == CAJON ||
-			get_codec_version(msm8x16_wcd) == CAJON_2_0) {
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST,
-				0x80, 0x80);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST,
-				0x80, 0x80);
-		}
-		if (get_codec_version(msm8x16_wcd) > CAJON)
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
-				0x08, 0x00);
-		if (msm8x16_wcd->hph_mode == HD2_MODE) {
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x14);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0x10);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x80, 0x80);
-		}
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x02);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x01);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x02);
-		if (!ret)
-			wcd_imped_config(codec, impedl, true);
-		else
-			dev_err(codec->dev, "Failed to get mbhc impedance %d\n",
-				ret);
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x00);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		wcd_imped_config(codec, impedl, false);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x00);
-		if (msm8x16_wcd->hph_mode == HD2_MODE) {
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x00);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0xFF);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x80, 0x00);
-		}
-		break;
-	}
-	return 0;
-}
-
-static int msm8x16_wcd_lo_dac_event(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
-	dev_err(codec->dev, "%s %s %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x20, 0x20);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x80, 0x80);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x08);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x40, 0x40);
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x80, 0x80);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x40, 0x40);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		usleep_range(20000, 20100);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x80, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x40, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x80, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x40, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x20, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00);
-		break;
-	}
-	return 0;
-}
-
-static int msm8x16_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	dev_err(codec->dev, "%s %s %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		if (msm8x16_wcd->hph_mode == HD2_MODE) {
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x14);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0x10);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x80, 0x80);
-		}
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x02);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x02);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x01);
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x00);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x00);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x00);
-		if (msm8x16_wcd->hph_mode == HD2_MODE) {
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x00);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0xFF);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x80, 0x00);
-		}
-		break;
-	}
-	return 0;
-}
-
-static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w,
-			      struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	dev_err(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		if (w->shift == 5)
-			msm8x16_notifier_call(codec,
-					WCD_EVENT_PRE_HPHL_PA_ON);
-		else if (w->shift == 4)
-			msm8x16_notifier_call(codec,
-					WCD_EVENT_PRE_HPHR_PA_ON);
-		snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x20, 0x20);
-		break;
-
-	case SND_SOC_DAPM_POST_PMU:
-		usleep_range(7000, 7100);
-		if (w->shift == 5) {
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x04);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00);
-		} else if (w->shift == 4) {
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x04);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x00);
-		}
-		break;
-
-	case SND_SOC_DAPM_PRE_PMD:
-		if (w->shift == 5) {
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x01);
-			msleep(20);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x00);
-			msm8x16_wcd->mute_mask |= HPHL_PA_DISABLE;
-			msm8x16_notifier_call(codec,
-					WCD_EVENT_PRE_HPHL_PA_OFF);
-		} else if (w->shift == 4) {
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x01);
-			msleep(20);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x00);
-			msm8x16_wcd->mute_mask |= HPHR_PA_DISABLE;
-			msm8x16_notifier_call(codec,
-					WCD_EVENT_PRE_HPHR_PA_OFF);
-		}
-		if (get_codec_version(msm8x16_wcd) >= CAJON) {
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP,
-				0xF0, 0x30);
-		}
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		if (w->shift == 5) {
-			clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK,
-				&msm8x16_wcd->mbhc.hph_pa_dac_state);
-			msm8x16_notifier_call(codec,
-					WCD_EVENT_POST_HPHL_PA_OFF);
-		} else if (w->shift == 4) {
-			clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK,
-				&msm8x16_wcd->mbhc.hph_pa_dac_state);
-			msm8x16_notifier_call(codec,
-					WCD_EVENT_POST_HPHR_PA_OFF);
-		}
-		usleep_range(4000, 4100);
-		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-
-		dev_err(codec->dev,
-			"%s: sleep 10 ms after %s PA disable.\n", __func__,
-			w->name);
-		usleep_range(10000, 10100);
-		break;
-	}
-	return 0;
-}
-
-static const struct snd_soc_dapm_route audio_map[] = {
-	{"RX_I2S_CLK", NULL, "CDC_CONN"},
-	{"I2S RX1", NULL, "RX_I2S_CLK"},
-	{"I2S RX2", NULL, "RX_I2S_CLK"},
-	{"I2S RX3", NULL, "RX_I2S_CLK"},
-
-	{"I2S TX1", NULL, "TX_I2S_CLK"},
-	{"I2S TX2", NULL, "TX_I2S_CLK"},
-	{"AIF2 VI", NULL, "TX_I2S_CLK"},
-
-	{"I2S TX1", NULL, "DEC1 MUX"},
-	{"I2S TX2", NULL, "DEC2 MUX"},
-	{"AIF2 VI", NULL, "DEC3 MUX"},
-	{"AIF2 VI", NULL, "DEC4 MUX"},
-
-	/* RDAC Connections */
-	{"HPHR DAC", NULL, "RDAC2 MUX"},
-	{"RDAC2 MUX", "RX1", "RX1 CHAIN"},
-	{"RDAC2 MUX", "RX2", "RX2 CHAIN"},
-
-	/* WSA */
-	{"WSA_SPK OUT", NULL, "WSA Spk Switch"},
-	{"WSA Spk Switch", "WSA", "EAR PA"},
-
-	/* Earpiece (RX MIX1) */
-	{"EAR", NULL, "EAR_S"},
-	{"EAR_S", "Switch", "EAR PA"},
-	{"EAR PA", NULL, "RX_BIAS"},
-	{"EAR PA", NULL, "HPHL DAC"},
-	{"EAR PA", NULL, "HPHR DAC"},
-	{"EAR PA", NULL, "EAR CP"},
-
-	/* Headset (RX MIX1 and RX MIX2) */
-	{"HEADPHONE", NULL, "HPHL PA"},
-	{"HEADPHONE", NULL, "HPHR PA"},
-
-	{"Ext Spk", NULL, "Ext Spk Switch"},
-	{"Ext Spk Switch", "On", "HPHL PA"},
-	{"Ext Spk Switch", "On", "HPHR PA"},
-
-	{"HPHL PA", NULL, "HPHL"},
-	{"HPHR PA", NULL, "HPHR"},
-	{"HPHL", "Switch", "HPHL DAC"},
-	{"HPHR", "Switch", "HPHR DAC"},
-	{"HPHL PA", NULL, "CP"},
-	{"HPHL PA", NULL, "RX_BIAS"},
-	{"HPHR PA", NULL, "CP"},
-	{"HPHR PA", NULL, "RX_BIAS"},
-	{"HPHL DAC", NULL, "RX1 CHAIN"},
-
-	{"SPK_OUT", NULL, "SPK PA"},
-	{"SPK PA", NULL, "SPK_RX_BIAS"},
-	{"SPK PA", NULL, "SPK"},
-	{"SPK", "Switch", "SPK DAC"},
-	{"SPK DAC", NULL, "RX3 CHAIN"},
-	{"SPK DAC", NULL, "VDD_SPKDRV"},
-
-	/* lineout */
-	{"LINEOUT", NULL, "LINEOUT PA"},
-	{"LINEOUT PA", NULL, "SPK_RX_BIAS"},
-	{"LINEOUT PA", NULL, "LINE_OUT"},
-	{"LINE_OUT", "Switch", "LINEOUT DAC"},
-	{"LINEOUT DAC", NULL, "RX3 CHAIN"},
-
-	/* lineout to WSA */
-	{"WSA_SPK OUT", NULL, "LINEOUT PA"},
-
-	{"RX1 CHAIN", NULL, "RX1 CLK"},
-	{"RX2 CHAIN", NULL, "RX2 CLK"},
-	{"RX3 CHAIN", NULL, "RX3 CLK"},
-	{"RX1 CHAIN", NULL, "RX1 MIX2"},
-	{"RX2 CHAIN", NULL, "RX2 MIX2"},
-	{"RX3 CHAIN", NULL, "RX3 MIX1"},
-
-	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
-	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
-	{"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
-	{"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
-	{"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
-	{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
-	{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
-	{"RX1 MIX2", NULL, "RX1 MIX1"},
-	{"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
-	{"RX2 MIX2", NULL, "RX2 MIX1"},
-	{"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
-
-	{"RX1 MIX1 INP1", "RX1", "I2S RX1"},
-	{"RX1 MIX1 INP1", "RX2", "I2S RX2"},
-	{"RX1 MIX1 INP1", "RX3", "I2S RX3"},
-	{"RX1 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX1 MIX1 INP1", "IIR2", "IIR2"},
-	{"RX1 MIX1 INP2", "RX1", "I2S RX1"},
-	{"RX1 MIX1 INP2", "RX2", "I2S RX2"},
-	{"RX1 MIX1 INP2", "RX3", "I2S RX3"},
-	{"RX1 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX1 MIX1 INP2", "IIR2", "IIR2"},
-	{"RX1 MIX1 INP3", "RX1", "I2S RX1"},
-	{"RX1 MIX1 INP3", "RX2", "I2S RX2"},
-	{"RX1 MIX1 INP3", "RX3", "I2S RX3"},
-
-	{"RX2 MIX1 INP1", "RX1", "I2S RX1"},
-	{"RX2 MIX1 INP1", "RX2", "I2S RX2"},
-	{"RX2 MIX1 INP1", "RX3", "I2S RX3"},
-	{"RX2 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX2 MIX1 INP1", "IIR2", "IIR2"},
-	{"RX2 MIX1 INP2", "RX1", "I2S RX1"},
-	{"RX2 MIX1 INP2", "RX2", "I2S RX2"},
-	{"RX2 MIX1 INP2", "RX3", "I2S RX3"},
-	{"RX2 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX2 MIX1 INP2", "IIR2", "IIR2"},
-
-	{"RX3 MIX1 INP1", "RX1", "I2S RX1"},
-	{"RX3 MIX1 INP1", "RX2", "I2S RX2"},
-	{"RX3 MIX1 INP1", "RX3", "I2S RX3"},
-	{"RX3 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX3 MIX1 INP1", "IIR2", "IIR2"},
-	{"RX3 MIX1 INP2", "RX1", "I2S RX1"},
-	{"RX3 MIX1 INP2", "RX2", "I2S RX2"},
-	{"RX3 MIX1 INP2", "RX3", "I2S RX3"},
-	{"RX3 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX3 MIX1 INP2", "IIR2", "IIR2"},
-
-	{"RX1 MIX2 INP1", "IIR1", "IIR1"},
-	{"RX2 MIX2 INP1", "IIR1", "IIR1"},
-	{"RX1 MIX2 INP1", "IIR2", "IIR2"},
-	{"RX2 MIX2 INP1", "IIR2", "IIR2"},
-
-	/* Decimator Inputs */
-	{"DEC1 MUX", "DMIC1", "DMIC1"},
-	{"DEC1 MUX", "DMIC2", "DMIC2"},
-	{"DEC1 MUX", "ADC1", "ADC1"},
-	{"DEC1 MUX", "ADC2", "ADC2"},
-	{"DEC1 MUX", "ADC3", "ADC3"},
-	{"DEC1 MUX", NULL, "CDC_CONN"},
-
-	{"DEC2 MUX", "DMIC1", "DMIC1"},
-	{"DEC2 MUX", "DMIC2", "DMIC2"},
-	{"DEC2 MUX", "ADC1", "ADC1"},
-	{"DEC2 MUX", "ADC2", "ADC2"},
-	{"DEC2 MUX", "ADC3", "ADC3"},
-	{"DEC2 MUX", NULL, "CDC_CONN"},
-
-	{"DEC3 MUX", "DMIC3", "DMIC3"},
-	{"DEC4 MUX", "DMIC4", "DMIC4"},
-	{"DEC3 MUX", NULL, "CDC_CONN"},
-	{"DEC4 MUX", NULL, "CDC_CONN"},
-	/* ADC Connections */
-	{"ADC2", NULL, "ADC2 MUX"},
-	{"ADC3", NULL, "ADC2 MUX"},
-	{"ADC2 MUX", "INP2", "ADC2_INP2"},
-	{"ADC2 MUX", "INP3", "ADC2_INP3"},
-
-	{"ADC1", NULL, "AMIC1"},
-	{"ADC2_INP2", NULL, "AMIC2"},
-	{"ADC2_INP3", NULL, "AMIC3"},
-
-	/* TODO: Fix this */
-	{"IIR1", NULL, "IIR1 INP1 MUX"},
-	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
-	{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
-	{"IIR2", NULL, "IIR2 INP1 MUX"},
-	{"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
-	{"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"},
-	{"MIC BIAS Internal1", NULL, "INT_LDO_H"},
-	{"MIC BIAS Internal2", NULL, "INT_LDO_H"},
-	{"MIC BIAS External", NULL, "INT_LDO_H"},
-	{"MIC BIAS External2", NULL, "INT_LDO_H"},
-	{"MIC BIAS Internal1", NULL, "MICBIAS_REGULATOR"},
-	{"MIC BIAS Internal2", NULL, "MICBIAS_REGULATOR"},
-	{"MIC BIAS External", NULL, "MICBIAS_REGULATOR"},
-	{"MIC BIAS External2", NULL, "MICBIAS_REGULATOR"},
-};
-
-static int msm8x16_wcd_startup(struct snd_pcm_substream *substream,
-		struct snd_soc_dai *dai)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd =
-		snd_soc_codec_get_drvdata(dai->codec);
-
-	dev_err(dai->codec->dev, "%s(): substream = %s  stream = %d\n",
-		__func__,
-		substream->name, substream->stream);
-	/*
-	 * If status_mask is BU_DOWN it means SSR is not complete.
-	 * So retun error.
-	 */
-	if (test_bit(BUS_DOWN, &msm8x16_wcd->status_mask)) {
-		dev_err(dai->codec->dev, "Error, Device is not up post SSR\n");
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static void msm8x16_wcd_shutdown(struct snd_pcm_substream *substream,
-		struct snd_soc_dai *dai)
-{
-	dev_err(dai->codec->dev,
-		"%s(): substream = %s  stream = %d\n", __func__,
-		substream->name, substream->stream);
-}
-
-int msm8x16_wcd_mclk_enable(struct snd_soc_codec *codec,
-			    int mclk_enable, bool dapm)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	dev_err(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
-		__func__, mclk_enable, dapm);
-	if (mclk_enable) {
-		msm8x16_wcd->int_mclk0_enabled = true;
-		msm8x16_wcd_codec_enable_clock_block(codec, 1);
-	} else {
-		if (!msm8x16_wcd->int_mclk0_enabled) {
-			dev_err(codec->dev, "Error, MCLK already diabled\n");
-			return -EINVAL;
-		}
-		msm8x16_wcd->int_mclk0_enabled = false;
-		msm8x16_wcd_codec_enable_clock_block(codec, 0);
-	}
-	return 0;
-}
-
-static int msm8x16_wcd_set_dai_sysclk(struct snd_soc_dai *dai,
-		int clk_id, unsigned int freq, int dir)
-{
-	dev_err(dai->codec->dev, "%s\n", __func__);
-	return 0;
-}
-
-static int msm8x16_wcd_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-{
-	dev_err(dai->codec->dev, "%s\n", __func__);
-	return 0;
-}
-
-static int msm8x16_wcd_set_channel_map(struct snd_soc_dai *dai,
-				unsigned int tx_num, unsigned int *tx_slot,
-				unsigned int rx_num, unsigned int *rx_slot)
-
-{
-	dev_err(dai->codec->dev, "%s\n", __func__);
-	return 0;
-}
-
-static int msm8x16_wcd_get_channel_map(struct snd_soc_dai *dai,
-				 unsigned int *tx_num, unsigned int *tx_slot,
-				 unsigned int *rx_num, unsigned int *rx_slot)
-
-{
-	dev_err(dai->codec->dev, "%s\n", __func__);
-	return 0;
-}
-
-static int msm8x16_wcd_set_interpolator_rate(struct snd_soc_dai *dai,
-	u8 rx_fs_rate_reg_val, u32 sample_rate)
-{
-	snd_soc_update_bits_wrapper(dai->codec,
-			MSM89XX_CDC_CORE_RX1_B5_CTL, 0xF0, rx_fs_rate_reg_val);
-	snd_soc_update_bits_wrapper(dai->codec,
-			MSM89XX_CDC_CORE_RX2_B5_CTL, 0xF0, rx_fs_rate_reg_val);
-	return 0;
-}
-
-static int msm8x16_wcd_set_decimator_rate(struct snd_soc_dai *dai,
-	u8 tx_fs_rate_reg_val, u32 sample_rate)
-{
-	return 0;
-}
-
-static int msm8x16_wcd_hw_params(struct snd_pcm_substream *substream,
-			    struct snd_pcm_hw_params *params,
-			    struct snd_soc_dai *dai)
-{
-	u8 tx_fs_rate, rx_fs_rate, rx_clk_fs_rate;
-	int ret;
-
-	dev_err(dai->codec->dev,
-		"%s: dai_name = %s DAI-ID %x rate %d num_ch %d format %d\n",
-		__func__, dai->name, dai->id, params_rate(params),
-		params_channels(params), params_format(params));
-
-	switch (params_rate(params)) {
-	case 8000:
-		tx_fs_rate = 0x00;
-		rx_fs_rate = 0x00;
-		rx_clk_fs_rate = 0x00;
-		break;
-	case 16000:
-		tx_fs_rate = 0x20;
-		rx_fs_rate = 0x20;
-		rx_clk_fs_rate = 0x01;
-		break;
-	case 32000:
-		tx_fs_rate = 0x40;
-		rx_fs_rate = 0x40;
-		rx_clk_fs_rate = 0x02;
-		break;
-	case 48000:
-		tx_fs_rate = 0x60;
-		rx_fs_rate = 0x60;
-		rx_clk_fs_rate = 0x03;
-		break;
-	case 96000:
-		tx_fs_rate = 0x80;
-		rx_fs_rate = 0x80;
-		rx_clk_fs_rate = 0x04;
-		break;
-	case 192000:
-		tx_fs_rate = 0xA0;
-		rx_fs_rate = 0xA0;
-		rx_clk_fs_rate = 0x05;
-		break;
-	default:
-		dev_err(dai->codec->dev,
-			"%s: Invalid sampling rate %d\n", __func__,
-			params_rate(params));
-		return -EINVAL;
-	}
-
-	snd_soc_update_bits_wrapper(dai->codec,
-			MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x0F, rx_clk_fs_rate);
-
-	switch (substream->stream) {
-	case SNDRV_PCM_STREAM_CAPTURE:
-		ret = msm8x16_wcd_set_decimator_rate(dai, tx_fs_rate,
-					       params_rate(params));
-		if (ret < 0) {
-			dev_err(dai->codec->dev,
-				"%s: set decimator rate failed %d\n", __func__,
-				ret);
-			return ret;
-		}
-		break;
-	case SNDRV_PCM_STREAM_PLAYBACK:
-		ret = msm8x16_wcd_set_interpolator_rate(dai, rx_fs_rate,
-						  params_rate(params));
-		if (ret < 0) {
-			dev_err(dai->codec->dev,
-				"%s: set decimator rate failed %d\n", __func__,
-				ret);
-			return ret;
-		}
-		break;
-	default:
-		dev_err(dai->codec->dev,
-			"%s: Invalid stream type %d\n", __func__,
-			substream->stream);
-		return -EINVAL;
-	}
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S16_LE:
-		snd_soc_update_bits_wrapper(dai->codec,
-				MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x20, 0x20);
-		break;
-	case SNDRV_PCM_FORMAT_S24_LE:
-		snd_soc_update_bits_wrapper(dai->codec,
-				MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x20, 0x00);
-		break;
-	default:
-		dev_err(dai->codec->dev, "%s: wrong format selected\n",
-				__func__);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-int msm8x16_wcd_digital_mute(struct snd_soc_dai *dai, int mute)
-{
-	struct snd_soc_codec *codec = NULL;
-	u16 tx_vol_ctl_reg = 0;
-	u8 decimator = 0, i;
-	struct msm8x16_wcd_priv *msm8x16_wcd;
-
-	pr_err("%s: Digital Mute val = %d\n", __func__, mute);
-
-	if (!dai || !dai->codec) {
-		pr_err("%s: Invalid params\n", __func__);
-		return -EINVAL;
-	}
-	codec = dai->codec;
-	msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	if ((dai->id != AIF1_CAP) && (dai->id != AIF2_VIFEED)) {
-		dev_err(codec->dev, "%s: Not capture use case skip\n",
-		__func__);
-		return 0;
-	}
-
-	mute = (mute) ? 1 : 0;
-	if (!mute) {
-		/*
-		 * 15 ms is an emperical value for the mute time
-		 * that was arrived by checking the pop level
-		 * to be inaudible
-		 */
-		usleep_range(15000, 15010);
-	}
-
-	for (i = 0; i < NUM_DECIMATORS; i++) {
-		if (msm8x16_wcd->dec_active[i])
-			decimator = i + 1;
-		if (decimator && decimator <= NUM_DECIMATORS) {
-			pr_err("%s: Mute = %d Decimator = %d", __func__,
-					mute, decimator);
-			tx_vol_ctl_reg = MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG +
-				32 * (decimator - 1);
-			snd_soc_update_bits_wrapper(codec,
-				tx_vol_ctl_reg, 0x01, mute);
-		}
-		decimator = 0;
-	}
-	return 0;
-}
-
-static struct snd_soc_dai_ops msm8x16_wcd_dai_ops = {
-	.startup = msm8x16_wcd_startup,
-	.shutdown = msm8x16_wcd_shutdown,
-	.hw_params = msm8x16_wcd_hw_params,
-	.set_sysclk = msm8x16_wcd_set_dai_sysclk,
-	.set_fmt = msm8x16_wcd_set_dai_fmt,
-	.set_channel_map = msm8x16_wcd_set_channel_map,
-	.get_channel_map = msm8x16_wcd_get_channel_map,
-	.digital_mute = msm8x16_wcd_digital_mute,
-};
-
-static struct snd_soc_dai_driver msm8x16_wcd_i2s_dai[] = {
-	{
-		.name = "msm8x16_wcd_i2s_rx1",
-		.id = AIF1_PB,
-		.playback = {
-			.stream_name = "AIF1 Playback",
-			.rates = MSM89XX_RATES,
-			.formats = MSM89XX_FORMATS,
-			.rate_max = 192000,
-			.rate_min = 8000,
-			.channels_min = 1,
-			.channels_max = 3,
-		},
-		.ops = &msm8x16_wcd_dai_ops,
-	},
-	{
-		.name = "msm8x16_wcd_i2s_tx1",
-		.id = AIF1_CAP,
-		.capture = {
-			.stream_name = "AIF1 Capture",
-			.rates = MSM89XX_RATES,
-			.formats = MSM89XX_FORMATS,
-			.rate_max = 192000,
-			.rate_min = 8000,
-			.channels_min = 1,
-			.channels_max = 4,
-		},
-		.ops = &msm8x16_wcd_dai_ops,
-	},
-	{
-		.name = "cajon_vifeedback",
-		.id = AIF2_VIFEED,
-		.capture = {
-			.stream_name = "VIfeed",
-			.rates = MSM89XX_RATES,
-			.formats = MSM89XX_FORMATS,
-			.rate_max = 48000,
-			.rate_min = 48000,
-			.channels_min = 2,
-			.channels_max = 2,
-		},
-		.ops = &msm8x16_wcd_dai_ops,
-	},
-};
-
-static int msm8x16_wcd_codec_enable_rx_chain(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		dev_err(codec->dev,
-			"%s: PMU:Sleeping 20ms after disabling mute\n",
-			__func__);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		dev_err(codec->dev,
-			"%s: PMD:Sleeping 20ms after disabling mute\n",
-			__func__);
-		snd_soc_update_bits_wrapper(codec, w->reg,
-			    1 << w->shift, 0x00);
-		msleep(20);
-		break;
-	}
-	return 0;
-}
-
-static int msm8x16_wcd_codec_enable_lo_pa(struct snd_soc_dapm_widget *w,
-				     struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
-	dev_err(codec->dev, "%s: %d %s\n", __func__, event, w->name);
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00);
-		break;
-	}
-
-	return 0;
-}
-
-static int msm8x16_wcd_codec_enable_spk_ext_pa(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	dev_err(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		dev_err(codec->dev,
-			"%s: enable external speaker PA\n", __func__);
-		if (msm8x16_wcd->codec_spk_ext_pa_cb)
-			msm8x16_wcd->codec_spk_ext_pa_cb(codec, 1);
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		dev_err(codec->dev,
-			"%s: enable external speaker PA\n", __func__);
-		if (msm8x16_wcd->codec_spk_ext_pa_cb)
-			msm8x16_wcd->codec_spk_ext_pa_cb(codec, 0);
-		break;
-	}
-	return 0;
-}
-
-static int msm8x16_wcd_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		dev_err(codec->dev,
-			"%s: Sleeping 20ms after select EAR PA\n",
-			__func__);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x80, 0x80);
-		if (get_codec_version(msm8x16_wcd) < CONGA)
-			snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFF, 0x2A);
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		dev_err(codec->dev,
-			"%s: Sleeping 20ms after enabling EAR PA\n",
-			__func__);
-		snd_soc_update_bits_wrapper(codec,
-			 MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x40, 0x40);
-		usleep_range(7000, 7100);
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00);
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits_wrapper(codec,
-			MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x01);
-		msleep(20);
-		msm8x16_wcd->mute_mask |= EAR_PA_DISABLE;
-		if (msm8x16_wcd->boost_option == BOOST_ALWAYS) {
-			dev_err(codec->dev,
-				"%s: boost_option:%d, tear down ear\n",
-				__func__, msm8x16_wcd->boost_option);
-			msm8x16_wcd_boost_mode_sequence(codec, EAR_PMD);
-		}
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		dev_err(codec->dev,
-			"%s: Sleeping 7ms after disabling EAR PA\n",
-			__func__);
-		snd_soc_update_bits_wrapper(codec,
-			 MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x40, 0x00);
-		usleep_range(7000, 7100);
-		if (get_codec_version(msm8x16_wcd) < CONGA)
-			snd_soc_update_bits_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFF, 0x16);
-		break;
-	}
-	return 0;
-}
-
-static const struct snd_soc_dapm_widget msm8x16_wcd_dapm_widgets[] = {
-	/*RX stuff */
-	SND_SOC_DAPM_OUTPUT("EAR"),
-	SND_SOC_DAPM_OUTPUT("WSA_SPK OUT"),
-
-	SND_SOC_DAPM_PGA_E("EAR PA", SND_SOC_NOPM,
-			0, 0, NULL, 0, msm8x16_wcd_codec_enable_ear_pa,
-			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MUX("EAR_S", SND_SOC_NOPM, 0, 0,
-		ear_pa_mux),
-
-	SND_SOC_DAPM_MUX("WSA Spk Switch", SND_SOC_NOPM, 0, 0,
-		wsa_spk_mux),
-
-	SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
-
-	SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
-
-	SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
-
-	SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
-
-	SND_SOC_DAPM_SPK("Ext Spk", msm8x16_wcd_codec_enable_spk_ext_pa),
-
-	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
-	SND_SOC_DAPM_PGA_E("HPHL PA", MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
-		5, 0, NULL, 0,
-		msm8x16_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0,
-		hphl_mux),
-
-	SND_SOC_DAPM_MIXER_E("HPHL DAC",
-		MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL,
-		0, msm8x16_wcd_hphl_dac_event,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_PGA_E("HPHR PA", MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
-		4, 0, NULL, 0,
-		msm8x16_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0,
-		hphr_mux),
-
-	SND_SOC_DAPM_MIXER_E("HPHR DAC",
-		MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL,
-		0, msm8x16_wcd_hphr_dac_event,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX("SPK", SND_SOC_NOPM, 0, 0,
-		spkr_mux),
-
-	SND_SOC_DAPM_DAC("SPK DAC", NULL,
-		MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 7, 0),
-
-	SND_SOC_DAPM_MUX("LINE_OUT",
-		SND_SOC_NOPM, 0, 0, lo_mux),
-
-	SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL,
-		SND_SOC_NOPM, 0, 0, msm8x16_wcd_lo_dac_event,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	/* Speaker */
-	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
-
-	/* Lineout */
-	SND_SOC_DAPM_OUTPUT("LINEOUT"),
-
-	SND_SOC_DAPM_PGA_E("SPK PA", MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
-			6, 0, NULL, 0, msm8x16_wcd_codec_enable_spk_pa,
-			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_PGA_E("LINEOUT PA", MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL,
-			5, 0, NULL, 0, msm8x16_wcd_codec_enable_lo_pa,
-			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_SUPPLY("VDD_SPKDRV", SND_SOC_NOPM, 0, 0,
-			    msm89xx_wcd_codec_enable_vdd_spkr,
-			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX("Ext Spk Switch", SND_SOC_NOPM, 0, 0,
-		&ext_spk_mux),
-
-	SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
-
-	SND_SOC_DAPM_MIXER_E("RX1 MIX2",
-		MSM89XX_CDC_CORE_CLK_RX_B1_CTL, MSM89XX_RX1, 0, NULL,
-		0, msm8x16_wcd_codec_enable_interpolator,
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MIXER_E("RX2 MIX2",
-		MSM89XX_CDC_CORE_CLK_RX_B1_CTL, MSM89XX_RX2, 0, NULL,
-		0, msm8x16_wcd_codec_enable_interpolator,
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MIXER_E("RX3 MIX1",
-		MSM89XX_CDC_CORE_CLK_RX_B1_CTL, MSM89XX_RX3, 0, NULL,
-		0, msm8x16_wcd_codec_enable_interpolator,
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-		0, 0, NULL, 0),
-	SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-		1, 0, NULL, 0),
-	SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-		2, 0, msm8x16_wcd_codec_enable_dig_clk, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MIXER_E("RX1 CHAIN", MSM89XX_CDC_CORE_RX1_B6_CTL, 0, 0,
-		NULL, 0,
-		msm8x16_wcd_codec_enable_rx_chain,
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MIXER_E("RX2 CHAIN", MSM89XX_CDC_CORE_RX2_B6_CTL, 0, 0,
-		NULL, 0,
-		msm8x16_wcd_codec_enable_rx_chain,
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MIXER_E("RX3 CHAIN", MSM89XX_CDC_CORE_RX3_B6_CTL, 0, 0,
-		NULL, 0,
-		msm8x16_wcd_codec_enable_rx_chain,
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
-		&rx_mix1_inp3_mux),
-
-	SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx2_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx2_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0,
-		&rx2_mix1_inp3_mux),
-
-	SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx3_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx3_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
-		&rx3_mix1_inp3_mux),
-
-	SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
-		&rx1_mix2_inp1_mux),
-	SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
-		&rx2_mix2_inp1_mux),
-
-	SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
-		ON_DEMAND_MICBIAS, 0,
-		msm8x16_wcd_codec_enable_on_demand_supply,
-		SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_SUPPLY("CP", MSM89XX_PMIC_ANALOG_NCP_EN, 0, 0,
-		msm8x16_wcd_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU |	SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_SUPPLY("EAR CP", MSM89XX_PMIC_ANALOG_NCP_EN, 4, 0,
-		msm8x16_wcd_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_SUPPLY_S("RX_BIAS", 1, SND_SOC_NOPM,
-		0, 0, msm8x16_wcd_codec_enable_rx_bias,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_SUPPLY_S("SPK_RX_BIAS", 1, SND_SOC_NOPM, 0, 0,
-		msm8x16_wcd_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	/* TX */
-
-	SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, MSM89XX_CDC_CORE_CLK_OTHR_CTL,
-		2, 0, NULL, 0),
-
-
-	SND_SOC_DAPM_INPUT("AMIC1"),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1",
-		MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0,
-		msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal2",
-		MSM89XX_PMIC_ANALOG_MICB_2_EN, 7, 0,
-		msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal3",
-		MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0,
-		msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM89XX_PMIC_ANALOG_TX_1_EN, 7, 0,
-		msm8x16_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_ADC_E("ADC2_INP2",
-		NULL, MSM89XX_PMIC_ANALOG_TX_2_EN, 7, 0,
-		msm8x16_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_ADC_E("ADC2_INP3",
-		NULL, MSM89XX_PMIC_ANALOG_TX_3_EN, 7, 0,
-		msm8x16_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
-
-	SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0,
-		&tx_adc2_mux),
-
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS External",
-		MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0,
-		msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS External2",
-		MSM89XX_PMIC_ANALOG_MICB_2_EN, 7, 0,
-		msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-
-	SND_SOC_DAPM_INPUT("AMIC3"),
-
-	SND_SOC_DAPM_MUX_E("DEC1 MUX",
-		MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 0, 0,
-		&dec1_mux, msm8x16_wcd_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX_E("DEC2 MUX",
-		MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 1, 0,
-		&dec2_mux, msm8x16_wcd_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX_E("DEC3 MUX",
-		MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 2, 0,
-		&dec3_mux, msm8x16_wcd_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX_E("DEC4 MUX",
-		MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 3, 0,
-		&dec4_mux, msm8x16_wcd_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX("RDAC2 MUX", SND_SOC_NOPM, 0, 0, &rdac2_mux),
-
-	SND_SOC_DAPM_INPUT("AMIC2"),
-
-	SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM,
-		0, 0),
-	SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM,
-		0, 0),
-	SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM,
-		0, 0),
-
-	SND_SOC_DAPM_AIF_OUT("AIF2 VI", "VIfeed", 0, SND_SOC_NOPM,
-		0, 0),
-	/* Digital Mic Inputs */
-	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
-		msm8x16_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
-		msm8x16_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_INPUT("DMIC3"),
-
-	SND_SOC_DAPM_INPUT("DMIC4"),
-
-	/* Sidetone */
-	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
-	SND_SOC_DAPM_PGA_E("IIR1", MSM89XX_CDC_CORE_CLK_SD_CTL, 0, 0, NULL, 0,
-		msm8x16_wcd_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
-	SND_SOC_DAPM_PGA_E("IIR2", MSM89XX_CDC_CORE_CLK_SD_CTL, 1, 0, NULL, 0,
-		msm8x16_wcd_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_SUPPLY("RX_I2S_CLK",
-		MSM89XX_CDC_CORE_CLK_RX_I2S_CTL,	4, 0, NULL, 0),
-	SND_SOC_DAPM_SUPPLY("TX_I2S_CLK",
-		MSM89XX_CDC_CORE_CLK_TX_I2S_CTL, 4, 0,
-		NULL, 0),
-};
-
-static const struct msm8x16_wcd_reg_mask_val msm8x16_wcd_reg_defaults[] = {
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
-};
-
-static const struct msm8x16_wcd_reg_mask_val msm8x16_wcd_reg_defaults_2_0[] = {
-	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4F),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x28),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_BOOST_EN_CTL, 0x5F),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO, 0x88),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
-};
-
-static const struct msm8x16_wcd_reg_mask_val msm8909_wcd_reg_defaults[] = {
-	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x28),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE, 0x0A),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
-};
-
-static const struct msm8x16_wcd_reg_mask_val cajon_wcd_reg_defaults[] = {
-	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0xA8),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_VCTRL, 0xA4),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET, 0x41),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA, 0xFA),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
-};
-
-static const struct msm8x16_wcd_reg_mask_val cajon2p0_wcd_reg_defaults[] = {
-	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0xA2),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0xA8),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_VCTRL, 0xA4),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET, 0x41),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_EAR_STATUS, 0x10),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_BYPASS_MODE, 0x18),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA, 0xFA),
-	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
-};
-
-static void msm8x16_wcd_update_reg_defaults(struct snd_soc_codec *codec)
-{
-	u32 i, version;
-	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-	version = get_codec_version(msm8x16_wcd);
-	if (version == TOMBAK_1_0) {
-		for (i = 0; i < ARRAY_SIZE(msm8x16_wcd_reg_defaults); i++)
-			snd_soc_write_wrapper(codec,
-				msm8x16_wcd_reg_defaults[i].reg,
-				msm8x16_wcd_reg_defaults[i].val);
-	} else if (version == TOMBAK_2_0) {
-		for (i = 0; i < ARRAY_SIZE(msm8x16_wcd_reg_defaults_2_0); i++)
-			snd_soc_write_wrapper(codec,
-				msm8x16_wcd_reg_defaults_2_0[i].reg,
-				msm8x16_wcd_reg_defaults_2_0[i].val);
-	} else if (version == CONGA) {
-		for (i = 0; i < ARRAY_SIZE(msm8909_wcd_reg_defaults); i++)
-			snd_soc_write_wrapper(codec,
-				msm8909_wcd_reg_defaults[i].reg,
-				msm8909_wcd_reg_defaults[i].val);
-	} else if (version == CAJON) {
-		for (i = 0; i < ARRAY_SIZE(cajon_wcd_reg_defaults); i++)
-			snd_soc_write_wrapper(codec,
-				cajon_wcd_reg_defaults[i].reg,
-				cajon_wcd_reg_defaults[i].val);
-	} else if (version == CAJON_2_0 || version == DIANGU) {
-		for (i = 0; i < ARRAY_SIZE(cajon2p0_wcd_reg_defaults); i++)
-			snd_soc_write_wrapper(codec,
-				cajon2p0_wcd_reg_defaults[i].reg,
-				cajon2p0_wcd_reg_defaults[i].val);
-	}
-}
-
-static const struct msm8x16_wcd_reg_mask_val
-	msm8x16_wcd_codec_reg_init_val[] = {
-
-	/* Initialize current threshold to 350MA
-	 * number of wait and run cycles to 4096
-	 */
-	{MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL, 0xFF, 0x12},
-	{MSM89XX_PMIC_ANALOG_RX_COM_OCP_COUNT, 0xFF, 0xFF},
-};
-
-static void msm8x16_wcd_codec_init_reg(struct snd_soc_codec *codec)
-{
-	u32 i;
-
-	for (i = 0; i < ARRAY_SIZE(msm8x16_wcd_codec_reg_init_val); i++)
-		snd_soc_update_bits_wrapper(codec,
-			    msm8x16_wcd_codec_reg_init_val[i].reg,
-			    msm8x16_wcd_codec_reg_init_val[i].mask,
-			    msm8x16_wcd_codec_reg_init_val[i].val);
-}
-
-static int msm8x16_wcd_bringup(struct snd_soc_codec *codec)
-{
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_DIGITAL_SEC_ACCESS,
-		0xA5);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4, 0x01);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_SEC_ACCESS,
-		0xA5);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4, 0x01);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_DIGITAL_SEC_ACCESS,
-		0xA5);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4, 0x00);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_SEC_ACCESS,
-		0xA5);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4, 0x00);
-	return 0;
-}
-
-static struct regulator *wcd8x16_wcd_codec_find_regulator(
-				const struct msm8x16_wcd *msm8x16,
-				const char *name)
-{
-	int i;
-
-	for (i = 0; i < msm8x16->num_of_supplies; i++) {
-		if (msm8x16->supplies[i].supply &&
-		    !strcmp(msm8x16->supplies[i].supply, name))
-			return msm8x16->supplies[i].consumer;
-	}
-
-	dev_err(msm8x16->dev, "Error: regulator not found:%s\n"
-				, name);
-	return NULL;
-}
-
-static int msm8x16_wcd_device_down(struct snd_soc_codec *codec)
-{
-	struct msm_asoc_mach_data *pdata = NULL;
-	struct msm8x16_wcd_priv *msm8x16_wcd_priv =
-		snd_soc_codec_get_drvdata(codec);
-	int i;
-
-	pdata = snd_soc_card_get_drvdata(codec->component.card);
-	dev_err(codec->dev, "%s: device down!\n", __func__);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_TX_1_EN, 0x3);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_TX_2_EN, 0x3);
-	if (msm8x16_wcd_priv->boost_option == BOOST_ON_FOREVER) {
-		if ((snd_soc_read_wrapper(codec,
-			MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL)
-		& 0x80) == 0) {
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_CLK_MCLK_CTL,	0x01, 0x01);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x03);
-			snd_soc_write_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL,
-				0x0C, 0x0C);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
-				0x84, 0x84);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL,
-				0x10, 0x10);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL,
-				0x1F, 0x1F);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
-				0x90, 0x90);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
-				0xFF, 0xFF);
-			usleep_range(20, 21);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL,
-				0xFF, 0xFF);
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
-				0xE9, 0xE9);
-		}
-	}
-	msm8x16_wcd_boost_off(codec);
-	msm8x16_wcd_priv->hph_mode = NORMAL_MODE;
-	for (i = 0; i < MSM89XX_RX_MAX; i++)
-		msm8x16_wcd_priv->comp_enabled[i] = COMPANDER_NONE;
-
-	/* 40ms to allow boost to discharge */
-	msleep(40);
-	/* Disable PA to avoid pop during codec bring up */
-	snd_soc_update_bits_wrapper(codec, MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
-			0x30, 0x00);
-	snd_soc_update_bits_wrapper(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
-			0x80, 0x00);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x20);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x20);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x12);
-	snd_soc_write_wrapper(codec,
-		MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x93);
-
-	msm8x16_wcd_bringup(codec);
-	atomic_set(&pdata->int_mclk0_enabled, false);
-	set_bit(BUS_DOWN, &msm8x16_wcd_priv->status_mask);
-	snd_soc_card_change_online_state(codec->component.card, 0);
-	return 0;
-}
-
-static int msm8x16_wcd_device_up(struct snd_soc_codec *codec)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd_priv =
-		snd_soc_codec_get_drvdata(codec);
-	int ret = 0;
-
-	dev_err(codec->dev, "%s: device up!\n", __func__);
-
-	clear_bit(BUS_DOWN, &msm8x16_wcd_priv->status_mask);
-
-	snd_soc_card_change_online_state(codec->component.card, 1);
-	/* delay is required to make sure sound card state updated */
-	usleep_range(5000, 5100);
-
-	msm8x16_wcd_codec_init_reg(codec);
-	msm8x16_wcd_update_reg_defaults(codec);
-
-	snd_soc_write_wrapper(codec, MSM89XX_PMIC_DIGITAL_INT_EN_SET,
-				MSM89XX_PMIC_DIGITAL_INT_EN_SET__POR);
-	snd_soc_write_wrapper(codec, MSM89XX_PMIC_DIGITAL_INT_EN_CLR,
-				MSM89XX_PMIC_DIGITAL_INT_EN_CLR__POR);
-
-	msm8x16_wcd_set_boost_v(codec);
-
-	msm8x16_wcd_set_micb_v(codec);
-	if (msm8x16_wcd_priv->boost_option == BOOST_ON_FOREVER)
-		msm8x16_wcd_boost_on(codec);
-	else if (msm8x16_wcd_priv->boost_option == BYPASS_ALWAYS)
-		msm8x16_wcd_bypass_on(codec);
-
-	msm8x16_wcd_configure_cap(codec, false, false);
-	wcd_mbhc_stop(&msm8x16_wcd_priv->mbhc);
-	wcd_mbhc_deinit(&msm8x16_wcd_priv->mbhc);
-	ret = wcd_mbhc_init(&msm8x16_wcd_priv->mbhc, codec, &mbhc_cb, &intr_ids,
-			wcd_mbhc_registers, true);
-	if (ret)
-		dev_err(codec->dev, "%s: mbhc initialization failed\n",
-			__func__);
-	else
-		wcd_mbhc_start(&msm8x16_wcd_priv->mbhc,
-			msm8x16_wcd_priv->mbhc.mbhc_cfg);
-
-
-	return 0;
-}
-
-static int adsp_state_callback(struct notifier_block *nb, unsigned long value,
-			       void *priv)
-{
-	bool timedout;
-	unsigned long timeout;
-
-	if (value == SUBSYS_BEFORE_SHUTDOWN)
-		msm8x16_wcd_device_down(registered_codec);
-	else if (value == SUBSYS_AFTER_POWERUP) {
-
-		dev_err(registered_codec->dev,
-			"ADSP is about to power up. bring up codec\n");
-
-		if (!q6core_is_adsp_ready()) {
-			dev_err(registered_codec->dev,
-				"ADSP isn't ready\n");
-			timeout = jiffies +
-				  msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
-			while (!(timedout = time_after(jiffies, timeout))) {
-				if (!q6core_is_adsp_ready()) {
-					dev_err(registered_codec->dev,
-						"ADSP isn't ready\n");
-				} else {
-					dev_err(registered_codec->dev,
-						"ADSP is ready\n");
-					break;
-				}
-			}
-		} else {
-			dev_err(registered_codec->dev,
-				"%s: DSP is ready\n", __func__);
-		}
-
-		msm8x16_wcd_device_up(registered_codec);
-	}
-	return NOTIFY_OK;
-}
-
-static struct notifier_block adsp_state_notifier_block = {
-	.notifier_call = adsp_state_callback,
-	.priority = -INT_MAX,
-};
-
-int msm8x16_wcd_hs_detect(struct snd_soc_codec *codec,
-		    struct wcd_mbhc_config *mbhc_cfg)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd_priv =
-		snd_soc_codec_get_drvdata(codec);
-
-	return wcd_mbhc_start(&msm8x16_wcd_priv->mbhc, mbhc_cfg);
-}
-EXPORT_SYMBOL(msm8x16_wcd_hs_detect);
-
-void msm8x16_wcd_hs_detect_exit(struct snd_soc_codec *codec)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd_priv =
-		snd_soc_codec_get_drvdata(codec);
-
-	wcd_mbhc_stop(&msm8x16_wcd_priv->mbhc);
-}
-EXPORT_SYMBOL(msm8x16_wcd_hs_detect_exit);
-
-void msm8x16_update_int_spk_boost(bool enable)
-{
-	pr_err("%s: enable = %d\n", __func__, enable);
-	spkr_boost_en = enable;
-}
-EXPORT_SYMBOL(msm8x16_update_int_spk_boost);
-
-static void msm8x16_wcd_set_micb_v(struct snd_soc_codec *codec)
-{
-
-	struct msm8x16_wcd *msm8x16 = codec->control_data;
-	struct msm8x16_wcd_pdata *pdata = msm8x16->dev->platform_data;
-	u8 reg_val;
-
-	reg_val = VOLTAGE_CONVERTER(pdata->micbias.cfilt1_mv, MICBIAS_MIN_VAL,
-			MICBIAS_STEP_SIZE);
-	dev_err(codec->dev, "cfilt1_mv %d reg_val %x\n",
-			(u32)pdata->micbias.cfilt1_mv, reg_val);
-	snd_soc_update_bits_wrapper(codec, MSM89XX_PMIC_ANALOG_MICB_1_VAL,
-			0xF8, (reg_val << 3));
-}
-
-static void msm8x16_wcd_set_boost_v(struct snd_soc_codec *codec)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd_priv =
-				snd_soc_codec_get_drvdata(codec);
-
-	snd_soc_update_bits_wrapper(codec, MSM89XX_PMIC_ANALOG_OUTPUT_VOLTAGE,
-			0x1F, msm8x16_wcd_priv->boost_voltage);
-}
-
-static void msm8x16_wcd_configure_cap(struct snd_soc_codec *codec,
-		bool micbias1, bool micbias2)
-{
-
-	struct msm_asoc_mach_data *pdata = NULL;
-
-	pdata = snd_soc_card_get_drvdata(codec->component.card);
-
-	pr_err("\n %s: micbias1 %x micbias2 = %d\n", __func__, micbias1,
-			micbias2);
-	if (micbias1 && micbias2) {
-		if ((pdata->micbias1_cap_mode
-		     == MICBIAS_EXT_BYP_CAP) ||
-		    (pdata->micbias2_cap_mode
-		     == MICBIAS_EXT_BYP_CAP))
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MICB_1_EN,
-				0x40, (MICBIAS_EXT_BYP_CAP << 6));
-		else
-			snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MICB_1_EN,
-				0x40, (MICBIAS_NO_EXT_BYP_CAP << 6));
-	} else if (micbias2) {
-		snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MICB_1_EN,
-				0x40, (pdata->micbias2_cap_mode << 6));
-	} else if (micbias1) {
-		snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MICB_1_EN,
-				0x40, (pdata->micbias1_cap_mode << 6));
-	} else {
-		snd_soc_update_bits_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_MICB_1_EN,
-				0x40, 0x00);
-	}
-}
-
-static int msm89xx_digcodec_probe(struct snd_soc_codec *codec)
-{
-	registered_digcodec = codec;
-
-	return 0;
-}
-
-
-static int msm89xx_digcodec_remove(struct snd_soc_codec *codec)
-{
-	return 0;
-}
-
-static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd_priv;
-	int i, ret;
-
-	dev_err(codec->dev, "%s()\n", __func__);
-
-	msm8x16_wcd_priv = kzalloc(sizeof(struct msm8x16_wcd_priv), GFP_KERNEL);
-	if (!msm8x16_wcd_priv)
-		return -ENOMEM;
-
-	for (i = 0; i < NUM_DECIMATORS; i++) {
-		tx_hpf_work[i].msm8x16_wcd = msm8x16_wcd_priv;
-		tx_hpf_work[i].decimator = i + 1;
-		INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
-			tx_hpf_corner_freq_callback);
-	}
-
-	codec->control_data = dev_get_drvdata(codec->dev);
-	snd_soc_codec_set_drvdata(codec, msm8x16_wcd_priv);
-	msm8x16_wcd_priv->codec = codec;
-
-	msm8x16_wcd_priv->spkdrv_reg =
-		wcd8x16_wcd_codec_find_regulator(codec->control_data,
-					MSM89XX_VDD_SPKDRV_NAME);
-	msm8x16_wcd_priv->pmic_rev = snd_soc_read_wrapper(codec,
-				MSM89XX_PMIC_DIGITAL_REVISION1);
-	msm8x16_wcd_priv->codec_version = snd_soc_read_wrapper(codec,
-				MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE);
-	if (msm8x16_wcd_priv->codec_version == CONGA) {
-		dev_err(codec->dev, "%s :Conga REV: %d\n", __func__,
-				msm8x16_wcd_priv->codec_version);
-		msm8x16_wcd_priv->ext_spk_boost_set = true;
-	} else {
-		dev_err(codec->dev, "%s :PMIC REV: %d\n", __func__,
-					msm8x16_wcd_priv->pmic_rev);
-		if (msm8x16_wcd_priv->pmic_rev == TOMBAK_1_0 &&
-			msm8x16_wcd_priv->codec_version == CAJON_2_0) {
-			msm8x16_wcd_priv->codec_version = DIANGU;
-			dev_err(codec->dev, "%s : Diangu detected\n",
-						__func__);
-		} else if (msm8x16_wcd_priv->pmic_rev == TOMBAK_1_0 &&
-			(snd_soc_read_wrapper(codec,
-				 MSM89XX_PMIC_ANALOG_NCP_FBCTRL)
-			 & 0x80)) {
-			msm8x16_wcd_priv->codec_version = CAJON;
-			dev_err(codec->dev, "%s : Cajon detected\n", __func__);
-		} else if (msm8x16_wcd_priv->pmic_rev == TOMBAK_2_0 &&
-			(snd_soc_read_wrapper(codec,
-				MSM89XX_PMIC_ANALOG_NCP_FBCTRL)
-			 & 0x80)) {
-			msm8x16_wcd_priv->codec_version = CAJON_2_0;
-			dev_err(codec->dev, "%s : Cajon 2.0 detected\n",
-						__func__);
-		}
-	}
-	/*
-	 * set to default boost option BOOST_SWITCH, user mixer path can change
-	 * it to BOOST_ALWAYS or BOOST_BYPASS based on solution chosen.
-	 */
-	msm8x16_wcd_priv->boost_option = BOOST_SWITCH;
-	msm8x16_wcd_priv->hph_mode = NORMAL_MODE;
-
-	for (i = 0; i < MSM89XX_RX_MAX; i++)
-		msm8x16_wcd_priv->comp_enabled[i] = COMPANDER_NONE;
-
-	msm8x16_wcd_dt_parse_boost_info(codec);
-	msm8x16_wcd_set_boost_v(codec);
-
-	snd_soc_add_codec_controls(codec, impedance_detect_controls,
-				   ARRAY_SIZE(impedance_detect_controls));
-	snd_soc_add_codec_controls(codec, hph_type_detect_controls,
-				  ARRAY_SIZE(hph_type_detect_controls));
-
-	msm8x16_wcd_bringup(codec);
-	msm8x16_wcd_codec_init_reg(codec);
-	msm8x16_wcd_update_reg_defaults(codec);
-
-	wcd9xxx_spmi_set_codec(codec);
-
-	msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply =
-				wcd8x16_wcd_codec_find_regulator(
-				codec->control_data,
-				on_demand_supply_name[ON_DEMAND_MICBIAS]);
-	atomic_set(&msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
-
-	BLOCKING_INIT_NOTIFIER_HEAD(&msm8x16_wcd_priv->notifier);
-
-	msm8x16_wcd_priv->fw_data = kzalloc(sizeof(*(msm8x16_wcd_priv->fw_data))
-			, GFP_KERNEL);
-	if (!msm8x16_wcd_priv->fw_data) {
-		kfree(msm8x16_wcd_priv);
-		return -ENOMEM;
-	}
-
-	set_bit(WCD9XXX_MBHC_CAL, msm8x16_wcd_priv->fw_data->cal_bit);
-	ret = wcd_cal_create_hwdep(msm8x16_wcd_priv->fw_data,
-			WCD9XXX_CODEC_HWDEP_NODE, codec);
-	if (ret < 0) {
-		dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret);
-		kfree(msm8x16_wcd_priv->fw_data);
-		kfree(msm8x16_wcd_priv);
-		return ret;
-	}
-
-	wcd_mbhc_init(&msm8x16_wcd_priv->mbhc, codec, &mbhc_cb, &intr_ids,
-		      wcd_mbhc_registers, true);
-
-	msm8x16_wcd_priv->int_mclk0_enabled = false;
-	msm8x16_wcd_priv->clock_active = false;
-	msm8x16_wcd_priv->config_mode_active = false;
-
-	/*Update speaker boost configuration*/
-	msm8x16_wcd_priv->spk_boost_set = spkr_boost_en;
-	pr_err("%s: speaker boost configured = %d\n",
-			__func__, msm8x16_wcd_priv->spk_boost_set);
-
-	/* Set initial MICBIAS voltage level */
-	msm8x16_wcd_set_micb_v(codec);
-
-	/* Set initial cap mode */
-	msm8x16_wcd_configure_cap(codec, false, false);
-	registered_codec = codec;
-	adsp_state_notifier =
-	    subsys_notif_register_notifier("adsp",
-					   &adsp_state_notifier_block);
-	if (!adsp_state_notifier) {
-		dev_err(codec->dev, "Failed to register adsp state notifier\n");
-		kfree(msm8x16_wcd_priv->fw_data);
-		kfree(msm8x16_wcd_priv);
-		registered_codec = NULL;
-		return -ENOMEM;
-	}
-	return 0;
-}
-
-static int msm8x16_wcd_codec_remove(struct snd_soc_codec *codec)
-{
-	struct msm8x16_wcd_priv *msm8x16_wcd_priv =
-					snd_soc_codec_get_drvdata(codec);
-	struct msm8x16_wcd *msm8x16_wcd;
-
-	msm8x16_wcd = codec->control_data;
-	msm8x16_wcd_priv->spkdrv_reg = NULL;
-	msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL;
-	atomic_set(&msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
-	kfree(msm8x16_wcd_priv->fw_data);
-	kfree(msm8x16_wcd_priv);
-
-	return 0;
-}
-
-static int msm8x16_wcd_enable_static_supplies_to_optimum(
-				struct msm8x16_wcd *msm8x16,
-				struct msm8x16_wcd_pdata *pdata)
-{
-	int i;
-	int ret = 0;
-
-	for (i = 0; i < msm8x16->num_of_supplies; i++) {
-		if (pdata->regulator[i].ondemand)
-			continue;
-		if (regulator_count_voltages(msm8x16->supplies[i].consumer) <=
-			0)
-			continue;
-
-		ret = regulator_set_voltage(msm8x16->supplies[i].consumer,
-			pdata->regulator[i].min_uv,
-			pdata->regulator[i].max_uv);
-		if (ret) {
-			dev_err(msm8x16->dev,
-				"Setting volt failed for regulator %s err %d\n",
-				msm8x16->supplies[i].supply, ret);
-		}
-
-		ret = regulator_set_load(msm8x16->supplies[i].consumer,
-			pdata->regulator[i].optimum_ua);
-		dev_err(msm8x16->dev, "Regulator %s set optimum mode\n",
-			 msm8x16->supplies[i].supply);
-	}
-
-	return ret;
-}
-
-static int msm8x16_wcd_disable_static_supplies_to_optimum(
-			struct msm8x16_wcd *msm8x16,
-			struct msm8x16_wcd_pdata *pdata)
-{
-	int i;
-	int ret = 0;
-
-	for (i = 0; i < msm8x16->num_of_supplies; i++) {
-		if (pdata->regulator[i].ondemand)
-			continue;
-		if (regulator_count_voltages(msm8x16->supplies[i].consumer) <=
-			0)
-			continue;
-		regulator_set_voltage(msm8x16->supplies[i].consumer, 0,
-			pdata->regulator[i].max_uv);
-		regulator_set_load(msm8x16->supplies[i].consumer, 0);
-		dev_err(msm8x16->dev, "Regulator %s set optimum mode\n",
-				 msm8x16->supplies[i].supply);
-	}
-
-	return ret;
-}
-
-int msm8x16_wcd_suspend(struct snd_soc_codec *codec)
-{
-	struct msm_asoc_mach_data *pdata = NULL;
-	struct msm8x16_wcd *msm8x16 = codec->control_data;
-	struct msm8x16_wcd_pdata *msm8x16_pdata = msm8x16->dev->platform_data;
-
-	pdata = snd_soc_card_get_drvdata(codec->component.card);
-	pr_err("%s: mclk cnt = %d, mclk_enabled = %d\n",
-			__func__, atomic_read(&pdata->int_mclk0_rsc_ref),
-			atomic_read(&pdata->int_mclk0_enabled));
-	if (atomic_read(&pdata->int_mclk0_enabled) == true) {
-		cancel_delayed_work_sync(
-				&pdata->disable_int_mclk0_work);
-		mutex_lock(&pdata->cdc_int_mclk0_mutex);
-		pdata->digital_cdc_core_clk.enable = 0;
-		afe_set_lpass_clock_v2(AFE_PORT_ID_INT0_MI2S_RX,
-				       &pdata->digital_cdc_core_clk);
-		atomic_set(&pdata->int_mclk0_enabled, false);
-		mutex_unlock(&pdata->cdc_int_mclk0_mutex);
-	}
-	msm8x16_wcd_disable_static_supplies_to_optimum(msm8x16, msm8x16_pdata);
-	return 0;
-}
-
-int msm8x16_wcd_resume(struct snd_soc_codec *codec)
-{
-	struct msm_asoc_mach_data *pdata = NULL;
-	struct msm8x16_wcd *msm8x16 = codec->control_data;
-	struct msm8x16_wcd_pdata *msm8x16_pdata = msm8x16->dev->platform_data;
-
-	pdata = snd_soc_card_get_drvdata(codec->component.card);
-	msm8x16_wcd_enable_static_supplies_to_optimum(msm8x16, msm8x16_pdata);
-	return 0;
-}
-
-static struct regmap *msm89xx_pmic_cdc_regmap;
-static struct regmap *msm89xx_pmic_cdc_get_regmap(struct device *dev)
-{
-	return msm89xx_pmic_cdc_regmap;
-}
-
-static const struct snd_soc_codec_driver soc_codec_dev_msm8x16_wcd = {
-	.probe	= msm8x16_wcd_codec_probe,
-	.remove	= msm8x16_wcd_codec_remove,
-
-	.suspend = msm8x16_wcd_suspend,
-	.resume = msm8x16_wcd_resume,
-
-	.controls = msm8x16_wcd_snd_controls,
-	.num_controls = ARRAY_SIZE(msm8x16_wcd_snd_controls),
-	.dapm_widgets = msm8x16_wcd_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(msm8x16_wcd_dapm_widgets),
-	.dapm_routes = audio_map,
-	.num_dapm_routes = ARRAY_SIZE(audio_map),
-	.get_regmap = msm89xx_pmic_cdc_get_regmap,
-};
-
-static int msm8x16_wcd_init_supplies(struct msm8x16_wcd *msm8x16,
-				struct msm8x16_wcd_pdata *pdata)
-{
-	int ret;
-	int i;
-
-	msm8x16->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
-				   ARRAY_SIZE(pdata->regulator),
-				   GFP_KERNEL);
-	if (!msm8x16->supplies) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	msm8x16->num_of_supplies = 0;
-
-	if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
-		dev_err(msm8x16->dev, "%s: Array Size out of bound\n",
-			__func__);
-		ret = -EINVAL;
-		goto err;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
-		if (pdata->regulator[i].name) {
-			msm8x16->supplies[i].supply = pdata->regulator[i].name;
-			msm8x16->num_of_supplies++;
-		}
-	}
-
-	ret = regulator_bulk_get(msm8x16->dev, msm8x16->num_of_supplies,
-				 msm8x16->supplies);
-	if (ret != 0) {
-		dev_err(msm8x16->dev, "Failed to get supplies: err = %d\n",
-							ret);
-		goto err_supplies;
-	}
-
-	for (i = 0; i < msm8x16->num_of_supplies; i++) {
-		if (regulator_count_voltages(msm8x16->supplies[i].consumer) <=
-			0)
-			continue;
-
-		ret = regulator_set_voltage(msm8x16->supplies[i].consumer,
-			pdata->regulator[i].min_uv,
-			pdata->regulator[i].max_uv);
-		if (ret) {
-			dev_err(msm8x16->dev, "Setting regulator voltage failed for regulator %s err = %d\n",
-				msm8x16->supplies[i].supply, ret);
-			goto err_get;
-		}
-
-		ret = regulator_set_load(msm8x16->supplies[i].consumer,
-			pdata->regulator[i].optimum_ua);
-		if (ret < 0) {
-			dev_err(msm8x16->dev, "Setting regulator optimum mode failed for regulator %s err = %d\n",
-				msm8x16->supplies[i].supply, ret);
-			goto err_get;
-		} else {
-			ret = 0;
-		}
-	}
-
-	return ret;
-
-err_get:
-	regulator_bulk_free(msm8x16->num_of_supplies, msm8x16->supplies);
-err_supplies:
-	kfree(msm8x16->supplies);
-err:
-	return ret;
-}
-
-static int msm8x16_wcd_enable_static_supplies(struct msm8x16_wcd *msm8x16,
-					  struct msm8x16_wcd_pdata *pdata)
-{
-	int i;
-	int ret = 0;
-
-	for (i = 0; i < msm8x16->num_of_supplies; i++) {
-		if (pdata->regulator[i].ondemand)
-			continue;
-		ret = regulator_enable(msm8x16->supplies[i].consumer);
-		if (ret) {
-			dev_err(msm8x16->dev, "Failed to enable %s\n",
-			       msm8x16->supplies[i].supply);
-			break;
-		}
-		dev_err(msm8x16->dev, "Enabled regulator %s\n",
-				 msm8x16->supplies[i].supply);
-	}
-
-	while (ret && --i)
-		if (!pdata->regulator[i].ondemand)
-			regulator_disable(msm8x16->supplies[i].consumer);
-
-	return ret;
-}
-
-
-
-static void msm8x16_wcd_disable_supplies(struct msm8x16_wcd *msm8x16,
-				     struct msm8x16_wcd_pdata *pdata)
-{
-	int i;
-
-	regulator_bulk_disable(msm8x16->num_of_supplies,
-				    msm8x16->supplies);
-	for (i = 0; i < msm8x16->num_of_supplies; i++) {
-		if (regulator_count_voltages(msm8x16->supplies[i].consumer) <=
-			0)
-			continue;
-		regulator_set_voltage(msm8x16->supplies[i].consumer, 0,
-			pdata->regulator[i].max_uv);
-		regulator_set_load(msm8x16->supplies[i].consumer, 0);
-	}
-	regulator_bulk_free(msm8x16->num_of_supplies, msm8x16->supplies);
-	kfree(msm8x16->supplies);
-}
-
-static struct snd_soc_dai_driver msm_codec_dais[] = {
-	{
-		.name = "msm-codec-rx",
-		.playback = { /* Support maximum range */
-			.stream_name = "Playback",
-			.channels_min = 1,
-			.channels_max = 2,
-			.rates = SNDRV_PCM_RATE_8000_48000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
-		},
-	},
-	{
-		.name = "msm-codec-tx",
-		.capture = { /* Support maximum range */
-			.stream_name = "Record",
-			.channels_min = 1,
-			.channels_max = 4,
-			.rates = SNDRV_PCM_RATE_8000_48000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
-		},
-	},
-};
-
-static struct regmap *msm89xx_codec_regmap;
-static struct regmap *msm89xx_codec_get_regmap(struct device *dev)
-{
-	return msm89xx_codec_regmap;
-}
-
-static struct snd_soc_codec_driver soc_msm89xx_codec = {
-	.probe	= msm89xx_digcodec_probe,
-	.remove	= msm89xx_digcodec_remove,
-	.get_regmap = msm89xx_codec_get_regmap,
-};
-
-static const struct of_device_id msm89xx_codec_of_match[] = {
-	{ .compatible = "qcom,msm-codec-core",
-	  .data = "msm_codec"},
-	{ .compatible = "qcom,pmic-codec-digital",
-	  .data = "pmic-digital-codec"},
-	{ .compatible = "qcom,pmic-codec-analog",
-	  .data = "pmic-analog-codec"},
-	{},
-};
-MODULE_DEVICE_TABLE(of, msm89xx_codec_of_match);
-
-static struct msm8x16_wcd *temp_89xx;
-static int msm89xx_codec_probe(struct platform_device *pdev)
-{
-	int ret = 0;
-	struct msm8x16_wcd *msm8x16 = NULL;
-	struct msm8x16_wcd_pdata *pdata;
-	int adsp_state;
-	static int dev_registered_cnt;
-	const struct of_device_id *match;
-	const char *addr_prop_name = "qcom,dig-cdc-base-addr";
-	u32 dig_cdc_addr;
-	char __iomem *dig_base;
-
-	adsp_state = apr_get_subsys_state();
-	if (adsp_state != APR_SUBSYS_LOADED) {
-		dev_err(&pdev->dev, "Adsp is not loaded yet %d\n",
-				adsp_state);
-		return -EPROBE_DEFER;
-	}
-
-	match = of_match_node(msm89xx_codec_of_match,
-			pdev->dev.of_node);
-
-	dev_dbg(&pdev->dev, "%s(%d):%s\n",
-		__func__, __LINE__, (char *)match->data);
-
-	if (!strcmp(match->data, "pmic-digital-codec")) {
-		device_init_wakeup(&pdev->dev, true);
-
-		if (pdev->dev.of_node) {
-			dev_err(&pdev->dev, "%s:Platform data from device tree\n",
-				__func__);
-			pdata = msm8x16_wcd_populate_dt_pdata(&pdev->dev);
-			pdev->dev.platform_data = pdata;
-		} else {
-			dev_err(&pdev->dev, "%s:Platform data from board file\n",
-				__func__);
-			pdata = pdev->dev.platform_data;
-		}
-		if (pdata == NULL) {
-			dev_err(&pdev->dev, "%s:Platform data failed to populate\n",
-				__func__);
-			goto rtn;
-		}
-		msm8x16 = kzalloc(sizeof(struct msm8x16_wcd), GFP_KERNEL);
-		if (msm8x16 == NULL) {
-			ret = -ENOMEM;
-			goto rtn;
-		}
-
-		msm8x16->dev = &pdev->dev;
-		ret = msm8x16_wcd_init_supplies(msm8x16, pdata);
-		if (ret) {
-			dev_err(&pdev->dev, "%s: Fail to enable Codec supplies\n",
-				__func__);
-			goto err_codec;
-		}
-
-		ret = msm8x16_wcd_enable_static_supplies(msm8x16, pdata);
-		if (ret) {
-			dev_err(&pdev->dev,
-				"%s: Fail to enable Codec pre-reset supplies\n",
-				   __func__);
-			goto err_codec;
-		}
-		usleep_range(5, 6);
-
-		mutex_init(&msm8x16->io_lock);
-		dev_set_drvdata(&pdev->dev, msm8x16);
-		temp_89xx = msm8x16;
-		dev_registered_cnt++;
-	} else if (!strcmp(match->data, "pmic-analog-codec")) {
-		if (wcd9xxx_spmi_irq_init()) {
-			dev_err(&pdev->dev,
-				"%s: irq initialization failed\n", __func__);
-		} else {
-			dev_err(&pdev->dev,
-				"%s: irq initialization passed\n", __func__);
-		}
-		dev_registered_cnt++;
-	} else if (!strcmp(match->data, "msm-codec")) {
-		ret = of_property_read_u32(pdev->dev.of_node, addr_prop_name,
-							&dig_cdc_addr);
-		if (ret) {
-			dev_err(&pdev->dev, "%s: could not find %s entry in dt\n",
-					__func__, addr_prop_name);
-			dig_cdc_addr = MSM89XX_DIGITAL_CODEC_BASE_ADDR;
-		}
-		dig_base = ioremap(dig_cdc_addr,
-				 MSM89XX_DIGITAL_CODEC_REG_SIZE);
-		if (dig_base == NULL) {
-			dev_err(&pdev->dev, "%s ioremap failed\n", __func__);
-			return -ENOMEM;
-		}
-		msm89xx_codec_regmap =
-			devm_regmap_init_mmio_clk(&pdev->dev, NULL,
-				dig_base, &msm89xx_cdc_core_regmap_config);
-		snd_soc_register_codec(&pdev->dev, &soc_msm89xx_codec,
-				msm_codec_dais, ARRAY_SIZE(msm_codec_dais));
-		dev_registered_cnt++;
-	}
-
-	if ((dev_registered_cnt == MAX_MSM89XX_DEVICE) && (!ret)) {
-		msm89xx_pmic_cdc_regmap =
-			devm_regmap_init_spmi_ext(
-				(struct spmi_device *) &pdev->dev.parent,
-				&msm89xx_pmic_cdc_regmap_config);
-		ret = snd_soc_register_codec(temp_89xx->dev,
-				&soc_codec_dev_msm8x16_wcd,
-				msm8x16_wcd_i2s_dai,
-				ARRAY_SIZE(msm8x16_wcd_i2s_dai));
-		if (ret) {
-			dev_err(&pdev->dev,
-			"%s:snd_soc_register_codec failed with error %d\n",
-			__func__, ret);
-			goto err_supplies;
-		}
-	}
-	return ret;
-err_supplies:
-	msm8x16_wcd_disable_supplies(msm8x16, pdata);
-err_codec:
-	kfree(msm8x16);
-rtn:
-	return ret;
-}
-
-static int msm89xx_codec_remove(struct platform_device *pdev)
-{
-	struct msm8x16_wcd *msm8x16 = dev_get_drvdata(&pdev->dev);
-
-	mutex_destroy(&msm8x16->io_lock);
-	kfree(msm8x16);
-
-	return 0;
-}
-
-static struct platform_driver msm_codec_driver = {
-	.driver                 = {
-		.owner          = THIS_MODULE,
-		.name           = DRV_NAME,
-		.of_match_table = of_match_ptr(msm89xx_codec_of_match)
-	},
-	.probe                  = msm89xx_codec_probe,
-	.remove                 = msm89xx_codec_remove,
-};
-module_platform_driver(msm_codec_driver);
-
-MODULE_DESCRIPTION("MSM89xx Audio codec driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/msm8x16/msm8x16-wcd.h b/sound/soc/codecs/msm8x16/msm8x16-wcd.h
deleted file mode 100644
index 45ebab2..0000000
--- a/sound/soc/codecs/msm8x16/msm8x16-wcd.h
+++ /dev/null
@@ -1,315 +0,0 @@
-/* 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#ifndef MSM8X16_WCD_H
-#define MSM8X16_WCD_H
-
-#include <sound/soc.h>
-#include <sound/jack.h>
-#include <sound/q6afe-v2.h>
-#include "../wcd-mbhc-v2.h"
-#include "../wcdcal-hwdep.h"
-#include "msm8x16_wcd_registers.h"
-
-#define MICBIAS_EXT_BYP_CAP 0x00
-#define MICBIAS_NO_EXT_BYP_CAP 0x01
-
-#define MSM89XX_NUM_IRQ_REGS	2
-#define MAX_REGULATOR				7
-#define MSM89XX_REG_VAL(reg, val)		{reg, 0, val}
-#define MSM8X16_TOMBAK_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL	0xFE03B004
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_CMD_RCGR			0x0181C09C
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_CFG_RCGR			0x0181C0A0
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_M				0x0181C0A4
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_N				0x0181C0A8
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_D				0x0181C0AC
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_CBCR			0x0181C0B0
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_AHB_CBCR			0x0181C0B4
-
-#define MSM8X16_CODEC_NAME "msm8x16_wcd_codec"
-
-#define MSM89XX_IS_CDC_CORE_REG(reg) \
-	(((reg >= 0x00) && (reg <= 0x3FF)) ? 1 : 0)
-#define MSM89XX_IS_PMIC_CDC_REG(reg) \
-	(((reg >= 0xF000) && (reg <= 0xF1FF)) ? 1 : 0)
-/*
- * MCLK activity indicators during suspend and resume call
- */
-#define MCLK_SUS_DIS	1
-#define MCLK_SUS_RSC	2
-#define MCLK_SUS_NO_ACT	3
-
-#define NUM_DECIMATORS	4
-#define MSM89XX_VDD_SPKDRV_NAME "cdc-vdd-spkdrv"
-
-#define DEFAULT_MULTIPLIER 800
-#define DEFAULT_GAIN 9
-#define DEFAULT_OFFSET 100
-
-extern const u8 msm89xx_pmic_cdc_reg_readable[MSM89XX_PMIC_CDC_CACHE_SIZE];
-extern const u8 msm89xx_cdc_core_reg_readable[MSM89XX_CDC_CORE_CACHE_SIZE];
-extern struct regmap_config msm89xx_cdc_core_regmap_config;
-extern struct regmap_config msm89xx_pmic_cdc_regmap_config;
-
-enum codec_versions {
-	TOMBAK_1_0,
-	TOMBAK_2_0,
-	CONGA,
-	CAJON,
-	CAJON_2_0,
-	DIANGU,
-	UNSUPPORTED,
-};
-
-/* Support different hph modes */
-enum {
-	NORMAL_MODE = 0,
-	HD2_MODE,
-};
-
-/* Codec supports 1 compander */
-enum {
-	COMPANDER_NONE = 0,
-	COMPANDER_1, /* HPHL/R */
-	COMPANDER_MAX,
-};
-
-enum wcd_curr_ref {
-	I_h4_UA = 0,
-	I_pt5_UA,
-	I_14_UA,
-	I_l4_UA,
-	I_1_UA,
-};
-
-enum wcd_mbhc_imp_det_pin {
-	WCD_MBHC_DET_NONE = 0,
-	WCD_MBHC_DET_HPHL,
-	WCD_MBHC_DET_HPHR,
-	WCD_MBHC_DET_BOTH,
-};
-
-
-/* Each micbias can be assigned to one of three cfilters
- * Vbatt_min >= .15V + ldoh_v
- * ldoh_v >= .15v + cfiltx_mv
- * If ldoh_v = 1.95 160 mv < cfiltx_mv < 1800 mv
- * If ldoh_v = 2.35 200 mv < cfiltx_mv < 2200 mv
- * If ldoh_v = 2.75 240 mv < cfiltx_mv < 2600 mv
- * If ldoh_v = 2.85 250 mv < cfiltx_mv < 2700 mv
- */
-
-struct wcd9xxx_micbias_setting {
-	u8 ldoh_v;
-	u32 cfilt1_mv; /* in mv */
-	u32 cfilt2_mv; /* in mv */
-	u32 cfilt3_mv; /* in mv */
-	/* Different WCD9xxx series codecs may not
-	 * have 4 mic biases. If a codec has fewer
-	 * mic biases, some of these properties will
-	 * not be used.
-	 */
-	u8 bias1_cfilt_sel;
-	u8 bias2_cfilt_sel;
-	u8 bias3_cfilt_sel;
-	u8 bias4_cfilt_sel;
-	u8 bias1_cap_mode;
-	u8 bias2_cap_mode;
-	u8 bias3_cap_mode;
-	u8 bias4_cap_mode;
-	bool bias2_is_headset_only;
-};
-
-enum msm8x16_wcd_pid_current {
-	MSM89XX_PID_MIC_2P5_UA,
-	MSM89XX_PID_MIC_5_UA,
-	MSM89XX_PID_MIC_10_UA,
-	MSM89XX_PID_MIC_20_UA,
-};
-
-struct msm8x16_wcd_reg_mask_val {
-	u16	reg;
-	u8	mask;
-	u8	val;
-};
-
-enum msm8x16_wcd_mbhc_analog_pwr_cfg {
-	MSM89XX_ANALOG_PWR_COLLAPSED = 0,
-	MSM89XX_ANALOG_PWR_ON,
-	MSM89XX_NUM_ANALOG_PWR_CONFIGS,
-};
-
-/* Number of input and output I2S port */
-enum {
-	MSM89XX_RX1 = 0,
-	MSM89XX_RX2,
-	MSM89XX_RX3,
-	MSM89XX_RX_MAX,
-};
-
-enum {
-	MSM89XX_TX1 = 0,
-	MSM89XX_TX2,
-	MSM89XX_TX3,
-	MSM89XX_TX4,
-	MSM89XX_TX_MAX,
-};
-
-enum {
-	/* INTR_REG 0 - Digital Periph */
-	MSM89XX_IRQ_SPKR_CNP = 0,
-	MSM89XX_IRQ_SPKR_CLIP,
-	MSM89XX_IRQ_SPKR_OCP,
-	MSM89XX_IRQ_MBHC_INSREM_DET1,
-	MSM89XX_IRQ_MBHC_RELEASE,
-	MSM89XX_IRQ_MBHC_PRESS,
-	MSM89XX_IRQ_MBHC_INSREM_DET,
-	MSM89XX_IRQ_MBHC_HS_DET,
-	/* INTR_REG 1 - Analog Periph */
-	MSM89XX_IRQ_EAR_OCP,
-	MSM89XX_IRQ_HPHR_OCP,
-	MSM89XX_IRQ_HPHL_OCP,
-	MSM89XX_IRQ_EAR_CNP,
-	MSM89XX_IRQ_HPHR_CNP,
-	MSM89XX_IRQ_HPHL_CNP,
-	MSM89XX_NUM_IRQS,
-};
-
-enum {
-	ON_DEMAND_MICBIAS = 0,
-	ON_DEMAND_SPKDRV,
-	ON_DEMAND_SUPPLIES_MAX,
-};
-
-/*
- * The delay list is per codec HW specification.
- * Please add delay in the list in the future instead
- * of magic number
- */
-enum {
-	CODEC_DELAY_1_MS = 1000,
-	CODEC_DELAY_1_1_MS  = 1100,
-};
-
-struct msm8x16_wcd_regulator {
-	const char *name;
-	int min_uv;
-	int max_uv;
-	int optimum_ua;
-	bool ondemand;
-	struct regulator *regulator;
-};
-
-struct on_demand_supply {
-	struct regulator *supply;
-	atomic_t ref;
-};
-
-struct wcd_imped_i_ref {
-	enum wcd_curr_ref curr_ref;
-	int min_val;
-	int multiplier;
-	int gain_adj;
-	int offset;
-};
-
-struct msm8x16_wcd_pdata {
-	int irq;
-	int irq_base;
-	int num_irqs;
-	int reset_gpio;
-	void *msm8x16_wcd_ahb_base_vaddr;
-	struct wcd9xxx_micbias_setting micbias;
-	struct msm8x16_wcd_regulator regulator[MAX_REGULATOR];
-	u32 mclk_rate;
-	u32 is_lpass;
-};
-
-enum msm8x16_wcd_micbias_num {
-	MSM89XX_MICBIAS1 = 0,
-};
-
-struct msm8x16_wcd {
-	struct device *dev;
-	struct mutex io_lock;
-	u8 version;
-
-	int reset_gpio;
-	int (*read_dev)(struct snd_soc_codec *codec,
-			unsigned short reg);
-	int (*write_dev)(struct snd_soc_codec *codec,
-			 unsigned short reg, u8 val);
-
-	u32 num_of_supplies;
-	struct regulator_bulk_data *supplies;
-
-	u8 idbyte[4];
-
-	int num_irqs;
-	u32 mclk_rate;
-};
-
-struct msm8x16_wcd_priv {
-	struct snd_soc_codec *codec;
-	u16 pmic_rev;
-	u16 codec_version;
-	u32 boost_voltage;
-	u32 adc_count;
-	u32 rx_bias_count;
-	s32 dmic_1_2_clk_cnt;
-	u32 mute_mask;
-	bool int_mclk0_enabled;
-	bool clock_active;
-	bool config_mode_active;
-	u16 boost_option;
-	/* mode to select hd2 */
-	u32 hph_mode;
-	/* compander used for each rx chain */
-	u32 comp_enabled[MSM89XX_RX_MAX];
-	bool spk_boost_set;
-	bool ear_pa_boost_set;
-	bool ext_spk_boost_set;
-	bool dec_active[NUM_DECIMATORS];
-	struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
-	struct regulator *spkdrv_reg;
-	/* mbhc module */
-	struct wcd_mbhc mbhc;
-	/* cal info for codec */
-	struct fw_info *fw_data;
-	struct blocking_notifier_head notifier;
-	int (*codec_spk_ext_pa_cb)(struct snd_soc_codec *codec, int enable);
-	int (*codec_hph_comp_gpio)(bool enable);
-	unsigned long status_mask;
-	struct wcd_imped_i_ref imped_i_ref;
-	enum wcd_mbhc_imp_det_pin imped_det_pin;
-};
-
-extern int msm8x16_wcd_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
-			     bool dapm);
-
-extern int msm8x16_wcd_hs_detect(struct snd_soc_codec *codec,
-		    struct wcd_mbhc_config *mbhc_cfg);
-
-extern void msm8x16_wcd_hs_detect_exit(struct snd_soc_codec *codec);
-
-extern void msm8x16_update_int_spk_boost(bool enable);
-
-extern void msm8x16_wcd_spk_ext_pa_cb(
-		int (*codec_spk_ext_pa)(struct snd_soc_codec *codec,
-		int enable), struct snd_soc_codec *codec);
-
-extern void msm8x16_wcd_hph_comp_cb(
-		int (*codec_hph_comp_gpio)(bool enable),
-		struct snd_soc_codec *codec);
-void enable_digital_callback(void *flag);
-void disable_digital_callback(void *flag);
-
-#endif
diff --git a/sound/soc/codecs/msm_hdmi_codec_rx.c b/sound/soc/codecs/msm_hdmi_codec_rx.c
index cd5e707..46cfe7d 100644
--- a/sound/soc/codecs/msm_hdmi_codec_rx.c
+++ b/sound/soc/codecs/msm_hdmi_codec_rx.c
@@ -20,10 +20,17 @@
 #include <linux/msm_ext_display.h>
 
 #define MSM_EXT_DISP_PCM_RATES	SNDRV_PCM_RATE_48000
+#define AUD_EXT_DISP_ACK_DISCONNECT (AUDIO_ACK_CONNECT ^ AUDIO_ACK_CONNECT)
+#define AUD_EXT_DISP_ACK_CONNECT    (AUDIO_ACK_CONNECT)
+#define AUD_EXT_DISP_ACK_ENABLE     (AUDIO_ACK_SET_ENABLE | AUDIO_ACK_ENABLE)
 
 static const char *const ext_disp_audio_type_text[] = {"None", "HDMI", "DP"};
+static const char *const ext_disp_audio_ack_text[] = {"Disconnect",  "Connect",
+						      "Ack_Enable"};
 
 static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_audio_type, ext_disp_audio_type_text);
+static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_audio_ack_state,
+				ext_disp_audio_ack_text);
 
 struct msm_ext_disp_audio_codec_rx_data {
 	struct platform_device *ext_disp_core_pdev;
@@ -84,6 +91,15 @@
 	rc = codec_data->ext_disp_ops.get_audio_edid_blk(
 			codec_data->ext_disp_core_pdev, &edid_blk);
 	if (rc >= 0) {
+		if (sizeof(ucontrol->value.bytes.data) <
+			  (edid_blk.audio_data_blk_size +
+			   edid_blk.spk_alloc_data_blk_size)) {
+			dev_err(codec->dev,
+				"%s: Not enough memory to copy EDID data\n",
+				__func__);
+			return -ENOMEM;
+		}
+
 		memcpy(ucontrol->value.bytes.data,
 		       edid_blk.audio_data_blk,
 		       edid_blk.audio_data_blk_size);
@@ -166,6 +182,55 @@
 	return rc;
 }
 
+static int msm_ext_disp_audio_ack_set(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_ext_disp_audio_codec_rx_data *codec_data;
+	u32 ack_state = 0;
+	int rc;
+
+	codec_data = snd_soc_codec_get_drvdata(codec);
+	if (!codec_data ||
+	    !codec_data->ext_disp_ops.acknowledge) {
+		dev_err(codec->dev,
+			"%s: codec_data or ops acknowledge() is NULL\n",
+			__func__);
+		rc = -EINVAL;
+		goto done;
+	}
+
+	switch (ucontrol->value.enumerated.item[0]) {
+	case 0:
+		ack_state = AUD_EXT_DISP_ACK_DISCONNECT;
+		break;
+	case 1:
+		ack_state = AUD_EXT_DISP_ACK_CONNECT;
+		break;
+	case 2:
+		ack_state = AUD_EXT_DISP_ACK_ENABLE;
+		break;
+	default:
+		rc = -EINVAL;
+		dev_err(codec->dev,
+			"%s: invalid value %d for mixer ctl\n",
+			__func__, ucontrol->value.enumerated.item[0]);
+		goto done;
+	}
+	dev_dbg(codec->dev, "%s: control %d, ack set value 0x%x\n",
+		__func__, ucontrol->value.enumerated.item[0], ack_state);
+
+	rc = codec_data->ext_disp_ops.acknowledge(
+			 codec_data->ext_disp_core_pdev, ack_state);
+	if (rc < 0) {
+		dev_err(codec->dev, "%s: error from acknowledge(), err:%d\n",
+			__func__, rc);
+	}
+
+done:
+	return rc;
+}
+
 static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = {
 	{
 		.access = SNDRV_CTL_ELEM_ACCESS_READ |
@@ -185,6 +250,8 @@
 	},
 	SOC_ENUM_EXT("External Display Type", ext_disp_audio_type,
 		     msm_ext_disp_audio_type_get, NULL),
+	SOC_ENUM_EXT("External Display Audio Ack", ext_disp_audio_ack_state,
+		     NULL, msm_ext_disp_audio_ack_set),
 };
 
 static int msm_ext_disp_audio_codec_rx_dai_startup(
diff --git a/sound/soc/codecs/msm_sdw/Kconfig b/sound/soc/codecs/msm_sdw/Kconfig
new file mode 100644
index 0000000..abd7c8c
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/Kconfig
@@ -0,0 +1,6 @@
+config SND_SOC_MSM_SDW
+	tristate "MSM Internal soundwire codec"
+	 help
+	 MSM-based soundwire codec core driver
+	 supported along with internal digital
+	 codec core.
diff --git a/sound/soc/codecs/msm_sdw/Makefile b/sound/soc/codecs/msm_sdw/Makefile
new file mode 100644
index 0000000..64e932b
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/Makefile
@@ -0,0 +1,3 @@
+snd-soc-msm-sdw-objs := msm_sdw_cdc.o msm_sdw_regmap.o msm-sdw-tables.o msm_sdw_cdc_utils.o
+obj-$(CONFIG_SND_SOC_MSM_SDW)	+= snd-soc-msm-sdw.o
+ccflags-y += -I$(srctree)/sound/soc/msm
diff --git a/sound/soc/codecs/msm_sdw/msm-sdw-tables.c b/sound/soc/codecs/msm_sdw/msm-sdw-tables.c
new file mode 100644
index 0000000..4cbdb72
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/msm-sdw-tables.c
@@ -0,0 +1,222 @@
+/* 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
+ * 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/types.h>
+#include "msm_sdw.h"
+
+const u8 msm_sdw_page_map[MSM_SDW_MAX_REGISTER] = {
+	[MSM_SDW_TX9_SPKR_PROT_PATH_CTL] = 0xa,
+	[MSM_SDW_TX9_SPKR_PROT_PATH_CFG0] = 0xa,
+	[MSM_SDW_TX10_SPKR_PROT_PATH_CTL] = 0xa,
+	[MSM_SDW_TX10_SPKR_PROT_PATH_CFG0] = 0xa,
+	[MSM_SDW_TX11_SPKR_PROT_PATH_CTL] = 0xa,
+	[MSM_SDW_TX11_SPKR_PROT_PATH_CFG0] = 0xa,
+	[MSM_SDW_TX12_SPKR_PROT_PATH_CTL] = 0xa,
+	[MSM_SDW_TX12_SPKR_PROT_PATH_CFG0] = 0xa,
+	[MSM_SDW_COMPANDER7_CTL0] = 0xb,
+	[MSM_SDW_COMPANDER7_CTL1] = 0xb,
+	[MSM_SDW_COMPANDER7_CTL2] = 0xb,
+	[MSM_SDW_COMPANDER7_CTL3] = 0xb,
+	[MSM_SDW_COMPANDER7_CTL4] = 0xb,
+	[MSM_SDW_COMPANDER7_CTL5] = 0xb,
+	[MSM_SDW_COMPANDER7_CTL6] = 0xb,
+	[MSM_SDW_COMPANDER7_CTL7] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL0] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL1] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL2] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL3] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL4] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL5] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL6] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL7] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_CTL] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_CFG0] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_CFG1] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_CFG2] = 0xb,
+	[MSM_SDW_RX7_RX_VOL_CTL] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_MIX_CTL] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_MIX_CFG] = 0xb,
+	[MSM_SDW_RX7_RX_VOL_MIX_CTL] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_SEC0] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_SEC1] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_SEC2] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_SEC3] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_SEC5] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_SEC6] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_SEC7] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_MIX_SEC0] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_MIX_SEC1] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_CTL] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_CFG0] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_CFG1] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_CFG2] = 0xb,
+	[MSM_SDW_RX8_RX_VOL_CTL] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_MIX_CTL] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_MIX_CFG] = 0xb,
+	[MSM_SDW_RX8_RX_VOL_MIX_CTL] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_SEC0] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_SEC1] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_SEC2] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_SEC3] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_SEC5] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_SEC6] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_SEC7] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_MIX_SEC0] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_MIX_SEC1] = 0xb,
+	[MSM_SDW_BOOST0_BOOST_PATH_CTL] = 0xc,
+	[MSM_SDW_BOOST0_BOOST_CTL] = 0xc,
+	[MSM_SDW_BOOST0_BOOST_CFG1] = 0xc,
+	[MSM_SDW_BOOST0_BOOST_CFG2] = 0xc,
+	[MSM_SDW_BOOST1_BOOST_PATH_CTL] = 0xc,
+	[MSM_SDW_BOOST1_BOOST_CTL] = 0xc,
+	[MSM_SDW_BOOST1_BOOST_CFG1] = 0xc,
+	[MSM_SDW_BOOST1_BOOST_CFG2] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_0] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_1] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_2] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_3] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_0] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_1] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_2] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_3] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_0] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_1] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_2] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_3] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_0] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_1] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_2] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_3] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_ACCESS_CFG] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_ACCESS_STATUS] = 0xc,
+	[MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL] = 0xd,
+	[MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL] = 0xd,
+	[MSM_SDW_CLK_RST_CTRL_SWR_CONTROL] = 0xd,
+	[MSM_SDW_TOP_TOP_CFG0] = 0xd,
+	[MSM_SDW_TOP_TOP_CFG1] = 0xd,
+	[MSM_SDW_TOP_RX_I2S_CTL] = 0xd,
+	[MSM_SDW_TOP_TX_I2S_CTL] = 0xd,
+	[MSM_SDW_TOP_I2S_CLK] = 0xd,
+	[MSM_SDW_TOP_RX7_PATH_INPUT0_MUX] = 0xd,
+	[MSM_SDW_TOP_RX7_PATH_INPUT1_MUX] = 0xd,
+	[MSM_SDW_TOP_RX8_PATH_INPUT0_MUX] = 0xd,
+	[MSM_SDW_TOP_RX8_PATH_INPUT1_MUX] = 0xd,
+	[MSM_SDW_TOP_FREQ_MCLK] = 0xd,
+	[MSM_SDW_TOP_DEBUG_BUS_SEL] = 0xd,
+	[MSM_SDW_TOP_DEBUG_EN] = 0xd,
+	[MSM_SDW_TOP_I2S_RESET] = 0xd,
+	[MSM_SDW_TOP_BLOCKS_RESET] = 0xd,
+};
+
+const u8 msm_sdw_reg_readable[MSM_SDW_MAX_REGISTER] = {
+	[MSM_SDW_PAGE_REGISTER] = 1,
+	[MSM_SDW_TX9_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX9_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_TX10_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX10_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_TX11_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX11_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_TX12_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX12_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_COMPANDER7_CTL0] = 1,
+	[MSM_SDW_COMPANDER7_CTL1] = 1,
+	[MSM_SDW_COMPANDER7_CTL2] = 1,
+	[MSM_SDW_COMPANDER7_CTL3] = 1,
+	[MSM_SDW_COMPANDER7_CTL4] = 1,
+	[MSM_SDW_COMPANDER7_CTL5] = 1,
+	[MSM_SDW_COMPANDER7_CTL6] = 1,
+	[MSM_SDW_COMPANDER7_CTL7] = 1,
+	[MSM_SDW_COMPANDER8_CTL0] = 1,
+	[MSM_SDW_COMPANDER8_CTL1] = 1,
+	[MSM_SDW_COMPANDER8_CTL2] = 1,
+	[MSM_SDW_COMPANDER8_CTL3] = 1,
+	[MSM_SDW_COMPANDER8_CTL4] = 1,
+	[MSM_SDW_COMPANDER8_CTL5] = 1,
+	[MSM_SDW_COMPANDER8_CTL6] = 1,
+	[MSM_SDW_COMPANDER8_CTL7] = 1,
+	[MSM_SDW_RX7_RX_PATH_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_CFG0] = 1,
+	[MSM_SDW_RX7_RX_PATH_CFG1] = 1,
+	[MSM_SDW_RX7_RX_PATH_CFG2] = 1,
+	[MSM_SDW_RX7_RX_VOL_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_CFG] = 1,
+	[MSM_SDW_RX7_RX_VOL_MIX_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC0] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC1] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC2] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC3] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC5] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC6] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC7] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_SEC0] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_SEC1] = 1,
+	[MSM_SDW_RX8_RX_PATH_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_CFG0] = 1,
+	[MSM_SDW_RX8_RX_PATH_CFG1] = 1,
+	[MSM_SDW_RX8_RX_PATH_CFG2] = 1,
+	[MSM_SDW_RX8_RX_VOL_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_CFG] = 1,
+	[MSM_SDW_RX8_RX_VOL_MIX_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC0] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC1] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC2] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC3] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC5] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC6] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC7] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_SEC0] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_SEC1] = 1,
+	[MSM_SDW_BOOST0_BOOST_PATH_CTL] = 1,
+	[MSM_SDW_BOOST0_BOOST_CTL] = 1,
+	[MSM_SDW_BOOST0_BOOST_CFG1] = 1,
+	[MSM_SDW_BOOST0_BOOST_CFG2] = 1,
+	[MSM_SDW_BOOST1_BOOST_PATH_CTL] = 1,
+	[MSM_SDW_BOOST1_BOOST_CTL] = 1,
+	[MSM_SDW_BOOST1_BOOST_CFG1] = 1,
+	[MSM_SDW_BOOST1_BOOST_CFG2] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_0] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_1] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_2] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_3] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_0] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_1] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_2] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_3] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_0] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_1] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_2] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_3] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_0] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_1] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_2] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_3] = 1,
+	[MSM_SDW_AHB_BRIDGE_ACCESS_CFG] = 1,
+	[MSM_SDW_AHB_BRIDGE_ACCESS_STATUS] = 1,
+	[MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL] = 1,
+	[MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL] = 1,
+	[MSM_SDW_CLK_RST_CTRL_SWR_CONTROL] = 1,
+	[MSM_SDW_TOP_TOP_CFG0] = 1,
+	[MSM_SDW_TOP_TOP_CFG1] = 1,
+	[MSM_SDW_TOP_RX_I2S_CTL] = 1,
+	[MSM_SDW_TOP_TX_I2S_CTL] = 1,
+	[MSM_SDW_TOP_RX7_PATH_INPUT0_MUX] = 1,
+	[MSM_SDW_TOP_RX7_PATH_INPUT1_MUX] = 1,
+	[MSM_SDW_TOP_RX8_PATH_INPUT0_MUX] = 1,
+	[MSM_SDW_TOP_RX8_PATH_INPUT1_MUX] = 1,
+	[MSM_SDW_TOP_FREQ_MCLK] = 1,
+	[MSM_SDW_TOP_DEBUG_BUS_SEL] = 1,
+	[MSM_SDW_TOP_DEBUG_EN] = 1,
+	[MSM_SDW_TOP_I2S_RESET] = 1,
+	[MSM_SDW_TOP_BLOCKS_RESET] = 1,
+};
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw.h b/sound/soc/codecs/msm_sdw/msm_sdw.h
new file mode 100644
index 0000000..3691e84
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/msm_sdw.h
@@ -0,0 +1,169 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef MSM_SDW_H
+#define MSM_SDW_H
+
+#include <sound/soc.h>
+#include <sound/q6afe-v2.h>
+#include "msm_sdw_registers.h"
+
+#define MSM_SDW_MAX_REGISTER 0x400
+
+extern const struct regmap_config msm_sdw_regmap_config;
+extern const u8 msm_sdw_page_map[MSM_SDW_MAX_REGISTER];
+extern const u8 msm_sdw_reg_readable[MSM_SDW_MAX_REGISTER];
+
+enum {
+	MSM_SDW_RX4 = 0,
+	MSM_SDW_RX5,
+	MSM_SDW_RX_MAX,
+};
+
+enum {
+	MSM_SDW_TX0 = 0,
+	MSM_SDW_TX1,
+	MSM_SDW_TX_MAX,
+};
+
+enum {
+	COMP1, /* SPK_L */
+	COMP2, /* SPK_R */
+	COMP_MAX
+};
+
+/*
+ * Structure used to update codec
+ * register defaults after reset
+ */
+struct msm_sdw_reg_mask_val {
+	u16 reg;
+	u8 mask;
+	u8 val;
+};
+
+/*
+ * Selects compander and smart boost settings
+ * for a given speaker mode
+ */
+enum {
+	SPKR_MODE_DEFAULT,
+	SPKR_MODE_1,          /* COMP Gain = 12dB, Smartboost Max = 5.5V */
+};
+
+/* Rx path gain offsets */
+enum {
+	RX_GAIN_OFFSET_M1P5_DB,
+	RX_GAIN_OFFSET_0_DB,
+};
+
+struct msm_sdw_reg_val {
+	unsigned short reg; /* register address */
+	u8 *buf;            /* buffer to be written to reg. addr */
+	int bytes;          /* number of bytes to be written */
+};
+
+/* Hold instance to soundwire platform device */
+struct msm_sdw_ctrl_data {
+	struct platform_device *sdw_pdev;
+};
+
+struct wcd_sdw_ctrl_platform_data {
+	void *handle; /* holds codec private data */
+	int (*read)(void *handle, int reg);
+	int (*write)(void *handle, int reg, int val);
+	int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
+	int (*clk)(void *handle, bool enable);
+	int (*handle_irq)(void *handle,
+			  irqreturn_t (*swrm_irq_handler)(int irq,
+							  void *data),
+			  void *swrm_handle,
+			  int action);
+};
+
+struct msm_sdw_priv {
+	struct device *dev;
+	struct mutex io_lock;
+
+	int (*read_dev)(struct msm_sdw_priv *msm_sdw, unsigned short reg,
+			int bytes, void *dest);
+	int (*write_dev)(struct msm_sdw_priv *msm_sdw, unsigned short reg,
+			 int bytes, void *src);
+	int (*multi_reg_write)(struct msm_sdw_priv *msm_sdw, const void *data,
+			       size_t count);
+	struct snd_soc_codec *codec;
+	struct device_node *sdw_gpio_p; /* used by pinctrl API */
+	/* SoundWire data structure */
+	struct msm_sdw_ctrl_data *sdw_ctrl_data;
+	int nr;
+
+	/* compander */
+	int comp_enabled[COMP_MAX];
+	int ear_spkr_gain;
+
+	/* to track the status */
+	unsigned long status_mask;
+
+	struct work_struct msm_sdw_add_child_devices_work;
+	struct wcd_sdw_ctrl_platform_data sdw_plat_data;
+
+	unsigned int vi_feed_value;
+
+	struct mutex sdw_read_lock;
+	struct mutex sdw_write_lock;
+	struct mutex sdw_clk_lock;
+	int sdw_clk_users;
+	int sdw_mclk_users;
+
+	int sdw_irq;
+	int int_mclk1_rsc_ref;
+	bool int_mclk1_enabled;
+	bool sdw_npl_clk_enabled;
+	struct mutex cdc_int_mclk1_mutex;
+	struct mutex sdw_npl_clk_mutex;
+	struct delayed_work disable_int_mclk1_work;
+	struct afe_clk_set sdw_cdc_core_clk;
+	struct afe_clk_set sdw_npl_clk;
+	struct notifier_block service_nb;
+	int (*sdw_cdc_gpio_fn)(bool enable, struct snd_soc_codec *codec);
+	bool dev_up;
+
+	int spkr_gain_offset;
+	int spkr_mode;
+	struct mutex codec_mutex;
+	int rx_4_count;
+	int rx_5_count;
+	u32 mclk_rate;
+	struct regmap *regmap;
+
+	bool prev_pg_valid;
+	u8 prev_pg;
+	u32 sdw_base_addr;
+	char __iomem *sdw_base;
+	u32 version;
+
+	/* Entry for version info */
+	struct snd_info_entry *entry;
+	struct snd_info_entry *version_entry;
+};
+
+extern int msm_sdw_set_spkr_mode(struct snd_soc_codec *codec, int mode);
+extern int msm_sdw_set_spkr_gain_offset(struct snd_soc_codec *codec,
+					int offset);
+extern void msm_sdw_gpio_cb(
+	int (*sdw_cdc_gpio_fn)(bool enable, struct snd_soc_codec *codec),
+	struct snd_soc_codec *codec);
+extern struct regmap *msm_sdw_regmap_init(struct device *dev,
+					  const struct regmap_config *config);
+extern int msm_sdw_codec_info_create_codec_entry(
+	struct snd_info_entry *codec_root,
+	struct snd_soc_codec *codec);
+#endif
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
new file mode 100644
index 0000000..502aa4f
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
@@ -0,0 +1,1991 @@
+/* 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
+ * 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/device.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/msm-cdc-pinctrl.h>
+#include <linux/printk.h>
+#include <linux/debugfs.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/qdsp6v2/apr.h>
+#include <linux/soundwire/swr-wcd.h>
+#include <linux/qdsp6v2/audio_notifier.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/q6core.h>
+#include <sound/tlv.h>
+#include "msm_sdw.h"
+#include "msm_sdw_registers.h"
+
+#define MSM_SDW_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+#define MSM_SDW_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+		SNDRV_PCM_FMTBIT_S24_LE |\
+		SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define MSM_SDW_STRING_LEN 80
+
+#define INT_MCLK1_FREQ 9600000
+#define SDW_NPL_FREQ 153600000
+
+#define MSM_SDW_VERSION_1_0 0x0001
+#define MSM_SDW_VERSION_ENTRY_SIZE 32
+
+/*
+ * 200 Milliseconds sufficient for DSP bring up in the modem
+ * after Sub System Restart
+ */
+#define ADSP_STATE_READY_TIMEOUT_MS 200
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+static struct snd_soc_dai_driver msm_sdw_dai[];
+static bool skip_irq = true;
+
+static int msm_sdw_config_ear_spkr_gain(struct snd_soc_codec *codec,
+					int event, int gain_reg);
+static int msm_sdw_config_compander(struct snd_soc_codec *, int, int);
+static int msm_sdw_mclk_enable(struct msm_sdw_priv *msm_sdw,
+			       int mclk_enable, bool dapm);
+static int msm_int_enable_sdw_cdc_clk(struct msm_sdw_priv *msm_sdw,
+				      int enable, bool dapm);
+
+enum {
+	VI_SENSE_1,
+	VI_SENSE_2,
+};
+
+enum {
+	AIF1_SDW_PB = 0,
+	AIF1_SDW_VIFEED,
+	NUM_CODEC_DAIS,
+};
+
+static const struct msm_sdw_reg_mask_val msm_sdw_spkr_default[] = {
+	{MSM_SDW_COMPANDER7_CTL3, 0x80, 0x80},
+	{MSM_SDW_COMPANDER8_CTL3, 0x80, 0x80},
+	{MSM_SDW_COMPANDER7_CTL7, 0x01, 0x01},
+	{MSM_SDW_COMPANDER8_CTL7, 0x01, 0x01},
+	{MSM_SDW_BOOST0_BOOST_CTL, 0x7C, 0x50},
+	{MSM_SDW_BOOST1_BOOST_CTL, 0x7C, 0x50},
+};
+
+static const struct msm_sdw_reg_mask_val msm_sdw_spkr_mode1[] = {
+	{MSM_SDW_COMPANDER7_CTL3, 0x80, 0x00},
+	{MSM_SDW_COMPANDER8_CTL3, 0x80, 0x00},
+	{MSM_SDW_COMPANDER7_CTL7, 0x01, 0x00},
+	{MSM_SDW_COMPANDER8_CTL7, 0x01, 0x00},
+	{MSM_SDW_BOOST0_BOOST_CTL, 0x7C, 0x44},
+	{MSM_SDW_BOOST1_BOOST_CTL, 0x7C, 0x44},
+};
+
+/**
+ * msm_sdw_set_spkr_gain_offset - offset the speaker path
+ * gain with the given offset value.
+ *
+ * @codec: codec instance
+ * @offset: Indicates speaker path gain offset value.
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int msm_sdw_set_spkr_gain_offset(struct snd_soc_codec *codec, int offset)
+{
+	struct msm_sdw_priv *priv;
+
+	if (!codec) {
+		pr_err("%s: NULL codec pointer!\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = snd_soc_codec_get_drvdata(codec);
+	if (!priv)
+		return -EINVAL;
+
+	priv->spkr_gain_offset = offset;
+	return 0;
+}
+EXPORT_SYMBOL(msm_sdw_set_spkr_gain_offset);
+
+/**
+ * msm_sdw_set_spkr_mode - Configures speaker compander and smartboost
+ * settings based on speaker mode.
+ *
+ * @codec: codec instance
+ * @mode: Indicates speaker configuration mode.
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int msm_sdw_set_spkr_mode(struct snd_soc_codec *codec, int mode)
+{
+	struct msm_sdw_priv *priv;
+	int i;
+	const struct msm_sdw_reg_mask_val *regs;
+	int size;
+
+	if (!codec) {
+		pr_err("%s: NULL codec pointer!\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = snd_soc_codec_get_drvdata(codec);
+	if (!priv)
+		return -EINVAL;
+
+	switch (mode) {
+	case SPKR_MODE_1:
+		regs = msm_sdw_spkr_mode1;
+		size = ARRAY_SIZE(msm_sdw_spkr_mode1);
+		break;
+	default:
+		regs = msm_sdw_spkr_default;
+		size = ARRAY_SIZE(msm_sdw_spkr_default);
+		break;
+	}
+
+	priv->spkr_mode = mode;
+	for (i = 0; i < size; i++)
+		snd_soc_update_bits(codec, regs[i].reg,
+				    regs[i].mask, regs[i].val);
+	return 0;
+}
+EXPORT_SYMBOL(msm_sdw_set_spkr_mode);
+
+static int msm_enable_sdw_npl_clk(struct msm_sdw_priv *msm_sdw, int enable)
+{
+	int ret = 0;
+
+	dev_dbg(msm_sdw->dev, "%s: enable %d\n", __func__, enable);
+
+	mutex_lock(&msm_sdw->sdw_npl_clk_mutex);
+	if (enable) {
+		if (msm_sdw->sdw_npl_clk_enabled == false) {
+			msm_sdw->sdw_npl_clk.enable = 1;
+			ret = afe_set_lpass_clock_v2(
+				AFE_PORT_ID_INT4_MI2S_RX,
+				&msm_sdw->sdw_npl_clk);
+			if (ret < 0) {
+				dev_err(msm_sdw->dev,
+					"%s: failed to enable SDW NPL CLK\n",
+					__func__);
+				mutex_unlock(&msm_sdw->sdw_npl_clk_mutex);
+				return ret;
+			}
+			dev_dbg(msm_sdw->dev, "enabled sdw npl clk\n");
+			msm_sdw->sdw_npl_clk_enabled = true;
+		}
+	} else {
+		if (msm_sdw->sdw_npl_clk_enabled == true) {
+			msm_sdw->sdw_npl_clk.enable = 0;
+			ret = afe_set_lpass_clock_v2(
+				AFE_PORT_ID_INT4_MI2S_RX,
+				&msm_sdw->sdw_npl_clk);
+			if (ret < 0)
+				dev_err(msm_sdw->dev,
+					"%s: failed to disable SDW NPL CLK\n",
+					__func__);
+			msm_sdw->sdw_npl_clk_enabled = false;
+		}
+	}
+	mutex_unlock(&msm_sdw->sdw_npl_clk_mutex);
+	return ret;
+}
+
+static int msm_int_enable_sdw_cdc_clk(struct msm_sdw_priv *msm_sdw,
+				      int enable, bool dapm)
+{
+	int ret = 0;
+
+	mutex_lock(&msm_sdw->cdc_int_mclk1_mutex);
+	dev_dbg(msm_sdw->dev, "%s: enable %d mclk1 ref counter %d\n",
+		__func__, enable, msm_sdw->int_mclk1_rsc_ref);
+	if (enable) {
+		if (msm_sdw->int_mclk1_rsc_ref == 0) {
+			cancel_delayed_work_sync(
+					&msm_sdw->disable_int_mclk1_work);
+			if (msm_sdw->int_mclk1_enabled == false) {
+				msm_sdw->sdw_cdc_core_clk.enable = 1;
+				ret = afe_set_lpass_clock_v2(
+					AFE_PORT_ID_INT4_MI2S_RX,
+					&msm_sdw->sdw_cdc_core_clk);
+				if (ret < 0) {
+					dev_err(msm_sdw->dev,
+						"%s: failed to enable SDW MCLK\n",
+						__func__);
+					goto rtn;
+				}
+				dev_dbg(msm_sdw->dev,
+					"enabled sdw codec core mclk\n");
+				msm_sdw->int_mclk1_enabled = true;
+			}
+		}
+		msm_sdw->int_mclk1_rsc_ref++;
+	} else {
+		cancel_delayed_work_sync(&msm_sdw->disable_int_mclk1_work);
+		if (msm_sdw->int_mclk1_rsc_ref > 0) {
+			msm_sdw->int_mclk1_rsc_ref--;
+			dev_dbg(msm_sdw->dev,
+				"%s: decrementing mclk_res_ref %d\n",
+				 __func__, msm_sdw->int_mclk1_rsc_ref);
+		}
+		if (msm_sdw->int_mclk1_enabled == true &&
+			msm_sdw->int_mclk1_rsc_ref == 0) {
+			msm_sdw->sdw_cdc_core_clk.enable = 0;
+			ret = afe_set_lpass_clock_v2(
+				AFE_PORT_ID_INT4_MI2S_RX,
+				&msm_sdw->sdw_cdc_core_clk);
+			if (ret < 0)
+				dev_err(msm_sdw->dev,
+					"%s: failed to disable SDW MCLK\n",
+					__func__);
+			msm_sdw->int_mclk1_enabled = false;
+		}
+	}
+	mutex_unlock(&msm_sdw->cdc_int_mclk1_mutex);
+rtn:
+	return ret;
+}
+EXPORT_SYMBOL(msm_int_enable_sdw_cdc_clk);
+
+static void msm_disable_int_mclk1(struct work_struct *work)
+{
+	struct msm_sdw_priv *msm_sdw = NULL;
+	struct delayed_work *dwork;
+	int ret = 0;
+
+	dwork = to_delayed_work(work);
+	msm_sdw = container_of(dwork, struct msm_sdw_priv,
+			disable_int_mclk1_work);
+	mutex_lock(&msm_sdw->cdc_int_mclk1_mutex);
+	dev_dbg(msm_sdw->dev, "%s: mclk1_enabled %d mclk1_rsc_ref %d\n",
+		__func__, msm_sdw->int_mclk1_enabled,
+		msm_sdw->int_mclk1_rsc_ref);
+	if (msm_sdw->int_mclk1_enabled == true
+			&& msm_sdw->int_mclk1_rsc_ref == 0) {
+		dev_dbg(msm_sdw->dev, "Disable the mclk1\n");
+		msm_sdw->sdw_cdc_core_clk.enable = 0;
+		ret = afe_set_lpass_clock_v2(
+			AFE_PORT_ID_INT4_MI2S_RX,
+			&msm_sdw->sdw_cdc_core_clk);
+		if (ret < 0)
+			dev_err(msm_sdw->dev,
+				"%s failed to disable the MCLK1\n",
+				__func__);
+		msm_sdw->int_mclk1_enabled = false;
+	}
+	mutex_unlock(&msm_sdw->cdc_int_mclk1_mutex);
+}
+
+static int msm_int_mclk1_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	dev_dbg(msm_sdw->dev, "%s: event = %d\n", __func__, event);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* enable the codec mclk config */
+		msm_int_enable_sdw_cdc_clk(msm_sdw, 1, true);
+		msm_sdw_mclk_enable(msm_sdw, 1, true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* disable the codec mclk config */
+		msm_sdw_mclk_enable(msm_sdw, 0, true);
+		msm_int_enable_sdw_cdc_clk(msm_sdw, 0, true);
+		break;
+	default:
+		dev_err(msm_sdw->dev,
+			"%s: invalid DAPM event %d\n", __func__, event);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int msm_sdw_ahb_write_device(struct msm_sdw_priv *msm_sdw,
+					u16 reg, u8 *value)
+{
+	u32 temp = (u32)(*value) & 0x000000FF;
+
+	if (!msm_sdw->dev_up) {
+		dev_err_ratelimited(msm_sdw->dev, "%s: q6 not ready\n",
+				    __func__);
+		return 0;
+	}
+
+	iowrite32(temp, msm_sdw->sdw_base + reg);
+	return 0;
+}
+
+static int msm_sdw_ahb_read_device(struct msm_sdw_priv *msm_sdw,
+					u16 reg, u8 *value)
+{
+	u32 temp;
+
+	if (!msm_sdw->dev_up) {
+		dev_err_ratelimited(msm_sdw->dev, "%s: q6 not ready\n",
+				    __func__);
+		return 0;
+	}
+
+	temp = ioread32(msm_sdw->sdw_base + reg);
+	*value = (u8)temp;
+	return 0;
+}
+
+static int __msm_sdw_reg_read(struct msm_sdw_priv *msm_sdw, unsigned short reg,
+			int bytes, void *dest)
+{
+	int ret = -EINVAL, i;
+	u8 temp = 0;
+
+	dev_dbg(msm_sdw->dev, "%s reg = %x\n", __func__, reg);
+	mutex_lock(&msm_sdw->cdc_int_mclk1_mutex);
+	if (msm_sdw->int_mclk1_enabled == false) {
+		msm_sdw->sdw_cdc_core_clk.enable = 1;
+		ret = afe_set_lpass_clock_v2(
+					AFE_PORT_ID_INT4_MI2S_RX,
+					&msm_sdw->sdw_cdc_core_clk);
+		if (ret < 0) {
+			dev_err(msm_sdw->dev,
+				"%s:failed to enable the INT_MCLK1\n",
+				__func__);
+			goto unlock_exit;
+		}
+		dev_dbg(msm_sdw->dev, "%s:enabled sdw codec core clk\n",
+			__func__);
+		for (i = 0; i < bytes; i++)  {
+			ret = msm_sdw_ahb_read_device(
+				msm_sdw, reg + (4 * i), &temp);
+			((u8 *)dest)[i] = temp;
+		}
+		msm_sdw->int_mclk1_enabled = true;
+		schedule_delayed_work(&msm_sdw->disable_int_mclk1_work, 50);
+		goto unlock_exit;
+	}
+	for (i = 0; i < bytes; i++)  {
+		ret = msm_sdw_ahb_read_device(
+			msm_sdw, reg + (4 * i), &temp);
+		((u8 *)dest)[i] = temp;
+	}
+unlock_exit:
+	mutex_unlock(&msm_sdw->cdc_int_mclk1_mutex);
+	if (ret < 0) {
+		dev_err_ratelimited(msm_sdw->dev,
+				    "%s: codec read failed for reg 0x%x\n",
+				    __func__, reg);
+		return ret;
+	}
+	dev_dbg(msm_sdw->dev, "Read 0x%02x from 0x%x\n", temp, reg);
+
+	return 0;
+}
+
+static int __msm_sdw_reg_write(struct msm_sdw_priv *msm_sdw, unsigned short reg,
+			       int bytes, void *src)
+{
+	int ret = -EINVAL, i;
+
+	mutex_lock(&msm_sdw->cdc_int_mclk1_mutex);
+	if (msm_sdw->int_mclk1_enabled == false) {
+		msm_sdw->sdw_cdc_core_clk.enable = 1;
+		ret = afe_set_lpass_clock_v2(AFE_PORT_ID_INT4_MI2S_RX,
+					     &msm_sdw->sdw_cdc_core_clk);
+		if (ret < 0) {
+			dev_err(msm_sdw->dev,
+				"%s: failed to enable the INT_MCLK1\n",
+				__func__);
+			ret = 0;
+			goto unlock_exit;
+		}
+		dev_dbg(msm_sdw->dev, "%s: enabled INT_MCLK1\n", __func__);
+		for (i = 0; i < bytes; i++)
+			ret = msm_sdw_ahb_write_device(msm_sdw, reg + (4 * i),
+						       &((u8 *)src)[i]);
+		msm_sdw->int_mclk1_enabled = true;
+		schedule_delayed_work(&msm_sdw->disable_int_mclk1_work, 50);
+		goto unlock_exit;
+	}
+	for (i = 0; i < bytes; i++)
+		ret = msm_sdw_ahb_write_device(msm_sdw, reg + (4 * i),
+					       &((u8 *)src)[i]);
+unlock_exit:
+	mutex_unlock(&msm_sdw->cdc_int_mclk1_mutex);
+	dev_dbg(msm_sdw->dev, "Write 0x%x val 0x%02x\n",
+				reg, (u32)(*(u32 *)src));
+
+	return ret;
+}
+
+static int msm_sdw_codec_enable_vi_feedback(struct snd_soc_dapm_widget *w,
+					    struct snd_kcontrol *kcontrol,
+					    int event)
+{
+	struct snd_soc_codec *codec = NULL;
+	struct msm_sdw_priv *msm_sdw_p = NULL;
+	int ret = 0;
+
+	if (!w) {
+		pr_err("%s invalid params\n", __func__);
+		return -EINVAL;
+	}
+	codec = snd_soc_dapm_to_codec(w->dapm);
+	msm_sdw_p = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: num_dai %d stream name %s\n",
+		__func__, codec->component.num_dai, w->sname);
+
+	dev_dbg(codec->dev, "%s(): w->name %s event %d w->shift %d\n",
+		__func__, w->name, event, w->shift);
+	if (w->shift != AIF1_SDW_VIFEED) {
+		dev_err(codec->dev,
+			"%s:Error in enabling the vi feedback path\n",
+			__func__);
+		ret = -EINVAL;
+		goto out_vi;
+	}
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (test_bit(VI_SENSE_1, &msm_sdw_p->status_mask)) {
+			dev_dbg(codec->dev, "%s: spkr1 enabled\n", __func__);
+			/* Enable V&I sensing */
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x0F, 0x04);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x0F, 0x04);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x10);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x10,
+				0x10);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x00);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x20,
+				0x00);
+		}
+		if (test_bit(VI_SENSE_2, &msm_sdw_p->status_mask)) {
+			dev_dbg(codec->dev, "%s: spkr2 enabled\n", __func__);
+			/* Enable V&I sensing */
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x0F,
+				0x04);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x0F,
+				0x04);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x10,
+				0x10);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x10,
+				0x10);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x20,
+				0x00);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x20,
+				0x00);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (test_bit(VI_SENSE_1, &msm_sdw_p->status_mask)) {
+			/* Disable V&I sensing */
+			dev_dbg(codec->dev, "%s: spkr1 disabled\n", __func__);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x00);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x10,
+				0x00);
+		}
+		if (test_bit(VI_SENSE_2, &msm_sdw_p->status_mask)) {
+			/* Disable V&I sensing */
+			dev_dbg(codec->dev, "%s: spkr2 disabled\n", __func__);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x10,
+				0x00);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x10,
+				0x00);
+		}
+		break;
+	}
+out_vi:
+	return ret;
+}
+
+static int msm_sdwm_handle_irq(void *handle,
+			       irqreturn_t (*swrm_irq_handler)(int irq,
+							       void *data),
+			       void *swrm_handle,
+			       int action)
+{
+	struct msm_sdw_priv *msm_sdw;
+	int ret = 0;
+
+	if (!handle) {
+		pr_err("%s: null handle received\n", __func__);
+		return -EINVAL;
+	}
+	msm_sdw = (struct msm_sdw_priv *) handle;
+
+	if (skip_irq)
+		return ret;
+
+	if (action) {
+		ret = request_threaded_irq(msm_sdw->sdw_irq, NULL,
+					   swrm_irq_handler,
+					   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+					   "swr_master_irq", swrm_handle);
+		if (ret)
+			dev_err(msm_sdw->dev, "%s: Failed to request irq %d\n",
+				__func__, ret);
+	} else
+		free_irq(msm_sdw->sdw_irq, swrm_handle);
+
+	return ret;
+}
+
+static void msm_sdw_codec_hd2_control(struct snd_soc_codec *codec,
+				      u16 reg, int event)
+{
+	u16 hd2_scale_reg;
+	u16 hd2_enable_reg = 0;
+
+	if (reg == MSM_SDW_RX7_RX_PATH_CTL) {
+		hd2_scale_reg = MSM_SDW_RX7_RX_PATH_SEC3;
+		hd2_enable_reg = MSM_SDW_RX7_RX_PATH_CFG0;
+	}
+	if (reg == MSM_SDW_RX8_RX_PATH_CTL) {
+		hd2_scale_reg = MSM_SDW_RX8_RX_PATH_SEC3;
+		hd2_enable_reg = MSM_SDW_RX8_RX_PATH_CFG0;
+	}
+
+	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) {
+		snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x10);
+		snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x01);
+		snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x04);
+	}
+
+	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x00);
+		snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x00);
+		snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x00);
+	}
+}
+
+static int msm_sdw_enable_swr(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct msm_sdw_priv *msm_sdw;
+	int i, ch_cnt;
+
+	msm_sdw = snd_soc_codec_get_drvdata(codec);
+
+	if (!msm_sdw->nr)
+		return 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (!(strnstr(w->name, "RX4", sizeof("RX4 MIX"))) &&
+		    !msm_sdw->rx_4_count)
+			msm_sdw->rx_4_count++;
+		if (!(strnstr(w->name, "RX5", sizeof("RX5 MIX"))) &&
+		    !msm_sdw->rx_5_count)
+			msm_sdw->rx_5_count++;
+		ch_cnt = msm_sdw->rx_4_count + msm_sdw->rx_5_count;
+
+		for (i = 0; i < msm_sdw->nr; i++) {
+			swrm_wcd_notify(msm_sdw->sdw_ctrl_data[i].sdw_pdev,
+					SWR_DEVICE_UP, NULL);
+			swrm_wcd_notify(msm_sdw->sdw_ctrl_data[i].sdw_pdev,
+					SWR_SET_NUM_RX_CH, &ch_cnt);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (!(strnstr(w->name, "RX4", sizeof("RX4 MIX"))) &&
+		    msm_sdw->rx_4_count)
+			msm_sdw->rx_4_count--;
+		if (!(strnstr(w->name, "RX5", sizeof("RX5 MIX"))) &&
+		    msm_sdw->rx_5_count)
+			msm_sdw->rx_5_count--;
+		ch_cnt = msm_sdw->rx_4_count + msm_sdw->rx_5_count;
+
+		for (i = 0; i < msm_sdw->nr; i++)
+			swrm_wcd_notify(msm_sdw->sdw_ctrl_data[i].sdw_pdev,
+					SWR_SET_NUM_RX_CH, &ch_cnt);
+		break;
+	}
+	dev_dbg(msm_sdw->dev, "%s: current swr ch cnt: %d\n",
+		__func__, msm_sdw->rx_4_count + msm_sdw->rx_5_count);
+
+	return 0;
+}
+
+static int msm_sdw_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
+					     struct snd_kcontrol *kcontrol,
+					     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+	u16 gain_reg;
+	u16 reg;
+	int val;
+	int offset_val = 0;
+
+	dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
+
+	if (!(strcmp(w->name, "RX INT4 INTERP"))) {
+		reg = MSM_SDW_RX7_RX_PATH_CTL;
+		gain_reg = MSM_SDW_RX7_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT5 INTERP"))) {
+		reg = MSM_SDW_RX8_RX_PATH_CTL;
+		gain_reg = MSM_SDW_RX8_RX_VOL_CTL;
+	} else {
+		dev_err(codec->dev, "%s: Interpolator reg not found\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, reg, 0x10, 0x10);
+		msm_sdw_codec_hd2_control(codec, reg, event);
+		snd_soc_update_bits(codec, reg, 1 << 0x5, 1 << 0x5);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		msm_sdw_config_compander(codec, w->shift, event);
+		/* apply gain after int clk is enabled */
+		if ((msm_sdw->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) &&
+		    (msm_sdw->comp_enabled[COMP1] ||
+		     msm_sdw->comp_enabled[COMP2]) &&
+		    (gain_reg == MSM_SDW_RX7_RX_VOL_CTL ||
+		     gain_reg == MSM_SDW_RX8_RX_VOL_CTL)) {
+			snd_soc_update_bits(codec, MSM_SDW_RX7_RX_PATH_SEC1,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec,
+					    MSM_SDW_RX7_RX_PATH_MIX_SEC0,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec, MSM_SDW_RX8_RX_PATH_SEC1,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec,
+					    MSM_SDW_RX8_RX_PATH_MIX_SEC0,
+					    0x01, 0x01);
+			offset_val = -2;
+		}
+		val = snd_soc_read(codec, gain_reg);
+		val += offset_val;
+		snd_soc_write(codec, gain_reg, val);
+		msm_sdw_config_ear_spkr_gain(codec, event, gain_reg);
+		snd_soc_update_bits(codec, reg, 0x10, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, reg, 1 << 0x5, 0 << 0x5);
+		snd_soc_update_bits(codec, reg,	0x40, 0x40);
+		snd_soc_update_bits(codec, reg,	0x40, 0x00);
+		msm_sdw_codec_hd2_control(codec, reg, event);
+		msm_sdw_config_compander(codec, w->shift, event);
+		if ((msm_sdw->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) &&
+		    (msm_sdw->comp_enabled[COMP1] ||
+		     msm_sdw->comp_enabled[COMP2]) &&
+		    (gain_reg == MSM_SDW_RX7_RX_VOL_CTL ||
+		     gain_reg == MSM_SDW_RX8_RX_VOL_CTL)) {
+			snd_soc_update_bits(codec, MSM_SDW_RX7_RX_PATH_SEC1,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec,
+					    MSM_SDW_RX7_RX_PATH_MIX_SEC0,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec, MSM_SDW_RX8_RX_PATH_SEC1,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec,
+					    MSM_SDW_RX8_RX_PATH_MIX_SEC0,
+					    0x01, 0x00);
+			offset_val = 2;
+			val = snd_soc_read(codec, gain_reg);
+			val += offset_val;
+			snd_soc_write(codec, gain_reg, val);
+		}
+		msm_sdw_config_ear_spkr_gain(codec, event, gain_reg);
+		break;
+	};
+
+	return 0;
+}
+
+static int msm_sdw_config_ear_spkr_gain(struct snd_soc_codec *codec,
+					int event, int gain_reg)
+{
+	int comp_gain_offset, val;
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+
+	switch (msm_sdw->spkr_mode) {
+	/* Compander gain in SPKR_MODE1 case is 12 dB */
+	case SPKR_MODE_1:
+		comp_gain_offset = -12;
+		break;
+	/* Default case compander gain is 15 dB */
+	default:
+		comp_gain_offset = -15;
+		break;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* Apply ear spkr gain only if compander is enabled */
+		if (msm_sdw->comp_enabled[COMP1] &&
+		    (gain_reg == MSM_SDW_RX7_RX_VOL_CTL) &&
+		    (msm_sdw->ear_spkr_gain != 0)) {
+			/* For example, val is -8(-12+5-1) for 4dB of gain */
+			val = comp_gain_offset + msm_sdw->ear_spkr_gain - 1;
+			snd_soc_write(codec, gain_reg, val);
+
+			dev_dbg(codec->dev, "%s: RX4 Volume %d dB\n",
+				__func__, val);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/*
+		 * Reset RX4 volume to 0 dB if compander is enabled and
+		 * ear_spkr_gain is non-zero.
+		 */
+		if (msm_sdw->comp_enabled[COMP1] &&
+		    (gain_reg == MSM_SDW_RX7_RX_VOL_CTL) &&
+		    (msm_sdw->ear_spkr_gain != 0)) {
+			snd_soc_write(codec, gain_reg, 0x0);
+
+			dev_dbg(codec->dev, "%s: Reset RX4 Volume to 0 dB\n",
+				__func__);
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int msm_sdw_codec_spk_boost_event(struct snd_soc_dapm_widget *w,
+					 struct snd_kcontrol *kcontrol,
+					 int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	u16 boost_path_ctl, boost_path_cfg1;
+	u16 reg;
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	if (!strcmp(w->name, "RX INT4 CHAIN")) {
+		boost_path_ctl = MSM_SDW_BOOST0_BOOST_PATH_CTL;
+		boost_path_cfg1 = MSM_SDW_RX7_RX_PATH_CFG1;
+		reg = MSM_SDW_RX7_RX_PATH_CTL;
+	} else if (!strcmp(w->name, "RX INT5 CHAIN")) {
+		boost_path_ctl = MSM_SDW_BOOST1_BOOST_PATH_CTL;
+		boost_path_cfg1 = MSM_SDW_RX8_RX_PATH_CFG1;
+		reg = MSM_SDW_RX8_RX_PATH_CTL;
+	} else {
+		dev_err(codec->dev, "%s: boost reg not found\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, boost_path_ctl, 0x10, 0x10);
+		snd_soc_update_bits(codec, boost_path_cfg1, 0x01, 0x01);
+		snd_soc_update_bits(codec, reg, 0x10, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, boost_path_cfg1, 0x01, 0x00);
+		snd_soc_update_bits(codec, boost_path_ctl, 0x10, 0x00);
+		break;
+	};
+
+	return 0;
+}
+
+static int msm_sdw_config_compander(struct snd_soc_codec *codec, int comp,
+				    int event)
+{
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+	u16 comp_ctl0_reg, rx_path_cfg0_reg;
+
+	if (comp < COMP1 || comp >= COMP_MAX)
+		return 0;
+
+	dev_dbg(codec->dev, "%s: event %d compander %d, enabled %d\n",
+		__func__, event, comp + 1, msm_sdw->comp_enabled[comp]);
+
+	if (!msm_sdw->comp_enabled[comp])
+		return 0;
+
+	comp_ctl0_reg = MSM_SDW_COMPANDER7_CTL0 + (comp * 8);
+	rx_path_cfg0_reg = MSM_SDW_RX7_RX_PATH_CFG0 + (comp * 20);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		/* Enable Compander Clock */
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x01, 0x01);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x02);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x00);
+		snd_soc_update_bits(codec, rx_path_cfg0_reg, 0x02, 0x02);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x04);
+		snd_soc_update_bits(codec, rx_path_cfg0_reg, 0x02, 0x00);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x02);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x00);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x01, 0x00);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x00);
+	}
+
+	return 0;
+}
+
+static int msm_sdw_get_compander(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int comp = ((struct soc_multi_mixer_control *)
+		    kcontrol->private_value)->shift;
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = msm_sdw->comp_enabled[comp];
+	return 0;
+}
+
+static int msm_sdw_set_compander(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+	int comp = ((struct soc_multi_mixer_control *)
+		    kcontrol->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: Compander %d enable current %d, new %d\n",
+		__func__, comp + 1, msm_sdw->comp_enabled[comp], value);
+	msm_sdw->comp_enabled[comp] = value;
+
+	return 0;
+}
+
+static int msm_sdw_ear_spkr_pa_gain_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = msm_sdw->ear_spkr_gain;
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int msm_sdw_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+
+	msm_sdw->ear_spkr_gain =  ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: gain = %d\n", __func__,
+		msm_sdw->ear_spkr_gain);
+
+	return 0;
+}
+
+static int msm_sdw_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct msm_sdw_priv *msm_sdw_p = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = msm_sdw_p->vi_feed_value;
+
+	return 0;
+}
+
+static int msm_sdw_vi_feed_mixer_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct msm_sdw_priv *msm_sdw_p = snd_soc_codec_get_drvdata(codec);
+	struct soc_multi_mixer_control *mixer =
+		((struct soc_multi_mixer_control *)kcontrol->private_value);
+	u32 dai_id = widget->shift;
+	u32 port_id = mixer->shift;
+	u32 enable = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: enable: %d, port_id:%d, dai_id: %d\n",
+		__func__, enable, port_id, dai_id);
+
+	msm_sdw_p->vi_feed_value = ucontrol->value.integer.value[0];
+
+	mutex_lock(&msm_sdw_p->codec_mutex);
+	if (enable) {
+		if (port_id == MSM_SDW_TX0 && !test_bit(VI_SENSE_1,
+						&msm_sdw_p->status_mask))
+			set_bit(VI_SENSE_1, &msm_sdw_p->status_mask);
+		if (port_id == MSM_SDW_TX1 && !test_bit(VI_SENSE_2,
+						&msm_sdw_p->status_mask))
+			set_bit(VI_SENSE_2, &msm_sdw_p->status_mask);
+	} else {
+		if (port_id == MSM_SDW_TX0 && test_bit(VI_SENSE_1,
+					&msm_sdw_p->status_mask))
+			clear_bit(VI_SENSE_1, &msm_sdw_p->status_mask);
+		if (port_id == MSM_SDW_TX1 && test_bit(VI_SENSE_2,
+					&msm_sdw_p->status_mask))
+			clear_bit(VI_SENSE_2, &msm_sdw_p->status_mask);
+	}
+	mutex_unlock(&msm_sdw_p->codec_mutex);
+	snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL);
+
+	return 0;
+}
+
+static int msm_sdw_mclk_enable(struct msm_sdw_priv *msm_sdw,
+			       int mclk_enable, bool dapm)
+{
+	dev_dbg(msm_sdw->dev, "%s: mclk_enable = %u, dapm = %d clk_users= %d\n",
+		__func__, mclk_enable, dapm, msm_sdw->sdw_mclk_users);
+	if (mclk_enable) {
+		msm_sdw->sdw_mclk_users++;
+		if (msm_sdw->sdw_mclk_users == 1) {
+			regmap_update_bits(msm_sdw->regmap,
+					MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL,
+					0x01, 0x01);
+			regmap_update_bits(msm_sdw->regmap,
+				MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL,
+				0x01, 0x01);
+			/* 9.6MHz MCLK, set value 0x00 if other frequency */
+			regmap_update_bits(msm_sdw->regmap,
+				MSM_SDW_TOP_FREQ_MCLK, 0x01, 0x01);
+		}
+	} else {
+		msm_sdw->sdw_mclk_users--;
+		if (msm_sdw->sdw_mclk_users == 0) {
+			regmap_update_bits(msm_sdw->regmap,
+					MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL,
+					0x01, 0x00);
+			regmap_update_bits(msm_sdw->regmap,
+					MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL,
+					0x01, 0x00);
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(msm_sdw_mclk_enable);
+
+static int msm_sdw_swrm_read(void *handle, int reg)
+{
+	struct msm_sdw_priv *msm_sdw;
+	unsigned short sdw_rd_addr_base;
+	unsigned short sdw_rd_data_base;
+	int val, ret;
+
+	if (!handle) {
+		pr_err("%s: NULL handle\n", __func__);
+		return -EINVAL;
+	}
+	msm_sdw = (struct msm_sdw_priv *)handle;
+
+	dev_dbg(msm_sdw->dev, "%s: Reading soundwire register, 0x%x\n",
+		__func__, reg);
+	sdw_rd_addr_base = MSM_SDW_AHB_BRIDGE_RD_ADDR_0;
+	sdw_rd_data_base = MSM_SDW_AHB_BRIDGE_RD_DATA_0;
+
+	/*
+	 * Add sleep as SWR slave access read takes time.
+	 * Allow for RD_DONE to complete for previous register if any.
+	 */
+	usleep_range(50, 55);
+
+	/* read_lock */
+	mutex_lock(&msm_sdw->sdw_read_lock);
+	ret = regmap_bulk_write(msm_sdw->regmap, sdw_rd_addr_base,
+				(u8 *)&reg, 4);
+	if (ret < 0) {
+		dev_err(msm_sdw->dev, "%s: RD Addr Failure\n", __func__);
+		goto err;
+	}
+	/* Check for RD value */
+	ret = regmap_bulk_read(msm_sdw->regmap, sdw_rd_data_base,
+			       (u8 *)&val, 4);
+	if (ret < 0) {
+		dev_err(msm_sdw->dev, "%s: RD Data Failure\n", __func__);
+		goto err;
+	}
+	ret = val;
+err:
+	/* read_unlock */
+	mutex_unlock(&msm_sdw->sdw_read_lock);
+	return ret;
+}
+
+static int msm_sdw_bulk_write(struct msm_sdw_priv *msm_sdw,
+				struct msm_sdw_reg_val *bulk_reg,
+				size_t len)
+{
+	int i, ret = 0;
+	unsigned short sdw_wr_addr_base;
+	unsigned short sdw_wr_data_base;
+
+	sdw_wr_addr_base = MSM_SDW_AHB_BRIDGE_WR_ADDR_0;
+	sdw_wr_data_base = MSM_SDW_AHB_BRIDGE_WR_DATA_0;
+
+	for (i = 0; i < len; i += 2) {
+		/* First Write the Data to register */
+		ret = regmap_bulk_write(msm_sdw->regmap,
+			sdw_wr_data_base, bulk_reg[i].buf, 4);
+		if (ret < 0) {
+			dev_err(msm_sdw->dev, "%s: WR Data Failure\n",
+				__func__);
+			break;
+		}
+		/* Next Write Address */
+		ret = regmap_bulk_write(msm_sdw->regmap,
+			sdw_wr_addr_base, bulk_reg[i+1].buf, 4);
+		if (ret < 0) {
+			dev_err(msm_sdw->dev,
+				"%s: WR Addr Failure: 0x%x\n",
+				__func__, (u32)(bulk_reg[i+1].buf[0]));
+			break;
+		}
+	}
+	return ret;
+}
+
+static int msm_sdw_swrm_bulk_write(void *handle, u32 *reg, u32 *val, size_t len)
+{
+	struct msm_sdw_priv *msm_sdw;
+	struct msm_sdw_reg_val *bulk_reg;
+	unsigned short sdw_wr_addr_base;
+	unsigned short sdw_wr_data_base;
+	int i, j, ret;
+
+	if (!handle) {
+		pr_err("%s: NULL handle\n", __func__);
+		return -EINVAL;
+	}
+
+	msm_sdw = (struct msm_sdw_priv *)handle;
+	if (len <= 0) {
+		dev_err(msm_sdw->dev,
+			"%s: Invalid size: %zu\n", __func__, len);
+		return -EINVAL;
+	}
+
+	sdw_wr_addr_base = MSM_SDW_AHB_BRIDGE_WR_ADDR_0;
+	sdw_wr_data_base = MSM_SDW_AHB_BRIDGE_WR_DATA_0;
+
+	bulk_reg = kzalloc((2 * len * sizeof(struct msm_sdw_reg_val)),
+			   GFP_KERNEL);
+	if (!bulk_reg)
+		return -ENOMEM;
+
+	for (i = 0, j = 0; i < (len * 2); i += 2, j++) {
+		bulk_reg[i].reg = sdw_wr_data_base;
+		bulk_reg[i].buf = (u8 *)(&val[j]);
+		bulk_reg[i].bytes = 4;
+		bulk_reg[i+1].reg = sdw_wr_addr_base;
+		bulk_reg[i+1].buf = (u8 *)(&reg[j]);
+		bulk_reg[i+1].bytes = 4;
+	}
+	mutex_lock(&msm_sdw->sdw_write_lock);
+
+	ret = msm_sdw_bulk_write(msm_sdw, bulk_reg, (len * 2));
+	if (ret)
+		dev_err(msm_sdw->dev, "%s: swrm bulk write failed, ret: %d\n",
+			__func__, ret);
+
+	mutex_unlock(&msm_sdw->sdw_write_lock);
+	kfree(bulk_reg);
+
+	return ret;
+}
+
+static int msm_sdw_swrm_write(void *handle, int reg, int val)
+{
+	struct msm_sdw_priv *msm_sdw;
+	unsigned short sdw_wr_addr_base;
+	unsigned short sdw_wr_data_base;
+	struct msm_sdw_reg_val bulk_reg[2];
+	int ret;
+
+	if (!handle) {
+		pr_err("%s: NULL handle\n", __func__);
+		return -EINVAL;
+	}
+	msm_sdw = (struct msm_sdw_priv *)handle;
+
+	sdw_wr_addr_base = MSM_SDW_AHB_BRIDGE_WR_ADDR_0;
+	sdw_wr_data_base = MSM_SDW_AHB_BRIDGE_WR_DATA_0;
+
+	/* First Write the Data to register */
+	bulk_reg[0].reg = sdw_wr_data_base;
+	bulk_reg[0].buf = (u8 *)(&val);
+	bulk_reg[0].bytes = 4;
+	bulk_reg[1].reg = sdw_wr_addr_base;
+	bulk_reg[1].buf = (u8 *)(&reg);
+	bulk_reg[1].bytes = 4;
+
+	mutex_lock(&msm_sdw->sdw_write_lock);
+
+	ret = msm_sdw_bulk_write(msm_sdw, bulk_reg, 2);
+	if (ret < 0)
+		dev_err(msm_sdw->dev, "%s: WR Data Failure\n", __func__);
+
+	mutex_unlock(&msm_sdw->sdw_write_lock);
+	return ret;
+}
+
+static int msm_sdw_swrm_clock(void *handle, bool enable)
+{
+	struct msm_sdw_priv *msm_sdw = (struct msm_sdw_priv *) handle;
+
+	mutex_lock(&msm_sdw->sdw_clk_lock);
+
+	dev_dbg(msm_sdw->dev, "%s: swrm clock %s\n",
+		__func__, (enable ? "enable" : "disable"));
+	if (enable) {
+		msm_sdw->sdw_clk_users++;
+		if (msm_sdw->sdw_clk_users == 1) {
+			msm_int_enable_sdw_cdc_clk(msm_sdw, 1, true);
+			msm_sdw_mclk_enable(msm_sdw, 1, true);
+			regmap_update_bits(msm_sdw->regmap,
+				MSM_SDW_CLK_RST_CTRL_SWR_CONTROL, 0x01, 0x01);
+			msm_enable_sdw_npl_clk(msm_sdw, true);
+			msm_cdc_pinctrl_select_active_state(
+							msm_sdw->sdw_gpio_p);
+		}
+	} else {
+		msm_sdw->sdw_clk_users--;
+		if (msm_sdw->sdw_clk_users == 0) {
+			regmap_update_bits(msm_sdw->regmap,
+				MSM_SDW_CLK_RST_CTRL_SWR_CONTROL,
+				0x01, 0x00);
+			msm_sdw_mclk_enable(msm_sdw, 0, true);
+			msm_int_enable_sdw_cdc_clk(msm_sdw, 0, true);
+			msm_enable_sdw_npl_clk(msm_sdw, false);
+			msm_cdc_pinctrl_select_sleep_state(msm_sdw->sdw_gpio_p);
+		}
+	}
+	dev_dbg(msm_sdw->dev, "%s: swrm clock users %d\n",
+		__func__, msm_sdw->sdw_clk_users);
+	mutex_unlock(&msm_sdw->sdw_clk_lock);
+	return 0;
+}
+
+static int msm_sdw_startup(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	dev_dbg(dai->codec->dev, "%s(): substream = %s  stream = %d\n",
+		__func__,
+		substream->name, substream->stream);
+	return 0;
+}
+
+static int msm_sdw_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	u8 clk_fs_rate, fs_rate;
+
+	dev_dbg(dai->codec->dev,
+		"%s: dai_name = %s DAI-ID %x rate %d num_ch %d format %d\n",
+		__func__, dai->name, dai->id, params_rate(params),
+		params_channels(params), params_format(params));
+
+	switch (params_rate(params)) {
+	case 8000:
+		clk_fs_rate = 0x00;
+		fs_rate = 0x00;
+		break;
+	case 16000:
+		clk_fs_rate = 0x01;
+		fs_rate = 0x01;
+		break;
+	case 32000:
+		clk_fs_rate = 0x02;
+		fs_rate = 0x03;
+		break;
+	case 48000:
+		clk_fs_rate = 0x03;
+		fs_rate = 0x04;
+		break;
+	case 96000:
+		clk_fs_rate = 0x04;
+		fs_rate = 0x05;
+		break;
+	case 192000:
+		clk_fs_rate = 0x05;
+		fs_rate = 0x06;
+		break;
+	default:
+		dev_err(dai->codec->dev,
+			"%s: Invalid sampling rate %d\n", __func__,
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		snd_soc_update_bits(dai->codec,
+				MSM_SDW_TOP_TX_I2S_CTL, 0x1C,
+				(clk_fs_rate << 2));
+	} else {
+		snd_soc_update_bits(dai->codec,
+				MSM_SDW_TOP_RX_I2S_CTL, 0x1C,
+				(clk_fs_rate << 2));
+		snd_soc_update_bits(dai->codec,
+				MSM_SDW_RX7_RX_PATH_CTL, 0x0F,
+				fs_rate);
+		snd_soc_update_bits(dai->codec,
+				MSM_SDW_RX8_RX_PATH_CTL, 0x0F,
+				fs_rate);
+	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			snd_soc_update_bits(dai->codec,
+					MSM_SDW_TOP_TX_I2S_CTL, 0x20, 0x20);
+		else
+			snd_soc_update_bits(dai->codec,
+					MSM_SDW_TOP_RX_I2S_CTL, 0x20, 0x20);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			snd_soc_update_bits(dai->codec,
+					MSM_SDW_TOP_TX_I2S_CTL, 0x20, 0x00);
+		else
+			snd_soc_update_bits(dai->codec,
+					MSM_SDW_TOP_RX_I2S_CTL, 0x20, 0x00);
+		break;
+	default:
+		dev_err(dai->codec->dev, "%s: wrong format selected\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void msm_sdw_shutdown(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	dev_dbg(dai->codec->dev,
+		"%s(): substream = %s  stream = %d\n", __func__,
+		substream->name, substream->stream);
+}
+
+static ssize_t msm_sdw_codec_version_read(struct snd_info_entry *entry,
+					  void *file_private_data,
+					  struct file *file,
+					  char __user *buf, size_t count,
+					  loff_t pos)
+{
+	struct msm_sdw_priv *msm_sdw;
+	char buffer[MSM_SDW_VERSION_ENTRY_SIZE];
+	int len = 0;
+
+	msm_sdw = (struct msm_sdw_priv *) entry->private_data;
+	if (!msm_sdw) {
+		pr_err("%s: msm_sdw priv is null\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (msm_sdw->version) {
+	case MSM_SDW_VERSION_1_0:
+		len = snprintf(buffer, sizeof(buffer), "SDW-CDC_1_0\n");
+		break;
+	default:
+		len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
+	}
+
+	return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops msm_sdw_codec_info_ops = {
+	.read = msm_sdw_codec_version_read,
+};
+
+/*
+ * msm_sdw_codec_info_create_codec_entry - creates msm_sdw module
+ * @codec_root: The parent directory
+ * @codec: Codec instance
+ *
+ * Creates msm_sdw module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int msm_sdw_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+					  struct snd_soc_codec *codec)
+{
+	struct snd_info_entry *version_entry;
+	struct msm_sdw_priv *msm_sdw;
+	struct snd_soc_card *card;
+
+	if (!codec_root || !codec)
+		return -EINVAL;
+
+	msm_sdw = snd_soc_codec_get_drvdata(codec);
+	card = codec->component.card;
+	msm_sdw->entry = snd_register_module_info(codec_root->module,
+						  "152c1000.msm-sdw-codec",
+						  codec_root);
+	if (!msm_sdw->entry) {
+		dev_err(codec->dev, "%s: failed to create msm_sdw entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry = snd_info_create_card_entry(card->snd_card,
+						   "version",
+						   msm_sdw->entry);
+	if (!version_entry) {
+		dev_err(codec->dev, "%s: failed to create msm_sdw version entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry->private_data = msm_sdw;
+	version_entry->size = MSM_SDW_VERSION_ENTRY_SIZE;
+	version_entry->content = SNDRV_INFO_CONTENT_DATA;
+	version_entry->c.ops = &msm_sdw_codec_info_ops;
+
+	if (snd_info_register(version_entry) < 0) {
+		snd_info_free_entry(version_entry);
+		return -ENOMEM;
+	}
+	msm_sdw->version_entry = version_entry;
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_sdw_codec_info_create_codec_entry);
+
+static struct snd_soc_dai_ops msm_sdw_dai_ops = {
+	.startup = msm_sdw_startup,
+	.shutdown = msm_sdw_shutdown,
+	.hw_params = msm_sdw_hw_params,
+};
+
+static struct snd_soc_dai_driver msm_sdw_dai[] = {
+	{
+		.name = "msm_sdw_i2s_rx1",
+		.id = AIF1_SDW_PB,
+		.playback = {
+			.stream_name = "AIF1_SDW Playback",
+			.rates = MSM_SDW_RATES,
+			.formats = MSM_SDW_FORMATS,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &msm_sdw_dai_ops,
+	},
+	{
+		.name = "msm_sdw_vifeedback",
+		.id = AIF1_SDW_VIFEED,
+		.capture = {
+			.stream_name = "VIfeed_SDW",
+			.rates = MSM_SDW_RATES,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 2,
+			.channels_max = 4,
+		},
+		.ops = &msm_sdw_dai_ops,
+	},
+};
+
+static const char * const rx_mix1_text[] = {
+	"ZERO", "RX4", "RX5"
+};
+
+static const char * const msm_sdw_ear_spkr_pa_gain_text[] = {
+	"G_DEFAULT", "G_0_DB", "G_1_DB", "G_2_DB", "G_3_DB",
+	"G_4_DB", "G_5_DB", "G_6_DB"
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(msm_sdw_ear_spkr_pa_gain_enum,
+				msm_sdw_ear_spkr_pa_gain_text);
+/* RX4 MIX1 */
+static const struct soc_enum rx4_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM_SDW_TOP_RX7_PATH_INPUT0_MUX,
+		0, 3, rx_mix1_text);
+
+static const struct soc_enum rx4_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM_SDW_TOP_RX7_PATH_INPUT1_MUX,
+		0, 3, rx_mix1_text);
+
+/* RX5 MIX1 */
+static const struct soc_enum rx5_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM_SDW_TOP_RX8_PATH_INPUT0_MUX,
+		0, 3, rx_mix1_text);
+
+static const struct soc_enum rx5_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM_SDW_TOP_RX8_PATH_INPUT1_MUX,
+		0, 3, rx_mix1_text);
+
+static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new aif1_vi_mixer[] = {
+	SOC_SINGLE_EXT("SPKR_VI_1", SND_SOC_NOPM, MSM_SDW_TX0, 1, 0,
+			msm_sdw_vi_feed_mixer_get, msm_sdw_vi_feed_mixer_put),
+	SOC_SINGLE_EXT("SPKR_VI_2", SND_SOC_NOPM, MSM_SDW_TX1, 1, 0,
+			msm_sdw_vi_feed_mixer_get, msm_sdw_vi_feed_mixer_put),
+};
+
+static const struct snd_soc_dapm_widget msm_sdw_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("I2S RX4", "AIF1_SDW Playback", 0,
+		SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_AIF_IN("I2S RX5", "AIF1_SDW Playback", 0,
+		SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_AIF_OUT_E("AIF1_SDW VI", "VIfeed_SDW", 0, SND_SOC_NOPM,
+		AIF1_SDW_VIFEED, 0, msm_sdw_codec_enable_vi_feedback,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER("AIF1_VI_SDW Mixer", SND_SOC_NOPM, AIF1_SDW_VIFEED,
+		0, aif1_vi_mixer, ARRAY_SIZE(aif1_vi_mixer)),
+
+	SND_SOC_DAPM_MUX_E("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx4_mix1_inp1_mux, msm_sdw_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx4_mix1_inp2_mux, msm_sdw_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx5_mix1_inp1_mux, msm_sdw_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx5_mix1_inp2_mux, msm_sdw_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER("RX4 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX5 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER_E("RX INT4 INTERP", SND_SOC_NOPM,
+		COMP1, 0, NULL, 0, msm_sdw_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX INT5 INTERP", SND_SOC_NOPM,
+		COMP2, 0, NULL, 0, msm_sdw_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER_E("RX INT4 CHAIN", SND_SOC_NOPM, 0, 0,
+		NULL, 0, msm_sdw_codec_spk_boost_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX INT5 CHAIN", SND_SOC_NOPM, 0, 0,
+		NULL, 0, msm_sdw_codec_spk_boost_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("VIINPUT_SDW"),
+
+	SND_SOC_DAPM_OUTPUT("SPK1 OUT"),
+	SND_SOC_DAPM_OUTPUT("SPK2 OUT"),
+
+	SND_SOC_DAPM_SUPPLY_S("SDW_CONN", -1, MSM_SDW_TOP_I2S_CLK,
+		0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("INT_MCLK1", -2, SND_SOC_NOPM, 0, 0,
+	msm_int_mclk1_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("SDW_RX_I2S_CLK",
+		MSM_SDW_TOP_RX_I2S_CTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("SDW_TX_I2S_CLK",
+		MSM_SDW_TOP_TX_I2S_CTL, 0, 0, NULL, 0),
+};
+
+static const struct snd_kcontrol_new msm_sdw_snd_controls[] = {
+	SOC_ENUM_EXT("EAR SPKR PA Gain", msm_sdw_ear_spkr_pa_gain_enum,
+		     msm_sdw_ear_spkr_pa_gain_get,
+		     msm_sdw_ear_spkr_pa_gain_put),
+	SOC_SINGLE_SX_TLV("RX4 Digital Volume", MSM_SDW_RX7_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX5 Digital Volume", MSM_SDW_RX8_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMP1, 1, 0,
+		msm_sdw_get_compander, msm_sdw_set_compander),
+	SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMP2, 1, 0,
+		msm_sdw_get_compander, msm_sdw_set_compander),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+
+	{"AIF1_SDW VI", NULL, "SDW_TX_I2S_CLK"},
+	{"SDW_TX_I2S_CLK", NULL, "INT_MCLK1"},
+	{"SDW_TX_I2S_CLK", NULL, "SDW_CONN"},
+
+	/* VI Feedback */
+	{"AIF1_VI_SDW Mixer", "SPKR_VI_1", "VIINPUT_SDW"},
+	{"AIF1_VI_SDW Mixer", "SPKR_VI_2", "VIINPUT_SDW"},
+	{"AIF1_SDW VI", NULL, "AIF1_VI_SDW Mixer"},
+
+	{"SDW_RX_I2S_CLK", NULL, "INT_MCLK1"},
+	{"SDW_RX_I2S_CLK", NULL, "SDW_CONN"},
+	{"I2S RX4", NULL, "SDW_RX_I2S_CLK"},
+	{"I2S RX5", NULL, "SDW_RX_I2S_CLK"},
+
+	{"RX4 MIX1 INP1", "RX4", "I2S RX4"},
+	{"RX4 MIX1 INP1", "RX5", "I2S RX5"},
+	{"RX4 MIX1 INP2", "RX4", "I2S RX4"},
+	{"RX4 MIX1 INP2", "RX5", "I2S RX5"},
+	{"RX5 MIX1 INP1", "RX4", "I2S RX4"},
+	{"RX5 MIX1 INP1", "RX5", "I2S RX5"},
+	{"RX5 MIX1 INP2", "RX4", "I2S RX4"},
+	{"RX5 MIX1 INP2", "RX5", "I2S RX5"},
+
+	{"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
+	{"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
+	{"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
+	{"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
+
+	{"RX INT4 INTERP", NULL, "RX4 MIX1"},
+	{"RX INT4 CHAIN", NULL, "RX INT4 INTERP"},
+	{"SPK1 OUT", NULL, "RX INT4 CHAIN"},
+
+	{"RX INT5 INTERP", NULL, "RX5 MIX1"},
+	{"RX INT5 CHAIN", NULL, "RX INT5 INTERP"},
+	{"SPK2 OUT", NULL, "RX INT5 CHAIN"},
+};
+
+static const struct msm_sdw_reg_mask_val msm_sdw_reg_init[] = {
+	{MSM_SDW_BOOST0_BOOST_CFG1, 0x3F, 0x12},
+	{MSM_SDW_BOOST0_BOOST_CFG2, 0x1C, 0x08},
+	{MSM_SDW_COMPANDER7_CTL7, 0x1E, 0x18},
+	{MSM_SDW_BOOST1_BOOST_CFG1, 0x3F, 0x12},
+	{MSM_SDW_BOOST1_BOOST_CFG2, 0x1C, 0x08},
+	{MSM_SDW_COMPANDER8_CTL7, 0x1E, 0x18},
+	{MSM_SDW_BOOST0_BOOST_CTL, 0x70, 0x50},
+	{MSM_SDW_BOOST1_BOOST_CTL, 0x70, 0x50},
+	{MSM_SDW_RX7_RX_PATH_CFG1, 0x08, 0x08},
+	{MSM_SDW_RX8_RX_PATH_CFG1, 0x08, 0x08},
+	{MSM_SDW_TOP_TOP_CFG1, 0x02, 0x02},
+	{MSM_SDW_TOP_TOP_CFG1, 0x01, 0x01},
+	{MSM_SDW_TX9_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{MSM_SDW_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{MSM_SDW_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{MSM_SDW_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{MSM_SDW_COMPANDER7_CTL3, 0x80, 0x80},
+	{MSM_SDW_COMPANDER8_CTL3, 0x80, 0x80},
+	{MSM_SDW_COMPANDER7_CTL7, 0x01, 0x01},
+	{MSM_SDW_COMPANDER8_CTL7, 0x01, 0x01},
+	{MSM_SDW_RX7_RX_PATH_CFG0, 0x01, 0x01},
+	{MSM_SDW_RX8_RX_PATH_CFG0, 0x01, 0x01},
+	{MSM_SDW_RX7_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{MSM_SDW_RX8_RX_PATH_MIX_CFG, 0x01, 0x01},
+};
+
+static void msm_sdw_init_reg(struct snd_soc_codec *codec)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(msm_sdw_reg_init); i++)
+		snd_soc_update_bits(codec,
+				msm_sdw_reg_init[i].reg,
+				msm_sdw_reg_init[i].mask,
+				msm_sdw_reg_init[i].val);
+}
+
+static int msm_sdw_notifier_service_cb(struct notifier_block *nb,
+				       unsigned long opcode, void *ptr)
+{
+	int i;
+	struct msm_sdw_priv *msm_sdw = container_of(nb,
+						    struct msm_sdw_priv,
+						    service_nb);
+	bool adsp_ready = false;
+	unsigned long timeout;
+
+	pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
+
+	mutex_lock(&msm_sdw->codec_mutex);
+	switch (opcode) {
+	case AUDIO_NOTIFIER_SERVICE_DOWN:
+		msm_sdw->dev_up = false;
+		for (i = 0; i < msm_sdw->nr; i++)
+			swrm_wcd_notify(msm_sdw->sdw_ctrl_data[i].sdw_pdev,
+					SWR_DEVICE_DOWN, NULL);
+		break;
+	case AUDIO_NOTIFIER_SERVICE_UP:
+		if (!q6core_is_adsp_ready()) {
+			dev_dbg(msm_sdw->dev, "ADSP isn't ready\n");
+			timeout = jiffies +
+				  msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+			while (!time_after(jiffies, timeout)) {
+				if (!q6core_is_adsp_ready()) {
+					dev_dbg(msm_sdw->dev,
+						"ADSP isn't ready\n");
+				} else {
+					dev_dbg(msm_sdw->dev,
+						"ADSP is ready\n");
+					adsp_ready = true;
+					goto powerup;
+				}
+			}
+		} else {
+			adsp_ready = true;
+			dev_dbg(msm_sdw->dev, "%s: DSP is ready\n", __func__);
+		}
+powerup:
+		if (adsp_ready) {
+			msm_sdw->dev_up = true;
+			msm_sdw_init_reg(msm_sdw->codec);
+			regcache_mark_dirty(msm_sdw->regmap);
+			regcache_sync(msm_sdw->regmap);
+			msm_sdw_set_spkr_mode(msm_sdw->codec,
+					      msm_sdw->spkr_mode);
+		}
+		break;
+	default:
+		break;
+	}
+	mutex_unlock(&msm_sdw->codec_mutex);
+	return NOTIFY_OK;
+}
+
+static int msm_sdw_codec_probe(struct snd_soc_codec *codec)
+{
+	struct msm_sdw_priv *msm_sdw;
+	int i, ret;
+
+	msm_sdw = snd_soc_codec_get_drvdata(codec);
+	if (!msm_sdw) {
+		pr_err("%s:SDW priv data null\n", __func__);
+		return -EINVAL;
+	}
+	msm_sdw->codec = codec;
+	for (i = 0; i < COMP_MAX; i++)
+		msm_sdw->comp_enabled[i] = 0;
+
+	msm_sdw->spkr_gain_offset = RX_GAIN_OFFSET_0_DB;
+	msm_sdw_init_reg(codec);
+	msm_sdw->version = MSM_SDW_VERSION_1_0;
+
+	msm_sdw->service_nb.notifier_call = msm_sdw_notifier_service_cb;
+	ret = audio_notifier_register("msm_sdw",
+				AUDIO_NOTIFIER_ADSP_DOMAIN,
+				&msm_sdw->service_nb);
+	if (ret < 0)
+		dev_err(msm_sdw->dev,
+			"%s: Audio notifier register failed ret = %d\n",
+			__func__, ret);
+	return 0;
+}
+
+static int msm_sdw_codec_remove(struct snd_soc_codec *codec)
+{
+	return 0;
+}
+
+static struct regmap *msm_sdw_get_regmap(struct device *dev)
+{
+	struct msm_sdw_priv *msm_sdw = dev_get_drvdata(dev);
+
+	return msm_sdw->regmap;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_msm_sdw = {
+	.probe = msm_sdw_codec_probe,
+	.remove = msm_sdw_codec_remove,
+	.controls = msm_sdw_snd_controls,
+	.num_controls = ARRAY_SIZE(msm_sdw_snd_controls),
+	.dapm_widgets = msm_sdw_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(msm_sdw_dapm_widgets),
+	.dapm_routes = audio_map,
+	.num_dapm_routes = ARRAY_SIZE(audio_map),
+	.get_regmap = msm_sdw_get_regmap,
+};
+
+static void msm_sdw_add_child_devices(struct work_struct *work)
+{
+	struct msm_sdw_priv *msm_sdw;
+	struct platform_device *pdev;
+	struct device_node *node;
+	struct msm_sdw_ctrl_data *sdw_ctrl_data = NULL, *temp;
+	int ret, ctrl_num = 0;
+	struct wcd_sdw_ctrl_platform_data *platdata;
+	char plat_dev_name[MSM_SDW_STRING_LEN];
+
+	msm_sdw = container_of(work, struct msm_sdw_priv,
+			     msm_sdw_add_child_devices_work);
+	if (!msm_sdw) {
+		pr_err("%s: Memory for msm_sdw does not exist\n",
+			__func__);
+		return;
+	}
+	if (!msm_sdw->dev->of_node) {
+		dev_err(msm_sdw->dev,
+			"%s: DT node for msm_sdw does not exist\n", __func__);
+		return;
+	}
+
+	platdata = &msm_sdw->sdw_plat_data;
+
+	for_each_available_child_of_node(msm_sdw->dev->of_node, node) {
+		if (!strcmp(node->name, "swr_master"))
+			strlcpy(plat_dev_name, "msm_sdw_swr_ctrl",
+				(MSM_SDW_STRING_LEN - 1));
+		else if (strnstr(node->name, "msm_cdc_pinctrl",
+				 strlen("msm_cdc_pinctrl")) != NULL)
+			strlcpy(plat_dev_name, node->name,
+				(MSM_SDW_STRING_LEN - 1));
+		else
+			continue;
+
+		pdev = platform_device_alloc(plat_dev_name, -1);
+		if (!pdev) {
+			dev_err(msm_sdw->dev, "%s: pdev memory alloc failed\n",
+				__func__);
+			ret = -ENOMEM;
+			goto err;
+		}
+		pdev->dev.parent = msm_sdw->dev;
+		pdev->dev.of_node = node;
+
+		if (!strcmp(node->name, "swr_master")) {
+			ret = platform_device_add_data(pdev, platdata,
+						       sizeof(*platdata));
+			if (ret) {
+				dev_err(&pdev->dev,
+					"%s: cannot add plat data ctrl:%d\n",
+					__func__, ctrl_num);
+				goto fail_pdev_add;
+			}
+		}
+
+		ret = platform_device_add(pdev);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"%s: Cannot add platform device\n",
+				__func__);
+			goto fail_pdev_add;
+		}
+
+		if (!strcmp(node->name, "swr_master")) {
+			temp = krealloc(sdw_ctrl_data,
+					(ctrl_num + 1) * sizeof(
+					struct msm_sdw_ctrl_data),
+					GFP_KERNEL);
+			if (!temp) {
+				dev_err(&pdev->dev, "out of memory\n");
+				ret = -ENOMEM;
+				goto err;
+			}
+			sdw_ctrl_data = temp;
+			sdw_ctrl_data[ctrl_num].sdw_pdev = pdev;
+			ctrl_num++;
+			dev_dbg(&pdev->dev,
+				"%s: Added soundwire ctrl device(s)\n",
+				__func__);
+			msm_sdw->nr = ctrl_num;
+			msm_sdw->sdw_ctrl_data = sdw_ctrl_data;
+		}
+	}
+
+	return;
+fail_pdev_add:
+	platform_device_put(pdev);
+err:
+	return;
+}
+
+static int msm_sdw_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct msm_sdw_priv *msm_sdw;
+	int adsp_state;
+
+	adsp_state = apr_get_subsys_state();
+	if (adsp_state != APR_SUBSYS_LOADED) {
+		dev_err(&pdev->dev, "Adsp is not loaded yet %d\n",
+				adsp_state);
+		return -EPROBE_DEFER;
+	}
+
+	msm_sdw = devm_kzalloc(&pdev->dev, sizeof(struct msm_sdw_priv),
+			    GFP_KERNEL);
+	if (!msm_sdw)
+		return -ENOMEM;
+	dev_set_drvdata(&pdev->dev, msm_sdw);
+	msm_sdw->dev_up = true;
+
+	msm_sdw->dev = &pdev->dev;
+	INIT_WORK(&msm_sdw->msm_sdw_add_child_devices_work,
+		  msm_sdw_add_child_devices);
+	msm_sdw->sdw_plat_data.handle = (void *) msm_sdw;
+	msm_sdw->sdw_plat_data.read = msm_sdw_swrm_read;
+	msm_sdw->sdw_plat_data.write = msm_sdw_swrm_write;
+	msm_sdw->sdw_plat_data.bulk_write = msm_sdw_swrm_bulk_write;
+	msm_sdw->sdw_plat_data.clk = msm_sdw_swrm_clock;
+	msm_sdw->sdw_plat_data.handle_irq = msm_sdwm_handle_irq;
+	ret = of_property_read_u32(pdev->dev.of_node, "reg",
+				   &msm_sdw->sdw_base_addr);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: could not find %s entry in dt\n",
+			__func__, "reg");
+		goto err_sdw_cdc;
+	}
+
+	msm_sdw->sdw_gpio_p = of_parse_phandle(pdev->dev.of_node,
+					"qcom,cdc-sdw-gpios", 0);
+	msm_sdw->sdw_base = ioremap(msm_sdw->sdw_base_addr,
+				    MSM_SDW_MAX_REGISTER);
+	msm_sdw->read_dev = __msm_sdw_reg_read;
+	msm_sdw->write_dev = __msm_sdw_reg_write;
+
+	msm_sdw->regmap = msm_sdw_regmap_init(msm_sdw->dev,
+					      &msm_sdw_regmap_config);
+	msm_sdw->sdw_irq = platform_get_irq_byname(pdev, "swr_master_irq");
+	if (msm_sdw->sdw_irq < 0) {
+		dev_err(msm_sdw->dev, "%s() error getting irq handle: %d\n",
+				__func__, msm_sdw->sdw_irq);
+		ret = -ENODEV;
+		goto err_sdw_cdc;
+	}
+	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_msm_sdw,
+				     msm_sdw_dai, ARRAY_SIZE(msm_sdw_dai));
+	if (ret) {
+		dev_err(&pdev->dev, "%s: Codec registration failed, ret = %d\n",
+			__func__, ret);
+		goto err_sdw_cdc;
+	}
+	/* initialize the int_mclk1 */
+	msm_sdw->sdw_cdc_core_clk.clk_set_minor_version =
+			AFE_API_VERSION_I2S_CONFIG;
+	msm_sdw->sdw_cdc_core_clk.clk_id =
+			Q6AFE_LPASS_CLK_ID_INT_MCLK_1;
+	msm_sdw->sdw_cdc_core_clk.clk_freq_in_hz =
+			INT_MCLK1_FREQ;
+	msm_sdw->sdw_cdc_core_clk.clk_attri =
+			Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO;
+	msm_sdw->sdw_cdc_core_clk.clk_root =
+			Q6AFE_LPASS_CLK_ROOT_DEFAULT;
+	msm_sdw->sdw_cdc_core_clk.enable = 0;
+
+	/* initialize the sdw_npl_clk */
+	msm_sdw->sdw_npl_clk.clk_set_minor_version =
+			AFE_API_VERSION_I2S_CONFIG;
+	msm_sdw->sdw_npl_clk.clk_id =
+			AFE_CLOCK_SET_CLOCK_ID_SWR_NPL_CLK;
+	msm_sdw->sdw_npl_clk.clk_freq_in_hz = SDW_NPL_FREQ;
+	msm_sdw->sdw_npl_clk.clk_attri =
+			Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO;
+	msm_sdw->sdw_npl_clk.clk_root =
+			Q6AFE_LPASS_CLK_ROOT_DEFAULT;
+	msm_sdw->sdw_npl_clk.enable = 0;
+
+	INIT_DELAYED_WORK(&msm_sdw->disable_int_mclk1_work,
+			  msm_disable_int_mclk1);
+	mutex_init(&msm_sdw->cdc_int_mclk1_mutex);
+	mutex_init(&msm_sdw->sdw_npl_clk_mutex);
+	mutex_init(&msm_sdw->io_lock);
+	mutex_init(&msm_sdw->sdw_read_lock);
+	mutex_init(&msm_sdw->sdw_write_lock);
+	mutex_init(&msm_sdw->sdw_clk_lock);
+	mutex_init(&msm_sdw->codec_mutex);
+	schedule_work(&msm_sdw->msm_sdw_add_child_devices_work);
+
+	dev_dbg(&pdev->dev, "%s: msm_sdw driver probe done\n", __func__);
+	return ret;
+
+err_sdw_cdc:
+	devm_kfree(&pdev->dev, msm_sdw);
+	return ret;
+}
+
+static int msm_sdw_remove(struct platform_device *pdev)
+{
+	struct msm_sdw_priv *msm_sdw;
+
+	msm_sdw = dev_get_drvdata(&pdev->dev);
+
+	mutex_destroy(&msm_sdw->io_lock);
+	mutex_destroy(&msm_sdw->sdw_read_lock);
+	mutex_destroy(&msm_sdw->sdw_write_lock);
+	mutex_destroy(&msm_sdw->sdw_clk_lock);
+	mutex_destroy(&msm_sdw->codec_mutex);
+	mutex_destroy(&msm_sdw->cdc_int_mclk1_mutex);
+	devm_kfree(&pdev->dev, msm_sdw);
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+
+static const struct of_device_id msm_sdw_codec_dt_match[] = {
+	{ .compatible = "qcom,msm-sdw-codec", },
+	{}
+};
+
+static struct platform_driver msm_sdw_codec_driver = {
+	.probe = msm_sdw_probe,
+	.remove = msm_sdw_remove,
+	.driver = {
+		.name = "msm_sdw_codec",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_sdw_codec_dt_match,
+	},
+};
+module_platform_driver(msm_sdw_codec_driver);
+
+MODULE_DESCRIPTION("MSM Soundwire Codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_cdc_utils.c b/sound/soc/codecs/msm_sdw/msm_sdw_cdc_utils.c
new file mode 100644
index 0000000..9a5c85b
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_cdc_utils.c
@@ -0,0 +1,211 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/regmap.h>
+#include "msm_sdw.h"
+
+#define REG_BYTES 2
+#define VAL_BYTES 1
+/*
+ * Page Register Address that APP Proc uses to
+ * access WCD9335 Codec registers is identified
+ * as 0x00
+ */
+#define PAGE_REG_ADDR 0x00
+
+/*
+ * msm_sdw_page_write:
+ * Retrieve page number from register and
+ * write that page number to the page address.
+ * Called under io_lock acquisition.
+ *
+ * @msm_sdw: pointer to msm_sdw
+ * @reg: Register address from which page number is retrieved
+ *
+ * Returns 0 for success and negative error code for failure.
+ */
+int msm_sdw_page_write(struct msm_sdw_priv *msm_sdw, unsigned short reg)
+{
+	int ret = 0;
+	u8 pg_num, prev_pg_num;
+
+	pg_num = msm_sdw_page_map[reg];
+	if (msm_sdw->prev_pg_valid) {
+		prev_pg_num = msm_sdw->prev_pg;
+		if (prev_pg_num != pg_num) {
+			ret = msm_sdw->write_dev(msm_sdw, PAGE_REG_ADDR, 1,
+						 (void *) &pg_num);
+			if (ret < 0) {
+				dev_err(msm_sdw->dev,
+					"page write error, pg_num: 0x%x\n",
+					pg_num);
+			} else {
+				msm_sdw->prev_pg = pg_num;
+				dev_dbg(msm_sdw->dev,
+					"%s: Page 0x%x Write to 0x00\n",
+					__func__, pg_num);
+			}
+		}
+	} else {
+		ret = msm_sdw->write_dev(msm_sdw, PAGE_REG_ADDR, 1,
+					 (void *) &pg_num);
+		if (ret < 0) {
+			dev_err(msm_sdw->dev,
+				"page write error, pg_num: 0x%x\n", pg_num);
+		} else {
+			msm_sdw->prev_pg = pg_num;
+			msm_sdw->prev_pg_valid = true;
+			dev_dbg(msm_sdw->dev, "%s: Page 0x%x Write to 0x00\n",
+				__func__, pg_num);
+		}
+	}
+	return ret;
+}
+EXPORT_SYMBOL(msm_sdw_page_write);
+
+static int regmap_bus_read(void *context, const void *reg, size_t reg_size,
+			   void *val, size_t val_size)
+{
+	struct device *dev = context;
+	struct msm_sdw_priv *msm_sdw = dev_get_drvdata(dev);
+	unsigned short c_reg;
+	int ret, i;
+
+	if (!msm_sdw) {
+		dev_err(dev, "%s: msm_sdw is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (!reg || !val) {
+		dev_err(dev, "%s: reg or val is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (reg_size != REG_BYTES) {
+		dev_err(dev, "%s: register size %zd bytes, not supported\n",
+			__func__, reg_size);
+		return -EINVAL;
+	}
+	if (!msm_sdw->dev_up) {
+		dev_dbg_ratelimited(dev, "%s: No read allowed. dev_up = %d\n",
+				    __func__, msm_sdw->dev_up);
+		return 0;
+	}
+
+	mutex_lock(&msm_sdw->io_lock);
+	c_reg = *(u16 *)reg;
+	ret = msm_sdw_page_write(msm_sdw, c_reg);
+	if (ret)
+		goto err;
+	ret = msm_sdw->read_dev(msm_sdw, c_reg, val_size, val);
+	if (ret < 0)
+		dev_err(dev, "%s: Codec read failed (%d), reg: 0x%x, size:%zd\n",
+			__func__, ret, c_reg, val_size);
+	else {
+		for (i = 0; i < val_size; i++)
+			dev_dbg(dev, "%s: Read 0x%02x from 0x%x\n",
+				__func__, ((u8 *)val)[i], c_reg + i);
+	}
+err:
+	mutex_unlock(&msm_sdw->io_lock);
+
+	return ret;
+}
+
+static int regmap_bus_gather_write(void *context,
+				   const void *reg, size_t reg_size,
+				   const void *val, size_t val_size)
+{
+	struct device *dev = context;
+	struct msm_sdw_priv *msm_sdw = dev_get_drvdata(dev);
+	unsigned short c_reg;
+	int ret, i;
+
+	if (!msm_sdw) {
+		dev_err(dev, "%s: msm_sdw is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (!reg || !val) {
+		dev_err(dev, "%s: reg or val is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (reg_size != REG_BYTES) {
+		dev_err(dev, "%s: register size %zd bytes, not supported\n",
+			__func__, reg_size);
+		return -EINVAL;
+	}
+	if (!msm_sdw->dev_up) {
+		dev_dbg_ratelimited(dev, "%s: No write allowed. dev_up = %d\n",
+				    __func__, msm_sdw->dev_up);
+		return 0;
+	}
+
+	mutex_lock(&msm_sdw->io_lock);
+	c_reg = *(u16 *)reg;
+	ret = msm_sdw_page_write(msm_sdw, c_reg);
+	if (ret)
+		goto err;
+
+	for (i = 0; i < val_size; i++)
+		dev_dbg(dev, "Write %02x to 0x%x\n", ((u8 *)val)[i],
+			c_reg + i*4);
+
+	ret = msm_sdw->write_dev(msm_sdw, c_reg, val_size, (void *) val);
+	if (ret < 0)
+		dev_err(dev,
+			"%s: Codec write failed (%d), reg:0x%x, size:%zd\n",
+			__func__, ret, c_reg, val_size);
+
+err:
+	mutex_unlock(&msm_sdw->io_lock);
+	return ret;
+}
+
+static int regmap_bus_write(void *context, const void *data, size_t count)
+{
+	struct device *dev = context;
+	struct msm_sdw_priv *msm_sdw = dev_get_drvdata(dev);
+
+	if (!msm_sdw)
+		return -EINVAL;
+
+	WARN_ON(count < REG_BYTES);
+
+	return regmap_bus_gather_write(context, data, REG_BYTES,
+				       data + REG_BYTES,
+				       count - REG_BYTES);
+
+}
+
+static struct regmap_bus regmap_bus_config = {
+	.write = regmap_bus_write,
+	.gather_write = regmap_bus_gather_write,
+	.read = regmap_bus_read,
+	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+	.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
+/*
+ * msm_sdw_regmap_init:
+ * Initialize msm_sdw register map
+ *
+ * @dev: pointer to wcd device
+ * @config: pointer to register map config
+ *
+ * Returns pointer to regmap structure for success
+ * or NULL in case of failure.
+ */
+struct regmap *msm_sdw_regmap_init(struct device *dev,
+				   const struct regmap_config *config)
+{
+	return devm_regmap_init(dev, &regmap_bus_config, dev, config);
+}
+EXPORT_SYMBOL(msm_sdw_regmap_init);
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_registers.h b/sound/soc/codecs/msm_sdw/msm_sdw_registers.h
new file mode 100644
index 0000000..1b7b0b0
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_registers.h
@@ -0,0 +1,126 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef MSM_SDW_REGISTERS_H
+#define MSM_SDW_REGISTERS_H
+
+#define MSM_SDW_PAGE_REGISTER                     0x0000
+
+/* Page-A Registers */
+#define MSM_SDW_TX9_SPKR_PROT_PATH_CTL               0x0308
+#define MSM_SDW_TX9_SPKR_PROT_PATH_CFG0              0x030c
+#define MSM_SDW_TX10_SPKR_PROT_PATH_CTL              0x0318
+#define MSM_SDW_TX10_SPKR_PROT_PATH_CFG0             0x031c
+#define MSM_SDW_TX11_SPKR_PROT_PATH_CTL              0x0328
+#define MSM_SDW_TX11_SPKR_PROT_PATH_CFG0             0x032c
+#define MSM_SDW_TX12_SPKR_PROT_PATH_CTL              0x0338
+#define MSM_SDW_TX12_SPKR_PROT_PATH_CFG0             0x033c
+
+/* Page-B Registers */
+#define MSM_SDW_COMPANDER7_CTL0                      0x0024
+#define MSM_SDW_COMPANDER7_CTL1                      0x0028
+#define MSM_SDW_COMPANDER7_CTL2                      0x002c
+#define MSM_SDW_COMPANDER7_CTL3                      0x0030
+#define MSM_SDW_COMPANDER7_CTL4                      0x0034
+#define MSM_SDW_COMPANDER7_CTL5                      0x0038
+#define MSM_SDW_COMPANDER7_CTL6                      0x003c
+#define MSM_SDW_COMPANDER7_CTL7                      0x0040
+#define MSM_SDW_COMPANDER8_CTL0                      0x0044
+#define MSM_SDW_COMPANDER8_CTL1                      0x0048
+#define MSM_SDW_COMPANDER8_CTL2                      0x004c
+#define MSM_SDW_COMPANDER8_CTL3                      0x0050
+#define MSM_SDW_COMPANDER8_CTL4                      0x0054
+#define MSM_SDW_COMPANDER8_CTL5                      0x0058
+#define MSM_SDW_COMPANDER8_CTL6                      0x005c
+#define MSM_SDW_COMPANDER8_CTL7                      0x0060
+#define MSM_SDW_RX7_RX_PATH_CTL                      0x01a4
+#define MSM_SDW_RX7_RX_PATH_CFG0                     0x01a8
+#define MSM_SDW_RX7_RX_PATH_CFG1                     0x01ac
+#define MSM_SDW_RX7_RX_PATH_CFG2                     0x01b0
+#define MSM_SDW_RX7_RX_VOL_CTL                       0x01b4
+#define MSM_SDW_RX7_RX_PATH_MIX_CTL                  0x01b8
+#define MSM_SDW_RX7_RX_PATH_MIX_CFG                  0x01bc
+#define MSM_SDW_RX7_RX_VOL_MIX_CTL                   0x01c0
+#define MSM_SDW_RX7_RX_PATH_SEC0                     0x01c4
+#define MSM_SDW_RX7_RX_PATH_SEC1                     0x01c8
+#define MSM_SDW_RX7_RX_PATH_SEC2                     0x01cc
+#define MSM_SDW_RX7_RX_PATH_SEC3                     0x01d0
+#define MSM_SDW_RX7_RX_PATH_SEC5                     0x01d8
+#define MSM_SDW_RX7_RX_PATH_SEC6                     0x01dc
+#define MSM_SDW_RX7_RX_PATH_SEC7                     0x01e0
+#define MSM_SDW_RX7_RX_PATH_MIX_SEC0                 0x01e4
+#define MSM_SDW_RX7_RX_PATH_MIX_SEC1                 0x01e8
+#define MSM_SDW_RX8_RX_PATH_CTL                      0x0384
+#define MSM_SDW_RX8_RX_PATH_CFG0                     0x0388
+#define MSM_SDW_RX8_RX_PATH_CFG1                     0x038c
+#define MSM_SDW_RX8_RX_PATH_CFG2                     0x0390
+#define MSM_SDW_RX8_RX_VOL_CTL                       0x0394
+#define MSM_SDW_RX8_RX_PATH_MIX_CTL                  0x0398
+#define MSM_SDW_RX8_RX_PATH_MIX_CFG                  0x039c
+#define MSM_SDW_RX8_RX_VOL_MIX_CTL                   0x03a0
+#define MSM_SDW_RX8_RX_PATH_SEC0                     0x03a4
+#define MSM_SDW_RX8_RX_PATH_SEC1                     0x03a8
+#define MSM_SDW_RX8_RX_PATH_SEC2                     0x03ac
+#define MSM_SDW_RX8_RX_PATH_SEC3                     0x03b0
+#define MSM_SDW_RX8_RX_PATH_SEC5                     0x03b8
+#define MSM_SDW_RX8_RX_PATH_SEC6                     0x03bc
+#define MSM_SDW_RX8_RX_PATH_SEC7                     0x03c0
+#define MSM_SDW_RX8_RX_PATH_MIX_SEC0                 0x03c4
+#define MSM_SDW_RX8_RX_PATH_MIX_SEC1                 0x03c8
+
+/* Page-C Registers */
+#define MSM_SDW_BOOST0_BOOST_PATH_CTL                0x0064
+#define MSM_SDW_BOOST0_BOOST_CTL                     0x0068
+#define MSM_SDW_BOOST0_BOOST_CFG1                    0x006c
+#define MSM_SDW_BOOST0_BOOST_CFG2                    0x0070
+#define MSM_SDW_BOOST1_BOOST_PATH_CTL                0x0084
+#define MSM_SDW_BOOST1_BOOST_CTL                     0x0088
+#define MSM_SDW_BOOST1_BOOST_CFG1                    0x008c
+#define MSM_SDW_BOOST1_BOOST_CFG2                    0x0090
+#define MSM_SDW_AHB_BRIDGE_WR_DATA_0                 0x00a4
+#define MSM_SDW_AHB_BRIDGE_WR_DATA_1                 0x00a8
+#define MSM_SDW_AHB_BRIDGE_WR_DATA_2                 0x00ac
+#define MSM_SDW_AHB_BRIDGE_WR_DATA_3                 0x00b0
+#define MSM_SDW_AHB_BRIDGE_WR_ADDR_0                 0x00b4
+#define MSM_SDW_AHB_BRIDGE_WR_ADDR_1                 0x00b8
+#define MSM_SDW_AHB_BRIDGE_WR_ADDR_2                 0x00bc
+#define MSM_SDW_AHB_BRIDGE_WR_ADDR_3                 0x00c0
+#define MSM_SDW_AHB_BRIDGE_RD_ADDR_0                 0x00c4
+#define MSM_SDW_AHB_BRIDGE_RD_ADDR_1                 0x00c8
+#define MSM_SDW_AHB_BRIDGE_RD_ADDR_2                 0x00cc
+#define MSM_SDW_AHB_BRIDGE_RD_ADDR_3                 0x00d0
+#define MSM_SDW_AHB_BRIDGE_RD_DATA_0                 0x00d4
+#define MSM_SDW_AHB_BRIDGE_RD_DATA_1                 0x00d8
+#define MSM_SDW_AHB_BRIDGE_RD_DATA_2                 0x00dc
+#define MSM_SDW_AHB_BRIDGE_RD_DATA_3                 0x00e0
+#define MSM_SDW_AHB_BRIDGE_ACCESS_CFG                0x00e4
+#define MSM_SDW_AHB_BRIDGE_ACCESS_STATUS             0x00e8
+
+/* Page-D Registers */
+#define MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL            0x0104
+#define MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL          0x0108
+#define MSM_SDW_CLK_RST_CTRL_SWR_CONTROL             0x010c
+#define MSM_SDW_TOP_TOP_CFG0                         0x0204
+#define MSM_SDW_TOP_TOP_CFG1                         0x0208
+#define MSM_SDW_TOP_RX_I2S_CTL                       0x020c
+#define MSM_SDW_TOP_TX_I2S_CTL                       0x0210
+#define MSM_SDW_TOP_I2S_CLK                          0x0214
+#define MSM_SDW_TOP_RX7_PATH_INPUT0_MUX              0x0218
+#define MSM_SDW_TOP_RX7_PATH_INPUT1_MUX              0x021c
+#define MSM_SDW_TOP_RX8_PATH_INPUT0_MUX              0x0220
+#define MSM_SDW_TOP_RX8_PATH_INPUT1_MUX              0x0224
+#define MSM_SDW_TOP_FREQ_MCLK                        0x0228
+#define MSM_SDW_TOP_DEBUG_BUS_SEL                    0x022c
+#define MSM_SDW_TOP_DEBUG_EN                         0x0230
+#define MSM_SDW_TOP_I2S_RESET                        0x0234
+#define MSM_SDW_TOP_BLOCKS_RESET                     0x0238
+
+#endif
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c b/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c
new file mode 100644
index 0000000..78858f0
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c
@@ -0,0 +1,155 @@
+/* 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
+ * 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/regmap.h>
+#include "msm_sdw.h"
+
+static const struct reg_default msm_sdw_defaults[] = {
+	/* Page #10 registers */
+	{ MSM_SDW_PAGE_REGISTER, 0x00 },
+	{ MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x02 },
+	{ MSM_SDW_TX9_SPKR_PROT_PATH_CFG0, 0x00 },
+	{ MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x02 },
+	{ MSM_SDW_TX10_SPKR_PROT_PATH_CFG0, 0x00 },
+	{ MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x02 },
+	{ MSM_SDW_TX11_SPKR_PROT_PATH_CFG0, 0x00 },
+	{ MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x02 },
+	{ MSM_SDW_TX12_SPKR_PROT_PATH_CFG0, 0x00 },
+	/* Page #11 registers */
+	{ MSM_SDW_COMPANDER7_CTL0, 0x60 },
+	{ MSM_SDW_COMPANDER7_CTL1, 0xdb },
+	{ MSM_SDW_COMPANDER7_CTL2, 0xff },
+	{ MSM_SDW_COMPANDER7_CTL3, 0x35 },
+	{ MSM_SDW_COMPANDER7_CTL4, 0xff },
+	{ MSM_SDW_COMPANDER7_CTL5, 0x00 },
+	{ MSM_SDW_COMPANDER7_CTL6, 0x01 },
+	{ MSM_SDW_COMPANDER8_CTL0, 0x60 },
+	{ MSM_SDW_COMPANDER8_CTL1, 0xdb },
+	{ MSM_SDW_COMPANDER8_CTL2, 0xff },
+	{ MSM_SDW_COMPANDER8_CTL3, 0x35 },
+	{ MSM_SDW_COMPANDER8_CTL4, 0xff },
+	{ MSM_SDW_COMPANDER8_CTL5, 0x00 },
+	{ MSM_SDW_COMPANDER8_CTL6, 0x01 },
+	{ MSM_SDW_RX7_RX_PATH_CTL, 0x04 },
+	{ MSM_SDW_RX7_RX_PATH_CFG0, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_CFG2, 0x8f },
+	{ MSM_SDW_RX7_RX_VOL_CTL, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_MIX_CTL, 0x04 },
+	{ MSM_SDW_RX7_RX_VOL_MIX_CTL, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_SEC2, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_SEC3, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_SEC5, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_SEC6, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_SEC7, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_MIX_SEC1, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_CTL, 0x04 },
+	{ MSM_SDW_RX8_RX_PATH_CFG0, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_CFG2, 0x8f },
+	{ MSM_SDW_RX8_RX_VOL_CTL, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_MIX_CTL, 0x04 },
+	{ MSM_SDW_RX8_RX_VOL_MIX_CTL, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_SEC2, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_SEC3, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_SEC5, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_SEC6, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_SEC7, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_MIX_SEC1, 0x00 },
+	/* Page #12 registers */
+	{ MSM_SDW_BOOST0_BOOST_PATH_CTL, 0x00 },
+	{ MSM_SDW_BOOST0_BOOST_CTL, 0xb2 },
+	{ MSM_SDW_BOOST0_BOOST_CFG1, 0x00 },
+	{ MSM_SDW_BOOST0_BOOST_CFG2, 0x00 },
+	{ MSM_SDW_BOOST1_BOOST_PATH_CTL, 0x00 },
+	{ MSM_SDW_BOOST1_BOOST_CTL, 0xb2 },
+	{ MSM_SDW_BOOST1_BOOST_CFG1, 0x00 },
+	{ MSM_SDW_BOOST1_BOOST_CFG2, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_DATA_0, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_DATA_1, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_DATA_2, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_DATA_3, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_ADDR_0, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_ADDR_1, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_ADDR_2, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_ADDR_3, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_ADDR_0, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_ADDR_1, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_ADDR_2, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_ADDR_3, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_DATA_0, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_DATA_1, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_DATA_2, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_DATA_3, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_ACCESS_CFG, 0x0f },
+	{ MSM_SDW_AHB_BRIDGE_ACCESS_STATUS, 0x03 },
+	/* Page #13 registers */
+	{ MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL, 0x00 },
+	{ MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00 },
+	{ MSM_SDW_CLK_RST_CTRL_SWR_CONTROL, 0x00 },
+	{ MSM_SDW_TOP_TOP_CFG0, 0x00 },
+	{ MSM_SDW_TOP_TOP_CFG1, 0x00 },
+	{ MSM_SDW_TOP_RX_I2S_CTL, 0x0C },
+	{ MSM_SDW_TOP_TX_I2S_CTL, 0x00 },
+	{ MSM_SDW_TOP_I2S_CLK, 0x00 },
+	{ MSM_SDW_TOP_RX7_PATH_INPUT0_MUX, 0x00 },
+	{ MSM_SDW_TOP_RX7_PATH_INPUT1_MUX, 0x00 },
+	{ MSM_SDW_TOP_RX8_PATH_INPUT0_MUX, 0x00 },
+	{ MSM_SDW_TOP_RX8_PATH_INPUT1_MUX, 0x00 },
+	{ MSM_SDW_TOP_FREQ_MCLK, 0x00 },
+	{ MSM_SDW_TOP_DEBUG_BUS_SEL, 0x00 },
+	{ MSM_SDW_TOP_DEBUG_EN, 0x00 },
+	{ MSM_SDW_TOP_I2S_RESET, 0x00 },
+	{ MSM_SDW_TOP_BLOCKS_RESET, 0x00 },
+};
+
+static bool msm_sdw_is_readable_register(struct device *dev, unsigned int reg)
+{
+	return msm_sdw_reg_readable[reg];
+}
+
+static bool msm_sdw_is_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MSM_SDW_AHB_BRIDGE_WR_DATA_0:
+	case MSM_SDW_AHB_BRIDGE_WR_DATA_1:
+	case MSM_SDW_AHB_BRIDGE_WR_DATA_2:
+	case MSM_SDW_AHB_BRIDGE_WR_DATA_3:
+	case MSM_SDW_AHB_BRIDGE_WR_ADDR_0:
+	case MSM_SDW_AHB_BRIDGE_WR_ADDR_1:
+	case MSM_SDW_AHB_BRIDGE_WR_ADDR_2:
+	case MSM_SDW_AHB_BRIDGE_WR_ADDR_3:
+	case MSM_SDW_AHB_BRIDGE_RD_DATA_0:
+	case MSM_SDW_AHB_BRIDGE_RD_DATA_1:
+	case MSM_SDW_AHB_BRIDGE_RD_DATA_2:
+	case MSM_SDW_AHB_BRIDGE_RD_DATA_3:
+	case MSM_SDW_AHB_BRIDGE_RD_ADDR_0:
+	case MSM_SDW_AHB_BRIDGE_RD_ADDR_1:
+	case MSM_SDW_AHB_BRIDGE_RD_ADDR_2:
+	case MSM_SDW_AHB_BRIDGE_RD_ADDR_3:
+	case MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL:
+	case MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+const struct regmap_config msm_sdw_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.reg_stride = 4,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = msm_sdw_defaults,
+	.num_reg_defaults = ARRAY_SIZE(msm_sdw_defaults),
+	.max_register = MSM_SDW_MAX_REGISTER,
+	.volatile_reg = msm_sdw_is_volatile_register,
+	.readable_reg = msm_sdw_is_readable_register,
+};
diff --git a/sound/soc/codecs/msm8x16/Kconfig b/sound/soc/codecs/sdm660_cdc/Kconfig
similarity index 61%
rename from sound/soc/codecs/msm8x16/Kconfig
rename to sound/soc/codecs/sdm660_cdc/Kconfig
index d225b7a..d370da3 100644
--- a/sound/soc/codecs/msm8x16/Kconfig
+++ b/sound/soc/codecs/sdm660_cdc/Kconfig
@@ -1,3 +1,3 @@
 
-config SND_SOC_MSM8X16_WCD
+config SND_SOC_SDM660_CDC
 	tristate "MSM Internal PMIC based codec"
diff --git a/sound/soc/codecs/sdm660_cdc/Makefile b/sound/soc/codecs/sdm660_cdc/Makefile
new file mode 100644
index 0000000..d846fae
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/Makefile
@@ -0,0 +1,2 @@
+snd-soc-sdm660-cdc-objs := msm-analog-cdc.o msm-digital-cdc.o sdm660-regmap.o
+obj-$(CONFIG_SND_SOC_SDM660_CDC) += snd-soc-sdm660-cdc.o sdm660-cdc-irq.o
diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
new file mode 100644
index 0000000..52e6815
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
@@ -0,0 +1,4607 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/qdsp6v2/apr.h>
+#include <linux/workqueue.h>
+#include <linux/regmap.h>
+#include <linux/qdsp6v2/audio_notifier.h>
+#include <sound/q6afe-v2.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/q6core.h>
+#include "msm-analog-cdc.h"
+#include "sdm660-cdc-irq.h"
+#include "sdm660-cdc-registers.h"
+#include "msm-cdc-common.h"
+#include "../../msm/sdm660-common.h"
+#include "../wcd-mbhc-v2.h"
+
+#define DRV_NAME "pmic_analog_codec"
+#define SDM660_CDC_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+			SNDRV_PCM_RATE_48000)
+#define SDM660_CDC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+		SNDRV_PCM_FMTBIT_S24_LE)
+#define MSM_DIG_CDC_STRING_LEN 80
+#define MSM_ANLG_CDC_VERSION_ENTRY_SIZE 32
+
+#define CODEC_DT_MAX_PROP_SIZE			40
+#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH	64
+#define BUS_DOWN 1
+
+/*
+ * 50 Milliseconds sufficient for DSP bring up in the lpass
+ * after Sub System Restart
+ */
+#define ADSP_STATE_READY_TIMEOUT_MS 50
+
+#define EAR_PMD 0
+#define EAR_PMU 1
+#define SPK_PMD 2
+#define SPK_PMU 3
+
+#define MICBIAS_DEFAULT_VAL 1800000
+#define MICBIAS_MIN_VAL 1600000
+#define MICBIAS_STEP_SIZE 50000
+
+#define DEFAULT_BOOST_VOLTAGE 5000
+#define MIN_BOOST_VOLTAGE 4000
+#define MAX_BOOST_VOLTAGE 5550
+#define BOOST_VOLTAGE_STEP 50
+
+#define SDM660_CDC_MBHC_BTN_COARSE_ADJ  100 /* in mV */
+#define SDM660_CDC_MBHC_BTN_FINE_ADJ 12 /* in mV */
+
+#define VOLTAGE_CONVERTER(value, min_value, step_size)\
+	((value - min_value)/step_size)
+
+enum {
+	BOOST_SWITCH = 0,
+	BOOST_ALWAYS,
+	BYPASS_ALWAYS,
+	BOOST_ON_FOREVER,
+};
+
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+static struct snd_soc_dai_driver msm_anlg_cdc_i2s_dai[];
+/* By default enable the internal speaker boost */
+static bool spkr_boost_en = true;
+
+static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = {
+	"cdc-vdd-mic-bias",
+};
+
+static struct wcd_mbhc_register
+	wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = {
+	WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x40, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x18, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x01, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0xC0, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x08, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x01, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x06, 1, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN",
+			  MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC",
+			  MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, 0xF0, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC",
+			  MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, 0x0C, 2, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF",
+			  MSM89XX_PMIC_ANALOG_MBHC_BTN3_CTL, 0x03, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT",
+			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x01,
+			  0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT",
+			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x02,
+			  1, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT",
+			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x08,
+			  3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT",
+			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x04,
+			  2, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN",
+			  MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT",
+			  MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT, 0xFF, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL",
+			  MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, 0x70, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT",
+			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0xFF,
+			  0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL",
+			  MSM89XX_PMIC_ANALOG_MICB_2_EN, 0xC0, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME",
+			  MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFC, 2, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN",
+			  MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN",
+			  MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN",
+			  MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x30, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE",
+			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT,
+			  0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL",
+			  MSM89XX_PMIC_ANALOG_MICB_2_EN, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN", 0, 0, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS", 0, 0, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", 0, 0, 0, 0),
+};
+
+/* Multiply gain_adj and offset by 1000 and 100 to avoid float arithmetic */
+static const struct wcd_imped_i_ref imped_i_ref[] = {
+	{I_h4_UA, 8, 800, 9000, 10000},
+	{I_pt5_UA, 10, 100, 990, 4600},
+	{I_14_UA, 17, 14, 1050, 700},
+	{I_l4_UA, 10, 4, 1165, 110},
+	{I_1_UA, 0, 1, 1200, 65},
+};
+
+static const struct wcd_mbhc_intr intr_ids = {
+	.mbhc_sw_intr =  MSM89XX_IRQ_MBHC_HS_DET,
+	.mbhc_btn_press_intr = MSM89XX_IRQ_MBHC_PRESS,
+	.mbhc_btn_release_intr = MSM89XX_IRQ_MBHC_RELEASE,
+	.mbhc_hs_ins_intr = MSM89XX_IRQ_MBHC_INSREM_DET1,
+	.mbhc_hs_rem_intr = MSM89XX_IRQ_MBHC_INSREM_DET,
+	.hph_left_ocp = MSM89XX_IRQ_HPHL_OCP,
+	.hph_right_ocp = MSM89XX_IRQ_HPHR_OCP,
+};
+
+static int msm_anlg_cdc_dt_parse_vreg_info(struct device *dev,
+					   struct sdm660_cdc_regulator *vreg,
+					   const char *vreg_name,
+					   bool ondemand);
+static struct sdm660_cdc_pdata *msm_anlg_cdc_populate_dt_pdata(
+						struct device *dev);
+static int msm_anlg_cdc_enable_ext_mb_source(struct wcd_mbhc *wcd_mbhc,
+					     bool turn_on);
+static void msm_anlg_cdc_trim_btn_reg(struct snd_soc_codec *codec);
+static void msm_anlg_cdc_set_micb_v(struct snd_soc_codec *codec);
+static void msm_anlg_cdc_set_boost_v(struct snd_soc_codec *codec);
+static void msm_anlg_cdc_set_auto_zeroing(struct snd_soc_codec *codec,
+					  bool enable);
+static void msm_anlg_cdc_configure_cap(struct snd_soc_codec *codec,
+				       bool micbias1, bool micbias2);
+static bool msm_anlg_cdc_use_mb(struct snd_soc_codec *codec);
+
+static int get_codec_version(struct sdm660_cdc_priv *sdm660_cdc)
+{
+	if (sdm660_cdc->codec_version == DRAX_CDC)
+		return DRAX_CDC;
+	else if (sdm660_cdc->codec_version == DIANGU)
+		return DIANGU;
+	else if (sdm660_cdc->codec_version == CAJON_2_0)
+		return CAJON_2_0;
+	else if (sdm660_cdc->codec_version == CAJON)
+		return CAJON;
+	else if (sdm660_cdc->codec_version == CONGA)
+		return CONGA;
+	else if (sdm660_cdc->pmic_rev == TOMBAK_2_0)
+		return TOMBAK_2_0;
+	else if (sdm660_cdc->pmic_rev == TOMBAK_1_0)
+		return TOMBAK_1_0;
+
+	pr_err("%s: unsupported codec version\n", __func__);
+	return UNSUPPORTED;
+}
+
+static void wcd_mbhc_meas_imped(struct snd_soc_codec *codec,
+				s16 *impedance_l, s16 *impedance_r)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if ((sdm660_cdc->imped_det_pin == WCD_MBHC_DET_BOTH) ||
+	    (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHL)) {
+		/* Enable ZDET_L_MEAS_EN */
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+				0x08, 0x08);
+		/* Wait for 2ms for measurement to complete */
+		usleep_range(2000, 2100);
+		/* Read Left impedance value from Result1 */
+		*impedance_l = snd_soc_read(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
+		/* Enable ZDET_R_MEAS_EN */
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+				0x08, 0x00);
+	}
+	if ((sdm660_cdc->imped_det_pin == WCD_MBHC_DET_BOTH) ||
+	    (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHR)) {
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+				0x04, 0x04);
+		/* Wait for 2ms for measurement to complete */
+		usleep_range(2000, 2100);
+		/* Read Right impedance value from Result1 */
+		*impedance_r = snd_soc_read(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+				0x04, 0x00);
+	}
+}
+
+static void msm_anlg_cdc_set_ref_current(struct snd_soc_codec *codec,
+					 enum wcd_curr_ref curr_ref)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: curr_ref: %d\n", __func__, curr_ref);
+
+	if (get_codec_version(sdm660_cdc) < CAJON)
+		dev_dbg(codec->dev, "%s: Setting ref current not required\n",
+			__func__);
+
+	sdm660_cdc->imped_i_ref = imped_i_ref[curr_ref];
+
+	switch (curr_ref) {
+	case I_h4_UA:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_2_EN,
+			0x07, 0x01);
+		break;
+	case I_pt5_UA:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_2_EN,
+			0x07, 0x04);
+		break;
+	case I_14_UA:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_2_EN,
+			0x07, 0x03);
+		break;
+	case I_l4_UA:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_2_EN,
+			0x07, 0x01);
+		break;
+	case I_1_UA:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_2_EN,
+			0x07, 0x00);
+		break;
+	default:
+		pr_debug("%s: No ref current set\n", __func__);
+		break;
+	}
+}
+
+static bool msm_anlg_cdc_adj_ref_current(struct snd_soc_codec *codec,
+					 s16 *impedance_l, s16 *impedance_r)
+{
+	int i = 2;
+	s16 compare_imp = 0;
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHR)
+		compare_imp = *impedance_r;
+	else
+		compare_imp = *impedance_l;
+
+	if (get_codec_version(sdm660_cdc) < CAJON) {
+		dev_dbg(codec->dev,
+			"%s: Reference current adjustment not required\n",
+			 __func__);
+		return false;
+	}
+
+	while (compare_imp < imped_i_ref[i].min_val) {
+		msm_anlg_cdc_set_ref_current(codec, imped_i_ref[++i].curr_ref);
+		wcd_mbhc_meas_imped(codec, impedance_l, impedance_r);
+		compare_imp = (sdm660_cdc->imped_det_pin ==
+			       WCD_MBHC_DET_HPHR) ? *impedance_r : *impedance_l;
+		if (i >= I_1_UA)
+			break;
+	}
+	return true;
+}
+
+void msm_anlg_cdc_spk_ext_pa_cb(
+		int (*codec_spk_ext_pa)(struct snd_soc_codec *codec,
+			int enable), struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc;
+
+	if (!codec) {
+		pr_err("%s: NULL codec pointer!\n", __func__);
+		return;
+	}
+
+	sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: Enter\n", __func__);
+	sdm660_cdc->codec_spk_ext_pa_cb = codec_spk_ext_pa;
+}
+
+static void msm_anlg_cdc_compute_impedance(struct snd_soc_codec *codec, s16 l,
+					   s16 r, uint32_t *zl, uint32_t *zr,
+					   bool high)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+	uint32_t rl = 0, rr = 0;
+	struct wcd_imped_i_ref R = sdm660_cdc->imped_i_ref;
+	int codec_ver = get_codec_version(sdm660_cdc);
+
+	switch (codec_ver) {
+	case TOMBAK_1_0:
+	case TOMBAK_2_0:
+	case CONGA:
+		if (high) {
+			dev_dbg(codec->dev,
+				"%s: This plug has high range impedance\n",
+				 __func__);
+			rl = (uint32_t)(((100 * (l * 400 - 200))/96) - 230);
+			rr = (uint32_t)(((100 * (r * 400 - 200))/96) - 230);
+		} else {
+			dev_dbg(codec->dev,
+				"%s: This plug has low range impedance\n",
+				 __func__);
+			rl = (uint32_t)(((1000 * (l * 2 - 1))/1165) - (13/10));
+			rr = (uint32_t)(((1000 * (r * 2 - 1))/1165) - (13/10));
+		}
+		break;
+	case CAJON:
+	case CAJON_2_0:
+	case DIANGU:
+	case DRAX_CDC:
+		if (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHL) {
+			rr = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * r - 5)) -
+			   (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
+			rl = (uint32_t)(((10000 * (R.multiplier * (10 * l - 5)))
+			      - R.offset * R.gain_adj)/(R.gain_adj * 100));
+		} else if (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHR) {
+			rr = (uint32_t)(((10000 * (R.multiplier * (10 * r - 5)))
+			      - R.offset * R.gain_adj)/(R.gain_adj * 100));
+			rl = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * l - 5))-
+			   (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
+		} else if (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_NONE) {
+			rr = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * r - 5)) -
+			   (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
+			rl = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * l - 5))-
+			   (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
+		} else {
+			rr = (uint32_t)(((10000 * (R.multiplier * (10 * r - 5)))
+			      - R.offset * R.gain_adj)/(R.gain_adj * 100));
+			rl = (uint32_t)(((10000 * (R.multiplier * (10 * l - 5)))
+			      - R.offset * R.gain_adj)/(R.gain_adj * 100));
+		}
+		break;
+	default:
+		dev_dbg(codec->dev, "%s: No codec mentioned\n", __func__);
+		break;
+	}
+	*zl = rl;
+	*zr = rr;
+}
+
+static struct firmware_cal *msm_anlg_cdc_get_hwdep_fw_cal(
+		struct wcd_mbhc *wcd_mbhc,
+		enum wcd_cal_type type)
+{
+	struct sdm660_cdc_priv *sdm660_cdc;
+	struct firmware_cal *hwdep_cal;
+	struct snd_soc_codec *codec = wcd_mbhc->codec;
+
+	if (!codec) {
+		pr_err("%s: NULL codec pointer\n", __func__);
+		return NULL;
+	}
+	sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+	hwdep_cal = wcdcal_get_fw_cal(sdm660_cdc->fw_data, type);
+	if (!hwdep_cal) {
+		dev_err(codec->dev, "%s: cal not sent by %d\n",
+				__func__, type);
+		return NULL;
+	}
+	return hwdep_cal;
+}
+
+static void wcd9xxx_spmi_irq_control(struct snd_soc_codec *codec,
+				     int irq, bool enable)
+{
+	if (enable)
+		wcd9xxx_spmi_enable_irq(irq);
+	else
+		wcd9xxx_spmi_disable_irq(irq);
+}
+
+static void msm_anlg_cdc_mbhc_clk_setup(struct snd_soc_codec *codec,
+					bool enable)
+{
+	if (enable)
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+				0x08, 0x08);
+	else
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+				0x08, 0x00);
+}
+
+static int msm_anlg_cdc_mbhc_map_btn_code_to_num(struct snd_soc_codec *codec)
+{
+	int btn_code;
+	int btn;
+
+	btn_code = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
+
+	switch (btn_code) {
+	case 0:
+		btn = 0;
+		break;
+	case 1:
+		btn = 1;
+		break;
+	case 3:
+		btn = 2;
+		break;
+	case 7:
+		btn = 3;
+		break;
+	case 15:
+		btn = 4;
+		break;
+	default:
+		btn = -EINVAL;
+		break;
+	};
+
+	return btn;
+}
+
+static bool msm_anlg_cdc_spmi_lock_sleep(struct wcd_mbhc *mbhc, bool lock)
+{
+	if (lock)
+		return wcd9xxx_spmi_lock_sleep();
+	wcd9xxx_spmi_unlock_sleep();
+	return 0;
+}
+
+static bool msm_anlg_cdc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num)
+{
+	if (micb_num == MIC_BIAS_1)
+		return (snd_soc_read(mbhc->codec,
+				     MSM89XX_PMIC_ANALOG_MICB_1_EN) &
+			0x80);
+	if (micb_num == MIC_BIAS_2)
+		return (snd_soc_read(mbhc->codec,
+				     MSM89XX_PMIC_ANALOG_MICB_2_EN) &
+			0x80);
+	return false;
+}
+
+static void msm_anlg_cdc_enable_master_bias(struct snd_soc_codec *codec,
+					    bool enable)
+{
+	if (enable)
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL,
+				    0x30, 0x30);
+	else
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL,
+				    0x30, 0x00);
+}
+
+static void msm_anlg_cdc_mbhc_common_micb_ctrl(struct snd_soc_codec *codec,
+					       int event, bool enable)
+{
+	u16 reg;
+	u8 mask;
+	u8 val;
+
+	switch (event) {
+	case MBHC_COMMON_MICB_PRECHARGE:
+		reg = MSM89XX_PMIC_ANALOG_MICB_1_CTL;
+		mask = 0x60;
+		val = (enable ? 0x60 : 0x00);
+		break;
+	case MBHC_COMMON_MICB_SET_VAL:
+		reg = MSM89XX_PMIC_ANALOG_MICB_1_VAL;
+		mask = 0xFF;
+		val = (enable ? 0xC0 : 0x00);
+		break;
+	case MBHC_COMMON_MICB_TAIL_CURR:
+		reg = MSM89XX_PMIC_ANALOG_MICB_1_EN;
+		mask = 0x04;
+		val = (enable ? 0x04 : 0x00);
+		break;
+	default:
+		dev_err(codec->dev,
+			"%s: Invalid event received\n", __func__);
+		return;
+	};
+	snd_soc_update_bits(codec, reg, mask, val);
+}
+
+static void msm_anlg_cdc_mbhc_internal_micbias_ctrl(struct snd_soc_codec *codec,
+						    int micbias_num,
+						    bool enable)
+{
+	if (micbias_num == 1) {
+		if (enable)
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS,
+				0x10, 0x10);
+		else
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS,
+				0x10, 0x00);
+	}
+}
+
+static bool msm_anlg_cdc_mbhc_hph_pa_on_status(struct snd_soc_codec *codec)
+{
+	return (snd_soc_read(codec, MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN) &
+		0x30) ? true : false;
+}
+
+static void msm_anlg_cdc_mbhc_program_btn_thr(struct snd_soc_codec *codec,
+					      s16 *btn_low, s16 *btn_high,
+					      int num_btn, bool is_micbias)
+{
+	int i;
+	u32 course, fine, reg_val;
+	u16 reg_addr = MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL;
+	s16 *btn_voltage;
+
+	btn_voltage = ((is_micbias) ? btn_high : btn_low);
+
+	for (i = 0; i <  num_btn; i++) {
+		course = (btn_voltage[i] / SDM660_CDC_MBHC_BTN_COARSE_ADJ);
+		fine = ((btn_voltage[i] % SDM660_CDC_MBHC_BTN_COARSE_ADJ) /
+				SDM660_CDC_MBHC_BTN_FINE_ADJ);
+
+		reg_val = (course << 5) | (fine << 2);
+		snd_soc_update_bits(codec, reg_addr, 0xFC, reg_val);
+		dev_dbg(codec->dev,
+			"%s: course: %d fine: %d reg_addr: %x reg_val: %x\n",
+			  __func__, course, fine, reg_addr, reg_val);
+		reg_addr++;
+	}
+}
+
+static void msm_anlg_cdc_mbhc_calc_impedance(struct wcd_mbhc *mbhc,
+					     uint32_t *zl, uint32_t *zr)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+	s16 impedance_l, impedance_r;
+	s16 impedance_l_fixed;
+	s16 reg0, reg1, reg2, reg3, reg4;
+	bool high = false;
+	bool min_range_used =  false;
+
+	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
+	reg0 = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER);
+	reg1 = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL);
+	reg2 = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2);
+	reg3 = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MICB_2_EN);
+	reg4 = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL);
+
+	sdm660_cdc->imped_det_pin = WCD_MBHC_DET_BOTH;
+	mbhc->hph_type = WCD_MBHC_HPH_NONE;
+
+	/* disable FSM and micbias and enable pullup*/
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x80, 0x00);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_2_EN,
+			0xA5, 0x25);
+	/*
+	 * Enable legacy electrical detection current sources
+	 * and disable fast ramp and enable manual switching
+	 * of extra capacitance
+	 */
+	dev_dbg(codec->dev, "%s: Setup for impedance det\n", __func__);
+
+	msm_anlg_cdc_set_ref_current(codec, I_h4_UA);
+
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2,
+			0x06, 0x02);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER,
+			0x02, 0x02);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL,
+			0x02, 0x00);
+
+	dev_dbg(codec->dev, "%s: Start performing impedance detection\n",
+		 __func__);
+
+	wcd_mbhc_meas_imped(codec, &impedance_l, &impedance_r);
+
+	if (impedance_l > 2 || impedance_r > 2) {
+		high = true;
+		if (!mbhc->mbhc_cfg->mono_stero_detection) {
+			/* Set ZDET_CHG to 0  to discharge ramp */
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+					0x02, 0x00);
+			/* wait 40ms for the discharge ramp to complete */
+			usleep_range(40000, 40100);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+				0x03, 0x00);
+			sdm660_cdc->imped_det_pin = (impedance_l > 2 &&
+						      impedance_r > 2) ?
+						      WCD_MBHC_DET_NONE :
+						      ((impedance_l > 2) ?
+						      WCD_MBHC_DET_HPHR :
+						      WCD_MBHC_DET_HPHL);
+			if (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_NONE)
+				goto exit;
+		} else {
+			if (get_codec_version(sdm660_cdc) >= CAJON) {
+				if (impedance_l == 63 && impedance_r == 63) {
+					dev_dbg(codec->dev,
+						"%s: HPHL and HPHR are floating\n",
+						 __func__);
+					sdm660_cdc->imped_det_pin =
+							WCD_MBHC_DET_NONE;
+					mbhc->hph_type = WCD_MBHC_HPH_NONE;
+				} else if (impedance_l == 63
+					   && impedance_r < 63) {
+					dev_dbg(codec->dev,
+						"%s: Mono HS with HPHL floating\n",
+						 __func__);
+					sdm660_cdc->imped_det_pin =
+							WCD_MBHC_DET_HPHR;
+					mbhc->hph_type = WCD_MBHC_HPH_MONO;
+				} else if (impedance_r == 63 &&
+					   impedance_l < 63) {
+					dev_dbg(codec->dev,
+						"%s: Mono HS with HPHR floating\n",
+						 __func__);
+					sdm660_cdc->imped_det_pin =
+							WCD_MBHC_DET_HPHL;
+					mbhc->hph_type = WCD_MBHC_HPH_MONO;
+				} else if (impedance_l > 3 && impedance_r > 3 &&
+					(impedance_l == impedance_r)) {
+					snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2,
+					0x06, 0x06);
+					wcd_mbhc_meas_imped(codec, &impedance_l,
+							    &impedance_r);
+					if (impedance_r == impedance_l)
+						dev_dbg(codec->dev,
+							"%s: Mono Headset\n",
+							__func__);
+						sdm660_cdc->imped_det_pin =
+							WCD_MBHC_DET_NONE;
+						mbhc->hph_type =
+							WCD_MBHC_HPH_MONO;
+				} else {
+					dev_dbg(codec->dev,
+						"%s: STEREO headset is found\n",
+						 __func__);
+					sdm660_cdc->imped_det_pin =
+							WCD_MBHC_DET_BOTH;
+					mbhc->hph_type = WCD_MBHC_HPH_STEREO;
+				}
+			}
+		}
+	}
+
+	msm_anlg_cdc_set_ref_current(codec, I_pt5_UA);
+	msm_anlg_cdc_set_ref_current(codec, I_14_UA);
+
+	/* Enable RAMP_L , RAMP_R & ZDET_CHG*/
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+			0x03, 0x03);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x02, 0x02);
+	/* wait for 50msec for the HW to apply ramp on HPHL and HPHR */
+	usleep_range(50000, 50100);
+	/* Enable ZDET_DISCHG_CAP_CTL  to add extra capacitance */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x01, 0x01);
+	/* wait for 5msec for the voltage to get stable */
+	usleep_range(5000, 5100);
+
+	wcd_mbhc_meas_imped(codec, &impedance_l, &impedance_r);
+
+	min_range_used = msm_anlg_cdc_adj_ref_current(codec,
+						&impedance_l, &impedance_r);
+	if (!mbhc->mbhc_cfg->mono_stero_detection) {
+		/* Set ZDET_CHG to 0  to discharge ramp */
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+				0x02, 0x00);
+		/* wait for 40msec for the capacitor to discharge */
+		usleep_range(40000, 40100);
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+				0x03, 0x00);
+		goto exit;
+	}
+
+	/* we are setting ref current to the minimun range or the measured
+	 * value larger than the minimum value, so min_range_used is true.
+	 * If the headset is mono headset with either HPHL or HPHR floating
+	 * then we have already done the mono stereo detection and do not
+	 * need to continue further.
+	 */
+
+	if (!min_range_used ||
+	    sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHL ||
+	    sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHR)
+		goto exit;
+
+
+	/* Disable Set ZDET_CONN_RAMP_L and enable ZDET_CONN_FIXED_L */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+			0x02, 0x00);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL,
+			0x02, 0x02);
+	/* Set ZDET_CHG to 0  */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x02, 0x00);
+	/* wait for 40msec for the capacitor to discharge */
+	usleep_range(40000, 40100);
+
+	/* Set ZDET_CONN_RAMP_R to 0  */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+			0x01, 0x00);
+	/* Enable ZDET_L_MEAS_EN */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x08, 0x08);
+	/* wait for 2msec for the HW to compute left inpedance value */
+	usleep_range(2000, 2100);
+	/* Read Left impedance value from Result1 */
+	impedance_l_fixed = snd_soc_read(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
+	/* Disable ZDET_L_MEAS_EN */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x08, 0x00);
+	/*
+	 * Assume impedance_l is L1, impedance_l_fixed is L2.
+	 * If the following condition is met, we can take this
+	 * headset as mono one with impedance of L2.
+	 * Otherwise, take it as stereo with impedance of L1.
+	 * Condition:
+	 * abs[(L2-0.5L1)/(L2+0.5L1)] < abs [(L2-L1)/(L2+L1)]
+	 */
+	if ((abs(impedance_l_fixed - impedance_l/2) *
+		(impedance_l_fixed + impedance_l)) >=
+		(abs(impedance_l_fixed - impedance_l) *
+		(impedance_l_fixed + impedance_l/2))) {
+		dev_dbg(codec->dev,
+			"%s: STEREO plug type detected\n",
+			 __func__);
+		mbhc->hph_type = WCD_MBHC_HPH_STEREO;
+	} else {
+		dev_dbg(codec->dev,
+			"%s: MONO plug type detected\n",
+			__func__);
+		mbhc->hph_type = WCD_MBHC_HPH_MONO;
+		impedance_l = impedance_l_fixed;
+	}
+	/* Enable ZDET_CHG  */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x02, 0x02);
+	/* wait for 10msec for the capacitor to charge */
+	usleep_range(10000, 10100);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+			0x02, 0x02);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL,
+			0x02, 0x00);
+	/* Set ZDET_CHG to 0  to discharge HPHL */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x02, 0x00);
+	/* wait for 40msec for the capacitor to discharge */
+	usleep_range(40000, 40100);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+			0x02, 0x00);
+
+exit:
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, reg4);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MICB_2_EN, reg3);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL, reg1);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, reg0);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, reg2);
+	msm_anlg_cdc_compute_impedance(codec, impedance_l, impedance_r,
+				      zl, zr, high);
+
+	dev_dbg(codec->dev, "%s: RL %d ohm, RR %d ohm\n", __func__, *zl, *zr);
+	dev_dbg(codec->dev, "%s: Impedance detection completed\n", __func__);
+}
+
+static int msm_anlg_cdc_dig_register_notifier(void *handle,
+					      struct notifier_block *nblock,
+					      bool enable)
+{
+	struct sdm660_cdc_priv *handle_cdc = handle;
+
+	if (enable)
+		return blocking_notifier_chain_register(&handle_cdc->notifier,
+							nblock);
+
+	return blocking_notifier_chain_unregister(&handle_cdc->notifier,
+						  nblock);
+}
+
+static int msm_anlg_cdc_mbhc_register_notifier(struct wcd_mbhc *wcd_mbhc,
+					       struct notifier_block *nblock,
+					       bool enable)
+{
+	struct snd_soc_codec *codec = wcd_mbhc->codec;
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (enable)
+		return blocking_notifier_chain_register(
+						&sdm660_cdc->notifier_mbhc,
+						nblock);
+
+	return blocking_notifier_chain_unregister(&sdm660_cdc->notifier_mbhc,
+						  nblock);
+}
+
+static int msm_anlg_cdc_request_irq(struct snd_soc_codec *codec,
+				    int irq, irq_handler_t handler,
+				    const char *name, void *data)
+{
+	return wcd9xxx_spmi_request_irq(irq, handler, name, data);
+}
+
+static int msm_anlg_cdc_free_irq(struct snd_soc_codec *codec,
+				 int irq, void *data)
+{
+	return wcd9xxx_spmi_free_irq(irq, data);
+}
+
+static const struct wcd_mbhc_cb mbhc_cb = {
+	.enable_mb_source = msm_anlg_cdc_enable_ext_mb_source,
+	.trim_btn_reg = msm_anlg_cdc_trim_btn_reg,
+	.compute_impedance = msm_anlg_cdc_mbhc_calc_impedance,
+	.set_micbias_value = msm_anlg_cdc_set_micb_v,
+	.set_auto_zeroing = msm_anlg_cdc_set_auto_zeroing,
+	.get_hwdep_fw_cal = msm_anlg_cdc_get_hwdep_fw_cal,
+	.set_cap_mode = msm_anlg_cdc_configure_cap,
+	.register_notifier = msm_anlg_cdc_mbhc_register_notifier,
+	.request_irq = msm_anlg_cdc_request_irq,
+	.irq_control = wcd9xxx_spmi_irq_control,
+	.free_irq = msm_anlg_cdc_free_irq,
+	.clk_setup = msm_anlg_cdc_mbhc_clk_setup,
+	.map_btn_code_to_num = msm_anlg_cdc_mbhc_map_btn_code_to_num,
+	.lock_sleep = msm_anlg_cdc_spmi_lock_sleep,
+	.micbias_enable_status = msm_anlg_cdc_micb_en_status,
+	.mbhc_bias = msm_anlg_cdc_enable_master_bias,
+	.mbhc_common_micb_ctrl = msm_anlg_cdc_mbhc_common_micb_ctrl,
+	.micb_internal = msm_anlg_cdc_mbhc_internal_micbias_ctrl,
+	.hph_pa_on_status = msm_anlg_cdc_mbhc_hph_pa_on_status,
+	.set_btn_thr = msm_anlg_cdc_mbhc_program_btn_thr,
+	.extn_use_mb = msm_anlg_cdc_use_mb,
+};
+
+static const uint32_t wcd_imped_val[] = {4, 8, 12, 13, 16,
+					20, 24, 28, 32,
+					36, 40, 44, 48};
+
+static void msm_anlg_cdc_dig_notifier_call(struct snd_soc_codec *codec,
+					const enum dig_cdc_notify_event event)
+{
+	struct sdm660_cdc_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: notifier call event %d\n", __func__, event);
+	blocking_notifier_call_chain(&sdm660_cdc->notifier,
+				     event, NULL);
+}
+
+static void msm_anlg_cdc_notifier_call(struct snd_soc_codec *codec,
+				       const enum wcd_notify_event event)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: notifier call event %d\n", __func__, event);
+	blocking_notifier_call_chain(&sdm660_cdc->notifier_mbhc, event,
+				     &sdm660_cdc->mbhc);
+}
+
+static void msm_anlg_cdc_boost_on(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F, 0x0F);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30);
+	if (get_codec_version(sdm660_cdc) < CAJON_2_0)
+		snd_soc_write(codec, MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82);
+	else
+		snd_soc_write(codec, MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0xA2);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+			    0x69, 0x69);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG,
+			    0x01, 0x01);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO,
+			    0x88, 0x88);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+			    0x03, 0x03);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL,
+			    0xE1, 0xE1);
+	if (get_codec_version(sdm660_cdc) < CAJON_2_0) {
+		snd_soc_update_bits(codec, MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x20, 0x20);
+		/* Wait for 1ms after clock ctl enable */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+				    0xDF, 0xDF);
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+	} else {
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+				    0x40, 0x00);
+		snd_soc_update_bits(codec, MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x20, 0x20);
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+				    0x80, 0x80);
+		/* Wait for 500us after BOOST_EN to happen */
+		usleep_range(500, 510);
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+				    0x40, 0x40);
+		/* Wait for 500us after BOOST pulse_skip */
+		usleep_range(500, 510);
+	}
+}
+
+static void msm_anlg_cdc_boost_off(struct snd_soc_codec *codec)
+{
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+			    0xDF, 0x5F);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+			    0x20, 0x00);
+}
+
+static void msm_anlg_cdc_bypass_on(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (get_codec_version(sdm660_cdc) < CAJON_2_0) {
+		snd_soc_write(codec,
+			MSM89XX_PMIC_ANALOG_SEC_ACCESS,
+			0xA5);
+		snd_soc_write(codec,
+			MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3,
+			0x07);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x02, 0x02);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x01, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x40, 0x40);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x80, 0x80);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+			0xDF, 0xDF);
+	} else {
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+			0x20, 0x20);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x20, 0x20);
+	}
+}
+
+static void msm_anlg_cdc_bypass_off(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (get_codec_version(sdm660_cdc) < CAJON_2_0) {
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+			0x80, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x80, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x02, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x40, 0x00);
+	} else {
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x20, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+			0x20, 0x00);
+	}
+}
+
+static void msm_anlg_cdc_boost_mode_sequence(struct snd_soc_codec *codec,
+					     int flag)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (flag == EAR_PMU) {
+		switch (sdm660_cdc->boost_option) {
+		case BOOST_SWITCH:
+			if (sdm660_cdc->ear_pa_boost_set) {
+				msm_anlg_cdc_boost_off(codec);
+				msm_anlg_cdc_bypass_on(codec);
+			}
+			break;
+		case BOOST_ALWAYS:
+			msm_anlg_cdc_boost_on(codec);
+			break;
+		case BYPASS_ALWAYS:
+			msm_anlg_cdc_bypass_on(codec);
+			break;
+		case BOOST_ON_FOREVER:
+			msm_anlg_cdc_boost_on(codec);
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s: invalid boost option: %d\n", __func__,
+				sdm660_cdc->boost_option);
+			break;
+		}
+	} else if (flag == EAR_PMD) {
+		switch (sdm660_cdc->boost_option) {
+		case BOOST_SWITCH:
+			if (sdm660_cdc->ear_pa_boost_set)
+				msm_anlg_cdc_bypass_off(codec);
+			break;
+		case BOOST_ALWAYS:
+			msm_anlg_cdc_boost_off(codec);
+			/* 80ms for EAR boost to settle down */
+			msleep(80);
+			break;
+		case BYPASS_ALWAYS:
+			/* nothing to do as bypass on always */
+			break;
+		case BOOST_ON_FOREVER:
+			/* nothing to do as boost on forever */
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s: invalid boost option: %d\n", __func__,
+				sdm660_cdc->boost_option);
+			break;
+		}
+	} else if (flag == SPK_PMU) {
+		switch (sdm660_cdc->boost_option) {
+		case BOOST_SWITCH:
+			if (sdm660_cdc->spk_boost_set) {
+				msm_anlg_cdc_bypass_off(codec);
+				msm_anlg_cdc_boost_on(codec);
+			}
+			break;
+		case BOOST_ALWAYS:
+			msm_anlg_cdc_boost_on(codec);
+			break;
+		case BYPASS_ALWAYS:
+			msm_anlg_cdc_bypass_on(codec);
+			break;
+		case BOOST_ON_FOREVER:
+			msm_anlg_cdc_boost_on(codec);
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s: invalid boost option: %d\n", __func__,
+				sdm660_cdc->boost_option);
+			break;
+		}
+	} else if (flag == SPK_PMD) {
+		switch (sdm660_cdc->boost_option) {
+		case BOOST_SWITCH:
+			if (sdm660_cdc->spk_boost_set) {
+				msm_anlg_cdc_boost_off(codec);
+				/*
+				 * Add 40 ms sleep for the spk
+				 * boost to settle down
+				 */
+				msleep(40);
+			}
+			break;
+		case BOOST_ALWAYS:
+			msm_anlg_cdc_boost_off(codec);
+			/*
+			 * Add 40 ms sleep for the spk
+			 * boost to settle down
+			 */
+			msleep(40);
+			break;
+		case BYPASS_ALWAYS:
+			/* nothing to do as bypass on always */
+			break;
+		case BOOST_ON_FOREVER:
+			/* nothing to do as boost on forever */
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s: invalid boost option: %d\n", __func__,
+				sdm660_cdc->boost_option);
+			break;
+		}
+	}
+}
+
+static int msm_anlg_cdc_dt_parse_vreg_info(struct device *dev,
+	struct sdm660_cdc_regulator *vreg, const char *vreg_name,
+	bool ondemand)
+{
+	int len, ret = 0;
+	const __be32 *prop;
+	char prop_name[CODEC_DT_MAX_PROP_SIZE];
+	struct device_node *regnode = NULL;
+	u32 prop_val;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply",
+		vreg_name);
+	regnode = of_parse_phandle(dev->of_node, prop_name, 0);
+
+	if (!regnode) {
+		dev_err(dev, "Looking up %s property in node %s failed\n",
+			prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+
+	dev_dbg(dev, "Looking up %s property in node %s\n",
+		prop_name, dev->of_node->full_name);
+
+	vreg->name = vreg_name;
+	vreg->ondemand = ondemand;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+		"qcom,%s-voltage", vreg_name);
+	prop = of_get_property(dev->of_node, prop_name, &len);
+
+	if (!prop || (len != (2 * sizeof(__be32)))) {
+		dev_err(dev, "%s %s property\n",
+			prop ? "invalid format" : "no", prop_name);
+		return -EINVAL;
+	}
+	vreg->min_uv = be32_to_cpup(&prop[0]);
+	vreg->max_uv = be32_to_cpup(&prop[1]);
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+		"qcom,%s-current", vreg_name);
+
+	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		return -EFAULT;
+	}
+	vreg->optimum_ua = prop_val;
+
+	dev_dbg(dev, "%s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n\n", vreg->name,
+		 vreg->min_uv, vreg->max_uv, vreg->optimum_ua, vreg->ondemand);
+	return 0;
+}
+
+static void msm_anlg_cdc_dt_parse_boost_info(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+		snd_soc_codec_get_drvdata(codec);
+	const char *prop_name = "qcom,cdc-boost-voltage";
+	int boost_voltage, ret;
+
+	ret = of_property_read_u32(codec->dev->of_node, prop_name,
+			&boost_voltage);
+	if (ret) {
+		dev_dbg(codec->dev, "Looking up %s property in node %s failed\n",
+			prop_name, codec->dev->of_node->full_name);
+		boost_voltage = DEFAULT_BOOST_VOLTAGE;
+	}
+	if (boost_voltage < MIN_BOOST_VOLTAGE ||
+			boost_voltage > MAX_BOOST_VOLTAGE) {
+		dev_err(codec->dev,
+				"Incorrect boost voltage. Reverting to default\n");
+		boost_voltage = DEFAULT_BOOST_VOLTAGE;
+	}
+
+	sdm660_cdc_priv->boost_voltage =
+		VOLTAGE_CONVERTER(boost_voltage, MIN_BOOST_VOLTAGE,
+				BOOST_VOLTAGE_STEP);
+	dev_dbg(codec->dev, "Boost voltage value is: %d\n",
+			boost_voltage);
+}
+
+static void msm_anlg_cdc_dt_parse_micbias_info(struct device *dev,
+				struct wcd_micbias_setting *micbias)
+{
+	const char *prop_name = "qcom,cdc-micbias-cfilt-mv";
+	int ret;
+
+	ret = of_property_read_u32(dev->of_node, prop_name,
+			&micbias->cfilt1_mv);
+	if (ret) {
+		dev_dbg(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		micbias->cfilt1_mv = MICBIAS_DEFAULT_VAL;
+	}
+}
+
+static struct sdm660_cdc_pdata *msm_anlg_cdc_populate_dt_pdata(
+						struct device *dev)
+{
+	struct sdm660_cdc_pdata *pdata;
+	int ret, static_cnt, ond_cnt, idx, i;
+	const char *name = NULL;
+	const char *static_prop_name = "qcom,cdc-static-supplies";
+	const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	static_cnt = of_property_count_strings(dev->of_node, static_prop_name);
+	if (static_cnt < 0) {
+		dev_err(dev, "%s: Failed to get static supplies %d\n", __func__,
+			static_cnt);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* On-demand supply list is an optional property */
+	ond_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
+	if (ond_cnt < 0)
+		ond_cnt = 0;
+
+	WARN_ON(static_cnt <= 0 || ond_cnt < 0);
+	if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) {
+		dev_err(dev, "%s: Num of supplies %u > max supported %zd\n",
+				__func__, (static_cnt + ond_cnt),
+					ARRAY_SIZE(pdata->regulator));
+		ret = -EINVAL;
+		goto err;
+	}
+
+	for (idx = 0; idx < static_cnt; idx++) {
+		ret = of_property_read_string_index(dev->of_node,
+						    static_prop_name, idx,
+						    &name);
+		if (ret) {
+			dev_err(dev, "%s: of read string %s idx %d error %d\n",
+				__func__, static_prop_name, idx, ret);
+			goto err;
+		}
+
+		dev_dbg(dev, "%s: Found static cdc supply %s\n", __func__,
+			name);
+		ret = msm_anlg_cdc_dt_parse_vreg_info(dev,
+						&pdata->regulator[idx],
+						name, false);
+		if (ret) {
+			dev_err(dev, "%s:err parsing vreg for %s idx %d\n",
+				__func__, name, idx);
+			goto err;
+		}
+	}
+
+	for (i = 0; i < ond_cnt; i++, idx++) {
+		ret = of_property_read_string_index(dev->of_node, ond_prop_name,
+						    i, &name);
+		if (ret) {
+			dev_err(dev, "%s: err parsing on_demand for %s idx %d\n",
+				__func__, ond_prop_name, i);
+			goto err;
+		}
+
+		dev_dbg(dev, "%s: Found on-demand cdc supply %s\n", __func__,
+			name);
+		ret = msm_anlg_cdc_dt_parse_vreg_info(dev,
+						&pdata->regulator[idx],
+						name, true);
+		if (ret) {
+			dev_err(dev, "%s: err parsing vreg on_demand for %s idx %d\n",
+				__func__, name, idx);
+			goto err;
+		}
+	}
+	msm_anlg_cdc_dt_parse_micbias_info(dev, &pdata->micbias);
+
+	return pdata;
+err:
+	devm_kfree(dev, pdata);
+	dev_err(dev, "%s: Failed to populate DT data ret = %d\n",
+		__func__, ret);
+	return NULL;
+}
+
+static int msm_anlg_cdc_codec_enable_on_demand_supply(
+		struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+	struct on_demand_supply *supply;
+
+	if (w->shift >= ON_DEMAND_SUPPLIES_MAX) {
+		dev_err(codec->dev, "%s: error index > MAX Demand supplies",
+			__func__);
+		ret = -EINVAL;
+		goto out;
+	}
+	dev_dbg(codec->dev, "%s: supply: %s event: %d ref: %d\n",
+		__func__, on_demand_supply_name[w->shift], event,
+		atomic_read(&sdm660_cdc->on_demand_list[w->shift].ref));
+
+	supply = &sdm660_cdc->on_demand_list[w->shift];
+	WARN_ONCE(!supply->supply, "%s isn't defined\n",
+		  on_demand_supply_name[w->shift]);
+	if (!supply->supply) {
+		dev_err(codec->dev, "%s: err supply not present ond for %d",
+			__func__, w->shift);
+		goto out;
+	}
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (atomic_inc_return(&supply->ref) == 1)
+			ret = regulator_enable(supply->supply);
+		if (ret)
+			dev_err(codec->dev, "%s: Failed to enable %s\n",
+				__func__,
+				on_demand_supply_name[w->shift]);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (atomic_read(&supply->ref) == 0) {
+			dev_dbg(codec->dev, "%s: %s supply has been disabled.\n",
+				 __func__, on_demand_supply_name[w->shift]);
+			goto out;
+		}
+		if (atomic_dec_return(&supply->ref) == 0)
+			ret = regulator_disable(supply->supply);
+			if (ret)
+				dev_err(codec->dev, "%s: Failed to disable %s\n",
+					__func__,
+					on_demand_supply_name[w->shift]);
+		break;
+	default:
+		break;
+	}
+out:
+	return ret;
+}
+
+static int msm_anlg_cdc_codec_enable_clock_block(struct snd_soc_codec *codec,
+						 int enable)
+{
+	struct msm_asoc_mach_data *pdata = NULL;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+	if (enable) {
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30, 0x30);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x0C);
+		msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_CLK_ON);
+	} else {
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x00);
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
+						 struct snd_kcontrol *kcontrol,
+						 int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		msm_anlg_cdc_codec_enable_clock_block(codec, 1);
+		if (!(strcmp(w->name, "EAR CP"))) {
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+					0x80, 0x80);
+			msm_anlg_cdc_boost_mode_sequence(codec, EAR_PMU);
+		} else if (get_codec_version(sdm660_cdc) >= DIANGU) {
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+					0x80, 0x80);
+		} else {
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+					0xC0, 0xC0);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* Wait for 1ms post powerup of chargepump */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Wait for 1ms post powerdown of chargepump */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		if (!(strcmp(w->name, "EAR CP"))) {
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+					0x80, 0x00);
+			if (sdm660_cdc->boost_option != BOOST_ALWAYS) {
+				dev_dbg(codec->dev,
+					"%s: boost_option:%d, tear down ear\n",
+					__func__, sdm660_cdc->boost_option);
+				msm_anlg_cdc_boost_mode_sequence(codec,
+								 EAR_PMD);
+			}
+			/*
+			 * Reset pa select bit from ear to hph after ear pa
+			 * is disabled and HPH DAC disable to reduce ear
+			 * turn off pop and avoid HPH pop in concurrency
+			 */
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x80, 0x00);
+		} else {
+			if (get_codec_version(sdm660_cdc) < DIANGU)
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+					0x40, 0x00);
+			if (sdm660_cdc->rx_bias_count == 0)
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+					0x80, 0x00);
+			dev_dbg(codec->dev, "%s: rx_bias_count = %d\n",
+					__func__, sdm660_cdc->rx_bias_count);
+		}
+		break;
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_ear_pa_boost_get(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] =
+		(sdm660_cdc->ear_pa_boost_set ? 1 : 0);
+	dev_dbg(codec->dev, "%s: sdm660_cdc->ear_pa_boost_set = %d\n",
+			__func__, sdm660_cdc->ear_pa_boost_set);
+	return 0;
+}
+
+static int msm_anlg_cdc_ear_pa_boost_set(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+	sdm660_cdc->ear_pa_boost_set =
+		(ucontrol->value.integer.value[0] ? true : false);
+	return 0;
+}
+
+static int msm_anlg_cdc_loopback_mode_get(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_asoc_mach_data *pdata = NULL;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	return pdata->lb_mode;
+}
+
+static int msm_anlg_cdc_loopback_mode_put(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_asoc_mach_data *pdata = NULL;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		pdata->lb_mode = false;
+		break;
+	case 1:
+		pdata->lb_mode = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int msm_anlg_cdc_pa_gain_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	u8 ear_pa_gain;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (get_codec_version(sdm660_cdc) >= DIANGU) {
+		ear_pa_gain = snd_soc_read(codec,
+					MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC);
+		ear_pa_gain = (ear_pa_gain >> 1) & 0x3;
+
+		if (ear_pa_gain == 0x00) {
+			ucontrol->value.integer.value[0] = 3;
+		} else if (ear_pa_gain == 0x01) {
+			ucontrol->value.integer.value[1] = 2;
+		} else if (ear_pa_gain == 0x02) {
+			ucontrol->value.integer.value[2] = 1;
+		} else if (ear_pa_gain == 0x03) {
+			ucontrol->value.integer.value[3] = 0;
+		} else {
+			dev_err(codec->dev,
+				"%s: ERROR: Unsupported Ear Gain = 0x%x\n",
+				__func__, ear_pa_gain);
+			return -EINVAL;
+		}
+	} else {
+		ear_pa_gain = snd_soc_read(codec,
+					   MSM89XX_PMIC_ANALOG_RX_EAR_CTL);
+		ear_pa_gain = (ear_pa_gain >> 5) & 0x1;
+		if (ear_pa_gain == 0x00) {
+			ucontrol->value.integer.value[0] = 0;
+		} else if (ear_pa_gain == 0x01) {
+			ucontrol->value.integer.value[0] = 3;
+		} else  {
+			dev_err(codec->dev,
+				"%s: ERROR: Unsupported Ear Gain = 0x%x\n",
+				__func__, ear_pa_gain);
+			return -EINVAL;
+		}
+	}
+	ucontrol->value.integer.value[0] = ear_pa_gain;
+	dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
+	return 0;
+}
+
+static int msm_anlg_cdc_pa_gain_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	u8 ear_pa_gain;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	if (get_codec_version(sdm660_cdc) >= DIANGU) {
+		switch (ucontrol->value.integer.value[0]) {
+		case 0:
+			ear_pa_gain = 0x06;
+			break;
+		case 1:
+			ear_pa_gain = 0x04;
+			break;
+		case 2:
+			ear_pa_gain = 0x02;
+			break;
+		case 3:
+			ear_pa_gain = 0x00;
+			break;
+		default:
+			return -EINVAL;
+		}
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+			    0x06, ear_pa_gain);
+	} else {
+		switch (ucontrol->value.integer.value[0]) {
+		case 0:
+			ear_pa_gain = 0x00;
+			break;
+		case 3:
+			ear_pa_gain = 0x20;
+			break;
+		case 1:
+		case 2:
+		default:
+			return -EINVAL;
+		}
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+			    0x20, ear_pa_gain);
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_hph_mode_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (sdm660_cdc->hph_mode == NORMAL_MODE) {
+		ucontrol->value.integer.value[0] = 0;
+	} else if (sdm660_cdc->hph_mode == HD2_MODE) {
+		ucontrol->value.integer.value[0] = 1;
+	} else  {
+		dev_err(codec->dev, "%s: ERROR: Default HPH Mode= %d\n",
+			__func__, sdm660_cdc->hph_mode);
+	}
+
+	dev_dbg(codec->dev, "%s: sdm660_cdc->hph_mode = %d\n", __func__,
+			sdm660_cdc->hph_mode);
+	return 0;
+}
+
+static int msm_anlg_cdc_hph_mode_set(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		sdm660_cdc->hph_mode = NORMAL_MODE;
+		break;
+	case 1:
+		if (get_codec_version(sdm660_cdc) >= DIANGU)
+			sdm660_cdc->hph_mode = HD2_MODE;
+		break;
+	default:
+		sdm660_cdc->hph_mode = NORMAL_MODE;
+		break;
+	}
+	dev_dbg(codec->dev, "%s: sdm660_cdc->hph_mode_set = %d\n",
+		__func__, sdm660_cdc->hph_mode);
+	return 0;
+}
+
+static int msm_anlg_cdc_boost_option_get(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (sdm660_cdc->boost_option == BOOST_SWITCH) {
+		ucontrol->value.integer.value[0] = 0;
+	} else if (sdm660_cdc->boost_option == BOOST_ALWAYS) {
+		ucontrol->value.integer.value[0] = 1;
+	} else if (sdm660_cdc->boost_option == BYPASS_ALWAYS) {
+		ucontrol->value.integer.value[0] = 2;
+	} else if (sdm660_cdc->boost_option == BOOST_ON_FOREVER) {
+		ucontrol->value.integer.value[0] = 3;
+	} else  {
+		dev_err(codec->dev, "%s: ERROR: Unsupported Boost option= %d\n",
+			__func__, sdm660_cdc->boost_option);
+		return -EINVAL;
+	}
+
+	dev_dbg(codec->dev, "%s: sdm660_cdc->boost_option = %d\n", __func__,
+			sdm660_cdc->boost_option);
+	return 0;
+}
+
+static int msm_anlg_cdc_boost_option_set(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		sdm660_cdc->boost_option = BOOST_SWITCH;
+		break;
+	case 1:
+		sdm660_cdc->boost_option = BOOST_ALWAYS;
+		break;
+	case 2:
+		sdm660_cdc->boost_option = BYPASS_ALWAYS;
+		msm_anlg_cdc_bypass_on(codec);
+		break;
+	case 3:
+		sdm660_cdc->boost_option = BOOST_ON_FOREVER;
+		msm_anlg_cdc_boost_on(codec);
+		break;
+	default:
+		pr_err("%s: invalid boost option: %d\n", __func__,
+					sdm660_cdc->boost_option);
+		return -EINVAL;
+	}
+	dev_dbg(codec->dev, "%s: sdm660_cdc->boost_option_set = %d\n",
+		__func__, sdm660_cdc->boost_option);
+	return 0;
+}
+
+static int msm_anlg_cdc_spk_boost_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (sdm660_cdc->spk_boost_set == false) {
+		ucontrol->value.integer.value[0] = 0;
+	} else if (sdm660_cdc->spk_boost_set == true) {
+		ucontrol->value.integer.value[0] = 1;
+	} else  {
+		dev_err(codec->dev, "%s: ERROR: Unsupported Speaker Boost = %d\n",
+				__func__, sdm660_cdc->spk_boost_set);
+		return -EINVAL;
+	}
+
+	dev_dbg(codec->dev, "%s: sdm660_cdc->spk_boost_set = %d\n", __func__,
+			sdm660_cdc->spk_boost_set);
+	return 0;
+}
+
+static int msm_anlg_cdc_spk_boost_set(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+			__func__, ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		sdm660_cdc->spk_boost_set = false;
+		break;
+	case 1:
+		sdm660_cdc->spk_boost_set = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+	dev_dbg(codec->dev, "%s: sdm660_cdc->spk_boost_set = %d\n",
+		__func__, sdm660_cdc->spk_boost_set);
+	return 0;
+}
+
+static int msm_anlg_cdc_ext_spk_boost_get(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (sdm660_cdc->ext_spk_boost_set == false)
+		ucontrol->value.integer.value[0] = 0;
+	else
+		ucontrol->value.integer.value[0] = 1;
+
+	dev_dbg(codec->dev, "%s: sdm660_cdc->ext_spk_boost_set = %d\n",
+				__func__, sdm660_cdc->ext_spk_boost_set);
+	return 0;
+}
+
+static int msm_anlg_cdc_ext_spk_boost_set(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		sdm660_cdc->ext_spk_boost_set = false;
+		break;
+	case 1:
+		sdm660_cdc->ext_spk_boost_set = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+	dev_dbg(codec->dev, "%s: sdm660_cdc->spk_boost_set = %d\n",
+		__func__, sdm660_cdc->spk_boost_set);
+	return 0;
+}
+
+
+static const char * const msm_anlg_cdc_loopback_mode_ctrl_text[] = {
+		"DISABLE", "ENABLE"};
+static const struct soc_enum msm_anlg_cdc_loopback_mode_ctl_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, msm_anlg_cdc_loopback_mode_ctrl_text),
+};
+
+static const char * const msm_anlg_cdc_ear_pa_boost_ctrl_text[] = {
+		"DISABLE", "ENABLE"};
+static const struct soc_enum msm_anlg_cdc_ear_pa_boost_ctl_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, msm_anlg_cdc_ear_pa_boost_ctrl_text),
+};
+
+static const char * const msm_anlg_cdc_ear_pa_gain_text[] = {
+		"POS_1P5_DB", "POS_3_DB", "POS_4P5_DB", "POS_6_DB"};
+static const struct soc_enum msm_anlg_cdc_ear_pa_gain_enum[] = {
+		SOC_ENUM_SINGLE_EXT(4, msm_anlg_cdc_ear_pa_gain_text),
+};
+
+static const char * const msm_anlg_cdc_boost_option_ctrl_text[] = {
+		"BOOST_SWITCH", "BOOST_ALWAYS", "BYPASS_ALWAYS",
+		"BOOST_ON_FOREVER"};
+static const struct soc_enum msm_anlg_cdc_boost_option_ctl_enum[] = {
+		SOC_ENUM_SINGLE_EXT(4, msm_anlg_cdc_boost_option_ctrl_text),
+};
+static const char * const msm_anlg_cdc_spk_boost_ctrl_text[] = {
+		"DISABLE", "ENABLE"};
+static const struct soc_enum msm_anlg_cdc_spk_boost_ctl_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, msm_anlg_cdc_spk_boost_ctrl_text),
+};
+
+static const char * const msm_anlg_cdc_ext_spk_boost_ctrl_text[] = {
+		"DISABLE", "ENABLE"};
+static const struct soc_enum msm_anlg_cdc_ext_spk_boost_ctl_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, msm_anlg_cdc_ext_spk_boost_ctrl_text),
+};
+
+static const char * const msm_anlg_cdc_hph_mode_ctrl_text[] = {
+		"NORMAL", "HD2"};
+static const struct soc_enum msm_anlg_cdc_hph_mode_ctl_enum[] = {
+		SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(msm_anlg_cdc_hph_mode_ctrl_text),
+			msm_anlg_cdc_hph_mode_ctrl_text),
+};
+
+/*cut of frequency for high pass filter*/
+static const char * const cf_text[] = {
+	"MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
+};
+
+
+static const struct snd_kcontrol_new msm_anlg_cdc_snd_controls[] = {
+
+	SOC_ENUM_EXT("RX HPH Mode", msm_anlg_cdc_hph_mode_ctl_enum[0],
+		msm_anlg_cdc_hph_mode_get, msm_anlg_cdc_hph_mode_set),
+
+	SOC_ENUM_EXT("Boost Option", msm_anlg_cdc_boost_option_ctl_enum[0],
+		msm_anlg_cdc_boost_option_get, msm_anlg_cdc_boost_option_set),
+
+	SOC_ENUM_EXT("EAR PA Boost", msm_anlg_cdc_ear_pa_boost_ctl_enum[0],
+		msm_anlg_cdc_ear_pa_boost_get, msm_anlg_cdc_ear_pa_boost_set),
+
+	SOC_ENUM_EXT("EAR PA Gain", msm_anlg_cdc_ear_pa_gain_enum[0],
+		msm_anlg_cdc_pa_gain_get, msm_anlg_cdc_pa_gain_put),
+
+	SOC_ENUM_EXT("Speaker Boost", msm_anlg_cdc_spk_boost_ctl_enum[0],
+		msm_anlg_cdc_spk_boost_get, msm_anlg_cdc_spk_boost_set),
+
+	SOC_ENUM_EXT("Ext Spk Boost", msm_anlg_cdc_ext_spk_boost_ctl_enum[0],
+		msm_anlg_cdc_ext_spk_boost_get, msm_anlg_cdc_ext_spk_boost_set),
+
+	SOC_ENUM_EXT("LOOPBACK Mode", msm_anlg_cdc_loopback_mode_ctl_enum[0],
+		msm_anlg_cdc_loopback_mode_get, msm_anlg_cdc_loopback_mode_put),
+	SOC_SINGLE_TLV("ADC1 Volume", MSM89XX_PMIC_ANALOG_TX_1_EN, 3,
+					8, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC2 Volume", MSM89XX_PMIC_ANALOG_TX_2_EN, 3,
+					8, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC3 Volume", MSM89XX_PMIC_ANALOG_TX_3_EN, 3,
+					8, 0, analog_gain),
+
+
+};
+
+static int tombak_hph_impedance_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	int ret;
+	uint32_t zl, zr;
+	bool hphr;
+	struct soc_multi_mixer_control *mc;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
+
+	hphr = mc->shift;
+	ret = wcd_mbhc_get_impedance(&priv->mbhc, &zl, &zr);
+	if (ret)
+		dev_dbg(codec->dev, "%s: Failed to get mbhc imped", __func__);
+	dev_dbg(codec->dev, "%s: zl %u, zr %u\n", __func__, zl, zr);
+	ucontrol->value.integer.value[0] = hphr ? zr : zl;
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new impedance_detect_controls[] = {
+	SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
+			tombak_hph_impedance_get, NULL),
+	SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
+			tombak_hph_impedance_get, NULL),
+};
+
+static int tombak_get_hph_type(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct wcd_mbhc *mbhc;
+
+	if (!priv) {
+		dev_err(codec->dev,
+			"%s: sdm660_cdc-wcd private data is NULL\n",
+			 __func__);
+		return -EINVAL;
+	}
+
+	mbhc = &priv->mbhc;
+	if (!mbhc) {
+		dev_err(codec->dev, "%s: mbhc not initialized\n", __func__);
+		return -EINVAL;
+	}
+
+	ucontrol->value.integer.value[0] = (u32) mbhc->hph_type;
+	dev_dbg(codec->dev, "%s: hph_type = %u\n", __func__, mbhc->hph_type);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new hph_type_detect_controls[] = {
+	SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0,
+	tombak_get_hph_type, NULL),
+};
+
+static const char * const rdac2_mux_text[] = {
+	"ZERO", "RX2", "RX1"
+};
+
+static const struct soc_enum rdac2_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL,
+		0, 3, rdac2_mux_text);
+
+static const char * const adc2_mux_text[] = {
+	"ZERO", "INP2", "INP3"
+};
+
+static const char * const ext_spk_text[] = {
+	"Off", "On"
+};
+
+static const char * const wsa_spk_text[] = {
+	"ZERO", "WSA"
+};
+
+static const struct soc_enum adc2_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+		ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
+static const struct soc_enum ext_spk_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+		ARRAY_SIZE(ext_spk_text), ext_spk_text);
+
+static const struct soc_enum wsa_spk_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+		ARRAY_SIZE(wsa_spk_text), wsa_spk_text);
+
+
+
+static const struct snd_kcontrol_new ext_spk_mux =
+	SOC_DAPM_ENUM("Ext Spk Switch Mux", ext_spk_enum);
+
+
+
+static const struct snd_kcontrol_new tx_adc2_mux =
+	SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
+
+static const struct snd_kcontrol_new rdac2_mux =
+	SOC_DAPM_ENUM("RDAC2 MUX Mux", rdac2_mux_enum);
+
+static const char * const ear_text[] = {
+	"ZERO", "Switch",
+};
+
+static const struct soc_enum ear_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(ear_text), ear_text);
+
+static const struct snd_kcontrol_new ear_pa_mux[] = {
+	SOC_DAPM_ENUM("EAR_S", ear_enum)
+};
+
+static const struct snd_kcontrol_new wsa_spk_mux[] = {
+	SOC_DAPM_ENUM("WSA Spk Switch", wsa_spk_enum)
+};
+
+
+
+static const char * const hph_text[] = {
+	"ZERO", "Switch",
+};
+
+static const struct soc_enum hph_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(hph_text), hph_text);
+
+static const struct snd_kcontrol_new hphl_mux[] = {
+	SOC_DAPM_ENUM("HPHL", hph_enum)
+};
+
+static const struct snd_kcontrol_new hphr_mux[] = {
+	SOC_DAPM_ENUM("HPHR", hph_enum)
+};
+
+static const struct snd_kcontrol_new spkr_mux[] = {
+	SOC_DAPM_ENUM("SPK", hph_enum)
+};
+
+static const char * const lo_text[] = {
+	"ZERO", "Switch",
+};
+
+static const struct soc_enum lo_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(hph_text), hph_text);
+
+static const struct snd_kcontrol_new lo_mux[] = {
+	SOC_DAPM_ENUM("LINE_OUT", lo_enum)
+};
+
+static void msm_anlg_cdc_codec_enable_adc_block(struct snd_soc_codec *codec,
+					 int enable)
+{
+	struct sdm660_cdc_priv *wcd8x16 = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %d\n", __func__, enable);
+
+	if (enable) {
+		wcd8x16->adc_count++;
+		snd_soc_update_bits(codec,
+				    MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL,
+				    0x20, 0x20);
+		snd_soc_update_bits(codec,
+				    MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x10, 0x10);
+	} else {
+		wcd8x16->adc_count--;
+		if (!wcd8x16->adc_count) {
+			snd_soc_update_bits(codec,
+				    MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x10, 0x00);
+			snd_soc_update_bits(codec,
+				    MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL,
+					    0x20, 0x0);
+		}
+	}
+}
+
+static int msm_anlg_cdc_codec_enable_adc(struct snd_soc_dapm_widget *w,
+					 struct snd_kcontrol *kcontrol,
+					 int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	u16 adc_reg;
+	u8 init_bit_shift;
+
+	dev_dbg(codec->dev, "%s %d\n", __func__, event);
+
+	adc_reg = MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_2;
+
+	if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN)
+		init_bit_shift = 5;
+	else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) ||
+		 (w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN))
+		init_bit_shift = 4;
+	else {
+		dev_err(codec->dev, "%s: Error, invalid adc register\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		msm_anlg_cdc_codec_enable_adc_block(codec, 1);
+		if (w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN)
+			snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_1_CTL, 0x02, 0x02);
+		/*
+		 * Add delay of 10 ms to give sufficient time for the voltage
+		 * to shoot up and settle so that the txfe init does not
+		 * happen when the input voltage is changing too much.
+		 */
+		usleep_range(10000, 10010);
+		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
+				1 << init_bit_shift);
+		if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN)
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL,
+				0x03, 0x00);
+		else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) ||
+			(w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN))
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL,
+				0x03, 0x00);
+		/* Wait for 1ms to allow txfe settling time */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/*
+		 * Add delay of 12 ms before deasserting the init
+		 * to reduce the tx pop
+		 */
+		usleep_range(12000, 12010);
+		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+		/* Wait for 1ms to allow txfe settling time post powerup */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		msm_anlg_cdc_codec_enable_adc_block(codec, 0);
+		if (w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN)
+			snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_1_CTL, 0x02, 0x00);
+		if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN)
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL,
+				0x03, 0x02);
+		else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) ||
+			(w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN))
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL,
+				0x03, 0x02);
+
+		break;
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
+					    struct snd_kcontrol *kcontrol,
+					    int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0x01, 0x01);
+		switch (sdm660_cdc->boost_option) {
+		case BOOST_SWITCH:
+			if (!sdm660_cdc->spk_boost_set)
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+					0x10, 0x10);
+			break;
+		case BOOST_ALWAYS:
+		case BOOST_ON_FOREVER:
+			break;
+		case BYPASS_ALWAYS:
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+				0x10, 0x10);
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s: invalid boost option: %d\n", __func__,
+				sdm660_cdc->boost_option);
+			break;
+		}
+		/* Wait for 1ms after SPK_DAC CTL setting */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0xE0, 0xE0);
+		if (get_codec_version(sdm660_cdc) != TOMBAK_1_0)
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x01, 0x01);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* Wait for 1ms after SPK_VBAT_LDO Enable */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		switch (sdm660_cdc->boost_option) {
+		case BOOST_SWITCH:
+			if (sdm660_cdc->spk_boost_set)
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+					0xEF, 0xEF);
+			else
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+					0x10, 0x00);
+			break;
+		case BOOST_ALWAYS:
+		case BOOST_ON_FOREVER:
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+				0xEF, 0xEF);
+			break;
+		case BYPASS_ALWAYS:
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x00);
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s: invalid boost option: %d\n", __func__,
+				sdm660_cdc->boost_option);
+			break;
+		}
+		msm_anlg_cdc_dig_notifier_call(codec,
+					       DIG_CDC_EVENT_RX3_MUTE_OFF);
+		snd_soc_update_bits(codec, w->reg, 0x80, 0x80);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		msm_anlg_cdc_dig_notifier_call(codec,
+					       DIG_CDC_EVENT_RX3_MUTE_ON);
+		/*
+		 * Add 1 ms sleep for the mute to take effect
+		 */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x10);
+		if (get_codec_version(sdm660_cdc) < CAJON_2_0)
+			msm_anlg_cdc_boost_mode_sequence(codec, SPK_PMD);
+		snd_soc_update_bits(codec, w->reg, 0x80, 0x00);
+		switch (sdm660_cdc->boost_option) {
+		case BOOST_SWITCH:
+			if (sdm660_cdc->spk_boost_set)
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+					0xEF, 0x69);
+			break;
+		case BOOST_ALWAYS:
+		case BOOST_ON_FOREVER:
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+				0xEF, 0x69);
+			break;
+		case BYPASS_ALWAYS:
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s: invalid boost option: %d\n", __func__,
+				sdm660_cdc->boost_option);
+			break;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0xE0, 0x00);
+		/* Wait for 1ms to allow setting time for spkr path disable */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0x01, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x00);
+		if (get_codec_version(sdm660_cdc) != TOMBAK_1_0)
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x01, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00);
+		if (get_codec_version(sdm660_cdc) >= CAJON_2_0)
+			msm_anlg_cdc_boost_mode_sequence(codec, SPK_PMD);
+		break;
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_codec_enable_dig_clk(struct snd_soc_dapm_widget *w,
+					     struct snd_kcontrol *kcontrol,
+					     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+	struct msm_asoc_mach_data *pdata = NULL;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+
+	dev_dbg(codec->dev, "%s event %d w->name %s\n", __func__,
+			event, w->name);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		msm_anlg_cdc_codec_enable_clock_block(codec, 1);
+		snd_soc_update_bits(codec, w->reg, 0x80, 0x80);
+		msm_anlg_cdc_boost_mode_sequence(codec, SPK_PMU);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (sdm660_cdc->rx_bias_count == 0)
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+					0x80, 0x00);
+	}
+	return 0;
+}
+
+
+
+static bool msm_anlg_cdc_use_mb(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (get_codec_version(sdm660_cdc) < CAJON)
+		return true;
+	else
+		return false;
+}
+
+static void msm_anlg_cdc_set_auto_zeroing(struct snd_soc_codec *codec,
+					  bool enable)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (get_codec_version(sdm660_cdc) < CONGA) {
+		if (enable)
+			/*
+			 * Set autozeroing for special headset detection and
+			 * buttons to work.
+			 */
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MICB_2_EN,
+				0x18, 0x10);
+		else
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MICB_2_EN,
+				0x18, 0x00);
+
+	} else {
+		dev_dbg(codec->dev,
+			"%s: Auto Zeroing is not required from CONGA\n",
+			__func__);
+	}
+}
+
+static void msm_anlg_cdc_trim_btn_reg(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (get_codec_version(sdm660_cdc) == TOMBAK_1_0) {
+		pr_debug("%s: This device needs to be trimmed\n", __func__);
+		/*
+		 * Calculate the trim value for each device used
+		 * till is comes in production by hardware team
+		 */
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SEC_ACCESS,
+				0xA5, 0xA5);
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_TRIM_CTRL2,
+				0xFF, 0x30);
+	} else {
+		dev_dbg(codec->dev, "%s: This device is trimmed at ATE\n",
+			__func__);
+	}
+}
+
+static int msm_anlg_cdc_enable_ext_mb_source(struct wcd_mbhc *wcd_mbhc,
+					     bool turn_on)
+{
+	int ret = 0;
+	static int count;
+	struct snd_soc_codec *codec = wcd_mbhc->codec;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+	dev_dbg(codec->dev, "%s turn_on: %d count: %d\n", __func__, turn_on,
+			count);
+	if (turn_on) {
+		if (!count) {
+			ret = snd_soc_dapm_force_enable_pin(dapm,
+				"MICBIAS_REGULATOR");
+			snd_soc_dapm_sync(dapm);
+		}
+		count++;
+	} else {
+		if (count > 0)
+			count--;
+		if (!count) {
+			ret = snd_soc_dapm_disable_pin(dapm,
+				"MICBIAS_REGULATOR");
+			snd_soc_dapm_sync(dapm);
+		}
+	}
+
+	if (ret)
+		dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
+			__func__, turn_on ? "enable" : "disabled");
+	else
+		dev_dbg(codec->dev, "%s: %s external micbias source\n",
+			 __func__, turn_on ? "Enabled" : "Disabled");
+
+	return ret;
+}
+
+static int msm_anlg_cdc_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+					     struct snd_kcontrol *kcontrol,
+					     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+				snd_soc_codec_get_drvdata(codec);
+	u16 micb_int_reg;
+	char *internal1_text = "Internal1";
+	char *internal2_text = "Internal2";
+	char *internal3_text = "Internal3";
+	char *external2_text = "External2";
+	char *external_text = "External";
+	bool micbias2;
+
+	dev_dbg(codec->dev, "%s %d\n", __func__, event);
+	switch (w->reg) {
+	case MSM89XX_PMIC_ANALOG_MICB_1_EN:
+	case MSM89XX_PMIC_ANALOG_MICB_2_EN:
+		micb_int_reg = MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS;
+		break;
+	default:
+		dev_err(codec->dev,
+			"%s: Error, invalid micbias register 0x%x\n",
+			__func__, w->reg);
+		return -EINVAL;
+	}
+
+	micbias2 = (snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MICB_2_EN) & 0x80);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (strnstr(w->name, internal1_text, strlen(w->name))) {
+			if (get_codec_version(sdm660_cdc) >= CAJON)
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2,
+					0x02, 0x02);
+			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
+		} else if (strnstr(w->name, internal2_text, strlen(w->name))) {
+			snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
+			snd_soc_update_bits(codec, w->reg, 0x60, 0x00);
+		} else if (strnstr(w->name, internal3_text, strlen(w->name))) {
+			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
+		/*
+		 * update MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2
+		 * for external bias only, not for external2.
+		*/
+		} else if (!strnstr(w->name, external2_text, strlen(w->name)) &&
+					strnstr(w->name, external_text,
+						strlen(w->name))) {
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2,
+					0x02, 0x02);
+		}
+		if (!strnstr(w->name, external_text, strlen(w->name)))
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MICB_1_EN, 0x05, 0x04);
+		if (w->reg == MSM89XX_PMIC_ANALOG_MICB_1_EN)
+			msm_anlg_cdc_configure_cap(codec, true, micbias2);
+
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if (get_codec_version(sdm660_cdc) <= TOMBAK_2_0)
+			/*
+			 * Wait for 20ms post micbias enable
+			 * for version < tombak 2.0.
+			 */
+			usleep_range(20000, 20100);
+		if (strnstr(w->name, internal1_text, strlen(w->name))) {
+			snd_soc_update_bits(codec, micb_int_reg, 0x40, 0x40);
+		} else if (strnstr(w->name, internal2_text,  strlen(w->name))) {
+			snd_soc_update_bits(codec, micb_int_reg, 0x08, 0x08);
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_POST_MICBIAS_2_ON);
+		} else if (strnstr(w->name, internal3_text, 30)) {
+			snd_soc_update_bits(codec, micb_int_reg, 0x01, 0x01);
+		} else if (strnstr(w->name, external2_text, strlen(w->name))) {
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_POST_MICBIAS_2_ON);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (strnstr(w->name, internal1_text, strlen(w->name))) {
+			snd_soc_update_bits(codec, micb_int_reg, 0xC0, 0x40);
+		} else if (strnstr(w->name, internal2_text, strlen(w->name))) {
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_POST_MICBIAS_2_OFF);
+		} else if (strnstr(w->name, internal3_text, 30)) {
+			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
+		} else if (strnstr(w->name, external2_text, strlen(w->name))) {
+			/*
+			 * send micbias turn off event to mbhc driver and then
+			 * break, as no need to set MICB_1_EN register.
+			 */
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_POST_MICBIAS_2_OFF);
+			break;
+		}
+		if (w->reg == MSM89XX_PMIC_ANALOG_MICB_1_EN)
+			msm_anlg_cdc_configure_cap(codec, false, micbias2);
+		break;
+	}
+	return 0;
+}
+
+static void update_clkdiv(void *handle, int val)
+{
+	struct sdm660_cdc_priv *handle_cdc = handle;
+	struct snd_soc_codec *codec = handle_cdc->codec;
+
+	snd_soc_update_bits(codec,
+			    MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV,
+			    0xFF, val);
+}
+
+static int get_cdc_version(void *handle)
+{
+	struct sdm660_cdc_priv *sdm660_cdc = handle;
+
+	return get_codec_version(sdm660_cdc);
+}
+
+static int sdm660_wcd_codec_enable_vdd_spkr(struct snd_soc_dapm_widget *w,
+					       struct snd_kcontrol *kcontrol,
+					       int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	if (!sdm660_cdc->ext_spk_boost_set) {
+		dev_dbg(codec->dev, "%s: ext_boost not supported/disabled\n",
+								__func__);
+		return 0;
+	}
+	dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (sdm660_cdc->spkdrv_reg) {
+			ret = regulator_enable(sdm660_cdc->spkdrv_reg);
+			if (ret)
+				dev_err(codec->dev,
+					"%s Failed to enable spkdrv reg %s\n",
+					__func__, MSM89XX_VDD_SPKDRV_NAME);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (sdm660_cdc->spkdrv_reg) {
+			ret = regulator_disable(sdm660_cdc->spkdrv_reg);
+			if (ret)
+				dev_err(codec->dev,
+					"%s: Failed to disable spkdrv_reg %s\n",
+					__func__, MSM89XX_VDD_SPKDRV_NAME);
+		}
+		break;
+	}
+	return 0;
+}
+
+
+/* The register address is the same as other codec so it can use resmgr */
+static int msm_anlg_cdc_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
+					     struct snd_kcontrol *kcontrol,
+					     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		sdm660_cdc->rx_bias_count++;
+		if (sdm660_cdc->rx_bias_count == 1) {
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+					0x80, 0x80);
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+					0x01, 0x01);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		sdm660_cdc->rx_bias_count--;
+		if (sdm660_cdc->rx_bias_count == 0) {
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+					0x01, 0x00);
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+					0x80, 0x00);
+		}
+		break;
+	}
+	dev_dbg(codec->dev, "%s rx_bias_count = %d\n",
+			__func__, sdm660_cdc->rx_bias_count);
+	return 0;
+}
+
+static uint32_t wcd_get_impedance_value(uint32_t imped)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wcd_imped_val) - 1; i++) {
+		if (imped >= wcd_imped_val[i] &&
+			imped < wcd_imped_val[i + 1])
+			break;
+	}
+
+	pr_debug("%s: selected impedance value = %d\n",
+		 __func__, wcd_imped_val[i]);
+	return wcd_imped_val[i];
+}
+
+static void wcd_imped_config(struct snd_soc_codec *codec,
+			     uint32_t imped, bool set_gain)
+{
+	uint32_t value;
+	int codec_version;
+	struct sdm660_cdc_priv *sdm660_cdc =
+				snd_soc_codec_get_drvdata(codec);
+
+	value = wcd_get_impedance_value(imped);
+
+	if (value < wcd_imped_val[0]) {
+		dev_dbg(codec->dev,
+			"%s, detected impedance is less than 4 Ohm\n",
+			 __func__);
+		return;
+	}
+
+	codec_version = get_codec_version(sdm660_cdc);
+
+	if (set_gain) {
+		switch (codec_version) {
+		case TOMBAK_1_0:
+		case TOMBAK_2_0:
+		case CONGA:
+			/*
+			 * For 32Ohm load and higher loads, Set 0x19E
+			 * bit 5 to 1 (POS_0_DB_DI). For loads lower
+			 * than 32Ohm (such as 16Ohm load), Set 0x19E
+			 * bit 5 to 0 (POS_M4P5_DB_DI)
+			 */
+			if (value >= 32)
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+					0x20, 0x20);
+			else
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+					0x20, 0x00);
+			break;
+		case CAJON:
+		case CAJON_2_0:
+		case DIANGU:
+		case DRAX_CDC:
+			if (value >= 13) {
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+					0x20, 0x20);
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_NCP_VCTRL,
+					0x07, 0x07);
+			} else {
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+					0x20, 0x00);
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_NCP_VCTRL,
+					0x07, 0x04);
+			}
+			break;
+		}
+	} else {
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+			0x20, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_NCP_VCTRL,
+			0x07, 0x04);
+	}
+
+	dev_dbg(codec->dev, "%s: Exit\n", __func__);
+}
+
+static int msm_anlg_cdc_hphl_dac_event(struct snd_soc_dapm_widget *w,
+				       struct snd_kcontrol *kcontrol,
+				       int event)
+{
+	uint32_t impedl, impedr;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+	ret = wcd_mbhc_get_impedance(&sdm660_cdc->mbhc,
+			&impedl, &impedr);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (get_codec_version(sdm660_cdc) > CAJON)
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
+				0x08, 0x08);
+		if (get_codec_version(sdm660_cdc) == CAJON ||
+			get_codec_version(sdm660_cdc) == CAJON_2_0) {
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST,
+				0x80, 0x80);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST,
+				0x80, 0x80);
+		}
+		if (get_codec_version(sdm660_cdc) > CAJON)
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
+				0x08, 0x00);
+		if (sdm660_cdc->hph_mode == HD2_MODE)
+			msm_anlg_cdc_dig_notifier_call(codec,
+					DIG_CDC_EVENT_PRE_RX1_INT_ON);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x02);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x01);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x02);
+		if (!ret)
+			wcd_imped_config(codec, impedl, true);
+		else
+			dev_dbg(codec->dev, "Failed to get mbhc impedance %d\n",
+				ret);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd_imped_config(codec, impedl, false);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x00);
+		if (sdm660_cdc->hph_mode == HD2_MODE)
+			msm_anlg_cdc_dig_notifier_call(codec,
+					DIG_CDC_EVENT_POST_RX1_INT_OFF);
+		break;
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_lo_dac_event(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol,
+				     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x20, 0x20);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x80, 0x80);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x08);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x40, 0x40);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x80, 0x80);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x40, 0x40);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Wait for 20ms before powerdown of lineout_dac */
+		usleep_range(20000, 20100);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x80, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x40, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x80, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x40, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x20, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00);
+		break;
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_hphr_dac_event(struct snd_soc_dapm_widget *w,
+				       struct snd_kcontrol *kcontrol,
+				       int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (sdm660_cdc->hph_mode == HD2_MODE)
+			msm_anlg_cdc_dig_notifier_call(codec,
+					DIG_CDC_EVENT_PRE_RX2_INT_ON);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x02);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x02);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x01);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x00);
+		if (sdm660_cdc->hph_mode == HD2_MODE)
+			msm_anlg_cdc_dig_notifier_call(codec,
+					DIG_CDC_EVENT_POST_RX2_INT_OFF);
+		break;
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_hph_pa_event(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol,
+				     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (w->shift == 5)
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_PRE_HPHL_PA_ON);
+		else if (w->shift == 4)
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_PRE_HPHR_PA_ON);
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x20, 0x20);
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		/* Wait for 7ms to allow setting time for HPH_PA Enable */
+		usleep_range(7000, 7100);
+		if (w->shift == 5) {
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x04);
+			msm_anlg_cdc_dig_notifier_call(codec,
+					       DIG_CDC_EVENT_RX1_MUTE_OFF);
+		} else if (w->shift == 4) {
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x04);
+			msm_anlg_cdc_dig_notifier_call(codec,
+					       DIG_CDC_EVENT_RX2_MUTE_OFF);
+		}
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		if (w->shift == 5) {
+			msm_anlg_cdc_dig_notifier_call(codec,
+					       DIG_CDC_EVENT_RX1_MUTE_ON);
+			/* Wait for 20ms after HPHL RX digital mute */
+			msleep(20);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x00);
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_PRE_HPHL_PA_OFF);
+		} else if (w->shift == 4) {
+			msm_anlg_cdc_dig_notifier_call(codec,
+					       DIG_CDC_EVENT_RX2_MUTE_ON);
+			/* Wait for 20ms after HPHR RX digital mute */
+			msleep(20);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x00);
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_PRE_HPHR_PA_OFF);
+		}
+		if (get_codec_version(sdm660_cdc) >= CAJON) {
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP,
+				0xF0, 0x30);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (w->shift == 5) {
+			clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK,
+				&sdm660_cdc->mbhc.hph_pa_dac_state);
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_POST_HPHL_PA_OFF);
+		} else if (w->shift == 4) {
+			clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK,
+				&sdm660_cdc->mbhc.hph_pa_dac_state);
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_POST_HPHR_PA_OFF);
+		}
+		/* Wait for 15ms after HPH RX teardown */
+		usleep_range(15000, 15100);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* RDAC Connections */
+	{"HPHR DAC", NULL, "RDAC2 MUX"},
+	{"RDAC2 MUX", "RX1", "PDM_IN_RX1"},
+	{"RDAC2 MUX", "RX2", "PDM_IN_RX2"},
+
+	/* WSA */
+	{"WSA_SPK OUT", NULL, "WSA Spk Switch"},
+	{"WSA Spk Switch", "WSA", "EAR PA"},
+
+	/* Earpiece (RX MIX1) */
+	{"EAR", NULL, "EAR_S"},
+	{"EAR_S", "Switch", "EAR PA"},
+	{"EAR PA", NULL, "RX_BIAS"},
+	{"EAR PA", NULL, "HPHL DAC"},
+	{"EAR PA", NULL, "HPHR DAC"},
+	{"EAR PA", NULL, "EAR CP"},
+
+	/* Headset (RX MIX1 and RX MIX2) */
+	{"HEADPHONE", NULL, "HPHL PA"},
+	{"HEADPHONE", NULL, "HPHR PA"},
+
+	{"Ext Spk", NULL, "Ext Spk Switch"},
+	{"Ext Spk Switch", "On", "HPHL PA"},
+	{"Ext Spk Switch", "On", "HPHR PA"},
+
+	{"HPHL PA", NULL, "HPHL"},
+	{"HPHR PA", NULL, "HPHR"},
+	{"HPHL", "Switch", "HPHL DAC"},
+	{"HPHR", "Switch", "HPHR DAC"},
+	{"HPHL PA", NULL, "CP"},
+	{"HPHL PA", NULL, "RX_BIAS"},
+	{"HPHR PA", NULL, "CP"},
+	{"HPHR PA", NULL, "RX_BIAS"},
+	{"HPHL DAC", NULL, "PDM_IN_RX1"},
+
+	{"SPK_OUT", NULL, "SPK PA"},
+	{"SPK PA", NULL, "SPK_RX_BIAS"},
+	{"SPK PA", NULL, "SPK"},
+	{"SPK", "Switch", "SPK DAC"},
+	{"SPK DAC", NULL, "PDM_IN_RX3"},
+	{"SPK DAC", NULL, "VDD_SPKDRV"},
+
+	/* lineout */
+	{"LINEOUT", NULL, "LINEOUT PA"},
+	{"LINEOUT PA", NULL, "SPK_RX_BIAS"},
+	{"LINEOUT PA", NULL, "LINE_OUT"},
+	{"LINE_OUT", "Switch", "LINEOUT DAC"},
+	{"LINEOUT DAC", NULL, "PDM_IN_RX3"},
+
+	/* lineout to WSA */
+	{"WSA_SPK OUT", NULL, "LINEOUT PA"},
+
+	{"PDM_IN_RX1", NULL, "RX1 CLK"},
+	{"PDM_IN_RX2", NULL, "RX2 CLK"},
+	{"PDM_IN_RX3", NULL, "RX3 CLK"},
+
+	{"ADC1_OUT", NULL, "ADC1"},
+	{"ADC2_OUT", NULL, "ADC2"},
+	{"ADC3_OUT", NULL, "ADC3"},
+
+	/* ADC Connections */
+	{"ADC2", NULL, "ADC2 MUX"},
+	{"ADC3", NULL, "ADC2 MUX"},
+	{"ADC2 MUX", "INP2", "ADC2_INP2"},
+	{"ADC2 MUX", "INP3", "ADC2_INP3"},
+
+	{"ADC1", NULL, "AMIC1"},
+	{"ADC2_INP2", NULL, "AMIC2"},
+	{"ADC2_INP3", NULL, "AMIC3"},
+
+	{"MIC BIAS Internal1", NULL, "INT_LDO_H"},
+	{"MIC BIAS Internal2", NULL, "INT_LDO_H"},
+	{"MIC BIAS External", NULL, "INT_LDO_H"},
+	{"MIC BIAS External2", NULL, "INT_LDO_H"},
+	{"MIC BIAS Internal1", NULL, "MICBIAS_REGULATOR"},
+	{"MIC BIAS Internal2", NULL, "MICBIAS_REGULATOR"},
+	{"MIC BIAS External", NULL, "MICBIAS_REGULATOR"},
+	{"MIC BIAS External2", NULL, "MICBIAS_REGULATOR"},
+};
+
+static int msm_anlg_cdc_startup(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+		snd_soc_codec_get_drvdata(dai->codec);
+
+	dev_dbg(dai->codec->dev, "%s(): substream = %s  stream = %d\n",
+		__func__,
+		substream->name, substream->stream);
+	/*
+	 * If status_mask is BUS_DOWN it means SSR is not complete.
+	 * So return error.
+	 */
+	if (test_bit(BUS_DOWN, &sdm660_cdc->status_mask)) {
+		dev_err(dai->codec->dev, "Error, Device is not up post SSR\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void msm_anlg_cdc_shutdown(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	dev_dbg(dai->codec->dev,
+		"%s(): substream = %s  stream = %d\n", __func__,
+		substream->name, substream->stream);
+}
+
+int msm_anlg_cdc_mclk_enable(struct snd_soc_codec *codec,
+			     int mclk_enable, bool dapm)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
+		__func__, mclk_enable, dapm);
+	if (mclk_enable) {
+		sdm660_cdc->int_mclk0_enabled = true;
+		msm_anlg_cdc_codec_enable_clock_block(codec, 1);
+	} else {
+		if (!sdm660_cdc->int_mclk0_enabled) {
+			dev_err(codec->dev, "Error, MCLK already diabled\n");
+			return -EINVAL;
+		}
+		sdm660_cdc->int_mclk0_enabled = false;
+		msm_anlg_cdc_codec_enable_clock_block(codec, 0);
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	dev_dbg(dai->codec->dev, "%s\n", __func__);
+	return 0;
+}
+
+static int msm_anlg_cdc_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	dev_dbg(dai->codec->dev, "%s\n", __func__);
+	return 0;
+}
+
+static int msm_anlg_cdc_set_channel_map(struct snd_soc_dai *dai,
+				unsigned int tx_num, unsigned int *tx_slot,
+				unsigned int rx_num, unsigned int *rx_slot)
+
+{
+	dev_dbg(dai->codec->dev, "%s\n", __func__);
+	return 0;
+}
+
+static int msm_anlg_cdc_get_channel_map(struct snd_soc_dai *dai,
+				 unsigned int *tx_num, unsigned int *tx_slot,
+				 unsigned int *rx_num, unsigned int *rx_slot)
+
+{
+	dev_dbg(dai->codec->dev, "%s\n", __func__);
+	return 0;
+}
+
+static struct snd_soc_dai_ops msm_anlg_cdc_dai_ops = {
+	.startup = msm_anlg_cdc_startup,
+	.shutdown = msm_anlg_cdc_shutdown,
+	.set_sysclk = msm_anlg_cdc_set_dai_sysclk,
+	.set_fmt = msm_anlg_cdc_set_dai_fmt,
+	.set_channel_map = msm_anlg_cdc_set_channel_map,
+	.get_channel_map = msm_anlg_cdc_get_channel_map,
+};
+
+static struct snd_soc_dai_driver msm_anlg_cdc_i2s_dai[] = {
+	{
+		.name = "msm_anlg_cdc_i2s_rx1",
+		.id = AIF1_PB,
+		.playback = {
+			.stream_name = "Playback",
+			.rates = SDM660_CDC_RATES,
+			.formats = SDM660_CDC_FORMATS,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 3,
+		},
+		.ops = &msm_anlg_cdc_dai_ops,
+	},
+	{
+		.name = "msm_anlg_cdc_i2s_tx1",
+		.id = AIF1_CAP,
+		.capture = {
+			.stream_name = "Record",
+			.rates = SDM660_CDC_RATES,
+			.formats = SDM660_CDC_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &msm_anlg_cdc_dai_ops,
+	},
+	{
+		.name = "msm_anlg_cdc_i2s_tx2",
+		.id = AIF3_SVA,
+		.capture = {
+			.stream_name = "RecordSVA",
+			.rates = SDM660_CDC_RATES,
+			.formats = SDM660_CDC_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &msm_anlg_cdc_dai_ops,
+	},
+	{
+		.name = "msm_anlg_vifeedback",
+		.id = AIF2_VIFEED,
+		.capture = {
+			.stream_name = "VIfeed",
+			.rates = SDM660_CDC_RATES,
+			.formats = SDM660_CDC_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 48000,
+			.channels_min = 2,
+			.channels_max = 2,
+		},
+		.ops = &msm_anlg_cdc_dai_ops,
+	},
+};
+
+
+static int msm_anlg_cdc_codec_enable_lo_pa(struct snd_soc_dapm_widget *w,
+					   struct snd_kcontrol *kcontrol,
+					   int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	dev_dbg(codec->dev, "%s: %d %s\n", __func__, event, w->name);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		msm_anlg_cdc_dig_notifier_call(codec,
+				       DIG_CDC_EVENT_RX3_MUTE_OFF);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		msm_anlg_cdc_dig_notifier_call(codec,
+				       DIG_CDC_EVENT_RX3_MUTE_ON);
+		break;
+	}
+
+	return 0;
+}
+
+static int msm_anlg_cdc_codec_enable_spk_ext_pa(struct snd_soc_dapm_widget *w,
+						struct snd_kcontrol *kcontrol,
+						int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		dev_dbg(codec->dev,
+			"%s: enable external speaker PA\n", __func__);
+		if (sdm660_cdc->codec_spk_ext_pa_cb)
+			sdm660_cdc->codec_spk_ext_pa_cb(codec, 1);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		dev_dbg(codec->dev,
+			"%s: enable external speaker PA\n", __func__);
+		if (sdm660_cdc->codec_spk_ext_pa_cb)
+			sdm660_cdc->codec_spk_ext_pa_cb(codec, 0);
+		break;
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
+					    struct snd_kcontrol *kcontrol,
+					    int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		dev_dbg(codec->dev,
+			"%s: Sleeping 20ms after select EAR PA\n",
+			__func__);
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+			    0x80, 0x80);
+		if (get_codec_version(sdm660_cdc) < CONGA)
+			snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFF, 0x2A);
+		if (get_codec_version(sdm660_cdc) >= DIANGU) {
+			snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC, 0x08, 0x00);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x04);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x04);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		dev_dbg(codec->dev,
+			"%s: Sleeping 20ms after enabling EAR PA\n",
+			__func__);
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+			    0x40, 0x40);
+		/* Wait for 7ms after EAR PA enable */
+		usleep_range(7000, 7100);
+		msm_anlg_cdc_dig_notifier_call(codec,
+				       DIG_CDC_EVENT_RX1_MUTE_OFF);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		msm_anlg_cdc_dig_notifier_call(codec,
+				       DIG_CDC_EVENT_RX1_MUTE_ON);
+		/* Wait for 20ms for RX digital mute to take effect */
+		msleep(20);
+		if (sdm660_cdc->boost_option == BOOST_ALWAYS) {
+			dev_dbg(codec->dev,
+				"%s: boost_option:%d, tear down ear\n",
+				__func__, sdm660_cdc->boost_option);
+			msm_anlg_cdc_boost_mode_sequence(codec, EAR_PMD);
+		}
+		if (get_codec_version(sdm660_cdc) >= DIANGU) {
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x0);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x0);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		dev_dbg(codec->dev,
+			"%s: Sleeping 7ms after disabling EAR PA\n",
+			__func__);
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+			    0x40, 0x00);
+		/* Wait for 7ms after EAR PA teardown */
+		usleep_range(7000, 7100);
+		if (get_codec_version(sdm660_cdc) < CONGA)
+			snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFF, 0x16);
+		if (get_codec_version(sdm660_cdc) >= DIANGU)
+			snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC, 0x08, 0x08);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget msm_anlg_cdc_dapm_widgets[] = {
+	SND_SOC_DAPM_PGA_E("EAR PA", SND_SOC_NOPM,
+			0, 0, NULL, 0, msm_anlg_cdc_codec_enable_ear_pa,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("HPHL PA", MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
+		5, 0, NULL, 0,
+		msm_anlg_cdc_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("HPHR PA", MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
+		4, 0, NULL, 0,
+		msm_anlg_cdc_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("SPK PA", SND_SOC_NOPM,
+			0, 0, NULL, 0, msm_anlg_cdc_codec_enable_spk_pa,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT PA", MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL,
+			5, 0, NULL, 0, msm_anlg_cdc_codec_enable_lo_pa,
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("EAR_S", SND_SOC_NOPM, 0, 0, ear_pa_mux),
+	SND_SOC_DAPM_MUX("SPK", SND_SOC_NOPM, 0, 0, spkr_mux),
+	SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, hphl_mux),
+	SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0, hphr_mux),
+	SND_SOC_DAPM_MUX("RDAC2 MUX", SND_SOC_NOPM, 0, 0, &rdac2_mux),
+	SND_SOC_DAPM_MUX("WSA Spk Switch", SND_SOC_NOPM, 0, 0, wsa_spk_mux),
+	SND_SOC_DAPM_MUX("Ext Spk Switch", SND_SOC_NOPM, 0, 0, &ext_spk_mux),
+	SND_SOC_DAPM_MUX("LINE_OUT", SND_SOC_NOPM, 0, 0, lo_mux),
+	SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux),
+
+	SND_SOC_DAPM_MIXER_E("HPHL DAC",
+		MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL,
+		0, msm_anlg_cdc_hphl_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("HPHR DAC",
+		MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL,
+		0, msm_anlg_cdc_hphr_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_DAC("SPK DAC", NULL, MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+			 7, 0),
+	SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL,
+		SND_SOC_NOPM, 0, 0, msm_anlg_cdc_lo_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SPK("Ext Spk", msm_anlg_cdc_codec_enable_spk_ext_pa),
+
+	SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+			    0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+			    1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+			    2, 0, msm_anlg_cdc_codec_enable_dig_clk,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("CP", MSM89XX_PMIC_ANALOG_NCP_EN, 0, 0,
+			    msm_anlg_cdc_codec_enable_charge_pump,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			    SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("EAR CP", MSM89XX_PMIC_ANALOG_NCP_EN, 4, 0,
+			    msm_anlg_cdc_codec_enable_charge_pump,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			    SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("RX_BIAS", 1, SND_SOC_NOPM,
+		0, 0, msm_anlg_cdc_codec_enable_rx_bias,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("SPK_RX_BIAS", 1, SND_SOC_NOPM, 0, 0,
+		msm_anlg_cdc_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("VDD_SPKDRV", SND_SOC_NOPM, 0, 0,
+			    sdm660_wcd_codec_enable_vdd_spkr,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
+		ON_DEMAND_MICBIAS, 0,
+		msm_anlg_cdc_codec_enable_on_demand_supply,
+		SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1",
+		MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal2",
+		MSM89XX_PMIC_ANALOG_MICB_2_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal3",
+		MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM89XX_PMIC_ANALOG_TX_1_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2_INP2",
+		NULL, MSM89XX_PMIC_ANALOG_TX_2_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2_INP3",
+		NULL, MSM89XX_PMIC_ANALOG_TX_3_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS External",
+		MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS External2",
+		MSM89XX_PMIC_ANALOG_MICB_2_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_micbias, SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_INPUT("AMIC2"),
+	SND_SOC_DAPM_INPUT("AMIC3"),
+	SND_SOC_DAPM_AIF_IN("PDM_IN_RX1", "PDM Playback",
+		0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PDM_IN_RX2", "PDM Playback",
+		0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PDM_IN_RX3", "PDM Playback",
+		0, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_OUTPUT("EAR"),
+	SND_SOC_DAPM_OUTPUT("WSA_SPK OUT"),
+	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
+	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT"),
+	SND_SOC_DAPM_AIF_OUT("ADC1_OUT", "PDM Capture",
+		0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("ADC2_OUT", "PDM Capture",
+		0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("ADC3_OUT", "PDM Capture",
+		0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct sdm660_cdc_reg_mask_val msm_anlg_cdc_reg_defaults[] = {
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
+};
+
+static const struct sdm660_cdc_reg_mask_val
+					msm_anlg_cdc_reg_defaults_2_0[] = {
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x28),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_BOOST_EN_CTL, 0x5F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO, 0x88),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
+};
+
+static const struct sdm660_cdc_reg_mask_val conga_wcd_reg_defaults[] = {
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x28),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE, 0x0A),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
+};
+
+static const struct sdm660_cdc_reg_mask_val cajon_wcd_reg_defaults[] = {
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0xA8),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_VCTRL, 0xA4),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET, 0x41),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA, 0xFA),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
+};
+
+static const struct sdm660_cdc_reg_mask_val cajon2p0_wcd_reg_defaults[] = {
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0xA2),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0xA8),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_VCTRL, 0xA4),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET, 0x41),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_EAR_STATUS, 0x10),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_BYPASS_MODE, 0x18),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA, 0xFA),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
+};
+
+static void msm_anlg_cdc_update_reg_defaults(struct snd_soc_codec *codec)
+{
+	u32 i, version;
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	version = get_codec_version(sdm660_cdc);
+	if (version == TOMBAK_1_0) {
+		for (i = 0; i < ARRAY_SIZE(msm_anlg_cdc_reg_defaults); i++)
+			snd_soc_write(codec, msm_anlg_cdc_reg_defaults[i].reg,
+					msm_anlg_cdc_reg_defaults[i].val);
+	} else if (version == TOMBAK_2_0) {
+		for (i = 0; i < ARRAY_SIZE(msm_anlg_cdc_reg_defaults_2_0); i++)
+			snd_soc_write(codec,
+				msm_anlg_cdc_reg_defaults_2_0[i].reg,
+				msm_anlg_cdc_reg_defaults_2_0[i].val);
+	} else if (version == CONGA) {
+		for (i = 0; i < ARRAY_SIZE(conga_wcd_reg_defaults); i++)
+			snd_soc_write(codec,
+				conga_wcd_reg_defaults[i].reg,
+				conga_wcd_reg_defaults[i].val);
+	} else if (version == CAJON) {
+		for (i = 0; i < ARRAY_SIZE(cajon_wcd_reg_defaults); i++)
+			snd_soc_write(codec,
+				cajon_wcd_reg_defaults[i].reg,
+				cajon_wcd_reg_defaults[i].val);
+	} else if (version == CAJON_2_0 || version == DIANGU
+				|| version == DRAX_CDC) {
+		for (i = 0; i < ARRAY_SIZE(cajon2p0_wcd_reg_defaults); i++)
+			snd_soc_write(codec,
+				cajon2p0_wcd_reg_defaults[i].reg,
+				cajon2p0_wcd_reg_defaults[i].val);
+	}
+}
+
+static const struct sdm660_cdc_reg_mask_val
+	msm_anlg_cdc_codec_reg_init_val[] = {
+
+	/* Initialize current threshold to 350MA
+	 * number of wait and run cycles to 4096
+	 */
+	{MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL, 0xFF, 0x12},
+	{MSM89XX_PMIC_ANALOG_RX_COM_OCP_COUNT, 0xFF, 0xFF},
+};
+
+static void msm_anlg_cdc_codec_init_cache(struct snd_soc_codec *codec)
+{
+	u32 i;
+
+	regcache_cache_only(codec->component.regmap, true);
+	/* update cache with POR values */
+	for (i = 0; i < ARRAY_SIZE(msm89xx_pmic_cdc_defaults); i++)
+		snd_soc_write(codec, msm89xx_pmic_cdc_defaults[i].reg,
+			      msm89xx_pmic_cdc_defaults[i].def);
+	regcache_cache_only(codec->component.regmap, false);
+}
+
+static void msm_anlg_cdc_codec_init_reg(struct snd_soc_codec *codec)
+{
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(msm_anlg_cdc_codec_reg_init_val); i++)
+		snd_soc_update_bits(codec,
+				    msm_anlg_cdc_codec_reg_init_val[i].reg,
+				    msm_anlg_cdc_codec_reg_init_val[i].mask,
+				    msm_anlg_cdc_codec_reg_init_val[i].val);
+}
+
+static int msm_anlg_cdc_bringup(struct snd_soc_codec *codec)
+{
+	snd_soc_write(codec,
+		MSM89XX_PMIC_DIGITAL_SEC_ACCESS,
+		0xA5);
+	snd_soc_write(codec, MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4, 0x01);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_SEC_ACCESS,
+		0xA5);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4, 0x01);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_DIGITAL_SEC_ACCESS,
+		0xA5);
+	snd_soc_write(codec, MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4, 0x00);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_SEC_ACCESS,
+		0xA5);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4, 0x00);
+
+	return 0;
+}
+
+static struct regulator *msm_anlg_cdc_find_regulator(
+				const struct sdm660_cdc_priv *sdm660_cdc,
+				const char *name)
+{
+	int i;
+
+	for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+		if (sdm660_cdc->supplies[i].supply &&
+		    !strcmp(sdm660_cdc->supplies[i].supply, name))
+			return sdm660_cdc->supplies[i].consumer;
+	}
+
+	dev_err(sdm660_cdc->dev, "Error: regulator not found:%s\n"
+				, name);
+	return NULL;
+}
+
+static int msm_anlg_cdc_device_down(struct snd_soc_codec *codec)
+{
+	struct msm_asoc_mach_data *pdata = NULL;
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+		snd_soc_codec_get_drvdata(codec);
+	unsigned int tx_1_en;
+	unsigned int tx_2_en;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+	dev_dbg(codec->dev, "%s: device down!\n", __func__);
+
+	tx_1_en = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_TX_1_EN);
+	tx_2_en = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_TX_2_EN);
+	tx_1_en = tx_1_en & 0x7f;
+	tx_2_en = tx_2_en & 0x7f;
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_TX_1_EN, tx_1_en);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_TX_2_EN, tx_2_en);
+	if (sdm660_cdc_priv->boost_option == BOOST_ON_FOREVER) {
+		if ((snd_soc_read(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL)
+			& 0x80) == 0) {
+			msm_anlg_cdc_dig_notifier_call(codec,
+						       DIG_CDC_EVENT_CLK_ON);
+			snd_soc_write(codec,
+				MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL,
+				0x0C, 0x0C);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+				0x84, 0x84);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL,
+				0x10, 0x10);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL,
+				0x1F, 0x1F);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+				0x90, 0x90);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+				0xFF, 0xFF);
+			/* Wait for 20us for boost settings to take effect */
+			usleep_range(20, 21);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL,
+				0xFF, 0xFF);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+				0xE9, 0xE9);
+		}
+	}
+	msm_anlg_cdc_boost_off(codec);
+	sdm660_cdc_priv->hph_mode = NORMAL_MODE;
+
+	/* 40ms to allow boost to discharge */
+	msleep(40);
+	/* Disable PA to avoid pop during codec bring up */
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
+			0x30, 0x00);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+			0x80, 0x00);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x20);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x20);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x12);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x93);
+
+	atomic_set(&pdata->int_mclk0_enabled, false);
+	msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_SSR_DOWN);
+	set_bit(BUS_DOWN, &sdm660_cdc_priv->status_mask);
+	snd_soc_card_change_online_state(codec->component.card, 0);
+
+	return 0;
+}
+
+static int msm_anlg_cdc_device_up(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+		snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s: device up!\n", __func__);
+
+	msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_SSR_UP);
+	clear_bit(BUS_DOWN, &sdm660_cdc_priv->status_mask);
+	snd_soc_card_change_online_state(codec->component.card, 1);
+	/* delay is required to make sure sound card state updated */
+	usleep_range(5000, 5100);
+
+	snd_soc_write(codec, MSM89XX_PMIC_DIGITAL_INT_EN_SET,
+				MSM89XX_PMIC_DIGITAL_INT_EN_SET__POR);
+	snd_soc_write(codec, MSM89XX_PMIC_DIGITAL_INT_EN_CLR,
+				MSM89XX_PMIC_DIGITAL_INT_EN_CLR__POR);
+
+	msm_anlg_cdc_set_boost_v(codec);
+	msm_anlg_cdc_set_micb_v(codec);
+	if (sdm660_cdc_priv->boost_option == BOOST_ON_FOREVER)
+		msm_anlg_cdc_boost_on(codec);
+	else if (sdm660_cdc_priv->boost_option == BYPASS_ALWAYS)
+		msm_anlg_cdc_bypass_on(codec);
+
+	msm_anlg_cdc_configure_cap(codec, false, false);
+	wcd_mbhc_stop(&sdm660_cdc_priv->mbhc);
+	wcd_mbhc_deinit(&sdm660_cdc_priv->mbhc);
+	ret = wcd_mbhc_init(&sdm660_cdc_priv->mbhc, codec, &mbhc_cb,
+			    &intr_ids, wcd_mbhc_registers, true);
+	if (ret)
+		dev_err(codec->dev, "%s: mbhc initialization failed\n",
+			__func__);
+	else
+		wcd_mbhc_start(&sdm660_cdc_priv->mbhc,
+			sdm660_cdc_priv->mbhc.mbhc_cfg);
+
+	return 0;
+}
+
+static int sdm660_cdc_notifier_service_cb(struct notifier_block *nb,
+					     unsigned long opcode, void *ptr)
+{
+	struct snd_soc_codec *codec;
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+				container_of(nb, struct sdm660_cdc_priv,
+					     audio_ssr_nb);
+	bool adsp_ready = false;
+	bool timedout;
+	unsigned long timeout;
+
+	codec = sdm660_cdc_priv->codec;
+	dev_dbg(codec->dev, "%s: Service opcode 0x%lx\n", __func__, opcode);
+
+	switch (opcode) {
+	case AUDIO_NOTIFIER_SERVICE_DOWN:
+		dev_dbg(codec->dev,
+			"ADSP is about to power down. teardown/reset codec\n");
+		msm_anlg_cdc_device_down(codec);
+		break;
+	case AUDIO_NOTIFIER_SERVICE_UP:
+		dev_dbg(codec->dev,
+			"ADSP is about to power up. bring up codec\n");
+
+		if (!q6core_is_adsp_ready()) {
+			dev_dbg(codec->dev,
+				"ADSP isn't ready\n");
+			timeout = jiffies +
+				  msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+			while (!(timedout = time_after(jiffies, timeout))) {
+				if (!q6core_is_adsp_ready()) {
+					dev_dbg(codec->dev,
+						"ADSP isn't ready\n");
+				} else {
+					dev_dbg(codec->dev,
+						"ADSP is ready\n");
+					adsp_ready = true;
+					goto powerup;
+				}
+			}
+		} else {
+			adsp_ready = true;
+			dev_dbg(codec->dev, "%s: DSP is ready\n", __func__);
+		}
+powerup:
+		if (adsp_ready)
+			msm_anlg_cdc_device_up(codec);
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+int msm_anlg_cdc_hs_detect(struct snd_soc_codec *codec,
+			   struct wcd_mbhc_config *mbhc_cfg)
+{
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+		snd_soc_codec_get_drvdata(codec);
+
+	return wcd_mbhc_start(&sdm660_cdc_priv->mbhc, mbhc_cfg);
+}
+EXPORT_SYMBOL(msm_anlg_cdc_hs_detect);
+
+void msm_anlg_cdc_hs_detect_exit(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+		snd_soc_codec_get_drvdata(codec);
+
+	wcd_mbhc_stop(&sdm660_cdc_priv->mbhc);
+}
+EXPORT_SYMBOL(msm_anlg_cdc_hs_detect_exit);
+
+void msm_anlg_cdc_update_int_spk_boost(bool enable)
+{
+	pr_debug("%s: enable = %d\n", __func__, enable);
+	spkr_boost_en = enable;
+}
+EXPORT_SYMBOL(msm_anlg_cdc_update_int_spk_boost);
+
+static void msm_anlg_cdc_set_micb_v(struct snd_soc_codec *codec)
+{
+
+	struct sdm660_cdc_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+	struct sdm660_cdc_pdata *pdata = sdm660_cdc->dev->platform_data;
+	u8 reg_val;
+
+	reg_val = VOLTAGE_CONVERTER(pdata->micbias.cfilt1_mv, MICBIAS_MIN_VAL,
+			MICBIAS_STEP_SIZE);
+	dev_dbg(codec->dev, "cfilt1_mv %d reg_val %x\n",
+			(u32)pdata->micbias.cfilt1_mv, reg_val);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MICB_1_VAL,
+			0xF8, (reg_val << 3));
+}
+
+static void msm_anlg_cdc_set_boost_v(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+				snd_soc_codec_get_drvdata(codec);
+
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_OUTPUT_VOLTAGE,
+			0x1F, sdm660_cdc_priv->boost_voltage);
+}
+
+static void msm_anlg_cdc_configure_cap(struct snd_soc_codec *codec,
+				       bool micbias1, bool micbias2)
+{
+
+	struct msm_asoc_mach_data *pdata = NULL;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+
+	pr_debug("\n %s: micbias1 %x micbias2 = %d\n", __func__, micbias1,
+			micbias2);
+	if (micbias1 && micbias2) {
+		if ((pdata->micbias1_cap_mode
+		     == MICBIAS_EXT_BYP_CAP) ||
+		    (pdata->micbias2_cap_mode
+		     == MICBIAS_EXT_BYP_CAP))
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MICB_1_EN,
+				0x40, (MICBIAS_EXT_BYP_CAP << 6));
+		else
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MICB_1_EN,
+				0x40, (MICBIAS_NO_EXT_BYP_CAP << 6));
+	} else if (micbias2) {
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MICB_1_EN,
+				0x40, (pdata->micbias2_cap_mode << 6));
+	} else if (micbias1) {
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MICB_1_EN,
+				0x40, (pdata->micbias1_cap_mode << 6));
+	} else {
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MICB_1_EN,
+				0x40, 0x00);
+	}
+}
+
+static ssize_t msm_anlg_codec_version_read(struct snd_info_entry *entry,
+					   void *file_private_data,
+					   struct file *file,
+					   char __user *buf, size_t count,
+					   loff_t pos)
+{
+	struct sdm660_cdc_priv *sdm660_cdc_priv;
+	char buffer[MSM_ANLG_CDC_VERSION_ENTRY_SIZE];
+	int len = 0;
+
+	sdm660_cdc_priv = (struct sdm660_cdc_priv *) entry->private_data;
+	if (!sdm660_cdc_priv) {
+		pr_err("%s: sdm660_cdc_priv is null\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (get_codec_version(sdm660_cdc_priv)) {
+	case DRAX_CDC:
+		len = snprintf(buffer, sizeof(buffer), "DRAX-CDC_1_0\n");
+		break;
+	default:
+		len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
+	}
+
+	return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops msm_anlg_codec_info_ops = {
+	.read = msm_anlg_codec_version_read,
+};
+
+/*
+ * msm_anlg_codec_info_create_codec_entry - creates pmic_analog module
+ * @codec_root: The parent directory
+ * @codec: Codec instance
+ *
+ * Creates pmic_analog module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int msm_anlg_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+					   struct snd_soc_codec *codec)
+{
+	struct snd_info_entry *version_entry;
+	struct sdm660_cdc_priv *sdm660_cdc_priv;
+	struct snd_soc_card *card;
+	int ret;
+
+	if (!codec_root || !codec)
+		return -EINVAL;
+
+	sdm660_cdc_priv = snd_soc_codec_get_drvdata(codec);
+	card = codec->component.card;
+	sdm660_cdc_priv->entry = snd_register_module_info(codec_root->module,
+							     "spmi0-03",
+							     codec_root);
+	if (!sdm660_cdc_priv->entry) {
+		dev_dbg(codec->dev, "%s: failed to create pmic_analog entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry = snd_info_create_card_entry(card->snd_card,
+						   "version",
+						   sdm660_cdc_priv->entry);
+	if (!version_entry) {
+		dev_dbg(codec->dev, "%s: failed to create pmic_analog version entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry->private_data = sdm660_cdc_priv;
+	version_entry->size = MSM_ANLG_CDC_VERSION_ENTRY_SIZE;
+	version_entry->content = SNDRV_INFO_CONTENT_DATA;
+	version_entry->c.ops = &msm_anlg_codec_info_ops;
+
+	if (snd_info_register(version_entry) < 0) {
+		snd_info_free_entry(version_entry);
+		return -ENOMEM;
+	}
+	sdm660_cdc_priv->version_entry = version_entry;
+
+	sdm660_cdc_priv->audio_ssr_nb.notifier_call =
+				sdm660_cdc_notifier_service_cb;
+	ret = audio_notifier_register("pmic_analog_cdc",
+				      AUDIO_NOTIFIER_ADSP_DOMAIN,
+				      &sdm660_cdc_priv->audio_ssr_nb);
+	if (ret < 0) {
+		pr_err("%s: Audio notifier register failed ret = %d\n",
+			__func__, ret);
+		return ret;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(msm_anlg_codec_info_create_codec_entry);
+
+static int msm_anlg_cdc_soc_probe(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	int ret;
+
+	sdm660_cdc = dev_get_drvdata(codec->dev);
+	sdm660_cdc->codec = codec;
+
+	/* codec resmgr module init */
+	sdm660_cdc->spkdrv_reg =
+				msm_anlg_cdc_find_regulator(sdm660_cdc,
+						MSM89XX_VDD_SPKDRV_NAME);
+	sdm660_cdc->pmic_rev =
+				snd_soc_read(codec,
+					     MSM89XX_PMIC_DIGITAL_REVISION1);
+	sdm660_cdc->codec_version =
+				snd_soc_read(codec,
+					MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE);
+	sdm660_cdc->analog_major_rev =
+				snd_soc_read(codec,
+					     MSM89XX_PMIC_ANALOG_REVISION4);
+
+	if (sdm660_cdc->codec_version == CONGA) {
+		dev_dbg(codec->dev, "%s :Conga REV: %d\n", __func__,
+					sdm660_cdc->codec_version);
+		sdm660_cdc->ext_spk_boost_set = true;
+	} else {
+		dev_dbg(codec->dev, "%s :PMIC REV: %d\n", __func__,
+					sdm660_cdc->pmic_rev);
+		if (sdm660_cdc->pmic_rev == TOMBAK_1_0 &&
+			sdm660_cdc->codec_version == CAJON_2_0) {
+			if (sdm660_cdc->analog_major_rev == 0x02) {
+				sdm660_cdc->codec_version = DRAX_CDC;
+				dev_dbg(codec->dev,
+					"%s : Drax codec detected\n", __func__);
+			} else {
+				sdm660_cdc->codec_version = DIANGU;
+				dev_dbg(codec->dev, "%s : Diangu detected\n",
+					__func__);
+			}
+		} else if (sdm660_cdc->pmic_rev == TOMBAK_1_0 &&
+			(snd_soc_read(codec, MSM89XX_PMIC_ANALOG_NCP_FBCTRL)
+			 & 0x80)) {
+			sdm660_cdc->codec_version = CAJON;
+			dev_dbg(codec->dev, "%s : Cajon detected\n", __func__);
+		} else if (sdm660_cdc->pmic_rev == TOMBAK_2_0 &&
+			(snd_soc_read(codec, MSM89XX_PMIC_ANALOG_NCP_FBCTRL)
+			 & 0x80)) {
+			sdm660_cdc->codec_version = CAJON_2_0;
+			dev_dbg(codec->dev, "%s : Cajon 2.0 detected\n",
+						__func__);
+		}
+	}
+	/*
+	 * set to default boost option BOOST_SWITCH, user mixer path can change
+	 * it to BOOST_ALWAYS or BOOST_BYPASS based on solution chosen.
+	 */
+	sdm660_cdc->boost_option = BOOST_SWITCH;
+	sdm660_cdc->hph_mode = NORMAL_MODE;
+
+	msm_anlg_cdc_dt_parse_boost_info(codec);
+	msm_anlg_cdc_set_boost_v(codec);
+
+	snd_soc_add_codec_controls(codec, impedance_detect_controls,
+				   ARRAY_SIZE(impedance_detect_controls));
+	snd_soc_add_codec_controls(codec, hph_type_detect_controls,
+				  ARRAY_SIZE(hph_type_detect_controls));
+
+	msm_anlg_cdc_bringup(codec);
+	msm_anlg_cdc_codec_init_cache(codec);
+	msm_anlg_cdc_codec_init_reg(codec);
+	msm_anlg_cdc_update_reg_defaults(codec);
+
+	wcd9xxx_spmi_set_codec(codec);
+
+	sdm660_cdc->on_demand_list[ON_DEMAND_MICBIAS].supply =
+				msm_anlg_cdc_find_regulator(
+				sdm660_cdc,
+				on_demand_supply_name[ON_DEMAND_MICBIAS]);
+	atomic_set(&sdm660_cdc->on_demand_list[ON_DEMAND_MICBIAS].ref,
+		   0);
+
+	sdm660_cdc->fw_data = devm_kzalloc(codec->dev,
+					sizeof(*(sdm660_cdc->fw_data)),
+					GFP_KERNEL);
+	if (!sdm660_cdc->fw_data)
+		return -ENOMEM;
+
+	set_bit(WCD9XXX_MBHC_CAL, sdm660_cdc->fw_data->cal_bit);
+	ret = wcd_cal_create_hwdep(sdm660_cdc->fw_data,
+			WCD9XXX_CODEC_HWDEP_NODE, codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret);
+		return ret;
+	}
+
+	wcd_mbhc_init(&sdm660_cdc->mbhc, codec, &mbhc_cb, &intr_ids,
+		      wcd_mbhc_registers, true);
+
+	sdm660_cdc->int_mclk0_enabled = false;
+	/*Update speaker boost configuration*/
+	sdm660_cdc->spk_boost_set = spkr_boost_en;
+	pr_debug("%s: speaker boost configured = %d\n",
+			__func__, sdm660_cdc->spk_boost_set);
+
+	/* Set initial MICBIAS voltage level */
+	msm_anlg_cdc_set_micb_v(codec);
+
+	/* Set initial cap mode */
+	msm_anlg_cdc_configure_cap(codec, false, false);
+
+	snd_soc_dapm_ignore_suspend(dapm, "PDM Playback");
+	snd_soc_dapm_ignore_suspend(dapm, "PDM Capture");
+
+	return 0;
+}
+
+static int msm_anlg_cdc_soc_remove(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+					dev_get_drvdata(codec->dev);
+
+	sdm660_cdc_priv->spkdrv_reg = NULL;
+	sdm660_cdc_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL;
+	atomic_set(&sdm660_cdc_priv->on_demand_list[ON_DEMAND_MICBIAS].ref,
+		   0);
+	wcd_mbhc_deinit(&sdm660_cdc_priv->mbhc);
+
+	return 0;
+}
+
+static int msm_anlg_cdc_enable_static_supplies_to_optimum(
+				struct sdm660_cdc_priv *sdm660_cdc,
+				struct sdm660_cdc_pdata *pdata)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+		if (pdata->regulator[i].ondemand)
+			continue;
+		if (regulator_count_voltages(
+				sdm660_cdc->supplies[i].consumer) <=	0)
+			continue;
+
+		ret = regulator_set_voltage(
+				sdm660_cdc->supplies[i].consumer,
+				pdata->regulator[i].min_uv,
+				pdata->regulator[i].max_uv);
+		if (ret) {
+			dev_err(sdm660_cdc->dev,
+				"Setting volt failed for regulator %s err %d\n",
+				sdm660_cdc->supplies[i].supply, ret);
+		}
+
+		ret = regulator_set_load(sdm660_cdc->supplies[i].consumer,
+			pdata->regulator[i].optimum_ua);
+		dev_dbg(sdm660_cdc->dev, "Regulator %s set optimum mode\n",
+			 sdm660_cdc->supplies[i].supply);
+	}
+
+	return ret;
+}
+
+static int msm_anlg_cdc_disable_static_supplies_to_optimum(
+			struct sdm660_cdc_priv *sdm660_cdc,
+			struct sdm660_cdc_pdata *pdata)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+		if (pdata->regulator[i].ondemand)
+			continue;
+		if (regulator_count_voltages(
+				sdm660_cdc->supplies[i].consumer) <=	0)
+			continue;
+		regulator_set_voltage(sdm660_cdc->supplies[i].consumer, 0,
+				pdata->regulator[i].max_uv);
+		regulator_set_load(sdm660_cdc->supplies[i].consumer, 0);
+		dev_dbg(sdm660_cdc->dev, "Regulator %s set optimum mode\n",
+				 sdm660_cdc->supplies[i].supply);
+	}
+
+	return ret;
+}
+
+static int msm_anlg_cdc_suspend(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+	struct sdm660_cdc_pdata *sdm660_cdc_pdata =
+					sdm660_cdc->dev->platform_data;
+
+	msm_anlg_cdc_disable_static_supplies_to_optimum(sdm660_cdc,
+							sdm660_cdc_pdata);
+	return 0;
+}
+
+static int msm_anlg_cdc_resume(struct snd_soc_codec *codec)
+{
+	struct msm_asoc_mach_data *pdata = NULL;
+	struct sdm660_cdc_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+	struct sdm660_cdc_pdata *sdm660_cdc_pdata =
+					sdm660_cdc->dev->platform_data;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+	msm_anlg_cdc_enable_static_supplies_to_optimum(sdm660_cdc,
+						       sdm660_cdc_pdata);
+	return 0;
+}
+
+static struct regmap *msm_anlg_get_regmap(struct device *dev)
+{
+	return dev_get_regmap(dev->parent, NULL);
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_sdm660_cdc = {
+	.probe	= msm_anlg_cdc_soc_probe,
+	.remove	= msm_anlg_cdc_soc_remove,
+	.suspend = msm_anlg_cdc_suspend,
+	.resume = msm_anlg_cdc_resume,
+	.reg_word_size = 1,
+	.controls = msm_anlg_cdc_snd_controls,
+	.num_controls = ARRAY_SIZE(msm_anlg_cdc_snd_controls),
+	.dapm_widgets = msm_anlg_cdc_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(msm_anlg_cdc_dapm_widgets),
+	.dapm_routes = audio_map,
+	.num_dapm_routes = ARRAY_SIZE(audio_map),
+	.get_regmap = msm_anlg_get_regmap,
+};
+
+static int msm_anlg_cdc_init_supplies(struct sdm660_cdc_priv *sdm660_cdc,
+				struct sdm660_cdc_pdata *pdata)
+{
+	int ret;
+	int i;
+
+	sdm660_cdc->supplies = devm_kzalloc(sdm660_cdc->dev,
+					sizeof(struct regulator_bulk_data) *
+					ARRAY_SIZE(pdata->regulator),
+					GFP_KERNEL);
+	if (!sdm660_cdc->supplies) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	sdm660_cdc->num_of_supplies = 0;
+	if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
+		dev_err(sdm660_cdc->dev, "%s: Array Size out of bound\n",
+			__func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		if (pdata->regulator[i].name) {
+			sdm660_cdc->supplies[i].supply =
+						pdata->regulator[i].name;
+			sdm660_cdc->num_of_supplies++;
+		}
+	}
+
+	ret = devm_regulator_bulk_get(sdm660_cdc->dev,
+				      sdm660_cdc->num_of_supplies,
+				      sdm660_cdc->supplies);
+	if (ret != 0) {
+		dev_err(sdm660_cdc->dev,
+			"Failed to get supplies: err = %d\n",
+			ret);
+		goto err_supplies;
+	}
+
+	for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+		if (regulator_count_voltages(
+			sdm660_cdc->supplies[i].consumer) <= 0)
+			continue;
+		ret = regulator_set_voltage(sdm660_cdc->supplies[i].consumer,
+					    pdata->regulator[i].min_uv,
+					    pdata->regulator[i].max_uv);
+		if (ret) {
+			dev_err(sdm660_cdc->dev,
+				"Setting regulator voltage failed for regulator %s err = %d\n",
+				sdm660_cdc->supplies[i].supply, ret);
+			goto err_supplies;
+		}
+		ret = regulator_set_load(sdm660_cdc->supplies[i].consumer,
+					 pdata->regulator[i].optimum_ua);
+		if (ret < 0) {
+			dev_err(sdm660_cdc->dev,
+				"Setting regulator optimum mode failed for regulator %s err = %d\n",
+				sdm660_cdc->supplies[i].supply, ret);
+			goto err_supplies;
+		} else {
+			ret = 0;
+		}
+	}
+
+	return ret;
+
+err_supplies:
+	kfree(sdm660_cdc->supplies);
+err:
+	return ret;
+}
+
+static int msm_anlg_cdc_enable_static_supplies(
+					struct sdm660_cdc_priv *sdm660_cdc,
+					struct sdm660_cdc_pdata *pdata)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+		if (pdata->regulator[i].ondemand)
+			continue;
+		ret = regulator_enable(sdm660_cdc->supplies[i].consumer);
+		if (ret) {
+			dev_err(sdm660_cdc->dev, "Failed to enable %s\n",
+			       sdm660_cdc->supplies[i].supply);
+			break;
+		}
+		dev_dbg(sdm660_cdc->dev, "Enabled regulator %s\n",
+				 sdm660_cdc->supplies[i].supply);
+	}
+
+	while (ret && --i)
+		if (!pdata->regulator[i].ondemand)
+			regulator_disable(sdm660_cdc->supplies[i].consumer);
+	return ret;
+}
+
+static void msm_anlg_cdc_disable_supplies(struct sdm660_cdc_priv *sdm660_cdc,
+				     struct sdm660_cdc_pdata *pdata)
+{
+	int i;
+
+	regulator_bulk_disable(sdm660_cdc->num_of_supplies,
+			       sdm660_cdc->supplies);
+	for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+		if (regulator_count_voltages(
+				sdm660_cdc->supplies[i].consumer) <= 0)
+			continue;
+		regulator_set_voltage(sdm660_cdc->supplies[i].consumer, 0,
+				pdata->regulator[i].max_uv);
+		regulator_set_load(sdm660_cdc->supplies[i].consumer, 0);
+	}
+	regulator_bulk_free(sdm660_cdc->num_of_supplies,
+			    sdm660_cdc->supplies);
+	kfree(sdm660_cdc->supplies);
+}
+
+static const struct of_device_id sdm660_codec_of_match[] = {
+	{ .compatible = "qcom,pmic-analog-codec", },
+	{},
+};
+
+static void msm_anlg_add_child_devices(struct work_struct *work)
+{
+	struct sdm660_cdc_priv *pdata;
+	struct platform_device *pdev;
+	struct device_node *node;
+	struct msm_dig_ctrl_data *dig_ctrl_data = NULL, *temp;
+	int ret, ctrl_num = 0;
+	struct msm_dig_ctrl_platform_data *platdata;
+	char plat_dev_name[MSM_DIG_CDC_STRING_LEN];
+
+	pdata = container_of(work, struct sdm660_cdc_priv,
+			     msm_anlg_add_child_devices_work);
+	if (!pdata) {
+		pr_err("%s: Memory for pdata does not exist\n",
+			__func__);
+		return;
+	}
+	if (!pdata->dev->of_node) {
+		dev_err(pdata->dev,
+			"%s: DT node for pdata does not exist\n", __func__);
+		return;
+	}
+
+	platdata = &pdata->dig_plat_data;
+
+	for_each_child_of_node(pdata->dev->of_node, node) {
+		if (!strcmp(node->name, "msm-dig-codec"))
+			strlcpy(plat_dev_name, "msm_digital_codec",
+				(MSM_DIG_CDC_STRING_LEN - 1));
+		else
+			continue;
+
+		pdev = platform_device_alloc(plat_dev_name, -1);
+		if (!pdev) {
+			dev_err(pdata->dev, "%s: pdev memory alloc failed\n",
+				__func__);
+			ret = -ENOMEM;
+			goto err;
+		}
+		pdev->dev.parent = pdata->dev;
+		pdev->dev.of_node = node;
+
+		if (!strcmp(node->name, "msm-dig-codec")) {
+			ret = platform_device_add_data(pdev, platdata,
+						       sizeof(*platdata));
+			if (ret) {
+				dev_err(&pdev->dev,
+					"%s: cannot add plat data ctrl:%d\n",
+					__func__, ctrl_num);
+				goto fail_pdev_add;
+			}
+		}
+
+		ret = platform_device_add(pdev);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"%s: Cannot add platform device\n",
+				__func__);
+			goto fail_pdev_add;
+		}
+
+		if (!strcmp(node->name, "msm-dig-codec")) {
+			temp = krealloc(dig_ctrl_data,
+					(ctrl_num + 1) * sizeof(
+					struct msm_dig_ctrl_data),
+					GFP_KERNEL);
+			if (!temp) {
+				dev_err(&pdev->dev, "out of memory\n");
+				ret = -ENOMEM;
+				goto err;
+			}
+			dig_ctrl_data = temp;
+			dig_ctrl_data[ctrl_num].dig_pdev = pdev;
+			ctrl_num++;
+			dev_dbg(&pdev->dev,
+				"%s: Added digital codec device(s)\n",
+				__func__);
+			pdata->dig_ctrl_data = dig_ctrl_data;
+		}
+	}
+
+	return;
+fail_pdev_add:
+	platform_device_put(pdev);
+err:
+	return;
+}
+
+static int msm_anlg_cdc_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct sdm660_cdc_priv *sdm660_cdc = NULL;
+	struct sdm660_cdc_pdata *pdata;
+	int adsp_state;
+
+	adsp_state = apr_get_subsys_state();
+	if (adsp_state != APR_SUBSYS_LOADED) {
+		dev_err(&pdev->dev, "Adsp is not loaded yet %d\n",
+			adsp_state);
+		return -EPROBE_DEFER;
+	}
+	device_init_wakeup(&pdev->dev, true);
+
+	if (pdev->dev.of_node) {
+		dev_dbg(&pdev->dev, "%s:Platform data from device tree\n",
+			__func__);
+		pdata = msm_anlg_cdc_populate_dt_pdata(&pdev->dev);
+		pdev->dev.platform_data = pdata;
+	} else {
+		dev_dbg(&pdev->dev, "%s:Platform data from board file\n",
+			__func__);
+		pdata = pdev->dev.platform_data;
+	}
+	if (pdata == NULL) {
+		dev_err(&pdev->dev, "%s:Platform data failed to populate\n",
+			__func__);
+		goto rtn;
+	}
+	sdm660_cdc = devm_kzalloc(&pdev->dev, sizeof(struct sdm660_cdc_priv),
+				     GFP_KERNEL);
+	if (sdm660_cdc == NULL) {
+		ret = -ENOMEM;
+		goto rtn;
+	}
+
+	sdm660_cdc->dev = &pdev->dev;
+	ret = msm_anlg_cdc_init_supplies(sdm660_cdc, pdata);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: Fail to enable Codec supplies\n",
+			__func__);
+		goto rtn;
+	}
+	ret = msm_anlg_cdc_enable_static_supplies(sdm660_cdc, pdata);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"%s: Fail to enable Codec pre-reset supplies\n",
+			__func__);
+		goto rtn;
+	}
+	/* Allow supplies to be ready */
+	usleep_range(5, 6);
+
+	wcd9xxx_spmi_set_dev(pdev, 0);
+	wcd9xxx_spmi_set_dev(pdev, 1);
+	if (wcd9xxx_spmi_irq_init()) {
+		dev_err(&pdev->dev,
+			"%s: irq initialization failed\n", __func__);
+	} else {
+		dev_dbg(&pdev->dev,
+			"%s: irq initialization passed\n", __func__);
+	}
+	dev_set_drvdata(&pdev->dev, sdm660_cdc);
+
+	ret = snd_soc_register_codec(&pdev->dev,
+				     &soc_codec_dev_sdm660_cdc,
+				     msm_anlg_cdc_i2s_dai,
+				     ARRAY_SIZE(msm_anlg_cdc_i2s_dai));
+	if (ret) {
+		dev_err(&pdev->dev,
+			"%s:snd_soc_register_codec failed with error %d\n",
+			__func__, ret);
+		goto err_supplies;
+	}
+	BLOCKING_INIT_NOTIFIER_HEAD(&sdm660_cdc->notifier);
+	BLOCKING_INIT_NOTIFIER_HEAD(&sdm660_cdc->notifier_mbhc);
+
+	sdm660_cdc->dig_plat_data.handle = (void *) sdm660_cdc;
+	sdm660_cdc->dig_plat_data.update_clkdiv = update_clkdiv;
+	sdm660_cdc->dig_plat_data.get_cdc_version = get_cdc_version;
+	sdm660_cdc->dig_plat_data.register_notifier =
+					msm_anlg_cdc_dig_register_notifier;
+	INIT_WORK(&sdm660_cdc->msm_anlg_add_child_devices_work,
+		  msm_anlg_add_child_devices);
+	schedule_work(&sdm660_cdc->msm_anlg_add_child_devices_work);
+
+	return ret;
+err_supplies:
+	msm_anlg_cdc_disable_supplies(sdm660_cdc, pdata);
+rtn:
+	return ret;
+}
+
+static int msm_anlg_cdc_remove(struct platform_device *pdev)
+{
+	struct sdm660_cdc_priv *sdm660_cdc = dev_get_drvdata(&pdev->dev);
+	struct sdm660_cdc_pdata *pdata = sdm660_cdc->dev->platform_data;
+
+	snd_soc_unregister_codec(&pdev->dev);
+	msm_anlg_cdc_disable_supplies(sdm660_cdc, pdata);
+	return 0;
+}
+
+static struct platform_driver msm_anlg_codec_driver = {
+	.driver		= {
+		.owner          = THIS_MODULE,
+		.name           = DRV_NAME,
+		.of_match_table = of_match_ptr(sdm660_codec_of_match)
+	},
+	.probe          = msm_anlg_cdc_probe,
+	.remove         = msm_anlg_cdc_remove,
+};
+module_platform_driver(msm_anlg_codec_driver);
+
+MODULE_DESCRIPTION("MSM Audio Analog codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h
new file mode 100644
index 0000000..0c9e9a6
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h
@@ -0,0 +1,237 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef MSM_ANALOG_CDC_H
+#define MSM_ANALOG_CDC_H
+
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/q6afe-v2.h>
+#include "../wcd-mbhc-v2.h"
+#include "../wcdcal-hwdep.h"
+#include "sdm660-cdc-registers.h"
+
+#define MICBIAS_EXT_BYP_CAP 0x00
+#define MICBIAS_NO_EXT_BYP_CAP 0x01
+
+#define MSM89XX_NUM_IRQ_REGS	2
+#define MAX_REGULATOR		7
+#define MSM89XX_REG_VAL(reg, val)	{reg, 0, val}
+
+#define MSM89XX_VDD_SPKDRV_NAME "cdc-vdd-spkdrv"
+
+#define DEFAULT_MULTIPLIER 800
+#define DEFAULT_GAIN 9
+#define DEFAULT_OFFSET 100
+
+extern const u8 msm89xx_pmic_cdc_reg_readable[MSM89XX_PMIC_CDC_CACHE_SIZE];
+extern const u8 msm89xx_cdc_core_reg_readable[MSM89XX_CDC_CORE_CACHE_SIZE];
+extern struct regmap_config msm89xx_cdc_core_regmap_config;
+extern struct regmap_config msm89xx_pmic_cdc_regmap_config;
+
+enum wcd_curr_ref {
+	I_h4_UA = 0,
+	I_pt5_UA,
+	I_14_UA,
+	I_l4_UA,
+	I_1_UA,
+};
+
+enum wcd_mbhc_imp_det_pin {
+	WCD_MBHC_DET_NONE = 0,
+	WCD_MBHC_DET_HPHL,
+	WCD_MBHC_DET_HPHR,
+	WCD_MBHC_DET_BOTH,
+};
+
+
+/* Each micbias can be assigned to one of three cfilters
+ * Vbatt_min >= .15V + ldoh_v
+ * ldoh_v >= .15v + cfiltx_mv
+ * If ldoh_v = 1.95 160 mv < cfiltx_mv < 1800 mv
+ * If ldoh_v = 2.35 200 mv < cfiltx_mv < 2200 mv
+ * If ldoh_v = 2.75 240 mv < cfiltx_mv < 2600 mv
+ * If ldoh_v = 2.85 250 mv < cfiltx_mv < 2700 mv
+ */
+
+struct wcd_micbias_setting {
+	u8 ldoh_v;
+	u32 cfilt1_mv; /* in mv */
+	u32 cfilt2_mv; /* in mv */
+	u32 cfilt3_mv; /* in mv */
+	/* Different WCD9xxx series codecs may not
+	 * have 4 mic biases. If a codec has fewer
+	 * mic biases, some of these properties will
+	 * not be used.
+	 */
+	u8 bias1_cfilt_sel;
+	u8 bias2_cfilt_sel;
+	u8 bias3_cfilt_sel;
+	u8 bias4_cfilt_sel;
+	u8 bias1_cap_mode;
+	u8 bias2_cap_mode;
+	u8 bias3_cap_mode;
+	u8 bias4_cap_mode;
+	bool bias2_is_headset_only;
+};
+
+enum sdm660_cdc_pid_current {
+	MSM89XX_PID_MIC_2P5_UA,
+	MSM89XX_PID_MIC_5_UA,
+	MSM89XX_PID_MIC_10_UA,
+	MSM89XX_PID_MIC_20_UA,
+};
+
+struct sdm660_cdc_reg_mask_val {
+	u16	reg;
+	u8	mask;
+	u8	val;
+};
+
+enum {
+	/* INTR_REG 0 - Digital Periph */
+	MSM89XX_IRQ_SPKR_CNP = 0,
+	MSM89XX_IRQ_SPKR_CLIP,
+	MSM89XX_IRQ_SPKR_OCP,
+	MSM89XX_IRQ_MBHC_INSREM_DET1,
+	MSM89XX_IRQ_MBHC_RELEASE,
+	MSM89XX_IRQ_MBHC_PRESS,
+	MSM89XX_IRQ_MBHC_INSREM_DET,
+	MSM89XX_IRQ_MBHC_HS_DET,
+	/* INTR_REG 1 - Analog Periph */
+	MSM89XX_IRQ_EAR_OCP,
+	MSM89XX_IRQ_HPHR_OCP,
+	MSM89XX_IRQ_HPHL_OCP,
+	MSM89XX_IRQ_EAR_CNP,
+	MSM89XX_IRQ_HPHR_CNP,
+	MSM89XX_IRQ_HPHL_CNP,
+	MSM89XX_NUM_IRQS,
+};
+
+enum {
+	ON_DEMAND_MICBIAS = 0,
+	ON_DEMAND_SPKDRV,
+	ON_DEMAND_SUPPLIES_MAX,
+};
+
+/*
+ * The delay list is per codec HW specification.
+ * Please add delay in the list in the future instead
+ * of magic number
+ */
+enum {
+	CODEC_DELAY_1_MS = 1000,
+	CODEC_DELAY_1_1_MS  = 1100,
+};
+
+struct sdm660_cdc_regulator {
+	const char *name;
+	int min_uv;
+	int max_uv;
+	int optimum_ua;
+	bool ondemand;
+	struct regulator *regulator;
+};
+
+struct on_demand_supply {
+	struct regulator *supply;
+	atomic_t ref;
+};
+
+struct wcd_imped_i_ref {
+	enum wcd_curr_ref curr_ref;
+	int min_val;
+	int multiplier;
+	int gain_adj;
+	int offset;
+};
+
+enum sdm660_cdc_micbias_num {
+	MSM89XX_MICBIAS1 = 0,
+};
+
+/* Hold instance to digital codec platform device */
+struct msm_dig_ctrl_data {
+	struct platform_device *dig_pdev;
+};
+
+struct msm_dig_ctrl_platform_data {
+	void *handle;
+	void (*update_clkdiv)(void *handle, int val);
+	int (*get_cdc_version)(void *handle);
+	int (*register_notifier)(void *handle,
+				 struct notifier_block *nblock,
+				 bool enable);
+};
+
+struct sdm660_cdc_priv {
+	struct device *dev;
+	u32 num_of_supplies;
+	struct regulator_bulk_data *supplies;
+	struct snd_soc_codec *codec;
+	struct work_struct msm_anlg_add_child_devices_work;
+	struct msm_dig_ctrl_platform_data dig_plat_data;
+	/* digital codec data structure */
+	struct msm_dig_ctrl_data *dig_ctrl_data;
+	struct blocking_notifier_head notifier;
+	u16 pmic_rev;
+	u16 codec_version;
+	u16 analog_major_rev;
+	u32 boost_voltage;
+	u32 adc_count;
+	u32 rx_bias_count;
+	bool int_mclk0_enabled;
+	u16 boost_option;
+	/* mode to select hd2 */
+	u32 hph_mode;
+	/* compander used for each rx chain */
+	bool spk_boost_set;
+	bool ear_pa_boost_set;
+	bool ext_spk_boost_set;
+	struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
+	struct regulator *spkdrv_reg;
+	struct blocking_notifier_head notifier_mbhc;
+	/* mbhc module */
+	struct wcd_mbhc mbhc;
+	/* cal info for codec */
+	struct fw_info *fw_data;
+	struct notifier_block audio_ssr_nb;
+	int (*codec_spk_ext_pa_cb)(struct snd_soc_codec *codec, int enable);
+	unsigned long status_mask;
+	struct wcd_imped_i_ref imped_i_ref;
+	enum wcd_mbhc_imp_det_pin imped_det_pin;
+	/* Entry for version info */
+	struct snd_info_entry *entry;
+	struct snd_info_entry *version_entry;
+};
+
+struct sdm660_cdc_pdata {
+	struct wcd_micbias_setting micbias;
+	struct sdm660_cdc_regulator regulator[MAX_REGULATOR];
+};
+
+
+extern int msm_anlg_cdc_mclk_enable(struct snd_soc_codec *codec,
+				    int mclk_enable, bool dapm);
+
+extern int msm_anlg_cdc_hs_detect(struct snd_soc_codec *codec,
+		    struct wcd_mbhc_config *mbhc_cfg);
+
+extern void msm_anlg_cdc_hs_detect_exit(struct snd_soc_codec *codec);
+
+extern void sdm660_cdc_update_int_spk_boost(bool enable);
+
+extern void msm_anlg_cdc_spk_ext_pa_cb(
+		int (*codec_spk_ext_pa)(struct snd_soc_codec *codec,
+		int enable), struct snd_soc_codec *codec);
+int msm_anlg_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+					   struct snd_soc_codec *codec);
+#endif
diff --git a/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h b/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h
new file mode 100644
index 0000000..95dbc76
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h
@@ -0,0 +1,66 @@
+/* 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
+ * 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/regmap.h>
+#include "sdm660-cdc-registers.h"
+
+extern struct reg_default
+		msm89xx_cdc_core_defaults[MSM89XX_CDC_CORE_CACHE_SIZE];
+extern struct reg_default
+		msm89xx_pmic_cdc_defaults[MSM89XX_PMIC_CDC_CACHE_SIZE];
+
+bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg);
+bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg);
+
+enum {
+	AIF1_PB = 0,
+	AIF1_CAP,
+	AIF2_VIFEED,
+	AIF3_SVA,
+	NUM_CODEC_DAIS,
+};
+
+enum codec_versions {
+	TOMBAK_1_0,
+	TOMBAK_2_0,
+	CONGA,
+	CAJON,
+	CAJON_2_0,
+	DIANGU,
+	DRAX_CDC,
+	UNSUPPORTED,
+};
+
+/* Support different hph modes */
+enum {
+	NORMAL_MODE = 0,
+	HD2_MODE,
+};
+
+enum dig_cdc_notify_event {
+	DIG_CDC_EVENT_INVALID,
+	DIG_CDC_EVENT_CLK_ON,
+	DIG_CDC_EVENT_CLK_OFF,
+	DIG_CDC_EVENT_RX1_MUTE_ON,
+	DIG_CDC_EVENT_RX1_MUTE_OFF,
+	DIG_CDC_EVENT_RX2_MUTE_ON,
+	DIG_CDC_EVENT_RX2_MUTE_OFF,
+	DIG_CDC_EVENT_RX3_MUTE_ON,
+	DIG_CDC_EVENT_RX3_MUTE_OFF,
+	DIG_CDC_EVENT_PRE_RX1_INT_ON,
+	DIG_CDC_EVENT_PRE_RX2_INT_ON,
+	DIG_CDC_EVENT_POST_RX1_INT_OFF,
+	DIG_CDC_EVENT_POST_RX2_INT_OFF,
+	DIG_CDC_EVENT_SSR_DOWN,
+	DIG_CDC_EVENT_SSR_UP,
+	DIG_CDC_EVENT_LAST,
+};
diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
new file mode 100644
index 0000000..f140b19
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
@@ -0,0 +1,2143 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/qdsp6v2/apr.h>
+#include <linux/workqueue.h>
+#include <linux/regmap.h>
+#include <sound/q6afe-v2.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "sdm660-cdc-registers.h"
+#include "msm-digital-cdc.h"
+#include "msm-cdc-common.h"
+#include "../../msm/sdm660-common.h"
+
+#define DRV_NAME "msm_digital_codec"
+#define MCLK_RATE_9P6MHZ        9600000
+#define MCLK_RATE_12P288MHZ     12288000
+#define TX_MUX_CTL_CUT_OFF_FREQ_MASK	0x30
+#define CF_MIN_3DB_4HZ			0x0
+#define CF_MIN_3DB_75HZ			0x1
+#define CF_MIN_3DB_150HZ		0x2
+
+#define MSM_DIG_CDC_VERSION_ENTRY_SIZE 32
+
+static unsigned long rx_digital_gain_reg[] = {
+	MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL,
+	MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL,
+	MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL,
+};
+
+static unsigned long tx_digital_gain_reg[] = {
+	MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN,
+	MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN,
+	MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN,
+	MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN,
+	MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN,
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+
+struct snd_soc_codec *registered_digcodec;
+struct hpf_work tx_hpf_work[NUM_DECIMATORS];
+
+/* Codec supports 2 IIR filters */
+enum {
+	IIR1 = 0,
+	IIR2,
+	IIR_MAX,
+};
+
+static int msm_digcdc_clock_control(bool flag)
+{
+	int ret = -EINVAL;
+	struct msm_asoc_mach_data *pdata = NULL;
+
+	pdata = snd_soc_card_get_drvdata(registered_digcodec->component.card);
+
+	mutex_lock(&pdata->cdc_int_mclk0_mutex);
+	if (flag) {
+		if (atomic_read(&pdata->int_mclk0_enabled) == false) {
+			pdata->digital_cdc_core_clk.enable = 1;
+			ret = afe_set_lpass_clock_v2(
+						AFE_PORT_ID_INT0_MI2S_RX,
+						&pdata->digital_cdc_core_clk);
+			if (ret < 0) {
+				pr_err("%s:failed to enable the MCLK\n",
+				       __func__);
+				mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+				return ret;
+			}
+			pr_debug("enabled digital codec core clk\n");
+			atomic_set(&pdata->int_mclk0_enabled, true);
+			schedule_delayed_work(&pdata->disable_int_mclk0_work,
+					      50);
+		}
+	} else {
+		dev_dbg(registered_digcodec->dev,
+			"disable MCLK, workq to disable set already\n");
+	}
+	mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+	return 0;
+}
+
+static void enable_digital_callback(void *flag)
+{
+	msm_digcdc_clock_control(true);
+}
+
+static void disable_digital_callback(void *flag)
+{
+	pr_debug("disable mclk happens in workq\n");
+}
+
+static int msm_dig_cdc_put_dec_enum(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+			dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *w = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int dec_mux, decimator;
+	char *dec_name = NULL;
+	char *widget_name = NULL;
+	char *temp;
+	u16 tx_mux_ctl_reg;
+	u8 adc_dmic_sel = 0x0;
+	int ret = 0;
+	char *dec_num;
+
+	if (ucontrol->value.enumerated.item[0] > e->items) {
+		dev_err(codec->dev, "%s: Invalid enum value: %d\n",
+			__func__, ucontrol->value.enumerated.item[0]);
+		return -EINVAL;
+	}
+	dec_mux = ucontrol->value.enumerated.item[0];
+
+	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+	if (!widget_name) {
+		dev_err(codec->dev, "%s: failed to copy string\n",
+			__func__);
+		return -ENOMEM;
+	}
+	temp = widget_name;
+
+	dec_name = strsep(&widget_name, " ");
+	widget_name = temp;
+	if (!dec_name) {
+		dev_err(codec->dev, "%s: Invalid decimator = %s\n",
+			__func__, w->name);
+		ret =  -EINVAL;
+		goto out;
+	}
+
+	dec_num = strpbrk(dec_name, "12345");
+	if (dec_num == NULL) {
+		dev_err(codec->dev, "%s: Invalid DEC selected\n", __func__);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = kstrtouint(dec_num, 10, &decimator);
+	if (ret < 0) {
+		dev_err(codec->dev, "%s: Invalid decimator = %s\n",
+			__func__, dec_name);
+		ret =  -EINVAL;
+		goto out;
+	}
+
+	dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
+		, __func__, w->name, decimator, dec_mux);
+
+	switch (decimator) {
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+		if ((dec_mux == 4) || (dec_mux == 5) ||
+		    (dec_mux == 6) || (dec_mux == 7))
+			adc_dmic_sel = 0x1;
+		else
+			adc_dmic_sel = 0x0;
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
+			__func__, decimator);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	tx_mux_ctl_reg =
+		MSM89XX_CDC_CORE_TX1_MUX_CTL + 32 * (decimator - 1);
+
+	snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
+
+	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+out:
+	kfree(widget_name);
+	return ret;
+}
+
+
+static int msm_dig_cdc_codec_config_compander(struct snd_soc_codec *codec,
+					      int interp_n, int event)
+{
+	struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: event %d shift %d, enabled %d\n",
+		__func__, event, interp_n,
+		dig_cdc->comp_enabled[interp_n]);
+
+	/* compander is not enabled */
+	if (!dig_cdc->comp_enabled[interp_n])
+		return 0;
+
+	switch (dig_cdc->comp_enabled[interp_n]) {
+	case COMPANDER_1:
+		if (SND_SOC_DAPM_EVENT_ON(event)) {
+			/* Enable Compander Clock */
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x09);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x01);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B1_CTL,
+				1 << interp_n, 1 << interp_n);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x01);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0x50);
+			/* add sleep for compander to settle */
+			usleep_range(1000, 1100);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x28);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0xB0);
+
+			/* Enable Compander GPIO */
+			if (dig_cdc->codec_hph_comp_gpio)
+				dig_cdc->codec_hph_comp_gpio(1, codec);
+		} else if (SND_SOC_DAPM_EVENT_OFF(event)) {
+			/* Disable Compander GPIO */
+			if (dig_cdc->codec_hph_comp_gpio)
+				dig_cdc->codec_hph_comp_gpio(0, codec);
+
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x05);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B1_CTL,
+				1 << interp_n, 0);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x00);
+		}
+		break;
+	default:
+		dev_dbg(codec->dev, "%s: Invalid compander %d\n", __func__,
+				dig_cdc->comp_enabled[interp_n]);
+		break;
+	};
+
+	return 0;
+}
+
+/**
+ * msm_dig_cdc_hph_comp_cb - registers callback to codec by machine driver.
+ *
+ * @codec_hph_comp_gpio: function pointer to set comp gpio at machine driver
+ * @codec: codec pointer
+ *
+ */
+void msm_dig_cdc_hph_comp_cb(
+	int (*codec_hph_comp_gpio)(bool enable, struct snd_soc_codec *codec),
+	struct snd_soc_codec *codec)
+{
+	struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: Enter\n", __func__);
+	dig_cdc->codec_hph_comp_gpio = codec_hph_comp_gpio;
+}
+EXPORT_SYMBOL(msm_dig_cdc_hph_comp_cb);
+
+static int msm_dig_cdc_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
+						 struct snd_kcontrol *kcontrol,
+						 int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct msm_dig_priv *msm_dig_cdc = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
+
+	if (w->shift >= MSM89XX_RX_MAX || w->shift < 0) {
+		dev_err(codec->dev, "%s: wrong RX index: %d\n",
+			__func__, w->shift);
+		return -EINVAL;
+	}
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		msm_dig_cdc_codec_config_compander(codec, w->shift, event);
+		/* apply the digital gain after the interpolator is enabled*/
+		if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
+			snd_soc_write(codec,
+				  rx_digital_gain_reg[w->shift],
+				  snd_soc_read(codec,
+				  rx_digital_gain_reg[w->shift])
+				  );
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		msm_dig_cdc_codec_config_compander(codec, w->shift, event);
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_CLK_RX_RESET_CTL,
+			1 << w->shift, 1 << w->shift);
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_CLK_RX_RESET_CTL,
+			1 << w->shift, 0x0);
+		/*
+		 * disable the mute enabled during the PMD of this device
+		 */
+		if ((w->shift == 0) &&
+			(msm_dig_cdc->mute_mask & HPHL_PA_DISABLE)) {
+			pr_debug("disabling HPHL mute\n");
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00);
+			msm_dig_cdc->mute_mask &= ~(HPHL_PA_DISABLE);
+		} else if ((w->shift == 1) &&
+				(msm_dig_cdc->mute_mask & HPHR_PA_DISABLE)) {
+			pr_debug("disabling HPHR mute\n");
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x00);
+			msm_dig_cdc->mute_mask &= ~(HPHR_PA_DISABLE);
+		} else if ((w->shift == 2) &&
+				(msm_dig_cdc->mute_mask & SPKR_PA_DISABLE)) {
+			pr_debug("disabling SPKR mute\n");
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00);
+			msm_dig_cdc->mute_mask &= ~(SPKR_PA_DISABLE);
+		}
+	}
+	return 0;
+}
+
+static int msm_dig_cdc_get_iir_enable_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	ucontrol->value.integer.value[0] =
+		(snd_soc_read(codec,
+			    (MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx)) &
+		(1 << band_idx)) != 0;
+
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
+		iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int msm_dig_cdc_put_iir_enable_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+
+	/* Mask first 5 bits, 6-8 are reserved */
+	snd_soc_update_bits(codec,
+		(MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx),
+			    (1 << band_idx), (value << band_idx));
+
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
+	  iir_idx, band_idx,
+		((snd_soc_read(codec,
+		(MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx)) &
+	  (1 << band_idx)) != 0));
+
+	return 0;
+}
+
+static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
+				   int iir_idx, int band_idx,
+				   int coeff_idx)
+{
+	uint32_t value = 0;
+
+	/* Address does not automatically update if reading */
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t)) & 0x7F);
+
+	value |= snd_soc_read(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx));
+
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 1) & 0x7F);
+
+	value |= (snd_soc_read(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 8);
+
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 2) & 0x7F);
+
+	value |= (snd_soc_read(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 16);
+
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 3) & 0x7F);
+
+	/* Mask bits top 2 bits since they are reserved */
+	value |= ((snd_soc_read(codec, (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL
+		+ 64 * iir_idx)) & 0x3f) << 24);
+
+	return value;
+
+}
+
+static void set_iir_band_coeff(struct snd_soc_codec *codec,
+			       int iir_idx, int band_idx,
+			       uint32_t value)
+{
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
+		(value & 0xFF));
+
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
+		(value >> 8) & 0xFF);
+
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
+		(value >> 16) & 0xFF);
+
+	/* Mask top 2 bits, 7-8 are reserved */
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
+		(value >> 24) & 0x3F);
+
+}
+
+static int msm_dig_cdc_get_iir_band_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	ucontrol->value.integer.value[0] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 0);
+	ucontrol->value.integer.value[1] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 1);
+	ucontrol->value.integer.value[2] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 2);
+	ucontrol->value.integer.value[3] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 3);
+	ucontrol->value.integer.value[4] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 4);
+
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
+		"%s: IIR #%d band #%d b1 = 0x%x\n"
+		"%s: IIR #%d band #%d b2 = 0x%x\n"
+		"%s: IIR #%d band #%d a1 = 0x%x\n"
+		"%s: IIR #%d band #%d a2 = 0x%x\n",
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[0],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[1],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[2],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[3],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[4]);
+	return 0;
+}
+
+static int msm_dig_cdc_put_iir_band_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	/* Mask top bit it is reserved */
+	/* Updates addr automatically for each B2 write */
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
+		(band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
+
+
+	set_iir_band_coeff(codec, iir_idx, band_idx,
+			   ucontrol->value.integer.value[0]);
+	set_iir_band_coeff(codec, iir_idx, band_idx,
+			   ucontrol->value.integer.value[1]);
+	set_iir_band_coeff(codec, iir_idx, band_idx,
+			   ucontrol->value.integer.value[2]);
+	set_iir_band_coeff(codec, iir_idx, band_idx,
+			   ucontrol->value.integer.value[3]);
+	set_iir_band_coeff(codec, iir_idx, band_idx,
+			   ucontrol->value.integer.value[4]);
+
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
+		"%s: IIR #%d band #%d b1 = 0x%x\n"
+		"%s: IIR #%d band #%d b2 = 0x%x\n"
+		"%s: IIR #%d band #%d a1 = 0x%x\n"
+		"%s: IIR #%d band #%d a2 = 0x%x\n",
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 0),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 1),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 2),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 3),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 4));
+	return 0;
+}
+
+static void tx_hpf_corner_freq_callback(struct work_struct *work)
+{
+	struct delayed_work *hpf_delayed_work;
+	struct hpf_work *hpf_work;
+	struct snd_soc_codec *codec;
+	struct msm_dig_priv *msm_dig_cdc;
+	u16 tx_mux_ctl_reg;
+	u8 hpf_cut_of_freq;
+
+	hpf_delayed_work = to_delayed_work(work);
+	hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
+	codec = hpf_work->dig_cdc->codec;
+	msm_dig_cdc = hpf_work->dig_cdc;
+	hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
+
+	tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX1_MUX_CTL +
+			(hpf_work->decimator - 1) * 32;
+
+	dev_dbg(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
+		 __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
+	msm_dig_cdc->update_clkdiv(msm_dig_cdc->handle, 0x51);
+
+	snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
+}
+
+static int msm_dig_cdc_codec_set_iir_gain(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	int value = 0, reg;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (w->shift == 0)
+			reg = MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL;
+		else if (w->shift == 1)
+			reg = MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL;
+		else
+			goto ret;
+		value = snd_soc_read(codec, reg);
+		snd_soc_write(codec, reg, value);
+		break;
+	default:
+		pr_err("%s: event = %d not expected\n", __func__, event);
+	}
+ret:
+	return 0;
+}
+
+static int msm_dig_cdc_compander_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+	int comp_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int rx_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	dev_dbg(codec->dev, "%s: msm_dig_cdc->comp[%d]_enabled[%d] = %d\n",
+			__func__, comp_idx, rx_idx,
+			dig_cdc->comp_enabled[rx_idx]);
+
+	ucontrol->value.integer.value[0] = dig_cdc->comp_enabled[rx_idx];
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int msm_dig_cdc_compander_set(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+	int comp_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int rx_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	if (dig_cdc->version >= DIANGU) {
+		if (!value)
+			dig_cdc->comp_enabled[rx_idx] = 0;
+		else
+			dig_cdc->comp_enabled[rx_idx] = comp_idx;
+	}
+
+	dev_dbg(codec->dev, "%s: msm_dig_cdc->comp[%d]_enabled[%d] = %d\n",
+		__func__, comp_idx, rx_idx,
+		dig_cdc->comp_enabled[rx_idx]);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new compander_kcontrols[] = {
+	SOC_SINGLE_EXT("COMP0 RX1", COMPANDER_1, MSM89XX_RX1, 1, 0,
+	msm_dig_cdc_compander_get, msm_dig_cdc_compander_set),
+
+	SOC_SINGLE_EXT("COMP0 RX2", COMPANDER_1, MSM89XX_RX2, 1, 0,
+	msm_dig_cdc_compander_get, msm_dig_cdc_compander_set),
+
+};
+
+static int msm_dig_cdc_set_interpolator_rate(struct snd_soc_dai *dai,
+					     u8 rx_fs_rate_reg_val,
+					     u32 sample_rate)
+{
+	snd_soc_update_bits(dai->codec,
+			MSM89XX_CDC_CORE_RX1_B5_CTL, 0xF0, rx_fs_rate_reg_val);
+	snd_soc_update_bits(dai->codec,
+			MSM89XX_CDC_CORE_RX2_B5_CTL, 0xF0, rx_fs_rate_reg_val);
+	return 0;
+}
+
+static int msm_dig_cdc_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	u8 tx_fs_rate, rx_fs_rate, rx_clk_fs_rate;
+	int ret;
+
+	dev_dbg(dai->codec->dev,
+		"%s: dai_name = %s DAI-ID %x rate %d num_ch %d format %d\n",
+		__func__, dai->name, dai->id, params_rate(params),
+		params_channels(params), params_format(params));
+
+	switch (params_rate(params)) {
+	case 8000:
+		tx_fs_rate = 0x00;
+		rx_fs_rate = 0x00;
+		rx_clk_fs_rate = 0x00;
+		break;
+	case 16000:
+		tx_fs_rate = 0x20;
+		rx_fs_rate = 0x20;
+		rx_clk_fs_rate = 0x01;
+		break;
+	case 32000:
+		tx_fs_rate = 0x40;
+		rx_fs_rate = 0x40;
+		rx_clk_fs_rate = 0x02;
+		break;
+	case 44100:
+	case 48000:
+		tx_fs_rate = 0x60;
+		rx_fs_rate = 0x60;
+		rx_clk_fs_rate = 0x03;
+		break;
+	case 96000:
+		tx_fs_rate = 0x80;
+		rx_fs_rate = 0x80;
+		rx_clk_fs_rate = 0x04;
+		break;
+	case 192000:
+		tx_fs_rate = 0xA0;
+		rx_fs_rate = 0xA0;
+		rx_clk_fs_rate = 0x05;
+		break;
+	default:
+		dev_err(dai->codec->dev,
+			"%s: Invalid sampling rate %d\n", __func__,
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(dai->codec,
+			MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x0F, rx_clk_fs_rate);
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_CAPTURE:
+		break;
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		ret = msm_dig_cdc_set_interpolator_rate(dai, rx_fs_rate,
+						  params_rate(params));
+		if (ret < 0) {
+			dev_err(dai->codec->dev,
+				"%s: set decimator rate failed %d\n", __func__,
+				ret);
+			return ret;
+		}
+		break;
+	default:
+		dev_err(dai->codec->dev,
+			"%s: Invalid stream type %d\n", __func__,
+			substream->stream);
+		return -EINVAL;
+	}
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		snd_soc_update_bits(dai->codec,
+				MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x20, 0x20);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		snd_soc_update_bits(dai->codec,
+				MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x20, 0x00);
+		break;
+	default:
+		dev_err(dai->codec->dev, "%s: wrong format selected\n",
+				__func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int msm_dig_cdc_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+					 struct snd_kcontrol *kcontrol,
+					 int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+	u8  dmic_clk_en;
+	u16 dmic_clk_reg;
+	s32 *dmic_clk_cnt;
+	unsigned int dmic;
+	int ret;
+	char *dmic_num = strpbrk(w->name, "1234");
+
+	if (dmic_num == NULL) {
+		dev_err(codec->dev, "%s: Invalid DMIC\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = kstrtouint(dmic_num, 10, &dmic);
+	if (ret < 0) {
+		dev_err(codec->dev,
+			"%s: Invalid DMIC line on the codec\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (dmic) {
+	case 1:
+	case 2:
+		dmic_clk_en = 0x01;
+		dmic_clk_cnt = &(dig_cdc->dmic_1_2_clk_cnt);
+		dmic_clk_reg = MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL;
+		dev_dbg(codec->dev,
+			"%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
+			__func__, event,  dmic, *dmic_clk_cnt);
+		break;
+	case 3:
+	case 4:
+		dmic_clk_en = 0x01;
+		dmic_clk_cnt = &(dig_cdc->dmic_3_4_clk_cnt);
+		dmic_clk_reg = MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL;
+		dev_dbg(codec->dev,
+			"%s() event %d DMIC%d dmic_3_4_clk_cnt %d\n",
+			__func__, event,  dmic, *dmic_clk_cnt);
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid DMIC Selection\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		(*dmic_clk_cnt)++;
+		if (*dmic_clk_cnt == 1) {
+			snd_soc_update_bits(codec, dmic_clk_reg,
+					0x0E, 0x04);
+			snd_soc_update_bits(codec, dmic_clk_reg,
+					dmic_clk_en, dmic_clk_en);
+		}
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_TX1_DMIC_CTL + (dmic - 1) * 0x20,
+			0x07, 0x02);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		(*dmic_clk_cnt)--;
+		if (*dmic_clk_cnt  == 0)
+			snd_soc_update_bits(codec, dmic_clk_reg,
+					dmic_clk_en, 0);
+		break;
+	}
+	return 0;
+}
+
+static int msm_dig_cdc_codec_enable_dec(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *kcontrol,
+					int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct msm_asoc_mach_data *pdata = NULL;
+	unsigned int decimator;
+	struct msm_dig_priv *msm_dig_cdc = snd_soc_codec_get_drvdata(codec);
+	char *dec_name = NULL;
+	char *widget_name = NULL;
+	char *temp;
+	int ret = 0, i;
+	u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
+	u8 dec_hpf_cut_of_freq;
+	int offset;
+	char *dec_num;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+	dev_dbg(codec->dev, "%s %d\n", __func__, event);
+
+	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+	if (!widget_name)
+		return -ENOMEM;
+	temp = widget_name;
+
+	dec_name = strsep(&widget_name, " ");
+	widget_name = temp;
+	if (!dec_name) {
+		dev_err(codec->dev,
+			"%s: Invalid decimator = %s\n", __func__, w->name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	dec_num = strpbrk(dec_name, "12345");
+	if (dec_num == NULL) {
+		dev_err(codec->dev, "%s: Invalid Decimator\n", __func__);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = kstrtouint(dec_num, 10, &decimator);
+	if (ret < 0) {
+		dev_err(codec->dev,
+			"%s: Invalid decimator = %s\n", __func__, dec_name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	dev_dbg(codec->dev,
+		"%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
+		w->name, dec_name, decimator);
+
+	if (w->reg == MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL) {
+		dec_reset_reg = MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL;
+		offset = 0;
+	} else {
+		dev_err(codec->dev, "%s: Error, incorrect dec\n", __func__);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	tx_vol_ctl_reg = MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG +
+			 32 * (decimator - 1);
+	tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX1_MUX_CTL +
+			  32 * (decimator - 1);
+	if (decimator == 5) {
+		tx_vol_ctl_reg = MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG;
+		tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX5_MUX_CTL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Enableable TX digital mute */
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+		for (i = 0; i < NUM_DECIMATORS; i++) {
+			if (decimator == i + 1)
+				msm_dig_cdc->dec_active[i] = true;
+		}
+
+		dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
+
+		dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
+
+		tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
+			dec_hpf_cut_of_freq;
+
+		if (dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ) {
+
+			/* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
+			snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
+					    CF_MIN_3DB_150HZ << 4);
+		}
+		msm_dig_cdc->update_clkdiv(msm_dig_cdc->handle, 0x42);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* enable HPF */
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x00);
+
+		if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
+				CF_MIN_3DB_150HZ) {
+
+			schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
+					msecs_to_jiffies(300));
+		}
+		/* apply the digital gain after the decimator is enabled*/
+		if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg))
+			snd_soc_write(codec,
+				  tx_digital_gain_reg[w->shift + offset],
+				  snd_soc_read(codec,
+				  tx_digital_gain_reg[w->shift + offset])
+				  );
+		if (pdata->lb_mode) {
+			pr_debug("%s: loopback mode unmute the DEC\n",
+							__func__);
+			snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
+		}
+				snd_soc_update_bits(codec, tx_vol_ctl_reg,
+						0x01, 0x00);
+
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+		msleep(20);
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
+		cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
+			1 << w->shift);
+		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
+			(tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
+		for (i = 0; i < NUM_DECIMATORS; i++) {
+			if (decimator == i + 1)
+				msm_dig_cdc->dec_active[i] = false;
+		}
+		break;
+	}
+out:
+	kfree(widget_name);
+	return ret;
+}
+
+static int msm_dig_cdc_event_notify(struct notifier_block *block,
+				    unsigned long val,
+				    void *data)
+{
+	enum dig_cdc_notify_event event = (enum dig_cdc_notify_event)val;
+	struct snd_soc_codec *codec = registered_digcodec;
+	struct msm_dig_priv *msm_dig_cdc = snd_soc_codec_get_drvdata(codec);
+	struct msm_asoc_mach_data *pdata = NULL;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+
+	switch (event) {
+	case DIG_CDC_EVENT_CLK_ON:
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x03);
+		if (pdata->mclk_freq == MCLK_RATE_12P288MHZ ||
+		    pdata->native_clk_set)
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_TOP_CTL, 0x01, 0x00);
+		else if (pdata->mclk_freq == MCLK_RATE_9P6MHZ)
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_TOP_CTL, 0x01, 0x01);
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x01, 0x01);
+		break;
+	case DIG_CDC_EVENT_CLK_OFF:
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x01, 0x00);
+		break;
+	case DIG_CDC_EVENT_RX1_MUTE_ON:
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x01);
+		msm_dig_cdc->mute_mask |= HPHL_PA_DISABLE;
+		break;
+	case DIG_CDC_EVENT_RX1_MUTE_OFF:
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00);
+		msm_dig_cdc->mute_mask &= (~HPHL_PA_DISABLE);
+		break;
+	case DIG_CDC_EVENT_RX2_MUTE_ON:
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x01);
+		msm_dig_cdc->mute_mask |= HPHR_PA_DISABLE;
+		break;
+	case DIG_CDC_EVENT_RX2_MUTE_OFF:
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x00);
+		msm_dig_cdc->mute_mask &= (~HPHR_PA_DISABLE);
+		break;
+	case DIG_CDC_EVENT_RX3_MUTE_ON:
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x01);
+		msm_dig_cdc->mute_mask |= SPKR_PA_DISABLE;
+		break;
+	case DIG_CDC_EVENT_RX3_MUTE_OFF:
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00);
+		msm_dig_cdc->mute_mask &= (~SPKR_PA_DISABLE);
+		break;
+	case DIG_CDC_EVENT_PRE_RX1_INT_ON:
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x14);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0x10);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x80, 0x80);
+		break;
+	case DIG_CDC_EVENT_PRE_RX2_INT_ON:
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x14);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0x10);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x80, 0x80);
+		break;
+	case DIG_CDC_EVENT_POST_RX1_INT_OFF:
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x00);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0xFF);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x80, 0x00);
+		break;
+	case DIG_CDC_EVENT_POST_RX2_INT_OFF:
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x00);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0xFF);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x80, 0x00);
+		break;
+	case DIG_CDC_EVENT_SSR_DOWN:
+		regcache_cache_only(msm_dig_cdc->regmap, true);
+		break;
+	case DIG_CDC_EVENT_SSR_UP:
+		regcache_cache_only(msm_dig_cdc->regmap, false);
+		regcache_mark_dirty(msm_dig_cdc->regmap);
+		regcache_sync(msm_dig_cdc->regmap);
+		break;
+	case DIG_CDC_EVENT_INVALID:
+	default:
+		break;
+	}
+	return 0;
+}
+
+static ssize_t msm_dig_codec_version_read(struct snd_info_entry *entry,
+					  void *file_private_data,
+					  struct file *file,
+					  char __user *buf, size_t count,
+					  loff_t pos)
+{
+	struct msm_dig_priv *msm_dig;
+	char buffer[MSM_DIG_CDC_VERSION_ENTRY_SIZE];
+	int len = 0;
+
+	msm_dig = (struct msm_dig_priv *) entry->private_data;
+	if (!msm_dig) {
+		pr_err("%s: msm_dig priv is null\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (msm_dig->version) {
+	case DRAX_CDC:
+		len = snprintf(buffer, sizeof(buffer), "SDM660-CDC_1_0\n");
+		break;
+	default:
+		len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
+	}
+
+	return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops msm_dig_codec_info_ops = {
+	.read = msm_dig_codec_version_read,
+};
+
+/*
+ * msm_dig_codec_info_create_codec_entry - creates msm_dig module
+ * @codec_root: The parent directory
+ * @codec: Codec instance
+ *
+ * Creates msm_dig module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int msm_dig_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+					  struct snd_soc_codec *codec)
+{
+	struct snd_info_entry *version_entry;
+	struct msm_dig_priv *msm_dig;
+	struct snd_soc_card *card;
+
+	if (!codec_root || !codec)
+		return -EINVAL;
+
+	msm_dig = snd_soc_codec_get_drvdata(codec);
+	card = codec->component.card;
+	msm_dig->entry = snd_register_module_info(codec_root->module,
+						  "msm_digital_codec",
+						  codec_root);
+	if (!msm_dig->entry) {
+		dev_dbg(codec->dev, "%s: failed to create msm_digital entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry = snd_info_create_card_entry(card->snd_card,
+						   "version",
+						   msm_dig->entry);
+	if (!version_entry) {
+		dev_dbg(codec->dev, "%s: failed to create msm_digital version entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry->private_data = msm_dig;
+	version_entry->size = MSM_DIG_CDC_VERSION_ENTRY_SIZE;
+	version_entry->content = SNDRV_INFO_CONTENT_DATA;
+	version_entry->c.ops = &msm_dig_codec_info_ops;
+
+	if (snd_info_register(version_entry) < 0) {
+		snd_info_free_entry(version_entry);
+		return -ENOMEM;
+	}
+	msm_dig->version_entry = version_entry;
+	if (msm_dig->get_cdc_version)
+		msm_dig->version = msm_dig->get_cdc_version(msm_dig->handle);
+	else
+		msm_dig->version = DRAX_CDC;
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_dig_codec_info_create_codec_entry);
+
+static int msm_dig_cdc_soc_probe(struct snd_soc_codec *codec)
+{
+	struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev);
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	int i, ret;
+
+	msm_dig_cdc->codec = codec;
+
+	snd_soc_add_codec_controls(codec, compander_kcontrols,
+			ARRAY_SIZE(compander_kcontrols));
+
+	for (i = 0; i < NUM_DECIMATORS; i++) {
+		tx_hpf_work[i].dig_cdc = msm_dig_cdc;
+		tx_hpf_work[i].decimator = i + 1;
+		INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
+			tx_hpf_corner_freq_callback);
+	}
+
+	for (i = 0; i < MSM89XX_RX_MAX; i++)
+		msm_dig_cdc->comp_enabled[i] = COMPANDER_NONE;
+
+	/* Register event notifier */
+	msm_dig_cdc->nblock.notifier_call = msm_dig_cdc_event_notify;
+	if (msm_dig_cdc->register_notifier) {
+		ret = msm_dig_cdc->register_notifier(msm_dig_cdc->handle,
+						     &msm_dig_cdc->nblock,
+						     true);
+		if (ret) {
+			pr_err("%s: Failed to register notifier %d\n",
+				__func__, ret);
+			return ret;
+		}
+	}
+	registered_digcodec = codec;
+
+	snd_soc_dapm_ignore_suspend(dapm, "AIF1 Playback");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF1 Capture");
+	snd_soc_dapm_ignore_suspend(dapm, "ADC1_IN");
+	snd_soc_dapm_ignore_suspend(dapm, "ADC2_IN");
+	snd_soc_dapm_ignore_suspend(dapm, "ADC3_IN");
+	snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX1");
+	snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX2");
+	snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX3");
+
+	return 0;
+}
+
+static int msm_dig_cdc_soc_remove(struct snd_soc_codec *codec)
+{
+	struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev);
+
+	if (msm_dig_cdc->register_notifier)
+		msm_dig_cdc->register_notifier(msm_dig_cdc->handle,
+					       &msm_dig_cdc->nblock,
+					       false);
+	iounmap(msm_dig_cdc->dig_base);
+	return 0;
+}
+
+static const struct snd_soc_dapm_route audio_dig_map[] = {
+	{"RX_I2S_CLK", NULL, "CDC_CONN"},
+	{"I2S RX1", NULL, "RX_I2S_CLK"},
+	{"I2S RX2", NULL, "RX_I2S_CLK"},
+	{"I2S RX3", NULL, "RX_I2S_CLK"},
+
+	{"I2S TX1", NULL, "TX_I2S_CLK"},
+	{"I2S TX2", NULL, "TX_I2S_CLK"},
+	{"I2S TX3", NULL, "TX_I2S_CLK"},
+	{"I2S TX4", NULL, "TX_I2S_CLK"},
+	{"I2S TX5", NULL, "TX_I2S_CLK"},
+	{"I2S TX6", NULL, "TX_I2S_CLK"},
+
+	{"I2S TX1", NULL, "DEC1 MUX"},
+	{"I2S TX2", NULL, "DEC2 MUX"},
+	{"I2S TX3", NULL, "I2S TX2 INP1"},
+	{"I2S TX4", NULL, "I2S TX2 INP2"},
+	{"I2S TX5", NULL, "DEC3 MUX"},
+	{"I2S TX6", NULL, "I2S TX3 INP2"},
+
+	{"I2S TX2 INP1", "RX_MIX1", "RX1 MIX2"},
+	{"I2S TX2 INP1", "DEC3", "DEC3 MUX"},
+	{"I2S TX2 INP2", "RX_MIX2", "RX2 MIX2"},
+	{"I2S TX2 INP2", "RX_MIX3", "RX3 MIX1"},
+	{"I2S TX2 INP2", "DEC4", "DEC4 MUX"},
+	{"I2S TX3 INP2", "DEC4", "DEC4 MUX"},
+	{"I2S TX3 INP2", "DEC5", "DEC5 MUX"},
+
+	{"PDM_OUT_RX1", NULL, "RX1 CHAIN"},
+	{"PDM_OUT_RX2", NULL, "RX2 CHAIN"},
+	{"PDM_OUT_RX3", NULL, "RX3 CHAIN"},
+
+	{"RX1 CHAIN", NULL, "RX1 MIX2"},
+	{"RX2 CHAIN", NULL, "RX2 MIX2"},
+	{"RX3 CHAIN", NULL, "RX3 MIX1"},
+
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
+	{"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
+	{"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
+	{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
+	{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
+	{"RX1 MIX2", NULL, "RX1 MIX1"},
+	{"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
+	{"RX2 MIX2", NULL, "RX2 MIX1"},
+	{"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
+
+	{"RX1 MIX1 INP1", "RX1", "I2S RX1"},
+	{"RX1 MIX1 INP1", "RX2", "I2S RX2"},
+	{"RX1 MIX1 INP1", "RX3", "I2S RX3"},
+	{"RX1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX1 MIX1 INP1", "IIR2", "IIR2"},
+	{"RX1 MIX1 INP2", "RX1", "I2S RX1"},
+	{"RX1 MIX1 INP2", "RX2", "I2S RX2"},
+	{"RX1 MIX1 INP2", "RX3", "I2S RX3"},
+	{"RX1 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX1 MIX1 INP2", "IIR2", "IIR2"},
+	{"RX1 MIX1 INP3", "RX1", "I2S RX1"},
+	{"RX1 MIX1 INP3", "RX2", "I2S RX2"},
+	{"RX1 MIX1 INP3", "RX3", "I2S RX3"},
+
+	{"RX2 MIX1 INP1", "RX1", "I2S RX1"},
+	{"RX2 MIX1 INP1", "RX2", "I2S RX2"},
+	{"RX2 MIX1 INP1", "RX3", "I2S RX3"},
+	{"RX2 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX2 MIX1 INP1", "IIR2", "IIR2"},
+	{"RX2 MIX1 INP2", "RX1", "I2S RX1"},
+	{"RX2 MIX1 INP2", "RX2", "I2S RX2"},
+	{"RX2 MIX1 INP2", "RX3", "I2S RX3"},
+	{"RX2 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX2 MIX1 INP2", "IIR2", "IIR2"},
+
+	{"RX3 MIX1 INP1", "RX1", "I2S RX1"},
+	{"RX3 MIX1 INP1", "RX2", "I2S RX2"},
+	{"RX3 MIX1 INP1", "RX3", "I2S RX3"},
+	{"RX3 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX3 MIX1 INP1", "IIR2", "IIR2"},
+	{"RX3 MIX1 INP2", "RX1", "I2S RX1"},
+	{"RX3 MIX1 INP2", "RX2", "I2S RX2"},
+	{"RX3 MIX1 INP2", "RX3", "I2S RX3"},
+	{"RX3 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX3 MIX1 INP2", "IIR2", "IIR2"},
+
+	{"RX1 MIX2 INP1", "IIR1", "IIR1"},
+	{"RX2 MIX2 INP1", "IIR1", "IIR1"},
+	{"RX1 MIX2 INP1", "IIR2", "IIR2"},
+	{"RX2 MIX2 INP1", "IIR2", "IIR2"},
+
+		/* Decimator Inputs */
+	{"DEC1 MUX", "DMIC1", "DMIC1"},
+	{"DEC1 MUX", "DMIC2", "DMIC2"},
+	{"DEC1 MUX", "DMIC3", "DMIC3"},
+	{"DEC1 MUX", "DMIC4", "DMIC4"},
+	{"DEC1 MUX", "ADC1", "ADC1_IN"},
+	{"DEC1 MUX", "ADC2", "ADC2_IN"},
+	{"DEC1 MUX", "ADC3", "ADC3_IN"},
+	{"DEC1 MUX", NULL, "CDC_CONN"},
+
+	{"DEC2 MUX", "DMIC1", "DMIC1"},
+	{"DEC2 MUX", "DMIC2", "DMIC2"},
+	{"DEC2 MUX", "DMIC3", "DMIC3"},
+	{"DEC2 MUX", "DMIC4", "DMIC4"},
+	{"DEC2 MUX", "ADC1", "ADC1_IN"},
+	{"DEC2 MUX", "ADC2", "ADC2_IN"},
+	{"DEC2 MUX", "ADC3", "ADC3_IN"},
+	{"DEC2 MUX", NULL, "CDC_CONN"},
+
+	{"DEC3 MUX", "DMIC1", "DMIC1"},
+	{"DEC3 MUX", "DMIC2", "DMIC2"},
+	{"DEC3 MUX", "DMIC3", "DMIC3"},
+	{"DEC3 MUX", "DMIC4", "DMIC4"},
+	{"DEC3 MUX", "ADC1", "ADC1_IN"},
+	{"DEC3 MUX", "ADC2", "ADC2_IN"},
+	{"DEC3 MUX", "ADC3", "ADC3_IN"},
+	{"DEC3 MUX", NULL, "CDC_CONN"},
+
+	{"DEC4 MUX", "DMIC1", "DMIC1"},
+	{"DEC4 MUX", "DMIC2", "DMIC2"},
+	{"DEC4 MUX", "DMIC3", "DMIC3"},
+	{"DEC4 MUX", "DMIC4", "DMIC4"},
+	{"DEC4 MUX", "ADC1", "ADC1_IN"},
+	{"DEC4 MUX", "ADC2", "ADC2_IN"},
+	{"DEC4 MUX", "ADC3", "ADC3_IN"},
+	{"DEC4 MUX", NULL, "CDC_CONN"},
+
+	{"DEC5 MUX", "DMIC1", "DMIC1"},
+	{"DEC5 MUX", "DMIC2", "DMIC2"},
+	{"DEC5 MUX", "DMIC3", "DMIC3"},
+	{"DEC5 MUX", "DMIC4", "DMIC4"},
+	{"DEC5 MUX", "ADC1", "ADC1_IN"},
+	{"DEC5 MUX", "ADC2", "ADC2_IN"},
+	{"DEC5 MUX", "ADC3", "ADC3_IN"},
+	{"DEC5 MUX", NULL, "CDC_CONN"},
+
+	{"IIR1", NULL, "IIR1 INP1 MUX"},
+	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
+	{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
+	{"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
+	{"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
+	{"IIR2", NULL, "IIR2 INP1 MUX"},
+	{"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
+	{"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"},
+	{"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
+	{"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
+};
+
+
+static const char * const i2s_tx2_inp1_text[] = {
+	"ZERO", "RX_MIX1", "DEC3"
+};
+
+static const char * const i2s_tx2_inp2_text[] = {
+	"ZERO", "RX_MIX2", "RX_MIX3", "DEC4"
+};
+
+static const char * const i2s_tx3_inp2_text[] = {
+	"DEC4", "DEC5"
+};
+
+static const char * const rx_mix1_text[] = {
+	"ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
+};
+
+static const char * const rx_mix2_text[] = {
+	"ZERO", "IIR1", "IIR2"
+};
+
+static const char * const dec_mux_text[] = {
+	"ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2", "DMIC3", "DMIC4"
+};
+
+static const char * const iir_inp1_text[] = {
+	"ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3", "DEC3", "DEC4"
+};
+
+/* I2S TX MUXes */
+static const struct soc_enum i2s_tx2_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL,
+		2, 3, i2s_tx2_inp1_text);
+
+static const struct soc_enum i2s_tx2_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL,
+		0, 4, i2s_tx2_inp2_text);
+
+static const struct soc_enum i2s_tx3_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL,
+		4, 2, i2s_tx3_inp2_text);
+
+/* RX1 MIX1 */
+static const struct soc_enum rx_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B1_CTL,
+		0, 6, rx_mix1_text);
+
+static const struct soc_enum rx_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B1_CTL,
+		3, 6, rx_mix1_text);
+
+static const struct soc_enum rx_mix1_inp3_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B2_CTL,
+		0, 6, rx_mix1_text);
+
+/* RX1 MIX2 */
+static const struct soc_enum rx_mix2_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B3_CTL,
+		0, 3, rx_mix2_text);
+
+/* RX2 MIX1 */
+static const struct soc_enum rx2_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL,
+		0, 6, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL,
+		3, 6, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp3_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL,
+		0, 6, rx_mix1_text);
+
+/* RX2 MIX2 */
+static const struct soc_enum rx2_mix2_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B3_CTL,
+		0, 3, rx_mix2_text);
+
+/* RX3 MIX1 */
+static const struct soc_enum rx3_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL,
+		0, 6, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL,
+		3, 6, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp3_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL,
+		0, 6, rx_mix1_text);
+
+/* DEC */
+static const struct soc_enum dec1_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B1_CTL,
+		0, 8, dec_mux_text);
+
+static const struct soc_enum dec2_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B1_CTL,
+		3, 8, dec_mux_text);
+
+static const struct soc_enum dec3_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B2_CTL,
+		0, 8, dec_mux_text);
+
+static const struct soc_enum dec4_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B2_CTL,
+		3, 8, dec_mux_text);
+
+static const struct soc_enum decsva_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B3_CTL,
+		0, 8, dec_mux_text);
+
+static const struct soc_enum iir1_inp1_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL,
+		0, 8, iir_inp1_text);
+
+static const struct soc_enum iir2_inp1_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL,
+		0, 8, iir_inp1_text);
+
+/*cut of frequency for high pass filter*/
+static const char * const cf_text[] = {
+	"MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
+};
+
+static const struct soc_enum cf_rxmix1_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX1_B4_CTL, 0, 3, cf_text);
+
+static const struct soc_enum cf_rxmix2_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX2_B4_CTL, 0, 3, cf_text);
+
+static const struct soc_enum cf_rxmix3_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX3_B4_CTL, 0, 3, cf_text);
+
+static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
+
+#define MSM89XX_DEC_ENUM(xname, xenum) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_enum_double, \
+	.get = snd_soc_dapm_get_enum_double, \
+	.put = msm_dig_cdc_put_dec_enum, \
+	.private_value = (unsigned long)&xenum }
+
+static const struct snd_kcontrol_new dec1_mux =
+	MSM89XX_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
+
+static const struct snd_kcontrol_new dec2_mux =
+	MSM89XX_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
+
+static const struct snd_kcontrol_new dec3_mux =
+	MSM89XX_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
+
+static const struct snd_kcontrol_new dec4_mux =
+	MSM89XX_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
+
+static const struct snd_kcontrol_new decsva_mux =
+	MSM89XX_DEC_ENUM("DEC5 MUX Mux", decsva_mux_enum);
+
+static const struct snd_kcontrol_new i2s_tx2_inp1_mux =
+	SOC_DAPM_ENUM("I2S TX2 INP1 Mux", i2s_tx2_inp1_chain_enum);
+
+static const struct snd_kcontrol_new i2s_tx2_inp2_mux =
+	SOC_DAPM_ENUM("I2S TX2 INP2 Mux", i2s_tx2_inp2_chain_enum);
+
+static const struct snd_kcontrol_new i2s_tx3_inp2_mux =
+	SOC_DAPM_ENUM("I2S TX3 INP2 Mux", i2s_tx3_inp2_chain_enum);
+
+static const struct snd_kcontrol_new iir1_inp1_mux =
+	SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
+
+static const struct snd_kcontrol_new iir2_inp1_mux =
+	SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp3_mux =
+	SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp3_mux =
+	SOC_DAPM_ENUM("RX2 MIX1 INP3 Mux", rx2_mix1_inp3_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp3_mux =
+	SOC_DAPM_ENUM("RX3 MIX1 INP3 Mux", rx3_mix1_inp3_chain_enum);
+
+static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
+	SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx_mix2_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
+	SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
+
+static const struct snd_soc_dapm_widget msm_dig_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S TX4", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S TX5", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S TX6", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MIXER_E("RX1 MIX2", MSM89XX_CDC_CORE_CLK_RX_B1_CTL,
+			     MSM89XX_RX1, 0, NULL, 0,
+			     msm_dig_cdc_codec_enable_interpolator,
+			     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX2 MIX2", MSM89XX_CDC_CORE_CLK_RX_B1_CTL,
+			     MSM89XX_RX2, 0, NULL, 0,
+			     msm_dig_cdc_codec_enable_interpolator,
+			     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX3 MIX1", MSM89XX_CDC_CORE_CLK_RX_B1_CTL,
+			     MSM89XX_RX3, 0, NULL, 0,
+			     msm_dig_cdc_codec_enable_interpolator,
+			     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("RX1 CHAIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX2 CHAIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX3 CHAIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp3_mux),
+
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx2_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx2_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+		&rx2_mix1_inp3_mux),
+
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx3_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx3_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+		&rx3_mix1_inp3_mux),
+
+	SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+		&rx1_mix2_inp1_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+		&rx2_mix2_inp1_mux),
+
+	SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, MSM89XX_CDC_CORE_CLK_OTHR_CTL,
+		2, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX_E("DEC1 MUX",
+		MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 0, 0,
+		&dec1_mux, msm_dig_cdc_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC2 MUX",
+		MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 1, 0,
+		&dec2_mux, msm_dig_cdc_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC3 MUX",
+		MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 2, 0,
+		&dec3_mux, msm_dig_cdc_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC4 MUX",
+		MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 3, 0,
+		&dec4_mux, msm_dig_cdc_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC5 MUX",
+		MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 4, 0,
+		&decsva_mux, msm_dig_cdc_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	/* Sidetone */
+	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+	SND_SOC_DAPM_PGA_E("IIR1", MSM89XX_CDC_CORE_CLK_SD_CTL, 0, 0, NULL, 0,
+		msm_dig_cdc_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
+	SND_SOC_DAPM_PGA_E("IIR2", MSM89XX_CDC_CORE_CLK_SD_CTL, 1, 0, NULL, 0,
+		msm_dig_cdc_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_SUPPLY("RX_I2S_CLK",
+		MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("TX_I2S_CLK",
+		MSM89XX_CDC_CORE_CLK_TX_I2S_CTL, 4, 0, NULL, 0),
+
+
+	SND_SOC_DAPM_MUX("I2S TX2 INP1", SND_SOC_NOPM, 0, 0,
+			&i2s_tx2_inp1_mux),
+	SND_SOC_DAPM_MUX("I2S TX2 INP2", SND_SOC_NOPM, 0, 0,
+			&i2s_tx2_inp2_mux),
+	SND_SOC_DAPM_MUX("I2S TX3 INP2", SND_SOC_NOPM, 0, 0,
+			&i2s_tx3_inp2_mux),
+
+	/* Digital Mic Inputs */
+	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+		msm_dig_cdc_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+		msm_dig_cdc_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+		msm_dig_cdc_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+		msm_dig_cdc_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("ADC1_IN"),
+	SND_SOC_DAPM_INPUT("ADC2_IN"),
+	SND_SOC_DAPM_INPUT("ADC3_IN"),
+	SND_SOC_DAPM_OUTPUT("PDM_OUT_RX1"),
+	SND_SOC_DAPM_OUTPUT("PDM_OUT_RX2"),
+	SND_SOC_DAPM_OUTPUT("PDM_OUT_RX3"),
+};
+
+static const struct soc_enum cf_dec1_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX1_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec2_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX2_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec3_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX3_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec4_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX4_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_decsva_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX5_MUX_CTL, 4, 3, cf_text);
+
+static const struct snd_kcontrol_new msm_dig_snd_controls[] = {
+	SOC_SINGLE_SX_TLV("DEC1 Volume",
+		MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC2 Volume",
+		  MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC3 Volume",
+		  MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC4 Volume",
+		  MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC5 Volume",
+		  MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN,
+		0, -84, 40, digital_gain),
+
+	SOC_SINGLE_SX_TLV("IIR1 INP1 Volume",
+			  MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL,
+			0,  -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP2 Volume",
+			  MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL,
+			0,  -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP3 Volume",
+			  MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL,
+			0,  -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP4 Volume",
+			  MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL,
+			0,  -84,	40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR2 INP1 Volume",
+			  MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL,
+			0,  -84, 40, digital_gain),
+
+	SOC_SINGLE_SX_TLV("RX1 Digital Volume",
+		MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX2 Digital Volume",
+		MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX3 Digital Volume",
+		MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL,
+		0, -84, 40, digital_gain),
+
+	SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+
+	SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+
+	SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+
+	SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+
+	SOC_SINGLE("RX1 HPF Switch",
+		MSM89XX_CDC_CORE_RX1_B5_CTL, 2, 1, 0),
+	SOC_SINGLE("RX2 HPF Switch",
+		MSM89XX_CDC_CORE_RX2_B5_CTL, 2, 1, 0),
+	SOC_SINGLE("RX3 HPF Switch",
+		MSM89XX_CDC_CORE_RX3_B5_CTL, 2, 1, 0),
+
+	SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
+	SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
+	SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
+
+	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
+	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
+	SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
+	SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
+	SOC_ENUM("TX5 HPF cut off", cf_decsva_enum),
+	SOC_SINGLE("TX1 HPF Switch",
+		MSM89XX_CDC_CORE_TX1_MUX_CTL, 3, 1, 0),
+	SOC_SINGLE("TX2 HPF Switch",
+		MSM89XX_CDC_CORE_TX2_MUX_CTL, 3, 1, 0),
+	SOC_SINGLE("TX3 HPF Switch",
+		MSM89XX_CDC_CORE_TX3_MUX_CTL, 3, 1, 0),
+	SOC_SINGLE("TX4 HPF Switch",
+		MSM89XX_CDC_CORE_TX4_MUX_CTL, 3, 1, 0),
+	SOC_SINGLE("TX5 HPF Switch",
+		MSM89XX_CDC_CORE_TX5_MUX_CTL, 3, 1, 0),
+};
+
+static int msm_dig_cdc_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = NULL;
+	u16 tx_vol_ctl_reg = 0;
+	u8 decimator = 0, i;
+	struct msm_dig_priv *dig_cdc;
+
+	pr_debug("%s: Digital Mute val = %d\n", __func__, mute);
+
+	if (!dai || !dai->codec) {
+		pr_err("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
+	codec = dai->codec;
+	dig_cdc = snd_soc_codec_get_drvdata(codec);
+
+	if (dai->id == AIF1_PB) {
+		dev_dbg(codec->dev, "%s: Not capture use case skip\n",
+			__func__);
+		return 0;
+	}
+
+	mute = (mute) ? 1 : 0;
+	if (!mute) {
+		/*
+		 * 15 ms is an emperical value for the mute time
+		 * that was arrived by checking the pop level
+		 * to be inaudible
+		 */
+		usleep_range(15000, 15010);
+	}
+
+	if (dai->id == AIF3_SVA) {
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG, 0x01, mute);
+		goto ret;
+	}
+	for (i = 0; i < (NUM_DECIMATORS - 1); i++) {
+		if (dig_cdc->dec_active[i])
+			decimator = i + 1;
+		if (decimator && decimator < NUM_DECIMATORS) {
+			/* mute/unmute decimators corresponding to Tx DAI's */
+			tx_vol_ctl_reg =
+			MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG +
+					32 * (decimator - 1);
+			snd_soc_update_bits(codec, tx_vol_ctl_reg,
+					    0x01, mute);
+		}
+		decimator = 0;
+	}
+ret:
+	return 0;
+}
+
+static struct snd_soc_dai_ops msm_dig_dai_ops = {
+	.hw_params = msm_dig_cdc_hw_params,
+	.digital_mute = msm_dig_cdc_digital_mute,
+};
+
+
+static struct snd_soc_dai_driver msm_codec_dais[] = {
+	{
+		.name = "msm_dig_cdc_dai_rx1",
+		.id = AIF1_PB,
+		.playback = { /* Support maximum range */
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		 .ops = &msm_dig_dai_ops,
+	},
+	{
+		.name = "msm_dig_cdc_dai_tx1",
+		.id = AIF1_CAP,
+		.capture = { /* Support maximum range */
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		 .ops = &msm_dig_dai_ops,
+	},
+	{
+		.name = "msm_dig_cdc_dai_tx2",
+		.id = AIF3_SVA,
+		.capture = { /* Support maximum range */
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		 .ops = &msm_dig_dai_ops,
+	},
+	{
+		.name = "msm_dig_cdc_dai_vifeed",
+		.id = AIF2_VIFEED,
+		.capture = { /* Support maximum range */
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		 .ops = &msm_dig_dai_ops,
+	},
+};
+
+static struct regmap *msm_digital_get_regmap(struct device *dev)
+{
+	struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(dev);
+
+	return msm_dig_cdc->regmap;
+}
+
+static int msm_dig_cdc_suspend(struct snd_soc_codec *codec)
+{
+	struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev);
+
+	msm_dig_cdc->dapm_bias_off = 1;
+	return 0;
+}
+
+static int msm_dig_cdc_resume(struct snd_soc_codec *codec)
+{
+	struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev);
+
+	msm_dig_cdc->dapm_bias_off = 0;
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_msm_dig_codec = {
+	.probe  = msm_dig_cdc_soc_probe,
+	.remove = msm_dig_cdc_soc_remove,
+	.suspend = msm_dig_cdc_suspend,
+	.resume = msm_dig_cdc_resume,
+	.controls = msm_dig_snd_controls,
+	.num_controls = ARRAY_SIZE(msm_dig_snd_controls),
+	.dapm_widgets = msm_dig_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(msm_dig_dapm_widgets),
+	.dapm_routes = audio_dig_map,
+	.num_dapm_routes = ARRAY_SIZE(audio_dig_map),
+	.get_regmap = msm_digital_get_regmap,
+};
+
+const struct regmap_config msm_digital_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.lock = enable_digital_callback,
+	.unlock = disable_digital_callback,
+	.cache_type = REGCACHE_FLAT,
+	.reg_defaults = msm89xx_cdc_core_defaults,
+	.num_reg_defaults = MSM89XX_CDC_CORE_MAX_REGISTER,
+	.readable_reg = msm89xx_cdc_core_readable_reg,
+	.volatile_reg = msm89xx_cdc_core_volatile_reg,
+	.reg_format_endian = REGMAP_ENDIAN_NATIVE,
+	.val_format_endian = REGMAP_ENDIAN_NATIVE,
+	.max_register = MSM89XX_CDC_CORE_MAX_REGISTER,
+};
+
+static int msm_dig_cdc_probe(struct platform_device *pdev)
+{
+	int ret;
+	u32 dig_cdc_addr;
+	struct msm_dig_priv *msm_dig_cdc;
+	struct dig_ctrl_platform_data *pdata;
+
+	msm_dig_cdc = devm_kzalloc(&pdev->dev, sizeof(struct msm_dig_priv),
+			      GFP_KERNEL);
+	if (!msm_dig_cdc)
+		return -ENOMEM;
+	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata) {
+		dev_err(&pdev->dev, "%s: pdata from parent is NULL\n",
+			__func__);
+		ret = -EINVAL;
+		goto rtn;
+	}
+
+	ret = of_property_read_u32(pdev->dev.of_node, "reg",
+					&dig_cdc_addr);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: could not find %s entry in dt\n",
+			__func__, "reg");
+		return ret;
+	}
+
+	msm_dig_cdc->dig_base = ioremap(dig_cdc_addr,
+					MSM89XX_CDC_CORE_MAX_REGISTER);
+	if (msm_dig_cdc->dig_base == NULL) {
+		dev_err(&pdev->dev, "%s ioremap failed\n", __func__);
+		return -ENOMEM;
+	}
+	msm_dig_cdc->regmap =
+		devm_regmap_init_mmio_clk(&pdev->dev, NULL,
+			msm_dig_cdc->dig_base, &msm_digital_regmap_config);
+
+	msm_dig_cdc->update_clkdiv = pdata->update_clkdiv;
+	msm_dig_cdc->get_cdc_version = pdata->get_cdc_version;
+	msm_dig_cdc->handle = pdata->handle;
+	msm_dig_cdc->register_notifier = pdata->register_notifier;
+
+	dev_set_drvdata(&pdev->dev, msm_dig_cdc);
+	snd_soc_register_codec(&pdev->dev, &soc_msm_dig_codec,
+				msm_codec_dais, ARRAY_SIZE(msm_codec_dais));
+	dev_dbg(&pdev->dev, "%s: registered DIG CODEC 0x%x\n",
+			__func__, dig_cdc_addr);
+rtn:
+	return ret;
+}
+
+static int msm_dig_cdc_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int msm_dig_suspend(struct device *dev)
+{
+	struct msm_asoc_mach_data *pdata =
+	snd_soc_card_get_drvdata(registered_digcodec->component.card);
+	struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(dev);
+
+	if (msm_dig_cdc->dapm_bias_off) {
+		pr_debug("%s: mclk cnt = %d, mclk_enabled = %d\n",
+			__func__, atomic_read(&pdata->int_mclk0_rsc_ref),
+			atomic_read(&pdata->int_mclk0_enabled));
+
+		if (atomic_read(&pdata->int_mclk0_enabled) == true) {
+			cancel_delayed_work_sync(
+				&pdata->disable_int_mclk0_work);
+			mutex_lock(&pdata->cdc_int_mclk0_mutex);
+			pdata->digital_cdc_core_clk.enable = 0;
+			afe_set_lpass_clock_v2(AFE_PORT_ID_INT0_MI2S_RX,
+						&pdata->digital_cdc_core_clk);
+			atomic_set(&pdata->int_mclk0_enabled, false);
+			mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+		}
+	}
+
+	return 0;
+}
+
+static int msm_dig_resume(struct device *dev)
+{
+	return 0;
+}
+
+static const struct dev_pm_ops msm_dig_pm_ops = {
+	.suspend = msm_dig_suspend,
+	.resume = msm_dig_resume,
+};
+#endif
+
+static const struct of_device_id msm_dig_cdc_of_match[] = {
+	{.compatible = "qcom,msm-digital-codec"},
+	{},
+};
+
+static struct platform_driver msm_digcodec_driver = {
+	.driver                 = {
+		.owner          = THIS_MODULE,
+		.name           = DRV_NAME,
+		.of_match_table = msm_dig_cdc_of_match,
+#ifdef CONFIG_PM
+	.pm = &msm_dig_pm_ops,
+#endif
+	},
+	.probe                  = msm_dig_cdc_probe,
+	.remove                 = msm_dig_cdc_remove,
+};
+module_platform_driver(msm_digcodec_driver);
+
+MODULE_DESCRIPTION("MSM Audio Digital codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h
new file mode 100644
index 0000000..f0e7a9c
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h
@@ -0,0 +1,91 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef MSM_DIGITAL_CDC_H
+#define MSM_DIGITAL_CDC_H
+
+#define HPHL_PA_DISABLE (0x01 << 1)
+#define HPHR_PA_DISABLE (0x01 << 2)
+#define SPKR_PA_DISABLE (0x01 << 3)
+
+#define NUM_DECIMATORS	5
+/* Codec supports 1 compander */
+enum {
+	COMPANDER_NONE = 0,
+	COMPANDER_1, /* HPHL/R */
+	COMPANDER_MAX,
+};
+
+/* Number of output I2S port */
+enum {
+	MSM89XX_RX1 = 0,
+	MSM89XX_RX2,
+	MSM89XX_RX3,
+	MSM89XX_RX_MAX,
+};
+
+struct msm_dig_priv {
+	struct snd_soc_codec *codec;
+	u32 comp_enabled[MSM89XX_RX_MAX];
+	int (*codec_hph_comp_gpio)(bool enable, struct snd_soc_codec *codec);
+	s32 dmic_1_2_clk_cnt;
+	s32 dmic_3_4_clk_cnt;
+	bool dec_active[NUM_DECIMATORS];
+	int version;
+	/* Entry for version info */
+	struct snd_info_entry *entry;
+	struct snd_info_entry *version_entry;
+	char __iomem *dig_base;
+	struct regmap *regmap;
+	struct notifier_block nblock;
+	u32 mute_mask;
+	int dapm_bias_off;
+	void *handle;
+	void (*update_clkdiv)(void *handle, int val);
+	int (*get_cdc_version)(void *handle);
+	int (*register_notifier)(void *handle,
+				 struct notifier_block *nblock,
+				 bool enable);
+};
+
+struct dig_ctrl_platform_data {
+	void *handle;
+	void (*update_clkdiv)(void *handle, int val);
+	int (*get_cdc_version)(void *handle);
+	int (*register_notifier)(void *handle,
+				 struct notifier_block *nblock,
+				 bool enable);
+};
+
+struct hpf_work {
+	struct msm_dig_priv *dig_cdc;
+	u32 decimator;
+	u8 tx_hpf_cut_of_freq;
+	struct delayed_work dwork;
+};
+
+/* Codec supports 5 bands */
+enum {
+	BAND1 = 0,
+	BAND2,
+	BAND3,
+	BAND4,
+	BAND5,
+	BAND_MAX,
+};
+
+extern void msm_dig_cdc_hph_comp_cb(
+		int (*codec_hph_comp_gpio)(
+			bool enable, struct snd_soc_codec *codec),
+		struct snd_soc_codec *codec);
+int msm_dig_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+					  struct snd_soc_codec *codec);
+#endif
diff --git a/sound/soc/codecs/msm8x16/msm8916-wcd-irq.c b/sound/soc/codecs/sdm660_cdc/sdm660-cdc-irq.c
similarity index 88%
rename from sound/soc/codecs/msm8x16/msm8916-wcd-irq.c
rename to sound/soc/codecs/sdm660_cdc/sdm660-cdc-irq.c
index a722842..ee4ec34 100644
--- a/sound/soc/codecs/msm8x16/msm8916-wcd-irq.c
+++ b/sound/soc/codecs/sdm660_cdc/sdm660-cdc-irq.c
@@ -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
@@ -13,6 +13,7 @@
 #include <linux/bitops.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/of_irq.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
@@ -25,9 +26,9 @@
 #include <linux/pm_qos.h>
 #include <soc/qcom/pm.h>
 #include <sound/soc.h>
-#include "msm8x16-wcd.h"
-#include "msm8916-wcd-irq.h"
-#include "msm8x16_wcd_registers.h"
+#include "msm-analog-cdc.h"
+#include "sdm660-cdc-irq.h"
+#include "sdm660-cdc-registers.h"
 
 #define MAX_NUM_IRQS 14
 #define NUM_IRQ_REGS 2
@@ -83,7 +84,7 @@
 	uint8_t mask[NUM_IRQ_REGS];
 	int linuxirq[MAX_NUM_IRQS];
 	irq_handler_t handler[MAX_NUM_IRQS];
-	struct spmi_device *spmi[NUM_IRQ_REGS];
+	struct platform_device *spmi[NUM_IRQ_REGS];
 	struct snd_soc_codec *codec;
 
 	enum wcd9xxx_spmi_pm_state pm_state;
@@ -99,22 +100,6 @@
 void wcd9xxx_spmi_enable_irq(int irq)
 {
 	pr_debug("%s: irqno =%d\n", __func__, irq);
-	if ((irq >= 0) && (irq <= 7)) {
-		snd_soc_update_bits(map.codec,
-				MSM89XX_PMIC_DIGITAL_INT_EN_CLR,
-				(0x01 << irq), 0x00);
-		snd_soc_update_bits(map.codec,
-				MSM89XX_PMIC_DIGITAL_INT_EN_SET,
-				(0x01 << irq), (0x01 << irq));
-	}
-	if ((irq > 7) && (irq <= 15)) {
-		snd_soc_update_bits(map.codec,
-				MSM89XX_PMIC_ANALOG_INT_EN_CLR,
-				(0x01 << (irq - 8)), 0x00);
-		snd_soc_update_bits(map.codec,
-				MSM89XX_PMIC_ANALOG_INT_EN_SET,
-				(0x01 << (irq - 8)), (0x01 << (irq - 8)));
-	}
 
 	if (!(map.mask[BIT_BYTE(irq)] & (BYTE_BIT_MASK(irq))))
 		return;
@@ -128,23 +113,6 @@
 void wcd9xxx_spmi_disable_irq(int irq)
 {
 	pr_debug("%s: irqno =%d\n", __func__, irq);
-	if ((irq >= 0) && (irq <= 7)) {
-		snd_soc_update_bits(map.codec,
-				MSM89XX_PMIC_DIGITAL_INT_EN_SET,
-				(0x01 << (irq)), 0x00);
-		snd_soc_update_bits(map.codec,
-				MSM89XX_PMIC_DIGITAL_INT_EN_CLR,
-				(0x01 << irq), (0x01 << irq));
-	}
-
-	if ((irq > 7) && (irq <= 15)) {
-		snd_soc_update_bits(map.codec,
-				MSM89XX_PMIC_ANALOG_INT_EN_SET,
-				(0x01 << (irq - 8)), 0x00);
-		snd_soc_update_bits(map.codec,
-				MSM89XX_PMIC_ANALOG_INT_EN_CLR,
-				(0x01 << (irq - 8)), (0x01 << (irq - 8)));
-	}
 
 	if (map.mask[BIT_BYTE(irq)] & (BYTE_BIT_MASK(irq)))
 		return;
@@ -161,6 +129,10 @@
 	int rc;
 	unsigned long irq_flags;
 
+	map.linuxirq[irq] =
+		platform_get_irq_byname(map.spmi[BIT_BYTE(irq)],
+					irq_names[irq]);
+
 	if (strcmp(name, "mbhc sw intr"))
 		irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
 			IRQF_ONESHOT;
@@ -414,7 +386,7 @@
 	map.codec = codec;
 }
 
-void wcd9xxx_spmi_set_dev(struct spmi_device *spmi, int i)
+void wcd9xxx_spmi_set_dev(struct platform_device *spmi, int i)
 {
 	if (i < NUM_IRQ_REGS)
 		map.spmi[i] = spmi;
diff --git a/sound/soc/codecs/msm8x16/msm8916-wcd-irq.h b/sound/soc/codecs/sdm660_cdc/sdm660-cdc-irq.h
similarity index 89%
rename from sound/soc/codecs/msm8x16/msm8916-wcd-irq.h
rename to sound/soc/codecs/sdm660_cdc/sdm660-cdc-irq.h
index 3862865..d0f48d0 100644
--- a/sound/soc/codecs/msm8x16/msm8916-wcd-irq.h
+++ b/sound/soc/codecs/sdm660_cdc/sdm660-cdc-irq.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, 2017 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,7 +24,7 @@
 				const char *name, void *priv);
 extern int wcd9xxx_spmi_free_irq(int irq, void *priv);
 extern void wcd9xxx_spmi_set_codec(struct snd_soc_codec *codec);
-extern void wcd9xxx_spmi_set_dev(struct spmi_device *spmi, int i);
+extern void wcd9xxx_spmi_set_dev(struct platform_device *spmi, int i);
 extern int wcd9xxx_spmi_irq_init(void);
 extern int wcd9xxx_spmi_suspend(pm_message_t pmesg);
 extern int wcd9xxx_spmi_resume(void);
diff --git a/sound/soc/codecs/msm8x16/msm8x16_wcd_registers.h b/sound/soc/codecs/sdm660_cdc/sdm660-cdc-registers.h
similarity index 82%
rename from sound/soc/codecs/msm8x16/msm8x16_wcd_registers.h
rename to sound/soc/codecs/sdm660_cdc/sdm660-cdc-registers.h
index ec26ef39..1317ce1 100644
--- a/sound/soc/codecs/msm8x16/msm8x16_wcd_registers.h
+++ b/sound/soc/codecs/sdm660_cdc/sdm660-cdc-registers.h
@@ -9,8 +9,8 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-#ifndef MSM8X16_WCD_REGISTERS_H
-#define MSM8X16_WCD_REGISTERS_H
+#ifndef SDM660_WCD_REGISTERS_H
+#define SDM660_WCD_REGISTERS_H
 
 #define CDC_DIG_BASE		0xF000
 #define CDC_ANA_BASE		0xF100
@@ -335,20 +335,20 @@
 		MSM89XX_PMIC_CDC_NUM_REGISTERS
 
 
-#define MSM89XX_CDC_CORE_CLK_RX_RESET_CTL		(0x00)
+#define MSM89XX_CDC_CORE_CLK_RX_RESET_CTL	(0x00)
 #define MSM89XX_CDC_CORE_CLK_RX_RESET_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL		(0x04)
-#define MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL		(0x08)
+#define MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL	(0x04)
+#define MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL	(0x08)
 #define MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL__POR		(0x00)
 #define MSM89XX_CDC_CORE_CLK_RX_I2S_CTL		(0x0C)
 #define MSM89XX_CDC_CORE_CLK_RX_I2S_CTL__POR		(0x13)
 #define MSM89XX_CDC_CORE_CLK_TX_I2S_CTL		(0x10)
 #define MSM89XX_CDC_CORE_CLK_TX_I2S_CTL__POR		(0x13)
-#define MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL		(0x14)
-#define MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL		(0x18)
-#define MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL	(0x14)
+#define MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL	(0x18)
+#define MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL__POR	(0x00)
 #define MSM89XX_CDC_CORE_CLK_OTHR_CTL		(0x1C)
 #define MSM89XX_CDC_CORE_CLK_OTHR_CTL__POR		(0x04)
 #define MSM89XX_CDC_CORE_CLK_RX_B1_CTL		(0x20)
@@ -359,10 +359,12 @@
 #define MSM89XX_CDC_CORE_CLK_PDM_CTL__POR		(0x00)
 #define MSM89XX_CDC_CORE_CLK_SD_CTL		(0x2C)
 #define MSM89XX_CDC_CORE_CLK_SD_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL		(0x30)
-#define MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL	(0x30)
+#define MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL__POR		(0x00)
 #define MSM89XX_CDC_CORE_CLK_RX_B2_CTL		(0x34)
 #define MSM89XX_CDC_CORE_CLK_RX_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL	(0x38)
+#define MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL__POR		(0x13)
 #define MSM89XX_CDC_CORE_RX1_B1_CTL		(0x40)
 #define MSM89XX_CDC_CORE_RX1_B1_CTL__POR		(0x00)
 #define MSM89XX_CDC_CORE_RX2_B1_CTL		(0x60)
@@ -399,19 +401,19 @@
 #define MSM89XX_CDC_CORE_RX2_B6_CTL__POR		(0x00)
 #define MSM89XX_CDC_CORE_RX3_B6_CTL		(0x94)
 #define MSM89XX_CDC_CORE_RX3_B6_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL		(0x58)
-#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL		(0x78)
-#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL		(0x98)
-#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL		(0x5C)
-#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL		(0x7C)
-#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL		(0x9C)
-#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_TOP_GAIN_UPDATE		(0xA0)
+#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL	(0x58)
+#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL	(0x78)
+#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL	(0x98)
+#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL	(0x5C)
+#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL	(0x7C)
+#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL	(0x9C)
+#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_TOP_GAIN_UPDATE	(0xA0)
 #define MSM89XX_CDC_CORE_TOP_GAIN_UPDATE__POR		(0x00)
 #define MSM89XX_CDC_CORE_TOP_CTL		(0xA4)
 #define MSM89XX_CDC_CORE_TOP_CTL__POR			(0x01)
@@ -427,129 +429,145 @@
 #define MSM89XX_CDC_CORE_COMP0_B5_CTL__POR		(0x7F)
 #define MSM89XX_CDC_CORE_COMP0_B6_CTL		(0xC4)
 #define MSM89XX_CDC_CORE_COMP0_B6_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS		(0xC8)
-#define MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS__POR		(0x03)
+#define MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS	(0xC8)
+#define MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS__POR	(0x03)
 #define MSM89XX_CDC_CORE_COMP0_FS_CFG		(0xCC)
 #define MSM89XX_CDC_CORE_COMP0_FS_CFG__POR		(0x03)
-#define MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL		(0xD0)
-#define MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL__POR		(0x02)
-#define MSM89XX_CDC_CORE_DEBUG_DESER1_CTL		(0xE0)
+#define MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL	(0xD0)
+#define MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL__POR	(0x02)
+#define MSM89XX_CDC_CORE_DEBUG_DESER1_CTL	(0xE0)
 #define MSM89XX_CDC_CORE_DEBUG_DESER1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_DEBUG_DESER2_CTL		(0xE4)
+#define MSM89XX_CDC_CORE_DEBUG_DESER2_CTL	(0xE4)
 #define MSM89XX_CDC_CORE_DEBUG_DESER2_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG		(0xE8)
+#define MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG	(0xE8)
 #define MSM89XX_CDC_CORE_DEBUG_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG		(0xEC)
+#define MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG	(0xEC)
 #define MSM89XX_CDC_CORE_DEBUG_B2_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG		(0xF0)
+#define MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG	(0xF0)
 #define MSM89XX_CDC_CORE_DEBUG_B3_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL		(0x100)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL	(0x100)
 #define MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL		(0x140)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL	(0x140)
 #define MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL		(0x104)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL	(0x104)
 #define MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL		(0x144)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL	(0x144)
 #define MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL		(0x108)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL	(0x108)
 #define MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL		(0x148)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL	(0x148)
 #define MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL		(0x10C)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL	(0x10C)
 #define MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL		(0x14C)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL	(0x14C)
 #define MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL		(0x110)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL	(0x110)
 #define MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL		(0x150)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL	(0x150)
 #define MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL		(0x114)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL	(0x114)
 #define MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL		(0x154)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL	(0x154)
 #define MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL		(0x118)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL	(0x118)
 #define MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL		(0x158)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL	(0x158)
 #define MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL		(0x11C)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL	(0x11C)
 #define MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL		(0x15C)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL	(0x15C)
 #define MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL__POR		(0x00)
 #define MSM89XX_CDC_CORE_IIR1_CTL		(0x120)
-#define MSM89XX_CDC_CORE_IIR1_CTL__POR		(0x40)
+#define MSM89XX_CDC_CORE_IIR1_CTL__POR			(0x40)
 #define MSM89XX_CDC_CORE_IIR2_CTL		(0x160)
-#define MSM89XX_CDC_CORE_IIR2_CTL__POR		(0x40)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL		(0x124)
-#define MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL		(0x164)
-#define MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL		(0x128)
+#define MSM89XX_CDC_CORE_IIR2_CTL__POR			(0x40)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL	(0x124)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL	(0x164)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL	(0x128)
 #define MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL		(0x168)
+#define MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL	(0x168)
 #define MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL		(0x12C)
+#define MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL	(0x12C)
 #define MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL		(0x16C)
+#define MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL	(0x16C)
 #define MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_RX1_B1_CTL		(0x180)
+#define MSM89XX_CDC_CORE_CONN_RX1_B1_CTL	(0x180)
 #define MSM89XX_CDC_CORE_CONN_RX1_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_RX1_B2_CTL		(0x184)
+#define MSM89XX_CDC_CORE_CONN_RX1_B2_CTL	(0x184)
 #define MSM89XX_CDC_CORE_CONN_RX1_B2_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_RX1_B3_CTL		(0x188)
+#define MSM89XX_CDC_CORE_CONN_RX1_B3_CTL	(0x188)
 #define MSM89XX_CDC_CORE_CONN_RX1_B3_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_RX2_B1_CTL		(0x18C)
+#define MSM89XX_CDC_CORE_CONN_RX2_B1_CTL	(0x18C)
 #define MSM89XX_CDC_CORE_CONN_RX2_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_RX2_B2_CTL		(0x190)
+#define MSM89XX_CDC_CORE_CONN_RX2_B2_CTL	(0x190)
 #define MSM89XX_CDC_CORE_CONN_RX2_B2_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_RX2_B3_CTL		(0x194)
+#define MSM89XX_CDC_CORE_CONN_RX2_B3_CTL	(0x194)
 #define MSM89XX_CDC_CORE_CONN_RX2_B3_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_RX3_B1_CTL		(0x198)
+#define MSM89XX_CDC_CORE_CONN_RX3_B1_CTL	(0x198)
 #define MSM89XX_CDC_CORE_CONN_RX3_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_RX3_B2_CTL		(0x19C)
+#define MSM89XX_CDC_CORE_CONN_RX3_B2_CTL	(0x19C)
 #define MSM89XX_CDC_CORE_CONN_RX3_B2_CTL__POR		(0x00)
 #define MSM89XX_CDC_CORE_CONN_TX_B1_CTL		(0x1A0)
 #define MSM89XX_CDC_CORE_CONN_TX_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL		(0x1A8)
+#define MSM89XX_CDC_CORE_CONN_TX_B2_CTL		(0x1A4)
+#define MSM89XX_CDC_CORE_CONN_TX_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL	(0x1A8)
 #define MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL		(0x1AC)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL	(0x1AC)
 #define MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL		(0x1B0)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL	(0x1B0)
 #define MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL		(0x1B4)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL	(0x1B4)
 #define MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL		(0x1B8)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL	(0x1B8)
 #define MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL		(0x1BC)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL	(0x1BC)
 #define MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL		(0x1C0)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL	(0x1C0)
 #define MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL		(0x1C4)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL	(0x1C4)
 #define MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL		(0x1C8)
-#define MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL__POR		(0x00)
-#define MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER		(0x280)
+#define MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL	(0x1C8)
+#define MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_CONN_TX_B3_CTL		(0x1CC)
+#define MSM89XX_CDC_CORE_CONN_TX_B3_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER	(0x1E0)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN	(0x1E4)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG	(0x1E8)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX5_MUX_CTL		(0x1EC)
+#define MSM89XX_CDC_CORE_TX5_MUX_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX5_CLK_FS_CTL		(0x1F0)
+#define MSM89XX_CDC_CORE_TX5_CLK_FS_CTL__POR		(0x03)
+#define MSM89XX_CDC_CORE_TX5_DMIC_CTL		(0x1F4)
+#define MSM89XX_CDC_CORE_TX5_DMIC_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER	(0x280)
 #define MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER__POR		(0x00)
-#define MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER		(0x2A0)
+#define MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER	(0x2A0)
 #define MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER__POR		(0x00)
-#define MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER		(0x2C0)
+#define MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER	(0x2C0)
 #define MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER__POR		(0x00)
-#define MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER		(0x2E0)
+#define MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER	(0x2E0)
 #define MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER__POR		(0x00)
-#define MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN		(0x284)
+#define MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN	(0x284)
 #define MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN__POR		(0x00)
-#define MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN		(0x2A4)
+#define MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN	(0x2A4)
 #define MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN__POR		(0x00)
-#define MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN		(0x2C4)
+#define MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN	(0x2C4)
 #define MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN__POR		(0x00)
-#define MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN		(0x2E4)
+#define MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN	(0x2E4)
 #define MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN__POR		(0x00)
-#define MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG		(0x288)
+#define MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG	(0x288)
 #define MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG__POR		(0x00)
-#define MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG		(0x2A8)
+#define MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG	(0x2A8)
 #define MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG__POR		(0x00)
-#define MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG		(0x2C8)
+#define MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG	(0x2C8)
 #define MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG__POR		(0x00)
-#define MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG		(0x2E8)
+#define MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG	(0x2E8)
 #define MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG__POR		(0x00)
 #define MSM89XX_CDC_CORE_TX1_MUX_CTL		(0x28C)
 #define MSM89XX_CDC_CORE_TX1_MUX_CTL__POR		(0x00)
diff --git a/sound/soc/codecs/msm8x16/msm89xx-regmap.c b/sound/soc/codecs/sdm660_cdc/sdm660-regmap.c
similarity index 67%
rename from sound/soc/codecs/msm8x16/msm89xx-regmap.c
rename to sound/soc/codecs/sdm660_cdc/sdm660-regmap.c
index 007b74c..fff1fdc 100644
--- a/sound/soc/codecs/msm8x16/msm89xx-regmap.c
+++ b/sound/soc/codecs/sdm660_cdc/sdm660-regmap.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
@@ -12,8 +12,7 @@
  */
 
 #include <linux/regmap.h>
-#include <linux/device.h>
-#include "msm8x16-wcd.h"
+#include "sdm660-cdc-registers.h"
 
 /*
  * Default register reset values that are common across different versions
@@ -21,7 +20,7 @@
  * then remove it from this structure and add it in version specific
  * structures.
  */
-static struct reg_default
+struct reg_default
 	msm89xx_cdc_core_defaults[MSM89XX_CDC_CORE_CACHE_SIZE] = {
 	{MSM89XX_CDC_CORE_CLK_RX_RESET_CTL, 0x00},
 	{MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL, 0x00},
@@ -35,8 +34,9 @@
 	{MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x00},
 	{MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x00},
 	{MSM89XX_CDC_CORE_CLK_SD_CTL, 0x00},
-	{MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL, 0x00},
 	{MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL, 0x13},
 	{MSM89XX_CDC_CORE_RX1_B1_CTL, 0x00},
 	{MSM89XX_CDC_CORE_RX2_B1_CTL, 0x00},
 	{MSM89XX_CDC_CORE_RX3_B1_CTL, 0x00},
@@ -78,8 +78,9 @@
 	{MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG, 0x00},
 	{MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG, 0x00},
 	{MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL, 0x00},
-	{MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL, 0x00},
 	{MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL, 0x00},
 	{MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL, 0x00},
 	{MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL, 0x00},
 	{MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL, 0x00},
@@ -92,7 +93,6 @@
 	{MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL, 0x00},
 	{MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL, 0x00},
 	{MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL, 0x00},
-	{MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL, 0x00},
 	{MSM89XX_CDC_CORE_IIR1_CTL, 0x40},
 	{MSM89XX_CDC_CORE_IIR2_CTL, 0x40},
 	{MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL, 0x00},
@@ -110,6 +110,7 @@
 	{MSM89XX_CDC_CORE_CONN_RX3_B1_CTL, 0x00},
 	{MSM89XX_CDC_CORE_CONN_RX3_B2_CTL, 0x00},
 	{MSM89XX_CDC_CORE_CONN_TX_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_TX_B2_CTL, 0x00},
 	{MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL, 0x00},
 	{MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL, 0x00},
 	{MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL, 0x00},
@@ -119,6 +120,13 @@
 	{MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL, 0x00},
 	{MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL, 0x00},
 	{MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_TX_B3_CTL, 0x00},
+	{MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER, 0x00},
+	{MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN, 0x00},
+	{MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG, 0x00},
+	{MSM89XX_CDC_CORE_TX5_MUX_CTL, 0x00},
+	{MSM89XX_CDC_CORE_TX5_CLK_FS_CTL, 0x03},
+	{MSM89XX_CDC_CORE_TX5_DMIC_CTL, 0x00},
 	{MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER, 0x00},
 	{MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER, 0x00},
 	{MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER, 0x00},
@@ -145,7 +153,7 @@
 	{MSM89XX_CDC_CORE_TX4_DMIC_CTL, 0x00},
 };
 
-static struct reg_default
+struct reg_default
 	msm89xx_pmic_cdc_defaults[MSM89XX_PMIC_CDC_CACHE_SIZE] = {
 	{MSM89XX_PMIC_DIGITAL_REVISION1, 0x00},
 	{MSM89XX_PMIC_DIGITAL_REVISION2, 0x00},
@@ -304,114 +312,148 @@
 	{MSM89XX_PMIC_ANALOG_TRIM_CTRL4, 0x00},
 };
 
-static bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg)
+static const u8 msm89xx_cdc_core_reg_readable[MSM89XX_CDC_CORE_CACHE_SIZE] = {
+		[MSM89XX_CDC_CORE_CLK_RX_RESET_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_RX_I2S_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX_I2S_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_OTHR_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_RX_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_MCLK_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_PDM_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_SD_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_RX_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_TOP_GAIN_UPDATE] = 1,
+		[MSM89XX_CDC_CORE_TOP_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS] = 1,
+		[MSM89XX_CDC_CORE_COMP0_FS_CFG] = 1,
+		[MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_DESER1_CTL] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_DESER2_CTL] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX1_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX1_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX1_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX2_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX2_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX2_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX3_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX3_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX1_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX2_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX3_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX4_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX1_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX2_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX3_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX4_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX5_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX5_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX5_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX1_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX2_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX3_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX4_DMIC_CTL] = 1,
+};
+
+bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg)
 {
 	return msm89xx_cdc_core_reg_readable[reg];
 }
 
-static bool msm89xx_pmic_cdc_readable_reg(struct device *dev, unsigned int reg)
-{
-	return msm89xx_pmic_cdc_reg_readable[reg];
-}
-
-static bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg)
+bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
-	case MSM89XX_CDC_CORE_RX1_B1_CTL:
-	case MSM89XX_CDC_CORE_RX2_B1_CTL:
-	case MSM89XX_CDC_CORE_RX3_B1_CTL:
-	case MSM89XX_CDC_CORE_RX1_B6_CTL:
-	case MSM89XX_CDC_CORE_RX2_B6_CTL:
-	case MSM89XX_CDC_CORE_RX3_B6_CTL:
-	case MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG:
-	case MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG:
-	case MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL:
-	case MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL:
-	case MSM89XX_CDC_CORE_CLK_MCLK_CTL:
-	case MSM89XX_CDC_CORE_CLK_PDM_CTL:
-	case MSM89XX_PMIC_ANALOG_BYPASS_MODE:
-	case MSM89XX_PMIC_ANALOG_BOOST_EN_CTL:
-	case MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL:
-	case MSM89XX_PMIC_ANALOG_CURRENT_LIMIT:
-	case MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL:
-	case MSM89XX_PMIC_ANALOG_NCP_FBCTRL:
-	case MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1:
-		return true;
+	/* cache bypass for initial version */
 	default:
-		return false;
+		return true;
 	}
 }
-
-static bool msm89xx_pmic_cdc_volatile_reg(struct device *dev, unsigned int reg)
-{
-	switch (reg) {
-	case MSM89XX_PMIC_DIGITAL_REVISION1:
-	case MSM89XX_PMIC_DIGITAL_REVISION2:
-	case MSM89XX_PMIC_DIGITAL_PERPH_TYPE:
-	case MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE:
-	case MSM89XX_PMIC_DIGITAL_INT_RT_STS:
-	case MSM89XX_PMIC_DIGITAL_INT_SET_TYPE:
-	case MSM89XX_PMIC_DIGITAL_INT_POLARITY_HIGH:
-	case MSM89XX_PMIC_DIGITAL_INT_POLARITY_LOW:
-	case MSM89XX_PMIC_DIGITAL_INT_LATCHED_STS:
-	case MSM89XX_PMIC_DIGITAL_INT_PENDING_STS:
-	case MSM89XX_PMIC_DIGITAL_PIN_STATUS:
-	case MSM89XX_PMIC_DIGITAL_SEC_ACCESS:
-	case MSM89XX_PMIC_ANALOG_SEC_ACCESS:
-	case MSM89XX_PMIC_ANALOG_REVISION1:
-	case MSM89XX_PMIC_ANALOG_REVISION2:
-	case MSM89XX_PMIC_ANALOG_REVISION3:
-	case MSM89XX_PMIC_ANALOG_REVISION4:
-	case MSM89XX_PMIC_ANALOG_PERPH_TYPE:
-	case MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE:
-	case MSM89XX_PMIC_ANALOG_INT_RT_STS:
-	case MSM89XX_PMIC_ANALOG_INT_SET_TYPE:
-	case MSM89XX_PMIC_ANALOG_INT_POLARITY_HIGH:
-	case MSM89XX_PMIC_ANALOG_INT_POLARITY_LOW:
-	case MSM89XX_PMIC_ANALOG_INT_LATCHED_STS:
-	case MSM89XX_PMIC_ANALOG_INT_PENDING_STS:
-	case MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT:
-	case MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT:
-	case MSM89XX_PMIC_ANALOG_RX_HPH_STATUS:
-	case MSM89XX_PMIC_ANALOG_RX_EAR_STATUS:
-	case MSM89XX_PMIC_ANALOG_SPKR_SAR_STATUS:
-	case MSM89XX_PMIC_ANALOG_SPKR_DRV_STATUS:
-		return true;
-	default:
-		return false;
-	}
-}
-
-struct regmap_config msm89xx_pmic_cdc_regmap_config = {
-	.reg_bits	= 16,
-	.val_bits	= 8,
-	.max_register	= MSM89XX_PMIC_CDC_CACHE_SIZE,
-	.fast_io	= true,
-	.reg_defaults = msm89xx_pmic_cdc_defaults,
-	.num_reg_defaults = ARRAY_SIZE(msm89xx_pmic_cdc_defaults),
-	.readable_reg = msm89xx_pmic_cdc_readable_reg,
-	.volatile_reg = msm89xx_pmic_cdc_volatile_reg,
-	.cache_type = REGCACHE_RBTREE,
-	.reg_format_endian = REGMAP_ENDIAN_NATIVE,
-	.val_format_endian = REGMAP_ENDIAN_NATIVE,
-	.can_multi_write = true,
-	.lock = enable_digital_callback,
-	.unlock = disable_digital_callback,
-
-};
-
-struct regmap_config msm89xx_cdc_core_regmap_config = {
-	.reg_bits = 32,
-	.reg_stride = 4,
-	.val_bits = 32,
-
-	.max_register = MSM89XX_CDC_CORE_CACHE_SIZE,
-	.reg_defaults = msm89xx_cdc_core_defaults,
-	.num_reg_defaults = ARRAY_SIZE(msm89xx_cdc_core_defaults),
-	.readable_reg = msm89xx_cdc_core_readable_reg,
-	.volatile_reg = msm89xx_cdc_core_volatile_reg,
-	.cache_type = REGCACHE_RBTREE,
-	.reg_format_endian = REGMAP_ENDIAN_NATIVE,
-	.val_format_endian = REGMAP_ENDIAN_NATIVE,
-	.can_multi_write = true,
-};
diff --git a/sound/soc/codecs/wcd-dsp-mgr.c b/sound/soc/codecs/wcd-dsp-mgr.c
index 5c27f10..ae53294 100644
--- a/sound/soc/codecs/wcd-dsp-mgr.c
+++ b/sound/soc/codecs/wcd-dsp-mgr.c
@@ -881,12 +881,50 @@
 
 static int wdsp_suspend(struct device *wdsp_dev)
 {
-	return 0;
+	struct wdsp_mgr_priv *wdsp;
+	int rc = 0, i;
+
+	if (!wdsp_dev) {
+		pr_err("%s: Invalid handle to device\n", __func__);
+		return -EINVAL;
+	}
+
+	wdsp = dev_get_drvdata(wdsp_dev);
+
+	for (i =  WDSP_CMPNT_TYPE_MAX - 1; i >= 0; i--) {
+		rc = wdsp_unicast_event(wdsp, i, WDSP_EVENT_SUSPEND, NULL);
+		if (rc < 0) {
+			WDSP_ERR(wdsp, "component %s failed to suspend\n",
+				WDSP_GET_CMPNT_TYPE_STR(i));
+			break;
+		}
+	}
+
+	return rc;
 }
 
 static int wdsp_resume(struct device *wdsp_dev)
 {
-	return 0;
+	struct wdsp_mgr_priv *wdsp;
+	int rc = 0, i;
+
+	if (!wdsp_dev) {
+		pr_err("%s: Invalid handle to device\n", __func__);
+		return -EINVAL;
+	}
+
+	wdsp = dev_get_drvdata(wdsp_dev);
+
+	for (i =  0; i < WDSP_CMPNT_TYPE_MAX; i++) {
+		rc = wdsp_unicast_event(wdsp, i, WDSP_EVENT_RESUME, NULL);
+		if (rc < 0) {
+			WDSP_ERR(wdsp, "component %s failed to resume\n",
+				WDSP_GET_CMPNT_TYPE_STR(i));
+			break;
+		}
+	}
+
+	return rc;
 }
 
 static struct wdsp_mgr_ops wdsp_ops = {
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index f4c68ff..75e2709 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -25,6 +25,7 @@
 #include <linux/input.h>
 #include <linux/firmware.h>
 #include <linux/completion.h>
+#include <linux/mfd/msm-cdc-pinctrl.h>
 #include <sound/soc.h>
 #include <sound/jack.h>
 #include "wcd-mbhc-v2.h"
@@ -52,7 +53,7 @@
 
 #define WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS  50
 #define ANC_DETECT_RETRY_CNT 7
-#define WCD_MBHC_SPL_HS_CNT  1
+#define WCD_MBHC_SPL_HS_CNT  2
 
 static int det_extn_cable_en;
 module_param(det_extn_cable_en, int, 0664);
@@ -570,6 +571,9 @@
 static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
 				enum snd_jack_types jack_type)
 {
+	struct snd_soc_codec *codec = mbhc->codec;
+	bool is_pa_on = false;
+
 	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
 
 	pr_debug("%s: enter insertion %d hph_status %x\n",
@@ -595,14 +599,14 @@
 		if (mbhc->micbias_enable) {
 			if (mbhc->mbhc_cb->mbhc_micbias_control)
 				mbhc->mbhc_cb->mbhc_micbias_control(
-						mbhc->codec, MIC_BIAS_2,
+						codec, MIC_BIAS_2,
 						MICB_DISABLE);
 			if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
 				mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
-						mbhc->codec,
+						codec,
 						MIC_BIAS_2, false);
 			if (mbhc->mbhc_cb->set_micbias_value) {
-				mbhc->mbhc_cb->set_micbias_value(mbhc->codec);
+				mbhc->mbhc_cb->set_micbias_value(codec);
 				WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0);
 			}
 			mbhc->micbias_enable = false;
@@ -632,15 +636,15 @@
 			if (mbhc->micbias_enable) {
 				if (mbhc->mbhc_cb->mbhc_micbias_control)
 					mbhc->mbhc_cb->mbhc_micbias_control(
-						mbhc->codec, MIC_BIAS_2,
+						codec, MIC_BIAS_2,
 						MICB_DISABLE);
 				if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
 					mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
-						mbhc->codec,
+						codec,
 						MIC_BIAS_2, false);
 				if (mbhc->mbhc_cb->set_micbias_value) {
 					mbhc->mbhc_cb->set_micbias_value(
-							mbhc->codec);
+							codec);
 					WCD_MBHC_REG_UPDATE_BITS(
 							WCD_MBHC_MICB_CTRL, 0);
 				}
@@ -691,9 +695,13 @@
 		} else if (jack_type == SND_JACK_ANC_HEADPHONE)
 			mbhc->current_plug = MBHC_PLUG_TYPE_ANC_HEADPHONE;
 
+		if (mbhc->mbhc_cb->hph_pa_on_status)
+			is_pa_on = mbhc->mbhc_cb->hph_pa_on_status(codec);
+
 		if (mbhc->impedance_detect &&
 			mbhc->mbhc_cb->compute_impedance &&
-			(mbhc->mbhc_cfg->linein_th != 0)) {
+			(mbhc->mbhc_cfg->linein_th != 0) &&
+			(!is_pa_on)) {
 			mbhc->mbhc_cb->compute_impedance(mbhc,
 					&mbhc->zl, &mbhc->zr);
 			if ((mbhc->zl > mbhc->mbhc_cfg->linein_th &&
@@ -1158,6 +1166,8 @@
 	bool micbias1 = false;
 	int ret = 0;
 	int rc, spl_hs_count = 0;
+	int cross_conn;
+	int try = 0;
 
 	pr_debug("%s: enter\n", __func__);
 
@@ -1175,11 +1185,6 @@
 	wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
 
 
-	if (mbhc->current_plug == MBHC_PLUG_TYPE_GND_MIC_SWAP) {
-		mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
-		goto correct_plug_type;
-	}
-
 	/* Enable HW FSM */
 	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
 	/*
@@ -1207,8 +1212,23 @@
 			plug_type = MBHC_PLUG_TYPE_INVALID;
 	}
 
-	pr_debug("%s: Valid plug found, plug type is %d\n",
+	do {
+		cross_conn = wcd_check_cross_conn(mbhc);
+		try++;
+	} while (try < GND_MIC_SWAP_THRESHOLD);
+	/*
+	 * check for cross coneection 4 times.
+	 * conisder the result of the fourth iteration.
+	 */
+	if (cross_conn > 0) {
+		pr_debug("%s: cross con found, start polling\n",
+			 __func__);
+		plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
+		pr_debug("%s: Plug found, plug type is %d\n",
 			 __func__, plug_type);
+		goto correct_plug_type;
+	}
+
 	if ((plug_type == MBHC_PLUG_TYPE_HEADSET ||
 	     plug_type == MBHC_PLUG_TYPE_HEADPHONE) &&
 	    (!wcd_swch_level_remove(mbhc))) {
@@ -1226,7 +1246,8 @@
 					mbhc->hs_detect_work_stop);
 			wcd_enable_curr_micbias(mbhc,
 						WCD_MBHC_EN_NONE);
-			if (mbhc->micbias_enable) {
+			if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic &&
+				mbhc->micbias_enable) {
 				mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
 					mbhc->codec, MIC_BIAS_2, false);
 				if (mbhc->mbhc_cb->set_micbias_value)
@@ -1251,7 +1272,8 @@
 					mbhc->hs_detect_work_stop);
 			wcd_enable_curr_micbias(mbhc,
 						WCD_MBHC_EN_NONE);
-			if (mbhc->micbias_enable) {
+			if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic &&
+				mbhc->micbias_enable) {
 				mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
 					mbhc->codec, MIC_BIAS_2, false);
 				if (mbhc->mbhc_cb->set_micbias_value)
@@ -1448,10 +1470,7 @@
 static void wcd_mbhc_detect_plug_type(struct wcd_mbhc *mbhc)
 {
 	struct snd_soc_codec *codec = mbhc->codec;
-	enum wcd_mbhc_plug_type plug_type;
 	bool micbias1 = false;
-	int cross_conn;
-	int try = 0;
 
 	pr_debug("%s: enter\n", __func__);
 	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
@@ -1472,21 +1491,6 @@
 	else
 		wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
 
-	do {
-		cross_conn = wcd_check_cross_conn(mbhc);
-		try++;
-	} while (try < GND_MIC_SWAP_THRESHOLD);
-
-	if (cross_conn > 0) {
-		pr_debug("%s: cross con found, start polling\n",
-			 __func__);
-		plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
-		if (!mbhc->current_plug)
-			mbhc->current_plug = plug_type;
-		pr_debug("%s: Plug found, plug type is %d\n",
-			 __func__, plug_type);
-	}
-
 	/* Re-initialize button press completion object */
 	reinit_completion(&mbhc->btn_press_compl);
 	wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
@@ -1549,6 +1553,7 @@
 		if (mbhc->mbhc_cb->enable_mb_source)
 			mbhc->mbhc_cb->enable_mb_source(mbhc, true);
 		mbhc->btn_press_intr = false;
+		mbhc->is_btn_press = false;
 		wcd_mbhc_detect_plug_type(mbhc);
 	} else if ((mbhc->current_plug != MBHC_PLUG_TYPE_NONE)
 			&& !detection_type) {
@@ -1566,6 +1571,7 @@
 			mbhc->mbhc_cb->set_cap_mode(codec, micbias1, false);
 
 		mbhc->btn_press_intr = false;
+		mbhc->is_btn_press = false;
 		if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
 			wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM,
 					     false);
@@ -1603,12 +1609,8 @@
 			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
 			wcd_mbhc_report_plug(mbhc, 0, SND_JACK_LINEOUT);
 		} else if (mbhc->current_plug == MBHC_PLUG_TYPE_ANC_HEADPHONE) {
-			mbhc->mbhc_cb->irq_control(codec,
-					mbhc->intr_ids->mbhc_hs_rem_intr,
-					false);
-			mbhc->mbhc_cb->irq_control(codec,
-					mbhc->intr_ids->mbhc_hs_ins_intr,
-					false);
+			wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, false);
+			wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false);
 			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE,
 						 0);
 			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
@@ -1754,6 +1756,7 @@
 	mic_trigerred = 0;
 	mbhc->is_extn_cable = true;
 	mbhc->btn_press_intr = false;
+	mbhc->is_btn_press = false;
 	wcd_mbhc_detect_plug_type(mbhc);
 	WCD_MBHC_RSC_UNLOCK(mbhc);
 	pr_debug("%s: leave\n", __func__);
@@ -1930,15 +1933,13 @@
 	pr_debug("%s: enter\n", __func__);
 	complete(&mbhc->btn_press_compl);
 	WCD_MBHC_RSC_LOCK(mbhc);
-	/* send event to sw intr handler*/
-	mbhc->is_btn_press = true;
 	wcd_cancel_btn_work(mbhc);
 	if (wcd_swch_level_remove(mbhc)) {
 		pr_debug("%s: Switch level is low ", __func__);
 		goto done;
 	}
-	mbhc->btn_press_intr = true;
 
+	mbhc->is_btn_press = true;
 	msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport);
 	pr_debug("%s: msec_val = %ld\n", __func__, msec_val);
 	if (msec_val < MBHC_BUTTON_PRESS_THRESHOLD_MIN) {
@@ -1952,12 +1953,15 @@
 			 __func__);
 		goto done;
 	}
+	mask = wcd_mbhc_get_button_mask(mbhc);
+	if (mask == SND_JACK_BTN_0)
+		mbhc->btn_press_intr = true;
+
 	if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET) {
 		pr_debug("%s: Plug isn't headset, ignore button press\n",
 				__func__);
 		goto done;
 	}
-	mask = wcd_mbhc_get_button_mask(mbhc);
 	mbhc->buttons_pressed |= mask;
 	mbhc->mbhc_cb->lock_sleep(mbhc, true);
 	if (schedule_delayed_work(&mbhc->mbhc_btn_dwork,
@@ -1983,8 +1987,8 @@
 		goto exit;
 	}
 
-	if (mbhc->btn_press_intr) {
-		mbhc->btn_press_intr = false;
+	if (mbhc->is_btn_press) {
+		mbhc->is_btn_press = false;
 	} else {
 		pr_debug("%s: This release is for fake btn press\n", __func__);
 		goto exit;
@@ -2128,6 +2132,22 @@
 	if (mbhc->mbhc_cfg->moisture_en && mbhc->mbhc_cb->mbhc_moisture_config)
 		mbhc->mbhc_cb->mbhc_moisture_config(mbhc);
 
+	/*
+	 * For USB analog we need to override the switch configuration.
+	 * Also, disable hph_l pull-up current source as HS_DET_L is driven
+	 * by an external source
+	 */
+	if (mbhc->mbhc_cfg->enable_usbc_analog) {
+		mbhc->hphl_swh = 1;
+		mbhc->gnd_swh = 1;
+
+		if (mbhc->mbhc_cb->hph_pull_up_control)
+			mbhc->mbhc_cb->hph_pull_up_control(codec, I_OFF);
+		else
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_CTRL,
+						 0);
+	}
+
 	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PLUG_TYPE, mbhc->hphl_swh);
 	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_GND_PLUG_TYPE, mbhc->gnd_swh);
 	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1);
@@ -2136,8 +2156,14 @@
 	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1);
 	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1);
 
-	/* Insertion debounce set to 96ms */
-	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_INSREM_DBNC, 6);
+	if (mbhc->mbhc_cfg->enable_usbc_analog) {
+		/* Insertion debounce set to 48ms */
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_INSREM_DBNC, 4);
+	} else {
+		/* Insertion debounce set to 96ms */
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_INSREM_DBNC, 6);
+	}
+
 	/* Button Debounce set to 16ms */
 	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_DBNC, 2);
 
@@ -2300,15 +2326,280 @@
 	return result;
 }
 
-int wcd_mbhc_start(struct wcd_mbhc *mbhc,
-		       struct wcd_mbhc_config *mbhc_cfg)
+static int wcd_mbhc_usb_c_analog_setup_gpios(struct wcd_mbhc *mbhc,
+					     bool active)
 {
 	int rc = 0;
+	struct usbc_ana_audio_config *config =
+		&mbhc->mbhc_cfg->usbc_analog_cfg;
+	union power_supply_propval pval;
 
-	pr_debug("%s: enter\n", __func__);
+	dev_dbg(mbhc->codec->dev, "%s: setting GPIOs active = %d\n",
+		__func__, active);
+
+	memset(&pval, 0, sizeof(pval));
+
+	if (active) {
+		pval.intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
+		if (power_supply_set_property(mbhc->usb_psy,
+				POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval))
+			dev_info(mbhc->codec->dev, "%s: force PR_SOURCE mode unsuccessful\n",
+				 __func__);
+		else
+			mbhc->usbc_force_pr_mode = true;
+
+		if (config->usbc_en1_gpio_p)
+			rc = msm_cdc_pinctrl_select_active_state(
+				config->usbc_en1_gpio_p);
+		if (rc == 0 && config->usbc_en2n_gpio_p)
+			rc = msm_cdc_pinctrl_select_active_state(
+				config->usbc_en2n_gpio_p);
+		if (rc == 0 && config->usbc_force_gpio_p)
+			rc = msm_cdc_pinctrl_select_active_state(
+				config->usbc_force_gpio_p);
+		mbhc->usbc_mode = POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
+	} else {
+		/* no delay is required when disabling GPIOs */
+		if (config->usbc_en2n_gpio_p)
+			msm_cdc_pinctrl_select_sleep_state(
+				config->usbc_en2n_gpio_p);
+		if (config->usbc_en1_gpio_p)
+			msm_cdc_pinctrl_select_sleep_state(
+				config->usbc_en1_gpio_p);
+		if (config->usbc_force_gpio_p)
+			msm_cdc_pinctrl_select_sleep_state(
+				config->usbc_force_gpio_p);
+
+		if (mbhc->usbc_force_pr_mode) {
+			pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
+			if (power_supply_set_property(mbhc->usb_psy,
+				POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval))
+				dev_info(mbhc->codec->dev, "%s: force PR_DUAL mode unsuccessful\n",
+					 __func__);
+
+			mbhc->usbc_force_pr_mode = false;
+		}
+
+		mbhc->usbc_mode = POWER_SUPPLY_TYPEC_NONE;
+	}
+
+	return rc;
+}
+
+/* workqueue */
+static void wcd_mbhc_usbc_analog_work_fn(struct work_struct *work)
+{
+	struct wcd_mbhc *mbhc =
+		container_of(work, struct wcd_mbhc, usbc_analog_work);
+
+	wcd_mbhc_usb_c_analog_setup_gpios(mbhc,
+			mbhc->usbc_mode != POWER_SUPPLY_TYPEC_NONE);
+}
+
+/* this callback function is used to process PMI notification */
+static int wcd_mbhc_usb_c_event_changed(struct notifier_block *nb,
+					unsigned long evt, void *ptr)
+{
+	int ret;
+	union power_supply_propval mode;
+	struct wcd_mbhc *mbhc = container_of(nb, struct wcd_mbhc, psy_nb);
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	if (ptr != mbhc->usb_psy || evt != PSY_EVENT_PROP_CHANGED)
+		return 0;
+
+	ret = power_supply_get_property(mbhc->usb_psy,
+			POWER_SUPPLY_PROP_TYPEC_MODE, &mode);
+	if (ret) {
+		dev_err(codec->dev, "%s: Unable to read USB TYPEC_MODE: %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	dev_dbg(codec->dev, "%s: USB change event received\n",
+		__func__);
+	dev_dbg(codec->dev, "%s: supply mode %d, expected %d\n", __func__,
+		mode.intval, POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER);
+
+	switch (mode.intval) {
+	case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER:
+	case POWER_SUPPLY_TYPEC_NONE:
+		dev_dbg(codec->dev, "%s: usbc_mode: %d; mode.intval: %d\n",
+			__func__, mbhc->usbc_mode, mode.intval);
+
+		if (mbhc->usbc_mode == mode.intval)
+			break; /* filter notifications received before */
+		mbhc->usbc_mode = mode.intval;
+
+		dev_dbg(codec->dev, "%s: queueing usbc_analog_work\n",
+			__func__);
+		schedule_work(&mbhc->usbc_analog_work);
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+/* PMI registration code */
+static int wcd_mbhc_usb_c_analog_init(struct wcd_mbhc *mbhc)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	dev_dbg(mbhc->codec->dev, "%s: usb-c analog setup start\n", __func__);
+	INIT_WORK(&mbhc->usbc_analog_work, wcd_mbhc_usbc_analog_work_fn);
+
+	mbhc->usb_psy = power_supply_get_by_name("usb");
+	if (IS_ERR_OR_NULL(mbhc->usb_psy)) {
+		dev_err(codec->dev, "%s: could not get USB psy info\n",
+			__func__);
+		ret = -EPROBE_DEFER;
+		if (IS_ERR(mbhc->usb_psy))
+			ret = PTR_ERR(mbhc->usb_psy);
+		mbhc->usb_psy = NULL;
+		goto err;
+	}
+
+	ret = wcd_mbhc_usb_c_analog_setup_gpios(mbhc, false);
+	if (ret) {
+		dev_err(codec->dev, "%s: error while setting USBC ana gpios\n",
+			__func__);
+		goto err;
+	}
+
+	mbhc->psy_nb.notifier_call = wcd_mbhc_usb_c_event_changed;
+	mbhc->psy_nb.priority = 0;
+	ret = power_supply_reg_notifier(&mbhc->psy_nb);
+	if (ret) {
+		dev_err(codec->dev, "%s: power supply registration failed\n",
+			__func__);
+		goto err;
+	}
+
+	/*
+	 * as part of the init sequence check if there is a connected
+	 * USB C analog adapter
+	 */
+	dev_dbg(mbhc->codec->dev, "%s: verify if USB adapter is already inserted\n",
+		__func__);
+	ret = wcd_mbhc_usb_c_event_changed(&mbhc->psy_nb,
+					   PSY_EVENT_PROP_CHANGED,
+					   mbhc->usb_psy);
+
+err:
+	return ret;
+}
+
+static int wcd_mbhc_usb_c_analog_deinit(struct wcd_mbhc *mbhc)
+{
+	wcd_mbhc_usb_c_analog_setup_gpios(mbhc, false);
+
+	/* deregister from PMI */
+	power_supply_unreg_notifier(&mbhc->psy_nb);
+
+	return 0;
+}
+
+static int wcd_mbhc_init_gpio(struct wcd_mbhc *mbhc,
+			      struct wcd_mbhc_config *mbhc_cfg,
+			      const char *gpio_dt_str,
+			      int *gpio, struct device_node **gpio_dn)
+{
+	int rc = 0;
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct snd_soc_card *card = codec->component.card;
+
+	dev_dbg(mbhc->codec->dev, "%s: gpio %s\n", __func__, gpio_dt_str);
+
+	*gpio_dn = of_parse_phandle(card->dev->of_node, gpio_dt_str, 0);
+
+	if (!(*gpio_dn)) {
+		*gpio = of_get_named_gpio(card->dev->of_node, gpio_dt_str, 0);
+		if (!gpio_is_valid(*gpio)) {
+			dev_err(card->dev, "%s, property %s not in node %s",
+				__func__, gpio_dt_str,
+				card->dev->of_node->full_name);
+			rc = -EINVAL;
+		}
+	}
+
+	return rc;
+}
+
+int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg)
+{
+	int rc = 0;
+	struct usbc_ana_audio_config *config;
+	struct snd_soc_codec *codec;
+	struct snd_soc_card *card;
+	const char *usb_c_dt = "qcom,msm-mbhc-usbc-audio-supported";
+
+	if (!mbhc || !mbhc_cfg)
+		return -EINVAL;
+
+	config = &mbhc_cfg->usbc_analog_cfg;
+	codec = mbhc->codec;
+	card = codec->component.card;
+
 	/* update the mbhc config */
 	mbhc->mbhc_cfg = mbhc_cfg;
 
+	dev_dbg(mbhc->codec->dev, "%s: enter\n", __func__);
+
+	/* check if USB C analog is defined on device tree */
+	mbhc_cfg->enable_usbc_analog = 0;
+	if (of_find_property(card->dev->of_node, usb_c_dt, NULL)) {
+		rc = of_property_read_u32(card->dev->of_node, usb_c_dt,
+				&mbhc_cfg->enable_usbc_analog);
+	}
+	if (mbhc_cfg->enable_usbc_analog == 0 || rc != 0) {
+		dev_info(card->dev,
+				"%s: %s in dt node is missing or false\n",
+				__func__, usb_c_dt);
+		dev_info(card->dev,
+			"%s: skipping USB c analog configuration\n", __func__);
+	}
+
+	/* initialize GPIOs */
+	if (mbhc_cfg->enable_usbc_analog) {
+		dev_dbg(mbhc->codec->dev, "%s: usbc analog enabled\n",
+				__func__);
+		rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg,
+				"qcom,usbc-analog-en1_gpio",
+				&config->usbc_en1_gpio,
+				&config->usbc_en1_gpio_p);
+		if (rc)
+			goto err;
+
+		rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg,
+				"qcom,usbc-analog-en2_n_gpio",
+				&config->usbc_en2n_gpio,
+				&config->usbc_en2n_gpio_p);
+		if (rc)
+			goto err;
+
+		if (of_find_property(card->dev->of_node,
+				     "qcom,usbc-analog-force_detect_gpio",
+				     NULL)) {
+			rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg,
+					"qcom,usbc-analog-force_detect_gpio",
+					&config->usbc_force_gpio,
+					&config->usbc_force_gpio_p);
+			if (rc)
+				goto err;
+		}
+
+		dev_dbg(mbhc->codec->dev, "%s: calling usb_c_analog_init\n",
+			__func__);
+		/* init PMI notifier */
+		rc = wcd_mbhc_usb_c_analog_init(mbhc);
+		if (rc) {
+			rc = EPROBE_DEFER;
+			goto err;
+		}
+	}
+
 	/* Set btn key code */
 	if ((!mbhc->is_btn_already_regd) && wcd_mbhc_set_keycode(mbhc))
 		pr_err("Set btn key code error!!!\n");
@@ -2325,14 +2616,44 @@
 			pr_err("%s: Skipping to read mbhc fw, 0x%pK %pK\n",
 				 __func__, mbhc->mbhc_fw, mbhc->mbhc_cal);
 	}
-	pr_debug("%s: leave %d\n", __func__, rc);
+
+	return rc;
+err:
+	if (config->usbc_en1_gpio > 0) {
+		dev_dbg(card->dev, "%s free usb en1 gpio %d\n",
+			__func__, config->usbc_en1_gpio);
+		gpio_free(config->usbc_en1_gpio);
+		config->usbc_en1_gpio = 0;
+	}
+	if (config->usbc_en2n_gpio > 0) {
+		dev_dbg(card->dev, "%s free usb_en2 gpio %d\n",
+			__func__, config->usbc_en2n_gpio);
+		gpio_free(config->usbc_en2n_gpio);
+		config->usbc_en2n_gpio = 0;
+	}
+	if (config->usbc_force_gpio > 0) {
+		dev_dbg(card->dev, "%s free usb_force gpio %d\n",
+			__func__, config->usbc_force_gpio);
+		gpio_free(config->usbc_force_gpio);
+		config->usbc_force_gpio = 0;
+	}
+	if (config->usbc_en1_gpio_p)
+		of_node_put(config->usbc_en1_gpio_p);
+	if (config->usbc_en2n_gpio_p)
+		of_node_put(config->usbc_en2n_gpio_p);
+	if (config->usbc_force_gpio_p)
+		of_node_put(config->usbc_force_gpio_p);
+	dev_dbg(mbhc->codec->dev, "%s: leave %d\n", __func__, rc);
 	return rc;
 }
 EXPORT_SYMBOL(wcd_mbhc_start);
 
 void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
 {
+	struct usbc_ana_audio_config *config = &mbhc->mbhc_cfg->usbc_analog_cfg;
+
 	pr_debug("%s: enter\n", __func__);
+
 	if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE) {
 		if (mbhc->mbhc_cb && mbhc->mbhc_cb->skip_imped_detect)
 			mbhc->mbhc_cb->skip_imped_detect(mbhc->codec);
@@ -2354,6 +2675,25 @@
 		mbhc->mbhc_fw = NULL;
 		mbhc->mbhc_cal = NULL;
 	}
+
+	if (mbhc->mbhc_cfg->enable_usbc_analog) {
+		wcd_mbhc_usb_c_analog_deinit(mbhc);
+		/* free GPIOs */
+		if (config->usbc_en1_gpio > 0)
+			gpio_free(config->usbc_en1_gpio);
+		if (config->usbc_en2n_gpio > 0)
+			gpio_free(config->usbc_en2n_gpio);
+		if (config->usbc_force_gpio)
+			gpio_free(config->usbc_force_gpio);
+
+		if (config->usbc_en1_gpio_p)
+			of_node_put(config->usbc_en1_gpio_p);
+		if (config->usbc_en2n_gpio_p)
+			of_node_put(config->usbc_en2n_gpio_p);
+		if (config->usbc_force_gpio_p)
+			of_node_put(config->usbc_force_gpio_p);
+	}
+
 	pr_debug("%s: leave\n", __func__);
 }
 EXPORT_SYMBOL(wcd_mbhc_stop);
@@ -2372,6 +2712,7 @@
 	int ret = 0;
 	int hph_swh = 0;
 	int gnd_swh = 0;
+	u32 hph_moist_config[3];
 	struct snd_soc_card *card = codec->component.card;
 	const char *hph_switch = "qcom,msm-mbhc-hphl-swh";
 	const char *gnd_switch = "qcom,msm-mbhc-gnd-swh";
@@ -2392,6 +2733,21 @@
 		goto err;
 	}
 
+	ret = of_property_read_u32_array(card->dev->of_node,
+					 "qcom,msm-mbhc-moist-cfg",
+					 hph_moist_config, 3);
+	if (ret) {
+		dev_dbg(card->dev, "%s: no qcom,msm-mbhc-moist-cfg in DT\n",
+			__func__);
+		mbhc->moist_vref = V_45_MV;
+		mbhc->moist_iref = I_3P0_UA;
+		mbhc->moist_rref = R_24_KOHM;
+	} else {
+		mbhc->moist_vref = hph_moist_config[0];
+		mbhc->moist_iref = hph_moist_config[1];
+		mbhc->moist_rref = hph_moist_config[2];
+	}
+
 	mbhc->in_swch_irq_handler = false;
 	mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
 	mbhc->is_btn_press = false;
diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h
index c9bd4fe..e6cd1971 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.h
+++ b/sound/soc/codecs/wcd-mbhc-v2.h
@@ -14,6 +14,7 @@
 
 #include <linux/wait.h>
 #include <linux/stringify.h>
+#include <linux/power_supply.h>
 #include "wcdcal-hwdep.h"
 
 #define TOMBAK_MBHC_NC	0
@@ -249,6 +250,15 @@
 	R_184_KOHM,
 };
 
+struct usbc_ana_audio_config {
+	int usbc_en1_gpio;
+	int usbc_en2n_gpio;
+	int usbc_force_gpio;
+	struct device_node *usbc_en1_gpio_p; /* used by pinctrl API */
+	struct device_node *usbc_en2n_gpio_p; /* used by pinctrl API */
+	struct device_node *usbc_force_gpio_p; /* used by pinctrl API */
+};
+
 struct wcd_mbhc_config {
 	bool read_fw_bin;
 	void *calibration;
@@ -263,6 +273,8 @@
 	int mbhc_micbias;
 	int anc_micbias;
 	bool enable_anc_mic_detect;
+	u32 enable_usbc_analog;
+	struct usbc_ana_audio_config usbc_analog_cfg;
 };
 
 struct wcd_mbhc_intr {
@@ -393,6 +405,9 @@
 	bool in_swch_irq_handler;
 	bool hphl_swh; /*track HPHL switch NC / NO */
 	bool gnd_swh; /*track GND switch NC / NO */
+	u32 moist_vref;
+	u32 moist_iref;
+	u32 moist_rref;
 	u8 micbias1_cap_mode; /* track ext cap setting */
 	u8 micbias2_cap_mode; /* track ext cap setting */
 	bool hs_detect_work_stop;
@@ -440,6 +455,12 @@
 
 	unsigned long intr_status;
 	bool is_hph_ocp_pending;
+
+	bool usbc_force_pr_mode;
+	int usbc_mode;
+	struct notifier_block psy_nb;
+	struct power_supply *usb_psy;
+	struct work_struct usbc_analog_work;
 };
 #define WCD_MBHC_CAL_SIZE(buttons, rload) ( \
 	sizeof(struct wcd_mbhc_general_cfg) + \
diff --git a/sound/soc/codecs/wcd-spi.c b/sound/soc/codecs/wcd-spi.c
index 869b39d..7e217a6 100644
--- a/sound/soc/codecs/wcd-spi.c
+++ b/sound/soc/codecs/wcd-spi.c
@@ -60,7 +60,8 @@
 
 /* Command delays */
 #define WCD_SPI_CLKREQ_DELAY_USECS (500)
-#define WCD_SPI_CLK_OFF_TIMER_MS   (3000)
+#define WCD_SPI_CLK_OFF_TIMER_MS   (500)
+#define WCD_SPI_RESUME_TIMEOUT_MS 100
 
 /* Command masks */
 #define WCD_CMD_ADDR_MASK            \
@@ -90,6 +91,7 @@
 
 /* Status mask bits */
 #define WCD_SPI_CLK_STATE_ENABLED BIT(0)
+#define WCD_SPI_IS_SUSPENDED BIT(1)
 
 /* Locking related */
 #define WCD_SPI_MUTEX_LOCK(spi, lock)              \
@@ -144,6 +146,9 @@
 
 	/* Debugfs related information */
 	struct wcd_spi_debug_data debug_data;
+
+	/* Completion object to indicate system resume completion */
+	struct completion resume_comp;
 };
 
 enum xfer_request {
@@ -170,6 +175,55 @@
 	xfer->len = 0;
 }
 
+static bool wcd_spi_is_suspended(struct wcd_spi_priv *wcd_spi)
+{
+	return test_bit(WCD_SPI_IS_SUSPENDED, &wcd_spi->status_mask);
+}
+
+static bool wcd_spi_can_suspend(struct wcd_spi_priv *wcd_spi)
+{
+	struct spi_device *spi = wcd_spi->spi;
+
+	if (wcd_spi->clk_users > 0 ||
+	    test_bit(WCD_SPI_CLK_STATE_ENABLED, &wcd_spi->status_mask)) {
+		dev_err(&spi->dev, "%s: cannot suspend, clk_users = %d\n",
+			__func__, wcd_spi->clk_users);
+		return false;
+	}
+
+	return true;
+}
+
+static int wcd_spi_wait_for_resume(struct wcd_spi_priv *wcd_spi)
+{
+	struct spi_device *spi = wcd_spi->spi;
+	int rc = 0;
+
+	WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+	/* If the system is already in resumed state, return right away */
+	if (!wcd_spi_is_suspended(wcd_spi))
+		goto done;
+
+	/* If suspended then wait for resume to happen */
+	reinit_completion(&wcd_spi->resume_comp);
+	WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+	rc = wait_for_completion_timeout(&wcd_spi->resume_comp,
+				msecs_to_jiffies(WCD_SPI_RESUME_TIMEOUT_MS));
+	WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+	if (rc == 0) {
+		dev_err(&spi->dev, "%s: failed to resume in %u msec\n",
+			__func__, WCD_SPI_RESUME_TIMEOUT_MS);
+		rc = -EIO;
+		goto done;
+	}
+
+	dev_dbg(&spi->dev, "%s: resume successful\n", __func__);
+	rc = 0;
+done:
+	WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+	return rc;
+}
+
 static int wcd_spi_read_single(struct spi_device *spi,
 			       u32 remote_addr, u32 *val)
 {
@@ -579,6 +633,18 @@
 	}
 
 	if (request == WCD_SPI_CLK_ENABLE) {
+		/*
+		 * If the SPI bus is suspended, then return error
+		 * as the transaction cannot be completed.
+		 */
+		if (wcd_spi_is_suspended(wcd_spi)) {
+			dev_err(&spi->dev,
+				"%s: SPI suspended, cannot enable clk\n",
+				__func__);
+			ret = -EIO;
+			goto done;
+		}
+
 		/* Cancel the disable clk work */
 		WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
 		cancel_delayed_work_sync(&wcd_spi->clk_dwork);
@@ -899,6 +965,17 @@
 		ret = wdsp_spi_read_section(spi, data);
 		break;
 
+	case WDSP_EVENT_SUSPEND:
+		WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+		if (!wcd_spi_can_suspend(wcd_spi))
+			ret = -EBUSY;
+		WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+		break;
+
+	case WDSP_EVENT_RESUME:
+		ret = wcd_spi_wait_for_resume(wcd_spi);
+		break;
+
 	default:
 		dev_dbg(&spi->dev, "%s: Unhandled event %d\n",
 			__func__, event);
@@ -1303,6 +1380,7 @@
 	mutex_init(&wcd_spi->clk_mutex);
 	mutex_init(&wcd_spi->xfer_mutex);
 	INIT_DELAYED_WORK(&wcd_spi->clk_dwork, wcd_spi_clk_work);
+	init_completion(&wcd_spi->resume_comp);
 
 	wcd_spi->spi = spi;
 	spi_set_drvdata(spi, wcd_spi);
@@ -1340,6 +1418,61 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int wcd_spi_suspend(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	int rc = 0;
+
+	WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+	if (!wcd_spi_can_suspend(wcd_spi)) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	/*
+	 * If we are here, it is okay to let the suspend go
+	 * through for this driver. But, still need to notify
+	 * the master to make sure all other components can suspend
+	 * as well.
+	 */
+	if (wcd_spi->m_dev && wcd_spi->m_ops &&
+	  wcd_spi->m_ops->suspend) {
+		WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+		rc = wcd_spi->m_ops->suspend(wcd_spi->m_dev);
+		WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+	}
+
+	if (rc == 0)
+		set_bit(WCD_SPI_IS_SUSPENDED, &wcd_spi->status_mask);
+	else
+		dev_dbg(&spi->dev, "%s: cannot suspend, err = %d\n",
+			__func__, rc);
+done:
+	WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+	return rc;
+}
+
+static int wcd_spi_resume(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+
+	WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+	clear_bit(WCD_SPI_IS_SUSPENDED, &wcd_spi->status_mask);
+	complete(&wcd_spi->resume_comp);
+	WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+
+	return 0;
+}
+
+static const struct dev_pm_ops wcd_spi_pm_ops = {
+	.suspend = wcd_spi_suspend,
+	.resume = wcd_spi_resume,
+};
+#endif
+
 static const struct of_device_id wcd_spi_of_match[] = {
 	{ .compatible = "qcom,wcd-spi-v2", },
 	{ }
@@ -1350,6 +1483,9 @@
 	.driver = {
 		.name = "wcd-spi-v2",
 		.of_match_table = wcd_spi_of_match,
+#ifdef CONFIG_PM
+		.pm = &wcd_spi_pm_ops,
+#endif
 	},
 	.probe = wcd_spi_probe,
 	.remove = wcd_spi_remove,
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 2185f4b..5ea0551 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -2197,7 +2197,7 @@
 {
 	struct snd_soc_codec *codec = mbhc->codec;
 
-	if (TASHA_MBHC_MOISTURE_VREF == V_OFF)
+	if (mbhc->moist_vref == V_OFF)
 		return;
 
 	/* Donot enable moisture detection if jack type is NC */
@@ -2208,8 +2208,8 @@
 	}
 
 	snd_soc_update_bits(codec, WCD9335_MBHC_CTL_2,
-			    0x0C, TASHA_MBHC_MOISTURE_VREF << 2);
-	tasha_mbhc_hph_l_pull_up_control(codec, TASHA_MBHC_MOISTURE_IREF);
+			    0x0C, mbhc->moist_vref << 2);
+	tasha_mbhc_hph_l_pull_up_control(codec, mbhc->moist_iref);
 }
 
 static const struct wcd_mbhc_cb mbhc_cb = {
@@ -7926,6 +7926,13 @@
 
 	tasha_mad_input = ucontrol->value.integer.value[0];
 
+	if (tasha_mad_input >= ARRAY_SIZE(tasha_conn_mad_text)) {
+		dev_err(codec->dev,
+			"%s: tasha_mad_input = %d out of bounds\n",
+			__func__, tasha_mad_input);
+		return -EINVAL;
+	}
+
 	if (!strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED1") ||
 	    !strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED2") ||
 	    !strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED3") ||
@@ -13436,8 +13443,6 @@
 
 	/* Class-H Init*/
 	wcd_clsh_init(&tasha->clsh_d);
-	/* Default HPH Mode to Class-H HiFi */
-	tasha->hph_mode = CLS_H_HIFI;
 
 	for (i = 0; i < TASHA_MAX_MICBIAS; i++)
 		tasha->micb_ref[i] = 0;
@@ -13445,8 +13450,6 @@
 	tasha_update_reg_defaults(tasha);
 
 	tasha->codec = codec;
-	for (i = 0; i < COMPANDER_MAX; i++)
-		tasha->comp_enabled[i] = 0;
 
 	dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
 		__func__, control->mclk_rate);
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsd.c b/sound/soc/codecs/wcd934x/wcd934x-dsd.c
index 580591a..3e23e37 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsd.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsd.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
@@ -97,6 +97,11 @@
 	{"DSD_FILTER_1", NULL, "DSD_R IF MUX"},
 	{"DSD_FILTER_1", NULL, "RX INT2 NATIVE SUPPLY"},
 	{"RX INT2 MIX3", "DSD HPHR Switch", "DSD_FILTER_1"},
+
+	{"DSD_FILTER_0", NULL, "RX INT3 NATIVE SUPPLY"},
+	{"RX INT3 MIX3", "DSD LO1 Switch", "DSD_FILTER_0"},
+	{"DSD_FILTER_1", NULL, "RX INT4 NATIVE SUPPLY"},
+	{"RX INT4 MIX3", "DSD LO2 Switch", "DSD_FILTER_1"},
 };
 
 static bool is_valid_dsd_interpolator(int interp_num)
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
index b57b3d4..8da0425 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
@@ -607,8 +607,6 @@
 	/* Disable WDOG */
 	snd_soc_update_bits(codec, WCD934X_CPE_SS_WDOG_CFG,
 			    0x3F, 0x01);
-	snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
-			    0x04, 0x00);
 
 	/* Put WDSP in reset state */
 	snd_soc_update_bits(codec, WCD934X_CPE_SS_CPE_CTL,
@@ -633,11 +631,7 @@
 	if (cntl->debug_mode) {
 		snd_soc_update_bits(codec, WCD934X_CPE_SS_WDOG_CFG,
 				    0x3F, 0x01);
-		snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
-				    0x04, 0x00);
 	} else {
-		snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
-				    0x04, 0x04);
 		snd_soc_update_bits(codec, WCD934X_CPE_SS_WDOG_CFG,
 				    0x3F, 0x21);
 	}
diff --git a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
index 0e0c26d..3d032f0 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.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
@@ -772,18 +772,24 @@
 {
 	struct snd_soc_codec *codec = mbhc->codec;
 
-	if (TAVIL_MBHC_MOISTURE_RREF == R_OFF)
+	if ((mbhc->moist_rref == R_OFF) ||
+	    (mbhc->mbhc_cfg->enable_usbc_analog)) {
+		snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_2,
+				    0x0C, R_OFF << 2);
 		return;
+	}
 
 	/* Donot enable moisture detection if jack type is NC */
 	if (!mbhc->hphl_swh) {
 		dev_dbg(codec->dev, "%s: disable moisture detection for NC\n",
 			__func__);
+		snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_2,
+				    0x0C, R_OFF << 2);
 		return;
 	}
 
 	snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_2,
-			    0x0C, TAVIL_MBHC_MOISTURE_RREF << 2);
+			    0x0C, mbhc->moist_rref << 2);
 }
 
 static bool tavil_hph_register_recovery(struct wcd_mbhc *mbhc)
diff --git a/sound/soc/codecs/wcd934x/wcd934x-mbhc.h b/sound/soc/codecs/wcd934x/wcd934x-mbhc.h
index d001fa2..d40546a 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.h
+++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.h
@@ -35,6 +35,7 @@
 	bool is_hph_recover;
 };
 
+#ifdef CONFIG_SND_SOC_WCD934X_MBHC
 extern int tavil_mbhc_init(struct wcd934x_mbhc **mbhc,
 			   struct snd_soc_codec *codec,
 			   struct fw_info *fw_data);
@@ -46,4 +47,38 @@
 				    struct snd_soc_codec *codec);
 extern int tavil_mbhc_get_impedance(struct wcd934x_mbhc *wcd934x_mbhc,
 				    uint32_t *zl, uint32_t *zr);
+#else
+static inline int tavil_mbhc_init(struct wcd934x_mbhc **mbhc,
+				  struct snd_soc_codec *codec,
+				  struct fw_info *fw_data)
+{
+	return 0;
+}
+static inline void tavil_mbhc_hs_detect_exit(struct snd_soc_codec *codec)
+{
+}
+static inline int tavil_mbhc_hs_detect(struct snd_soc_codec *codec,
+				       struct wcd_mbhc_config *mbhc_cfg)
+{
+		return 0;
+}
+static inline void tavil_mbhc_deinit(struct snd_soc_codec *codec)
+{
+}
+static inline int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc,
+					   struct snd_soc_codec *codec)
+{
+	return 0;
+}
+static inline int tavil_mbhc_get_impedance(struct wcd934x_mbhc *wcd934x_mbhc,
+					   uint32_t *zl, uint32_t *zr)
+{
+	if (zl)
+		*zl = 0;
+	if (zr)
+		*zr = 0;
+	return -EINVAL;
+}
+#endif
+
 #endif /* __WCD934X_MBHC_H__ */
diff --git a/sound/soc/codecs/wcd934x/wcd934x-routing.h b/sound/soc/codecs/wcd934x/wcd934x-routing.h
index 8ca4c07..afd93b2 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-routing.h
+++ b/sound/soc/codecs/wcd934x/wcd934x-routing.h
@@ -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
@@ -872,7 +872,8 @@
 	{"RX INT3 SEC MIX", NULL, "RX INT3_1 INTERP"},
 	{"RX INT3 MIX2", NULL, "RX INT3 SEC MIX"},
 	{"RX INT3 MIX2", NULL, "RX INT3 MIX2 INP"},
-	{"RX INT3 DAC", NULL, "RX INT3 MIX2"},
+	{"RX INT3 MIX3", NULL, "RX INT3 MIX2"},
+	{"RX INT3 DAC", NULL, "RX INT3 MIX3"},
 	{"RX INT3 DAC", NULL, "RX_BIAS"},
 	{"LINEOUT1 PA", NULL, "RX INT3 DAC"},
 	{"LINEOUT1", NULL, "LINEOUT1 PA"},
@@ -882,7 +883,8 @@
 	{"RX INT4 SEC MIX", NULL, "RX INT4_1 MIX1"},
 	{"RX INT4 MIX2", NULL, "RX INT4 SEC MIX"},
 	{"RX INT4 MIX2", NULL, "RX INT4 MIX2 INP"},
-	{"RX INT4 DAC", NULL, "RX INT4 MIX2"},
+	{"RX INT4 MIX3", NULL, "RX INT4 MIX2"},
+	{"RX INT4 DAC", NULL, "RX INT4 MIX3"},
 	{"RX INT4 DAC", NULL, "RX_BIAS"},
 	{"LINEOUT2 PA", NULL, "RX INT4 DAC"},
 	{"LINEOUT2", NULL, "LINEOUT2 PA"},
@@ -914,9 +916,23 @@
 	{"ANC OUT EAR Enable", "Switch", "ADC MUX11"},
 	{"RX INT0 MIX2", NULL, "ANC OUT EAR Enable"},
 
+	{"ANC OUT HPHL Enable", "Switch", "ADC MUX10"},
+	{"ANC OUT HPHL Enable", "Switch", "ADC MUX11"},
+	{"RX INT1 MIX2", NULL, "ANC OUT HPHL Enable"},
+
+	{"ANC OUT HPHR Enable", "Switch", "ADC MUX12"},
+	{"ANC OUT HPHR Enable", "Switch", "ADC MUX13"},
+	{"RX INT2 MIX2", NULL, "ANC OUT HPHR Enable"},
+
 	{"ANC EAR PA", NULL, "RX INT0 DAC"},
 	{"ANC EAR", NULL, "ANC EAR PA"},
 
+	{"ANC HPHL PA", NULL, "RX INT1 DAC"},
+	{"ANC HPHL", NULL, "ANC HPHL PA"},
+
+	{"ANC HPHR PA", NULL, "RX INT2 DAC"},
+	{"ANC HPHR", NULL, "ANC HPHR PA"},
+
 	{"ANC OUT EAR SPKR Enable", "Switch", "ADC MUX10"},
 	{"ANC OUT EAR SPKR Enable", "Switch", "ADC MUX11"},
 	{"RX INT7 MIX2", NULL, "ANC OUT EAR SPKR Enable"},
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index 724d961..4b6fcb0b 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -174,6 +174,10 @@
 	AUDIO_NOMINAL,
 	HPH_PA_DELAY,
 	CLSH_Z_CONFIG,
+	ANC_MIC_AMIC1,
+	ANC_MIC_AMIC2,
+	ANC_MIC_AMIC3,
+	ANC_MIC_AMIC4,
 };
 
 enum {
@@ -507,6 +511,7 @@
 module_param(tx_unmute_delay, int, 0664);
 MODULE_PARM_DESC(tx_unmute_delay, "delay to unmute the tx path");
 
+static void tavil_codec_set_tx_hold(struct snd_soc_codec *, u16, bool);
 
 /* Hold instance to soundwire platform device */
 struct tavil_swr_ctrl_data {
@@ -995,14 +1000,30 @@
 		snd_soc_dapm_enable_pin(dapm, "ANC EAR PA");
 		snd_soc_dapm_enable_pin(dapm, "ANC EAR");
 		snd_soc_dapm_enable_pin(dapm, "ANC SPK1 PA");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHL PA");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHR PA");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHL");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHR");
 		snd_soc_dapm_disable_pin(dapm, "EAR PA");
 		snd_soc_dapm_disable_pin(dapm, "EAR");
+		snd_soc_dapm_disable_pin(dapm, "HPHL PA");
+		snd_soc_dapm_disable_pin(dapm, "HPHR PA");
+		snd_soc_dapm_disable_pin(dapm, "HPHL");
+		snd_soc_dapm_disable_pin(dapm, "HPHR");
 	} else {
 		snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
 		snd_soc_dapm_disable_pin(dapm, "ANC EAR");
 		snd_soc_dapm_disable_pin(dapm, "ANC SPK1 PA");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHL PA");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHR PA");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
 		snd_soc_dapm_enable_pin(dapm, "EAR PA");
 		snd_soc_dapm_enable_pin(dapm, "EAR");
+		snd_soc_dapm_enable_pin(dapm, "HPHL");
+		snd_soc_dapm_enable_pin(dapm, "HPHR");
+		snd_soc_dapm_enable_pin(dapm, "HPHL PA");
+		snd_soc_dapm_enable_pin(dapm, "HPHR PA");
 	}
 	mutex_unlock(&tavil->codec_mutex);
 
@@ -1119,16 +1140,56 @@
 		}
 
 		/* Rate converter clk enable and set bypass mode */
-		snd_soc_update_bits(codec, WCD934X_CDC_ANC0_RC_COMMON_CTL,
-				    0x05, 0x05);
+		if (!strcmp(w->name, "RX INT0 DAC") ||
+		    !strcmp(w->name, "RX INT1 DAC") ||
+		    !strcmp(w->name, "ANC SPK1 PA")) {
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC0_RC_COMMON_CTL,
+					    0x05, 0x05);
+			if (!strcmp(w->name, "RX INT1 DAC")) {
+				snd_soc_update_bits(codec,
+					WCD934X_CDC_ANC0_FIFO_COMMON_CTL,
+					0x66, 0x66);
+			}
+		} else if (!strcmp(w->name, "RX INT2 DAC")) {
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC1_RC_COMMON_CTL,
+					    0x05, 0x05);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC1_FIFO_COMMON_CTL,
+					    0x66, 0x66);
+		}
+		if (!strcmp(w->name, "RX INT1 DAC"))
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_ANC0_CLK_RESET_CTL, 0x08, 0x08);
+		else if (!strcmp(w->name, "RX INT2 DAC"))
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_ANC1_CLK_RESET_CTL, 0x08, 0x08);
+
 		if (!hwdep_cal)
 			release_firmware(fw);
 		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		if (!strcmp(w->name, "ANC HPHL PA") ||
+		    !strcmp(w->name, "ANC HPHR PA")) {
+			/* Remove ANC Rx from reset */
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC0_CLK_RESET_CTL,
+					    0x08, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC1_CLK_RESET_CTL,
+					    0x08, 0x00);
+		}
+
+		break;
+
 	case SND_SOC_DAPM_POST_PMD:
 		snd_soc_update_bits(codec, WCD934X_CDC_ANC0_RC_COMMON_CTL,
 				    0x05, 0x00);
 		if (!strcmp(w->name, "ANC EAR PA") ||
-		    !strcmp(w->name, "ANC SPK1 PA")) {
+		    !strcmp(w->name, "ANC SPK1 PA") ||
+		    !strcmp(w->name, "ANC HPHL PA")) {
 			snd_soc_update_bits(codec, WCD934X_CDC_ANC0_MODE_1_CTL,
 					    0x30, 0x00);
 			msleep(50);
@@ -1143,6 +1204,21 @@
 			snd_soc_update_bits(codec,
 					    WCD934X_CDC_ANC0_CLK_RESET_CTL,
 					    0x38, 0x00);
+		} else if (!strcmp(w->name, "ANC HPHR PA")) {
+			snd_soc_update_bits(codec, WCD934X_CDC_ANC1_MODE_1_CTL,
+					    0x30, 0x00);
+			msleep(50);
+			snd_soc_update_bits(codec, WCD934X_CDC_ANC1_MODE_1_CTL,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC1_CLK_RESET_CTL,
+					    0x38, 0x38);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC1_CLK_RESET_CTL,
+					    0x07, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC1_CLK_RESET_CTL,
+					    0x38, 0x00);
 		}
 		break;
 	}
@@ -1879,12 +1955,8 @@
 		switch (event) {
 		case SND_SOC_DAPM_PRE_PMU:
 		case SND_SOC_DAPM_POST_PMU:
-			if (!(snd_soc_read(codec,
-					WCD934X_CDC_RX2_RX_PATH_CTL) & 0x10) &&
-				(!(snd_soc_read(codec,
-					WCD934X_CDC_RX1_RX_PATH_CTL) & 0x10)))
-				snd_soc_update_bits(codec,
-					WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x02);
+			snd_soc_update_bits(codec,
+				WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x02);
 		break;
 		case SND_SOC_DAPM_POST_PMD:
 			snd_soc_update_bits(codec,
@@ -1894,6 +1966,18 @@
 	}
 }
 
+static void tavil_codec_clear_anc_tx_hold(struct tavil_priv *tavil)
+{
+	if (test_and_clear_bit(ANC_MIC_AMIC1, &tavil->status_mask))
+		tavil_codec_set_tx_hold(tavil->codec, WCD934X_ANA_AMIC1, false);
+	if (test_and_clear_bit(ANC_MIC_AMIC2, &tavil->status_mask))
+		tavil_codec_set_tx_hold(tavil->codec, WCD934X_ANA_AMIC2, false);
+	if (test_and_clear_bit(ANC_MIC_AMIC3, &tavil->status_mask))
+		tavil_codec_set_tx_hold(tavil->codec, WCD934X_ANA_AMIC3, false);
+	if (test_and_clear_bit(ANC_MIC_AMIC4, &tavil->status_mask))
+		tavil_codec_set_tx_hold(tavil->codec, WCD934X_ANA_AMIC4, false);
+}
+
 static int tavil_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
 				      struct snd_kcontrol *kcontrol,
 				      int event)
@@ -1901,6 +1985,7 @@
 	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
 	struct tavil_dsd_config *dsd_conf = tavil->dsd_config;
+	int ret = 0;
 
 	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
 
@@ -1909,6 +1994,11 @@
 		if (TAVIL_IS_1_0(tavil->wcd9xxx))
 			snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL,
 					    0x06, (0x03 << 1));
+
+		if ((!(strcmp(w->name, "ANC HPHR PA"))) &&
+		    (test_bit(HPH_PA_DELAY, &tavil->status_mask)))
+			snd_soc_update_bits(codec, WCD934X_ANA_HPH, 0xC0, 0xC0);
+
 		set_bit(HPH_PA_DELAY, &tavil->status_mask);
 		if (dsd_conf &&
 		    (snd_soc_read(codec, WCD934X_CDC_DSD1_PATH_CTL) & 0x01)) {
@@ -1918,14 +2008,34 @@
 		}
 		break;
 	case SND_SOC_DAPM_POST_PMU:
+		if ((!(strcmp(w->name, "ANC HPHR PA")))) {
+			if ((snd_soc_read(codec, WCD934X_ANA_HPH) & 0xC0)
+					!= 0xC0)
+				/*
+				 * If PA_EN is not set (potentially in ANC case)
+				 * then do nothing for POST_PMU and let left
+				 * channel handle everything.
+				 */
+				break;
+		}
 		/*
 		 * 7ms sleep is required after PA is enabled as per
-		 * HW requirement
+		 * HW requirement. If compander is disabled, then
+		 * 20ms delay is needed.
 		 */
 		if (test_bit(HPH_PA_DELAY, &tavil->status_mask)) {
-			usleep_range(7000, 7100);
+			if (!tavil->comp_enabled[COMPANDER_2])
+				usleep_range(20000, 20100);
+			else
+				usleep_range(7000, 7100);
 			clear_bit(HPH_PA_DELAY, &tavil->status_mask);
 		}
+		if (tavil->anc_func) {
+			/* Clear Tx FE HOLD if both PAs are enabled */
+			if ((snd_soc_read(tavil->codec, WCD934X_ANA_HPH) &
+					0xC0) == 0xC0)
+				tavil_codec_clear_anc_tx_hold(tavil);
+		}
 
 		snd_soc_update_bits(codec, WCD934X_HPH_R_TEST, 0x01, 0x01);
 
@@ -1948,6 +2058,34 @@
 		    (snd_soc_read(codec, WCD934X_CDC_DSD1_PATH_CTL) & 0x01))
 			snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2,
 					    0x04, 0x00);
+		if (!(strcmp(w->name, "ANC HPHR PA"))) {
+			pr_debug("%s:Do everything needed for left channel\n",
+				__func__);
+			/* Do everything needed for left channel */
+			snd_soc_update_bits(codec, WCD934X_HPH_L_TEST,
+					    0x01, 0x01);
+
+			/* Remove mute */
+			snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CTL,
+					    0x10, 0x00);
+
+			/* Remove mix path mute if it is enabled */
+			if ((snd_soc_read(codec,
+					WCD934X_CDC_RX1_RX_PATH_MIX_CTL)) &
+					0x10)
+				snd_soc_update_bits(codec,
+					WCD934X_CDC_RX1_RX_PATH_MIX_CTL,
+					0x10, 0x00);
+
+			if (dsd_conf && (snd_soc_read(codec,
+						WCD934X_CDC_DSD0_PATH_CTL) &
+						0x01))
+				snd_soc_update_bits(codec,
+						    WCD934X_CDC_DSD0_CFG2,
+						    0x04, 0x00);
+			/* Remove ANC Rx from reset */
+			ret = tavil_codec_enable_anc(w, kcontrol, event);
+		}
 		tavil_codec_override(codec, tavil->hph_mode, event);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
@@ -1962,10 +2100,20 @@
 		snd_soc_update_bits(codec, WCD934X_HPH_R_TEST, 0x01, 0x00);
 		snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_CTL,
 				    0x10, 0x10);
+		snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_MIX_CTL,
+				    0x10, 0x10);
+		if (!(strcmp(w->name, "ANC HPHR PA")))
+			snd_soc_update_bits(codec, WCD934X_ANA_HPH, 0x40, 0x00);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		/* 5ms sleep is required after PA disable */
-		usleep_range(5000, 5100);
+		/*
+		 * 5ms sleep is required after PA disable. If compander is
+		 * disabled, then 20ms delay is needed after PA disable.
+		 */
+		if (!tavil->comp_enabled[COMPANDER_2])
+			usleep_range(20000, 20100);
+		else
+			usleep_range(5000, 5100);
 		tavil_codec_override(codec, tavil->hph_mode, event);
 		blocking_notifier_call_chain(&tavil->mbhc->notifier,
 					     WCD_EVENT_POST_HPHR_PA_OFF,
@@ -1973,10 +2121,16 @@
 		if (TAVIL_IS_1_0(tavil->wcd9xxx))
 			snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL,
 					    0x06, 0x0);
+		if (!(strcmp(w->name, "ANC HPHR PA"))) {
+			ret = tavil_codec_enable_anc(w, kcontrol, event);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX2_RX_PATH_CFG0,
+					    0x10, 0x00);
+		}
 		break;
 	};
 
-	return 0;
+	return ret;
 }
 
 static int tavil_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
@@ -1986,6 +2140,7 @@
 	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
 	struct tavil_dsd_config *dsd_conf = tavil->dsd_config;
+	int ret = 0;
 
 	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
 
@@ -1994,6 +2149,10 @@
 		if (TAVIL_IS_1_0(tavil->wcd9xxx))
 			snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL,
 					    0x06, (0x03 << 1));
+		if ((!(strcmp(w->name, "ANC HPHL PA"))) &&
+		    (test_bit(HPH_PA_DELAY, &tavil->status_mask)))
+			snd_soc_update_bits(codec, WCD934X_ANA_HPH,
+					    0xC0, 0xC0);
 		set_bit(HPH_PA_DELAY, &tavil->status_mask);
 		if (dsd_conf &&
 		    (snd_soc_read(codec, WCD934X_CDC_DSD0_PATH_CTL) & 0x01)) {
@@ -2003,14 +2162,35 @@
 		}
 		break;
 	case SND_SOC_DAPM_POST_PMU:
+		if (!(strcmp(w->name, "ANC HPHL PA"))) {
+			if ((snd_soc_read(codec, WCD934X_ANA_HPH) & 0xC0)
+								!= 0xC0)
+				/*
+				 * If PA_EN is not set (potentially in ANC
+				 * case) then do nothing for POST_PMU and
+				 * let right channel handle everything.
+				 */
+				break;
+		}
 		/*
 		 * 7ms sleep is required after PA is enabled as per
-		 * HW requirement
+		 * HW requirement. If compander is disabled, then
+		 * 20ms delay is needed.
 		 */
 		if (test_bit(HPH_PA_DELAY, &tavil->status_mask)) {
-			usleep_range(7000, 7100);
+			if (!tavil->comp_enabled[COMPANDER_1])
+				usleep_range(20000, 20100);
+			else
+				usleep_range(7000, 7100);
 			clear_bit(HPH_PA_DELAY, &tavil->status_mask);
 		}
+		if (tavil->anc_func) {
+			/* Clear Tx FE HOLD if both PAs are enabled */
+			if ((snd_soc_read(tavil->codec, WCD934X_ANA_HPH) &
+					0xC0) == 0xC0)
+				tavil_codec_clear_anc_tx_hold(tavil);
+		}
+
 		snd_soc_update_bits(codec, WCD934X_HPH_L_TEST, 0x01, 0x01);
 		/* Remove Mute on primary path */
 		snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CTL,
@@ -2031,6 +2211,33 @@
 		    (snd_soc_read(codec, WCD934X_CDC_DSD0_PATH_CTL) & 0x01))
 			snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2,
 					    0x04, 0x00);
+		if (!(strcmp(w->name, "ANC HPHL PA"))) {
+			pr_debug("%s:Do everything needed for right channel\n",
+				__func__);
+
+			/* Do everything needed for right channel */
+			snd_soc_update_bits(codec, WCD934X_HPH_R_TEST,
+					    0x01, 0x01);
+
+			/* Remove mute */
+			snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_CTL,
+						0x10, 0x00);
+
+			/* Remove mix path mute if it is enabled */
+			if ((snd_soc_read(codec,
+					WCD934X_CDC_RX2_RX_PATH_MIX_CTL)) &
+					0x10)
+				snd_soc_update_bits(codec,
+						WCD934X_CDC_RX2_RX_PATH_MIX_CTL,
+						0x10, 0x00);
+			if (dsd_conf && (snd_soc_read(codec,
+					WCD934X_CDC_DSD1_PATH_CTL) & 0x01))
+				snd_soc_update_bits(codec,
+						    WCD934X_CDC_DSD1_CFG2,
+						    0x04, 0x00);
+			/* Remove ANC Rx from reset */
+			ret = tavil_codec_enable_anc(w, kcontrol, event);
+		}
 		tavil_codec_override(codec, tavil->hph_mode, event);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
@@ -2046,10 +2253,21 @@
 		snd_soc_update_bits(codec, WCD934X_HPH_L_TEST, 0x01, 0x00);
 		snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CTL,
 				    0x10, 0x10);
+		snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_MIX_CTL,
+				    0x10, 0x10);
+		if (!(strcmp(w->name, "ANC HPHL PA")))
+			snd_soc_update_bits(codec, WCD934X_ANA_HPH,
+					    0x80, 0x00);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		/* 5ms sleep is required after PA disable */
-		usleep_range(5000, 5100);
+		/*
+		 * 5ms sleep is required after PA disable. If compander is
+		 * disabled, then 20ms delay is needed after PA disable.
+		 */
+		if (!tavil->comp_enabled[COMPANDER_1])
+			usleep_range(20000, 20100);
+		else
+			usleep_range(5000, 5100);
 		tavil_codec_override(codec, tavil->hph_mode, event);
 		blocking_notifier_call_chain(&tavil->mbhc->notifier,
 					     WCD_EVENT_POST_HPHL_PA_OFF,
@@ -2057,10 +2275,15 @@
 		if (TAVIL_IS_1_0(tavil->wcd9xxx))
 			snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL,
 					    0x06, 0x0);
+		if (!(strcmp(w->name, "ANC HPHL PA"))) {
+			ret = tavil_codec_enable_anc(w, kcontrol, event);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_RX1_RX_PATH_CFG0, 0x10, 0x00);
+		}
 		break;
 	};
 
-	return 0;
+	return ret;
 }
 
 static int tavil_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w,
@@ -2069,6 +2292,9 @@
 {
 	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	u16 lineout_vol_reg = 0, lineout_mix_vol_reg = 0;
+	u16 dsd_mute_reg = 0, dsd_clk_reg = 0;
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	struct tavil_dsd_config *dsd_conf = tavil->dsd_config;
 
 	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
 
@@ -2076,9 +2302,13 @@
 		if (w->shift == 7) {
 			lineout_vol_reg = WCD934X_CDC_RX3_RX_PATH_CTL;
 			lineout_mix_vol_reg = WCD934X_CDC_RX3_RX_PATH_MIX_CTL;
+			dsd_mute_reg = WCD934X_CDC_DSD0_CFG2;
+			dsd_clk_reg = WCD934X_CDC_DSD0_PATH_CTL;
 		} else if (w->shift == 6) {
 			lineout_vol_reg = WCD934X_CDC_RX4_RX_PATH_CTL;
 			lineout_mix_vol_reg = WCD934X_CDC_RX4_RX_PATH_MIX_CTL;
+			dsd_mute_reg = WCD934X_CDC_DSD1_CFG2;
+			dsd_clk_reg = WCD934X_CDC_DSD1_PATH_CTL;
 		}
 	} else {
 		dev_err(codec->dev, "%s: Error enabling lineout PA\n",
@@ -2103,6 +2333,12 @@
 			snd_soc_update_bits(codec,
 					    lineout_mix_vol_reg,
 					    0x10, 0x00);
+		if (dsd_conf && (snd_soc_read(codec, dsd_clk_reg) & 0x01))
+			snd_soc_update_bits(codec, dsd_mute_reg, 0x04, 0x00);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		if (dsd_conf && (snd_soc_read(codec, dsd_clk_reg) & 0x01))
+			snd_soc_update_bits(codec, dsd_mute_reg, 0x04, 0x04);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		/*
@@ -2167,12 +2403,18 @@
 	int hph_mode = tavil->hph_mode;
 	u8 dem_inp;
 	struct tavil_dsd_config *dsd_conf = tavil->dsd_config;
+	int ret = 0;
 
 	dev_dbg(codec->dev, "%s wname: %s event: %d hph_mode: %d\n", __func__,
 		w->name, event, hph_mode);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		if (tavil->anc_func) {
+			ret = tavil_codec_enable_anc(w, kcontrol, event);
+			/* 40 msec delay is needed to avoid click and pop */
+			msleep(40);
+		}
 		/* Read DEM INP Select */
 		dem_inp = snd_soc_read(codec, WCD934X_CDC_RX2_RX_PATH_SEC0) &
 			  0x03;
@@ -2203,6 +2445,10 @@
 			     WCD_CLSH_EVENT_PRE_DAC,
 			     WCD_CLSH_STATE_HPHR,
 			     hph_mode);
+		if (tavil->anc_func)
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX2_RX_PATH_CFG0,
+					    0x10, 0x10);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		/* 1000us required as per HW requirement */
@@ -2246,6 +2492,11 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		if (tavil->anc_func) {
+			ret = tavil_codec_enable_anc(w, kcontrol, event);
+			/* 40 msec delay is needed to avoid click and pop */
+			msleep(40);
+		}
 		/* Read DEM INP Select */
 		dem_inp = snd_soc_read(codec, WCD934X_CDC_RX1_RX_PATH_SEC0) &
 			  0x03;
@@ -2277,6 +2528,11 @@
 			     WCD_CLSH_STATE_HPHL,
 			     hph_mode);
 
+		if (tavil->anc_func)
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX1_RX_PATH_CFG0,
+					    0x10, 0x10);
+
 		ret = tavil_mbhc_get_impedance(tavil->mbhc,
 					       &impedl, &impedr);
 		if (!ret) {
@@ -2596,6 +2852,8 @@
 		/* Undo reset for MAD */
 		snd_soc_update_bits(codec, WCD934X_CPE_SS_MAD_CTL,
 				    0x02, 0x00);
+		snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+					0x04, 0x04);
 	} else {
 		snd_soc_update_bits(codec, WCD934X_SOC_MAD_AUDIO_CTL_2,
 				    0x03, 0x00);
@@ -2605,6 +2863,8 @@
 		/* Turn off MAD clk */
 		snd_soc_update_bits(codec, WCD934X_CPE_SS_MAD_CTL,
 				    0x01, 0x00);
+		snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+					0x04, 0x00);
 	}
 done:
 	return rc;
@@ -3157,6 +3417,15 @@
 }
 EXPORT_SYMBOL(tavil_codec_enable_interp_clk);
 
+static int tavil_anc_out_switch_cb(struct snd_soc_dapm_widget *w,
+				   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	tavil_codec_enable_interp_clk(codec, event, w->shift);
+
+	return 0;
+}
 static int tavil_codec_set_idle_detect_thr(struct snd_soc_codec *codec,
 					   int interp, int path_type)
 {
@@ -3611,8 +3880,8 @@
 {
 	int adc_mux_n = w->shift;
 	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
 	int amic_n;
-	u16 amic_reg;
 
 	dev_dbg(codec->dev, "%s: event: %d\n", __func__, event);
 
@@ -3620,8 +3889,13 @@
 	case SND_SOC_DAPM_POST_PMU:
 		amic_n = tavil_codec_find_amic_input(codec, adc_mux_n);
 		if (amic_n) {
-			amic_reg = WCD934X_ANA_AMIC1 + amic_n - 1;
-			tavil_codec_set_tx_hold(codec, amic_reg, false);
+			/*
+			 * Prevent ANC Rx pop by leaving Tx FE in HOLD
+			 * state until PA is up. Track AMIC being used
+			 * so we can release the HOLD later.
+			 */
+			set_bit(ANC_MIC_AMIC1 + amic_n - 1,
+				&tavil->status_mask);
 		}
 		break;
 	default:
@@ -5123,19 +5397,18 @@
 				  struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	u16 amic_reg;
+	u16 amic_reg = 0;
 
 	if (!strcmp(kcontrol->id.name, "AMIC_1_2 PWR MODE"))
 		amic_reg = WCD934X_ANA_AMIC1;
 	if (!strcmp(kcontrol->id.name, "AMIC_3_4 PWR MODE"))
 		amic_reg = WCD934X_ANA_AMIC3;
-	else
-		goto ret;
 
-	ucontrol->value.integer.value[0] =
-		(snd_soc_read(codec, amic_reg) & WCD934X_AMIC_PWR_LVL_MASK) >>
-			     WCD934X_AMIC_PWR_LVL_SHIFT;
-ret:
+	if (amic_reg)
+		ucontrol->value.integer.value[0] =
+			(snd_soc_read(codec, amic_reg) &
+			 WCD934X_AMIC_PWR_LVL_MASK) >>
+			  WCD934X_AMIC_PWR_LVL_SHIFT;
 	return 0;
 }
 
@@ -5144,7 +5417,7 @@
 {
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	u32 mode_val;
-	u16 amic_reg;
+	u16 amic_reg = 0;
 
 	mode_val = ucontrol->value.enumerated.item[0];
 
@@ -5154,12 +5427,10 @@
 		amic_reg = WCD934X_ANA_AMIC1;
 	if (!strcmp(kcontrol->id.name, "AMIC_3_4 PWR MODE"))
 		amic_reg = WCD934X_ANA_AMIC3;
-	else
-		goto ret;
 
-	snd_soc_update_bits(codec, amic_reg, WCD934X_AMIC_PWR_LVL_MASK,
-			    mode_val << WCD934X_AMIC_PWR_LVL_SHIFT);
-ret:
+	if (amic_reg)
+		snd_soc_update_bits(codec, amic_reg, WCD934X_AMIC_PWR_LVL_MASK,
+				    mode_val << WCD934X_AMIC_PWR_LVL_SHIFT);
 	return 0;
 }
 
@@ -6447,6 +6718,12 @@
 static const struct snd_kcontrol_new anc_spkr_pa_switch =
 	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
 
+static const struct snd_kcontrol_new anc_hphl_pa_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_hphr_pa_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
 static const struct snd_kcontrol_new mad_cpe1_switch =
 	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
 
@@ -6554,6 +6831,16 @@
 			tavil_dsd_mixer_get, tavil_dsd_mixer_put),
 };
 
+static const struct snd_kcontrol_new lo1_mixer[] = {
+	SOC_SINGLE_EXT("DSD LO1 Switch", SND_SOC_NOPM, INTERP_LO1, 1, 0,
+			tavil_dsd_mixer_get, tavil_dsd_mixer_put),
+};
+
+static const struct snd_kcontrol_new lo2_mixer[] = {
+	SOC_SINGLE_EXT("DSD LO2 Switch", SND_SOC_NOPM, INTERP_LO2, 1, 0,
+			tavil_dsd_mixer_get, tavil_dsd_mixer_put),
+};
+
 static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = {
 	SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
 		AIF1_PB, 0, tavil_codec_enable_slimrx,
@@ -6686,7 +6973,11 @@
 	SND_SOC_DAPM_MIXER("RX INT2 MIX3", SND_SOC_NOPM, 0, 0, hphr_mixer,
 			   ARRAY_SIZE(hphr_mixer)),
 	SND_SOC_DAPM_MIXER("RX INT3 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT3 MIX3", SND_SOC_NOPM, 0, 0, lo1_mixer,
+			   ARRAY_SIZE(lo1_mixer)),
 	SND_SOC_DAPM_MIXER("RX INT4 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT4 MIX3", SND_SOC_NOPM, 0, 0, lo2_mixer,
+			   ARRAY_SIZE(lo2_mixer)),
 	SND_SOC_DAPM_MIXER("RX INT7 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_MIXER_E("RX INT7 CHAIN", SND_SOC_NOPM, 0, 0,
 		NULL, 0, tavil_codec_spk_boost_event,
@@ -7075,17 +7366,25 @@
 	SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD934X_ANA_LO_1_2, 7, 0, NULL, 0,
 		tavil_codec_enable_lineout_pa,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_POST_PMD),
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD934X_ANA_LO_1_2, 6, 0, NULL, 0,
 		tavil_codec_enable_lineout_pa,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_POST_PMD),
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_PGA_E("ANC EAR PA", WCD934X_ANA_EAR, 7, 0, NULL, 0,
 		tavil_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
 		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_PGA_E("ANC SPK1 PA", SND_SOC_NOPM, 0, 0, NULL, 0,
 		tavil_codec_enable_spkr_anc,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("ANC HPHL PA", SND_SOC_NOPM, 0, 0, NULL, 0,
+		tavil_codec_enable_hphl_pa,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("ANC HPHR PA", SND_SOC_NOPM, 0, 0, NULL, 0,
+		tavil_codec_enable_hphr_pa,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_OUTPUT("EAR"),
 	SND_SOC_DAPM_OUTPUT("HPHL"),
@@ -7095,6 +7394,8 @@
 	SND_SOC_DAPM_OUTPUT("SPK1 OUT"),
 	SND_SOC_DAPM_OUTPUT("SPK2 OUT"),
 	SND_SOC_DAPM_OUTPUT("ANC EAR"),
+	SND_SOC_DAPM_OUTPUT("ANC HPHL"),
+	SND_SOC_DAPM_OUTPUT("ANC HPHR"),
 
 	SND_SOC_DAPM_SWITCH("ANC OUT EAR Enable", SND_SOC_NOPM, 0, 0,
 		&anc_ear_switch),
@@ -7103,6 +7404,13 @@
 	SND_SOC_DAPM_SWITCH("ANC SPKR PA Enable", SND_SOC_NOPM, 0, 0,
 		&anc_spkr_pa_switch),
 
+	SND_SOC_DAPM_SWITCH_E("ANC OUT HPHL Enable", SND_SOC_NOPM, INTERP_HPHL,
+		0, &anc_hphl_pa_switch, tavil_anc_out_switch_cb,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+	 SND_SOC_DAPM_SWITCH_E("ANC OUT HPHR Enable", SND_SOC_NOPM, INTERP_HPHR,
+		0, &anc_hphr_pa_switch, tavil_anc_out_switch_cb,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
 	SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
 		tavil_codec_enable_rx_bias,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
@@ -7787,13 +8095,8 @@
 
 static void tavil_codec_power_gate_digital_core(struct tavil_priv *tavil)
 {
-	struct snd_soc_codec *codec = tavil->codec;
-
-	if (!codec)
-		return;
-
 	mutex_lock(&tavil->power_lock);
-	dev_dbg(codec->dev, "%s: Entering power gating function, %d\n",
+	dev_dbg(tavil->dev, "%s: Entering power gating function, %d\n",
 		__func__, tavil->power_active_ref);
 
 	if (tavil->power_active_ref > 0)
@@ -7802,16 +8105,16 @@
 	wcd9xxx_set_power_state(tavil->wcd9xxx,
 			WCD_REGION_POWER_COLLAPSE_BEGIN,
 			WCD9XXX_DIG_CORE_REGION_1);
-	snd_soc_update_bits(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
-			0x04, 0x04);
-	snd_soc_update_bits(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
-			0x01, 0x00);
-	snd_soc_update_bits(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
-			0x02, 0x00);
+	regmap_update_bits(tavil->wcd9xxx->regmap,
+			   WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x04, 0x04);
+	regmap_update_bits(tavil->wcd9xxx->regmap,
+			   WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x01, 0x00);
+	regmap_update_bits(tavil->wcd9xxx->regmap,
+			   WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x02, 0x00);
 	wcd9xxx_set_power_state(tavil->wcd9xxx, WCD_REGION_POWER_DOWN,
 				WCD9XXX_DIG_CORE_REGION_1);
 exit:
-	dev_dbg(codec->dev, "%s: Exiting power gating function, %d\n",
+	dev_dbg(tavil->dev, "%s: Exiting power gating function, %d\n",
 		__func__, tavil->power_active_ref);
 	mutex_unlock(&tavil->power_lock);
 }
@@ -7820,34 +8123,32 @@
 {
 	struct tavil_priv *tavil;
 	struct delayed_work *dwork;
-	struct snd_soc_codec *codec;
 
 	dwork = to_delayed_work(work);
 	tavil = container_of(dwork, struct tavil_priv, power_gate_work);
-	codec = tavil->codec;
-
-	if (!codec)
-		return;
 
 	tavil_codec_power_gate_digital_core(tavil);
 }
 
 /* called under power_lock acquisition */
-static int tavil_dig_core_remove_power_collapse(struct snd_soc_codec *codec)
+static int tavil_dig_core_remove_power_collapse(struct tavil_priv *tavil)
 {
-	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
-
-	snd_soc_write(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
-	snd_soc_write(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
-	snd_soc_write(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
-	snd_soc_update_bits(codec, WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x00);
-	snd_soc_update_bits(codec, WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x02);
+	regmap_write(tavil->wcd9xxx->regmap,
+		     WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x05);
+	regmap_write(tavil->wcd9xxx->regmap,
+		     WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x07);
+	regmap_update_bits(tavil->wcd9xxx->regmap,
+			   WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x00);
+	regmap_update_bits(tavil->wcd9xxx->regmap,
+			   WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x02);
+	regmap_write(tavil->wcd9xxx->regmap,
+		     WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x03);
 
 	wcd9xxx_set_power_state(tavil->wcd9xxx,
 			WCD_REGION_POWER_COLLAPSE_REMOVE,
 			WCD9XXX_DIG_CORE_REGION_1);
-	regcache_mark_dirty(codec->component.regmap);
-	regcache_sync_region(codec->component.regmap,
+	regcache_mark_dirty(tavil->wcd9xxx->regmap);
+	regcache_sync_region(tavil->wcd9xxx->regmap,
 			     WCD934X_DIG_CORE_REG_MIN,
 			     WCD934X_DIG_CORE_REG_MAX);
 
@@ -7857,7 +8158,6 @@
 static int tavil_dig_core_power_collapse(struct tavil_priv *tavil,
 					 int req_state)
 {
-	struct snd_soc_codec *codec;
 	int cur_state;
 
 	/* Exit if feature is disabled */
@@ -7878,10 +8178,6 @@
 		goto unlock_mutex;
 	}
 
-	codec = tavil->codec;
-	if (!codec)
-		goto unlock_mutex;
-
 	if (req_state == POWER_COLLAPSE) {
 		if (tavil->power_active_ref == 0) {
 			schedule_delayed_work(&tavil->power_gate_work,
@@ -7899,7 +8195,7 @@
 						tavil->wcd9xxx,
 						WCD9XXX_DIG_CORE_REGION_1);
 			if (cur_state == WCD_REGION_POWER_DOWN) {
-				tavil_dig_core_remove_power_collapse(codec);
+				tavil_dig_core_remove_power_collapse(tavil);
 			} else {
 				mutex_unlock(&tavil->power_lock);
 				cancel_delayed_work_sync(
@@ -8799,13 +9095,8 @@
 				WCD9XXX_DIG_CORE_REGION_1);
 
 	mutex_lock(&tavil->codec_mutex);
-	/*
-	 * Codec hardware by default comes up in SVS mode.
-	 * Initialize the svs_ref_cnt to 1 to reflect the hardware
-	 * state in the driver.
-	 */
-	tavil->svs_ref_cnt = 1;
 
+	tavil_vote_svs(tavil, true);
 	tavil_slimbus_slave_port_cfg.slave_dev_intfdev_la =
 				control->slim_slave->laddr;
 	tavil_slimbus_slave_port_cfg.slave_dev_pgd_la =
@@ -8813,17 +9104,9 @@
 	tavil_init_slim_slave_cfg(codec);
 	snd_soc_card_change_online_state(codec->component.card, 1);
 
-	/* Class-H Init */
-	wcd_clsh_init(&tavil->clsh_d);
-	/* Default HPH Mode to Class-H LOHiFi */
-	tavil->hph_mode = CLS_H_LOHIFI;
-
 	for (i = 0; i < TAVIL_MAX_MICBIAS; i++)
 		tavil->micb_ref[i] = 0;
 
-	for (i = 0; i < COMPANDER_MAX; i++)
-		tavil->comp_enabled[i] = 0;
-
 	dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
 		__func__, control->mclk_rate);
 
@@ -9017,6 +9300,10 @@
 	mutex_lock(&tavil->codec_mutex);
 	snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
 	snd_soc_dapm_disable_pin(dapm, "ANC EAR");
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHL PA");
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHR PA");
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
 	snd_soc_dapm_enable_pin(dapm, "ANC SPK1 PA");
 	mutex_unlock(&tavil->codec_mutex);
 
@@ -9027,6 +9314,7 @@
 	snd_soc_dapm_ignore_suspend(dapm, "AIF3 Playback");
 	snd_soc_dapm_ignore_suspend(dapm, "AIF3 Capture");
 	snd_soc_dapm_ignore_suspend(dapm, "AIF4 Playback");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF4 MAD TX");
 	snd_soc_dapm_ignore_suspend(dapm, "VIfeed");
 
 	snd_soc_dapm_sync(dapm);
diff --git a/sound/soc/codecs/wcd9xxx-common-v2.c b/sound/soc/codecs/wcd9xxx-common-v2.c
index ad62d18..9ac38c2 100644
--- a/sound/soc/codecs/wcd9xxx-common-v2.c
+++ b/sound/soc/codecs/wcd9xxx-common-v2.c
@@ -130,6 +130,81 @@
 	},
 };
 
+static const struct wcd_reg_mask_val imped_table_tavil[][MAX_IMPED_PARAMS] = {
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf2},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf2},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf2},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf2},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf4},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf4},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf4},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf4},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf7},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf7},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf7},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf7},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf9},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf9},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf9},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf9},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfa},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfa},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfa},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfa},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfb},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfb},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfb},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfb},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfc},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfc},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfc},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfc},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+	},
+};
+
 static const struct wcd_imped_val imped_index[] = {
 	{4, 0},
 	{5, 1},
@@ -185,12 +260,26 @@
 {
 	int i;
 	int index = 0;
+	int table_size;
+
+	static const struct wcd_reg_mask_val
+				(*imped_table_ptr)[MAX_IMPED_PARAMS];
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+
+	if (IS_CODEC_TYPE(wcd9xxx, WCD934X)) {
+		table_size = ARRAY_SIZE(imped_table_tavil);
+		imped_table_ptr = imped_table_tavil;
+	} else {
+		table_size = ARRAY_SIZE(imped_table);
+		imped_table_ptr = imped_table;
+	}
 
 	/* reset = 1, which means request is to reset the register values */
 	if (reset) {
 		for (i = 0; i < MAX_IMPED_PARAMS; i++)
-			snd_soc_update_bits(codec, imped_table[index][i].reg,
-				imped_table[index][i].mask, 0);
+			snd_soc_update_bits(codec,
+				imped_table_ptr[index][i].reg,
+				imped_table_ptr[index][i].mask, 0);
 		return;
 	}
 	index = get_impedance_index(imped);
@@ -198,15 +287,16 @@
 		pr_debug("%s, impedance not in range = %d\n", __func__, imped);
 		return;
 	}
-	if (index >= ARRAY_SIZE(imped_table)) {
+	if (index >= table_size) {
 		pr_debug("%s, impedance index not in range = %d\n", __func__,
 			index);
 		return;
 	}
 	for (i = 0; i < MAX_IMPED_PARAMS; i++)
-		snd_soc_update_bits(codec, imped_table[index][i].reg,
-				imped_table[index][i].mask,
-				imped_table[index][i].val);
+		snd_soc_update_bits(codec,
+				imped_table_ptr[index][i].reg,
+				imped_table_ptr[index][i].mask,
+				imped_table_ptr[index][i].val);
 }
 EXPORT_SYMBOL(wcd_clsh_imped_config);
 
@@ -579,6 +669,11 @@
 static void wcd_clsh_set_flyback_vneg_ctl(struct snd_soc_codec *codec,
 					  bool enable)
 {
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+
+	if (!TASHA_IS_2_0(wcd9xxx))
+		return;
+
 	if (enable) {
 		snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_1, 0xE0,
 				    0x00);
@@ -758,35 +853,35 @@
 	dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
 		is_enable ? "enable" : "disable");
 
-	if (is_enable && (req_state == WCD_CLSH_STATE_LO)) {
-		wcd_clsh_set_buck_regulator_mode(codec, CLS_AB);
-	} else {
-		if (req_state == WCD_CLSH_STATE_EAR)
-			goto end;
-
-		/* LO powerdown.
-		 * If EAR Class-H is already enabled, just
-		 * turn on regulator other enable Class-H
-		 * configuration
+	if (is_enable) {
+		/* LO powerup is taken care in PA sequence.
+		 * No need to change to class AB here.
 		 */
-		if (wcd_clsh_enable_status(codec)) {
-			wcd_clsh_set_buck_regulator_mode(codec,
-					CLS_H_NORMAL);
-			goto end;
+		if (req_state == WCD_CLSH_STATE_EAR) {
+			/* EAR powerup.*/
+			if (!wcd_clsh_enable_status(codec)) {
+				wcd_enable_clsh_block(codec, clsh_d, true);
+				wcd_clsh_set_buck_mode(codec, mode);
+				wcd_clsh_set_flyback_mode(codec, mode);
+			}
+			snd_soc_update_bits(codec,
+					WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+					0x40, 0x40);
 		}
-		wcd_enable_clsh_block(codec, clsh_d, true);
-		snd_soc_update_bits(codec,
-				WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
-				0x40, 0x40);
-		wcd_clsh_set_buck_regulator_mode(codec,
-				CLS_H_NORMAL);
-		wcd_clsh_set_buck_mode(codec, mode);
-		wcd_clsh_set_flyback_mode(codec, mode);
-		wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
-		wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
+	} else {
+		if (req_state == WCD_CLSH_STATE_EAR) {
+			/* EAR powerdown.*/
+			wcd_enable_clsh_block(codec, clsh_d, false);
+			wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
+			wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
+			snd_soc_update_bits(codec,
+					WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+					0x40, 0x00);
+		}
+		/* LO powerdown is taken care in PA sequence.
+		 * No need to change to class H here.
+		 */
 	}
-end:
-	return;
 }
 
 static void wcd_clsh_state_hph_lo(struct snd_soc_codec *codec,
@@ -1135,6 +1230,7 @@
 	case WCD_CLSH_STATE_HPHL_LO:
 	case WCD_CLSH_STATE_HPHR_LO:
 	case WCD_CLSH_STATE_HPH_ST_LO:
+	case WCD_CLSH_STATE_EAR_LO:
 		return true;
 	default:
 		return false;
diff --git a/sound/soc/codecs/wcd9xxx-common-v2.h b/sound/soc/codecs/wcd9xxx-common-v2.h
index ee7e587..53c9a84 100644
--- a/sound/soc/codecs/wcd9xxx-common-v2.h
+++ b/sound/soc/codecs/wcd9xxx-common-v2.h
@@ -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
@@ -34,7 +34,12 @@
 #define	WCD_CLSH_STATE_HPHL (0x01 << 1)
 #define	WCD_CLSH_STATE_HPHR (0x01 << 2)
 #define	WCD_CLSH_STATE_LO (0x01 << 3)
-#define WCD_CLSH_STATE_MAX 4
+
+/*
+ * Though number of CLSH states are 4, max state shoulbe be 5
+ * because state array index starts from 1.
+ */
+#define WCD_CLSH_STATE_MAX 5
 #define NUM_CLSH_STATES_V2 (0x01 << WCD_CLSH_STATE_MAX)
 
 
diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.c b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
index fde13d2..8780888 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr-v2.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
@@ -247,9 +247,15 @@
 			 * to CLK_SYS_MCLK_PRG
 			 */
 			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD934X_CLK_SYS_MCLK_PRG, 0x80, 0x80);
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD934X_CLK_SYS_MCLK_PRG, 0x30, 0x10);
+			wcd_resmgr_codec_reg_update_bits(resmgr,
 					WCD934X_CLK_SYS_MCLK_PRG, 0x02, 0x00);
 			wcd_resmgr_codec_reg_update_bits(resmgr,
-					WCD934X_CLK_SYS_MCLK_PRG, 0x91, 0x91);
+					WCD934X_CLK_SYS_MCLK_PRG, 0x01, 0x01);
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD934X_CLK_SYS_MCLK_PRG, 0x02, 0x00);
 			wcd_resmgr_codec_reg_update_bits(resmgr,
 					WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
 					0x01, 0x01);
@@ -257,9 +263,6 @@
 					WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL,
 					0x01, 0x01);
 			wcd_resmgr_codec_reg_update_bits(resmgr,
-					WCD934X_CODEC_RPM_CLK_MCLK_CFG,
-					0x04, 0x04);
-			wcd_resmgr_codec_reg_update_bits(resmgr,
 					WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL,
 					0x01, 0x01);
 			wcd_resmgr_codec_reg_update_bits(resmgr,
@@ -305,6 +308,9 @@
 					0x08, 0x08);
 			wcd_resmgr_codec_reg_update_bits(resmgr,
 					WCD934X_CLK_SYS_MCLK_PRG, 0x02, 0x02);
+			/* Disable clock buffer */
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD934X_CLK_SYS_MCLK_PRG, 0x80, 0x00);
 			resmgr->clk_type = WCD_CLK_RCO;
 		} else {
 			wcd_resmgr_codec_reg_update_bits(resmgr,
diff --git a/sound/soc/codecs/wcd_cpe_core.c b/sound/soc/codecs/wcd_cpe_core.c
index c98fdc9..cf014d7 100644
--- a/sound/soc/codecs/wcd_cpe_core.c
+++ b/sound/soc/codecs/wcd_cpe_core.c
@@ -887,14 +887,7 @@
 			 * instead SSR handler will control CPE.
 			 */
 			wcd_cpe_enable_cpe_clks(core, false);
-			/*
-			 * During BUS_DOWN event, possibly the
-			 * irq driver is under cleanup, do not request
-			 * cleanup of irqs here, rather cleanup irqs
-			 * once BUS_UP event is received.
-			 */
-			if (core->ssr_type != WCD_CPE_BUS_DOWN_EVENT)
-				wcd_cpe_cleanup_irqs(core);
+			wcd_cpe_cleanup_irqs(core);
 			goto done;
 		}
 
@@ -1145,7 +1138,6 @@
 		break;
 
 	case WCD_CPE_BUS_UP_EVENT:
-		wcd_cpe_cleanup_irqs(core);
 		wcd_cpe_set_and_complete(core, WCD_CPE_BUS_READY);
 		/*
 		 * In case of bus up event ssr_type will be changed
@@ -3024,7 +3016,7 @@
 
 static int wcd_cpe_set_one_param(void *core_handle,
 	struct cpe_lsm_session *session, struct lsm_params_info *p_info,
-	void *data, enum LSM_PARAM_TYPE param_type)
+	void *data, uint32_t param_type)
 {
 	struct wcd_cpe_core *core = core_handle;
 	int rc = 0;
@@ -3039,25 +3031,9 @@
 		rc = wcd_cpe_send_param_epd_thres(core, session,
 						data, &ids);
 		break;
-	case LSM_OPERATION_MODE: {
-		struct cpe_lsm_ids connectport_ids;
-
-		rc = wcd_cpe_send_param_opmode(core, session,
-					data, &ids);
-		if (rc)
-			break;
-
-		connectport_ids.module_id = LSM_MODULE_ID_FRAMEWORK;
-		connectport_ids.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
-
-		rc = wcd_cpe_send_param_connectport(core, session, NULL,
-				       &connectport_ids, CPE_AFE_PORT_1_TX);
-		if (rc)
-			dev_err(core->dev,
-				"%s: send_param_connectport failed, err %d\n",
-				__func__, rc);
+	case LSM_OPERATION_MODE:
+		rc = wcd_cpe_send_param_opmode(core, session, data, &ids);
 		break;
-	}
 	case LSM_GAIN:
 		rc = wcd_cpe_send_param_gain(core, session, data, &ids);
 		break;
@@ -3076,13 +3052,13 @@
 		break;
 	default:
 		pr_err("%s: wrong param_type 0x%x\n",
-			__func__, p_info->param_type);
+			__func__, param_type);
 	}
 
 	if (rc)
 		dev_err(core->dev,
 			"%s: send_param(%d) failed, err %d\n",
-			 __func__, p_info->param_type, rc);
+			 __func__, param_type, rc);
 	return rc;
 }
 
diff --git a/sound/soc/codecs/wsa881x-temp-sensor.c b/sound/soc/codecs/wsa881x-temp-sensor.c
index 0079d0f..5ab0ecf 100644
--- a/sound/soc/codecs/wsa881x-temp-sensor.c
+++ b/sound/soc/codecs/wsa881x-temp-sensor.c
@@ -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,7 +23,7 @@
 #define LOW_TEMP_THRESHOLD 5
 #define HIGH_TEMP_THRESHOLD 45
 #define TEMP_INVALID	0xFFFF
-
+#define WSA881X_TEMP_RETRY 3
 /*
  * wsa881x_get_temp - get wsa temperature
  * @thermal: thermal zone device
@@ -44,6 +44,7 @@
 	int temp_val;
 	int t1 = T1_TEMP;
 	int t2 = T2_TEMP;
+	u8 retry = WSA881X_TEMP_RETRY;
 
 	if (!thermal)
 		return -EINVAL;
@@ -60,6 +61,7 @@
 		pr_err("%s: pdata is NULL\n", __func__);
 		return -EINVAL;
 	}
+temp_retry:
 	if (pdata->wsa_temp_reg_read) {
 		ret = pdata->wsa_temp_reg_read(codec, &reg);
 		if (ret) {
@@ -101,6 +103,10 @@
 		printk_ratelimited("%s: T0: %d is out of range[%d, %d]\n",
 				   __func__, temp_val, LOW_TEMP_THRESHOLD,
 				   HIGH_TEMP_THRESHOLD);
+		if (retry--) {
+			msleep(20);
+			goto temp_retry;
+		}
 	}
 	if (temp)
 		*temp = temp_val;
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index e689570..062bae2 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -757,15 +757,13 @@
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		wsa881x_resource_acquire(codec, ENABLE);
-		if (wsa881x->boost_enable)
-			wsa881x_boost_ctrl(codec, ENABLE);
+		wsa881x_boost_ctrl(codec, ENABLE);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		swr_slvdev_datapath_control(wsa881x->swr_slave,
 					    wsa881x->swr_slave->dev_num,
 					    false);
-		if (wsa881x->boost_enable)
-			wsa881x_boost_ctrl(codec, DISABLE);
+		wsa881x_boost_ctrl(codec, DISABLE);
 		wsa881x_resource_acquire(codec, DISABLE);
 		break;
 	}
@@ -988,6 +986,7 @@
 {
 	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
 	struct swr_device *dev;
+	u8 retry = WSA881X_NUM_RETRY;
 	u8 devnum = 0;
 
 	if (!wsa881x) {
@@ -996,7 +995,12 @@
 	}
 	dev = wsa881x->swr_slave;
 	if (dev && (wsa881x->state == WSA881X_DEV_DOWN)) {
-		if (swr_get_logical_dev_num(dev, dev->addr, &devnum)) {
+		while (swr_get_logical_dev_num(dev, dev->addr, &devnum) &&
+		       retry--) {
+			/* Retry after 1 msec delay */
+			usleep_range(1000, 1100);
+		}
+		if (retry == 0) {
 			dev_err(codec->dev,
 				"%s get devnum %d for dev addr %lx failed\n",
 				__func__, devnum, dev->addr);
@@ -1108,8 +1112,9 @@
 	usleep_range(5000, 5010);
 	ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum);
 	if (ret) {
-		dev_dbg(&swr_dev->dev, "%s failed to get devnum, err:%d\n",
-			__func__, ret);
+		dev_dbg(&swr_dev->dev,
+			"%s get devnum %d for dev addr %lx failed\n",
+			__func__, devnum, swr_dev->addr);
 		goto err;
 	}
 	swr_dev->dev_num = devnum;
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 5f9d42c..18585749 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -30,16 +30,6 @@
 	 is inducing kernel panic upon encountering critical
 	 errors from DSP audio modules
 
-config DOLBY_DAP
-	bool "Enable Dolby DAP"
-	depends on SND_SOC_MSM_QDSP6V2_INTF
-	help
-	 To add support for dolby DAP post processing.
-	 This support is to configure the post processing parameters
-	 to DSP. The configuration includes sending the end point
-	 device, end point dependent post processing parameters and
-	 the various posrt processing parameters
-
 config DOLBY_DS2
 	bool "Enable Dolby DS2"
 	depends on SND_SOC_MSM_QDSP6V2_INTF
@@ -108,7 +98,7 @@
 	 listen on codec.
 
 config SND_SOC_INT_CODEC
-	tristate "SoC Machine driver for MSMFALCON_INT"
+	tristate "SoC Machine driver for SDM660_INT"
 	depends on ARCH_QCOM
 	select SND_SOC_QDSP6V2
 	select SND_SOC_MSM_STUB
@@ -119,17 +109,19 @@
 	select MSM_QDSP6_PDR
 	select MSM_QDSP6_NOTIFIER
 	select MSM_QDSP6V2_CODECS
-	select SND_SOC_MSM_SWR
-	select SND_SOC_MSM8X16_WCD
+	select MSM_CDC_PINCTRL
+	select SND_SOC_MSM_SDW
+	select SND_SOC_SDM660_CDC
+	select SND_SOC_MSM_HDMI_CODEC_RX
 	select QTI_PP
 	select DTS_SRS_TM
-	select DOLBY_DAP
-	select DOLBY_DS2
+	select DOLBY_LICENSE
 	select SND_HWDEP
 	select MSM_ULTRASOUND
 	select DTS_EAGLE
-	select SND_SOC_MSMFALCON_COMMON
+	select SND_SOC_SDM660_COMMON
 	select SND_SOC_COMPRESS
+	select PINCTRL_LPI
 	help
 	To add support for SoC audio on MSM_INT.
 	This will enable sound soc drivers which
@@ -138,7 +130,7 @@
 	DAI-links
 
 config SND_SOC_EXT_CODEC
-	tristate "SoC Machine driver for MSMFALCON_EXT"
+	tristate "SoC Machine driver for SDM660_EXT"
 	depends on ARCH_QCOM
 	select SND_SOC_QDSP6V2
 	select SND_SOC_MSM_STUB
@@ -152,18 +144,19 @@
 	select SND_SOC_WCD9335
 	select SND_SOC_WCD934X
 	select SND_SOC_WSA881X
+	select SND_SOC_MSM_HDMI_CODEC_RX
 	select MFD_CORE
 	select QTI_PP
 	select DTS_SRS_TM
-	select DOLBY_DAP
-	select DOLBY_DS2
+	select DOLBY_LICENSE
 	select SND_SOC_CPE
 	select SND_SOC_WCD_CPE
 	select SND_HWDEP
 	select MSM_ULTRASOUND
 	select DTS_EAGLE
-	select SND_SOC_MSMFALCON_COMMON
+	select SND_SOC_SDM660_COMMON
 	select SND_SOC_COMPRESS
+	select PINCTRL_LPI
 	help
 	To add support for SoC audio on MSM_EXT.
 	This will enable sound soc drivers which
@@ -230,13 +223,13 @@
 	 the machine driver and the corresponding
 	 DAI-links
 
-config SND_SOC_FALCON
-	tristate "SoC Machine driver for MSMFALCON boards"
-	depends on ARCH_MSMFALCON
+config SND_SOC_660
+	tristate "SoC Machine driver for SDM660 boards"
+	depends on ARCH_SDM660
 	select SND_SOC_INT_CODEC
 	select SND_SOC_EXT_CODEC
 	help
-	 To add support for SoC audio on MSMFALCON.
+	 To add support for SoC audio on SDM660.
 	 This will enable sound soc drivers which
 	 interfaces with DSP, also it will enable
 	 the machine driver and the corresponding
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index e0544fc..5105cd9 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -20,18 +20,18 @@
 snd-soc-msm8998-objs := msm8998.o
 obj-$(CONFIG_SND_SOC_MSM8998) += snd-soc-msm8998.o
 
-# for MSMFALCON sound card driver
-snd-soc-msmfalcon-common-objs := msm-audio-pinctrl.o msmfalcon-common.o
-obj-$(CONFIG_SND_SOC_MSMFALCON_COMMON) += snd-soc-msmfalcon-common.o
+# for SDM660 sound card driver
+snd-soc-sdm660-common-objs := sdm660-common.o
+obj-$(CONFIG_SND_SOC_SDM660_COMMON) += snd-soc-sdm660-common.o
 
-# for MSMFALCON sound card driver
-snd-soc-int-codec-objs := msmfalcon-internal.o
-obj-$(CONFIG_SND_SOC_INT_CODEC) += snd-soc-msmfalcon-common.o
+# for SDM660 sound card driver
+snd-soc-int-codec-objs := sdm660-internal.o
+obj-$(CONFIG_SND_SOC_INT_CODEC) += snd-soc-sdm660-common.o
 obj-$(CONFIG_SND_SOC_INT_CODEC) += snd-soc-int-codec.o
 
-# for MSMFALCON sound card driver
-snd-soc-ext-codec-objs := msmfalcon-external.o msmfalcon-ext-dai-links.o
-obj-$(CONFIG_SND_SOC_EXT_CODEC) += snd-soc-msmfalcon-common.o
+# for SDM660 sound card driver
+snd-soc-ext-codec-objs := sdm660-external.o sdm660-ext-dai-links.o
+obj-$(CONFIG_SND_SOC_EXT_CODEC) += snd-soc-sdm660-common.o
 obj-$(CONFIG_SND_SOC_EXT_CODEC) += snd-soc-ext-codec.o
 
 # for SDM845 sound card driver
diff --git a/sound/soc/msm/msm-cpe-lsm.c b/sound/soc/msm/msm-cpe-lsm.c
index 44927c8..7b65dda 100644
--- a/sound/soc/msm/msm-cpe-lsm.c
+++ b/sound/soc/msm/msm-cpe-lsm.c
@@ -1046,7 +1046,6 @@
 	struct cpe_lsm_lab *lab_d = &lsm_d->lab;
 	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
 	struct msm_slim_dma_data *dma_data = NULL;
-	struct snd_lsm_event_status *user;
 	struct snd_lsm_detection_params det_params;
 	int rc = 0;
 
@@ -1176,13 +1175,6 @@
 		dev_dbg(rtd->dev,
 			"%s: %s\n",
 			__func__, "SNDRV_LSM_REG_SND_MODEL_V2");
-		if (!arg) {
-			dev_err(rtd->dev,
-				"%s: Invalid argument to ioctl %s\n",
-				__func__,
-				"SNDRV_LSM_REG_SND_MODEL_V2");
-			return -EINVAL;
-		}
 
 		memcpy(&snd_model, arg,
 			sizeof(struct snd_lsm_sound_model_v2));
@@ -1320,19 +1312,21 @@
 		break;
 
 	case SNDRV_LSM_EVENT_STATUS:
+	case SNDRV_LSM_EVENT_STATUS_V3: {
+		struct snd_lsm_event_status *user;
+		struct snd_lsm_event_status_v3 *user_v3;
+
 		dev_dbg(rtd->dev,
 			"%s: %s\n",
-			__func__, "SNDRV_LSM_EVENT_STATUS");
+			__func__, "SNDRV_LSM_EVENT_STATUS(_V3)");
 		if (!arg) {
 			dev_err(rtd->dev,
 				"%s: Invalid argument to ioctl %s\n",
 				__func__,
-				"SNDRV_LSM_EVENT_STATUS");
+				"SNDRV_LSM_EVENT_STATUS(_V3)");
 			return -EINVAL;
 		}
 
-		user = arg;
-
 		/*
 		 * Release the api lock before wait to allow
 		 * other IOCTLs to be invoked while waiting
@@ -1352,31 +1346,62 @@
 			if (atomic_read(&lsm_d->event_avail) == 1) {
 				rc = 0;
 				atomic_set(&lsm_d->event_avail, 0);
-				if (lsm_d->ev_det_pld_size >
-					user->payload_size) {
-					dev_err(rtd->dev,
-						"%s: avail pld_bytes = %u, needed = %u\n",
-						__func__,
-						user->payload_size,
-						lsm_d->ev_det_pld_size);
-					return -EINVAL;
+
+				if (cmd == SNDRV_LSM_EVENT_STATUS) {
+					user = arg;
+					if (lsm_d->ev_det_pld_size >
+						user->payload_size) {
+						dev_err(rtd->dev,
+							"%s: avail pld_bytes = %u, needed = %u\n",
+							__func__,
+							user->payload_size,
+							lsm_d->ev_det_pld_size);
+						return -EINVAL;
+					}
+
+					user->status = lsm_d->ev_det_status;
+					user->payload_size =
+							lsm_d->ev_det_pld_size;
+					memcpy(user->payload,
+					       lsm_d->ev_det_payload,
+					       lsm_d->ev_det_pld_size);
+				} else {
+					user_v3 = arg;
+					if (lsm_d->ev_det_pld_size >
+						user_v3->payload_size) {
+						dev_err(rtd->dev,
+							"%s: avail pld_bytes = %u, needed = %u\n",
+							__func__,
+							user_v3->payload_size,
+							lsm_d->ev_det_pld_size);
+						return -EINVAL;
+					}
+					/* event status timestamp not supported
+					 * on CPE mode. Set msw and lsw to 0.
+					 */
+					user_v3->timestamp_lsw = 0;
+					user_v3->timestamp_msw = 0;
+					user_v3->status = lsm_d->ev_det_status;
+					user_v3->payload_size =
+							lsm_d->ev_det_pld_size;
+					memcpy(user_v3->payload,
+					       lsm_d->ev_det_payload,
+					       lsm_d->ev_det_pld_size);
 				}
-
-				user->status = lsm_d->ev_det_status;
-				user->payload_size = lsm_d->ev_det_pld_size;
-
-				memcpy(user->payload,
-				       lsm_d->ev_det_payload,
-				       lsm_d->ev_det_pld_size);
-
 			} else if (atomic_read(&lsm_d->event_stop) == 1) {
 				dev_dbg(rtd->dev,
 					"%s: wait_aborted\n", __func__);
-				user->payload_size = 0;
+				if (cmd == SNDRV_LSM_EVENT_STATUS) {
+					user = arg;
+					user->payload_size = 0;
+				} else {
+					user_v3 = arg;
+					user_v3->payload_size = 0;
+				}
 				rc = 0;
 			}
 		}
-
+	}
 		break;
 
 	case SNDRV_LSM_ABORT_EVENT:
@@ -1432,12 +1457,6 @@
 		break;
 
 	case SNDRV_LSM_SET_PARAMS:
-		if (!arg) {
-			dev_err(rtd->dev,
-				"%s: %s Invalid argument\n",
-				__func__, "SNDRV_LSM_SET_PARAMS");
-			return -EINVAL;
-		}
 		memcpy(&det_params, arg,
 			sizeof(det_params));
 		if (det_params.num_confidence_levels <= 0) {
@@ -1514,6 +1533,20 @@
 		}
 		break;
 
+	case SNDRV_LSM_SET_PORT: {
+		u32 port_id = cpe->input_port_id;
+
+		dev_dbg(rtd->dev, "%s: %s\n", __func__, "SNDRV_LSM_SET_PORT");
+		rc = lsm_ops->lsm_set_port(cpe->core_handle, session, &port_id);
+		if (rc) {
+			dev_err(rtd->dev,
+				"%s: lsm_set_port failed, err = %d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+	break;
+
 	default:
 		dev_dbg(rtd->dev,
 			"%s: Default snd_lib_ioctl cmd 0x%x\n",
@@ -1525,7 +1558,7 @@
 }
 
 static int msm_cpe_lsm_lab_start(struct snd_pcm_substream *substream,
-		struct snd_lsm_event_status *event_status)
+		u16 event_det_status)
 {
 	struct snd_soc_pcm_runtime *rtd;
 	struct cpe_lsm_data *lsm_d = NULL;
@@ -1578,7 +1611,7 @@
 	reinit_completion(&lab_d->thread_complete);
 
 	if (session->lab_enable &&
-	    event_status->status ==
+	    event_det_status ==
 	    LSM_VOICE_WAKEUP_STATUS_DETECTED) {
 		out_port = &session->afe_out_port_cfg;
 		out_port->port_id = session->afe_out_port_id;
@@ -1873,6 +1906,13 @@
 
 	lsm_ops->lsm_get_snd_model_offset(cpe->core_handle,
 			session, &offset);
+	/* Check if 'p_info->param_size + offset' crosses U32_MAX. */
+	if (p_info->param_size > U32_MAX - offset) {
+		dev_err(rtd->dev,
+			"%s: Invalid param_size %d\n",
+			__func__, p_info->param_size);
+		return -EINVAL;
+	}
 	session->snd_model_size = p_info->param_size + offset;
 
 	session->snd_model_data = vzalloc(session->snd_model_size);
@@ -2108,7 +2148,8 @@
 			dev_err(rtd->dev,
 				"%s: %s: not supported if using topology\n",
 				__func__, "LSM_REG_SND_MODEL_V2");
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		if (copy_from_user(&snd_model, (void *)arg,
@@ -2173,7 +2214,60 @@
 			goto done;
 		}
 
-		msm_cpe_lsm_lab_start(substream, event_status);
+		msm_cpe_lsm_lab_start(substream, event_status->status);
+		msm_cpe_process_event_status_done(lsm_d);
+		kfree(event_status);
+	}
+		break;
+	case SNDRV_LSM_EVENT_STATUS_V3: {
+		struct snd_lsm_event_status_v3 u_event_status;
+		struct snd_lsm_event_status_v3 *event_status = NULL;
+		int u_pld_size = 0;
+
+		if (copy_from_user(&u_event_status, (void *)arg,
+				   sizeof(struct snd_lsm_event_status_v3))) {
+			dev_err(rtd->dev,
+				"%s: event status copy from user failed, size %zd\n",
+				__func__,
+				sizeof(struct snd_lsm_event_status_v3));
+			err = -EFAULT;
+			goto done;
+		}
+
+		if (u_event_status.payload_size >
+		    LISTEN_MAX_STATUS_PAYLOAD_SIZE) {
+			dev_err(rtd->dev,
+				"%s: payload_size %d is invalid, max allowed = %d\n",
+				__func__, u_event_status.payload_size,
+				LISTEN_MAX_STATUS_PAYLOAD_SIZE);
+			err = -EINVAL;
+			goto done;
+		}
+
+		u_pld_size = sizeof(struct snd_lsm_event_status_v3) +
+				u_event_status.payload_size;
+
+		event_status = kzalloc(u_pld_size, GFP_KERNEL);
+		if (!event_status) {
+			err = -ENOMEM;
+			goto done;
+		} else {
+			event_status->payload_size =
+				u_event_status.payload_size;
+			err = msm_cpe_lsm_ioctl_shared(substream,
+						       cmd, event_status);
+		}
+
+		if (!err  && copy_to_user(arg, event_status, u_pld_size)) {
+			dev_err(rtd->dev,
+				"%s: copy to user failed\n",
+				__func__);
+			kfree(event_status);
+			err = -EFAULT;
+			goto done;
+		}
+
+		msm_cpe_lsm_lab_start(substream, event_status->status);
 		msm_cpe_process_event_status_done(lsm_d);
 		kfree(event_status);
 	}
@@ -2185,7 +2279,8 @@
 			dev_err(rtd->dev,
 				"%s: %s: not supported if using topology\n",
 				__func__, "SNDRV_LSM_SET_PARAMS");
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		if (copy_from_user(&det_params, (void *) arg,
@@ -2212,14 +2307,16 @@
 			dev_err(rtd->dev,
 				"%s: %s: not supported if not using topology\n",
 				__func__, "SET_MODULE_PARAMS");
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		if (!arg) {
 			dev_err(rtd->dev,
 				"%s: %s: No Param data to set\n",
 				__func__, "SET_MODULE_PARAMS");
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		if (copy_from_user(&p_data, arg,
@@ -2227,7 +2324,8 @@
 			dev_err(rtd->dev,
 				"%s: %s: copy_from_user failed, size = %zd\n",
 				__func__, "p_data", sizeof(p_data));
-			return -EFAULT;
+			err = -EFAULT;
+			goto done;
 		}
 
 		if (p_data.num_params > LSM_PARAMS_MAX) {
@@ -2235,7 +2333,8 @@
 				"%s: %s: Invalid num_params %d\n",
 				__func__, "SET_MODULE_PARAMS",
 				p_data.num_params);
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		p_size = p_data.num_params *
@@ -2246,12 +2345,15 @@
 				"%s: %s: Invalid size %zd\n",
 				__func__, "SET_MODULE_PARAMS", p_size);
 
-			return -EFAULT;
+			err = -EFAULT;
+			goto done;
 		}
 
 		params = kzalloc(p_size, GFP_KERNEL);
-		if (!params)
-			return -ENOMEM;
+		if (!params) {
+			err = -ENOMEM;
+			goto done;
+		}
 
 		if (copy_from_user(params, p_data.params,
 				   p_data.data_size)) {
@@ -2259,7 +2361,8 @@
 				"%s: %s: copy_from_user failed, size = %d\n",
 				__func__, "params", p_data.data_size);
 			kfree(params);
-			return -EFAULT;
+			err = -EFAULT;
+			goto done;
 		}
 
 		err = msm_cpe_lsm_process_params(substream, &p_data, params);
@@ -2282,12 +2385,6 @@
 }
 
 #ifdef CONFIG_COMPAT
-struct snd_lsm_event_status32 {
-	u16 status;
-	u16 payload_size;
-	u8 payload[0];
-};
-
 struct snd_lsm_sound_model_v2_32 {
 	compat_uptr_t data;
 	compat_uptr_t confidence_level;
@@ -2309,7 +2406,7 @@
 	u32 param_id;
 	u32 param_size;
 	compat_uptr_t param_data;
-	enum LSM_PARAM_TYPE param_type;
+	uint32_t param_type;
 };
 
 struct snd_lsm_module_params_32 {
@@ -2319,8 +2416,6 @@
 };
 
 enum {
-	SNDRV_LSM_EVENT_STATUS32 =
-		_IOW('U', 0x02, struct snd_lsm_event_status32),
 	SNDRV_LSM_REG_SND_MODEL_V2_32 =
 		_IOW('U', 0x07, struct snd_lsm_sound_model_v2_32),
 	SNDRV_LSM_SET_PARAMS32 =
@@ -2378,7 +2473,8 @@
 			dev_err(rtd->dev,
 				"%s: %s: not supported if using topology\n",
 				__func__, "LSM_REG_SND_MODEL_V2_32");
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		dev_dbg(rtd->dev,
@@ -2414,7 +2510,7 @@
 				err);
 	}
 		break;
-	case SNDRV_LSM_EVENT_STATUS32: {
+	case SNDRV_LSM_EVENT_STATUS: {
 		struct snd_lsm_event_status *event_status = NULL;
 		struct snd_lsm_event_status u_event_status32;
 		struct snd_lsm_event_status *udata_32 = NULL;
@@ -2456,7 +2552,6 @@
 		} else {
 			event_status->payload_size =
 				u_event_status32.payload_size;
-			cmd = SNDRV_LSM_EVENT_STATUS;
 			err = msm_cpe_lsm_ioctl_shared(substream,
 						       cmd, event_status);
 			if (err)
@@ -2495,7 +2590,97 @@
 			goto done;
 		}
 
-		msm_cpe_lsm_lab_start(substream, event_status);
+		msm_cpe_lsm_lab_start(substream, event_status->status);
+		msm_cpe_process_event_status_done(lsm_d);
+		kfree(event_status);
+		kfree(udata_32);
+	}
+		break;
+	case SNDRV_LSM_EVENT_STATUS_V3: {
+		struct snd_lsm_event_status_v3 *event_status = NULL;
+		struct snd_lsm_event_status_v3 u_event_status32;
+		struct snd_lsm_event_status_v3 *udata_32 = NULL;
+		int u_pld_size = 0;
+
+		dev_dbg(rtd->dev,
+			"%s: ioctl %s\n", __func__,
+			"SNDRV_LSM_EVENT_STATUS_V3_32");
+
+		if (copy_from_user(&u_event_status32, (void *)arg,
+				   sizeof(struct snd_lsm_event_status_v3))) {
+			dev_err(rtd->dev,
+				"%s: event status copy from user failed, size %zd\n",
+				__func__,
+				sizeof(struct snd_lsm_event_status_v3));
+			err = -EFAULT;
+			goto done;
+		}
+
+		if (u_event_status32.payload_size >
+		   LISTEN_MAX_STATUS_PAYLOAD_SIZE) {
+			dev_err(rtd->dev,
+				"%s: payload_size %d is invalid, max allowed = %d\n",
+				__func__, u_event_status32.payload_size,
+				LISTEN_MAX_STATUS_PAYLOAD_SIZE);
+			err = -EINVAL;
+			goto done;
+		}
+
+		u_pld_size = sizeof(struct snd_lsm_event_status_v3) +
+				u_event_status32.payload_size;
+		event_status = kzalloc(u_pld_size, GFP_KERNEL);
+		if (!event_status) {
+			dev_err(rtd->dev,
+				"%s: No memory for event status\n",
+				__func__);
+			err = -ENOMEM;
+			goto done;
+		} else {
+			event_status->payload_size =
+				u_event_status32.payload_size;
+			err = msm_cpe_lsm_ioctl_shared(substream,
+						       cmd, event_status);
+			if (err)
+				dev_err(rtd->dev,
+					"%s: %s failed, error = %d\n",
+					__func__,
+					"SNDRV_LSM_EVENT_STATUS_V3_32",
+					err);
+		}
+
+		if (!err) {
+			udata_32 = kzalloc(u_pld_size, GFP_KERNEL);
+			if (!udata_32) {
+				dev_err(rtd->dev,
+					"%s: nomem for udata\n",
+					__func__);
+				err = -EFAULT;
+			} else {
+				udata_32->timestamp_lsw =
+					event_status->timestamp_lsw;
+				udata_32->timestamp_msw =
+					event_status->timestamp_msw;
+				udata_32->status = event_status->status;
+				udata_32->payload_size =
+					event_status->payload_size;
+				memcpy(udata_32->payload,
+				       event_status->payload,
+				       u_pld_size);
+			}
+		}
+
+		if (!err  && copy_to_user(arg, udata_32,
+					  u_pld_size)) {
+			dev_err(rtd->dev,
+				"%s: copy to user failed\n",
+				__func__);
+			kfree(event_status);
+			kfree(udata_32);
+			err = -EFAULT;
+			goto done;
+		}
+
+		msm_cpe_lsm_lab_start(substream, event_status->status);
 		msm_cpe_process_event_status_done(lsm_d);
 		kfree(event_status);
 		kfree(udata_32);
@@ -2509,7 +2694,9 @@
 			dev_err(rtd->dev,
 				"%s: %s: not supported if using topology\n",
 				__func__, "SNDRV_LSM_SET_PARAMS32");
-			return -EINVAL;
+
+			err = -EINVAL;
+			goto done;
 		}
 
 		if (copy_from_user(&det_params32, arg,
@@ -2553,14 +2740,8 @@
 			dev_err(rtd->dev,
 				"%s: %s: not supported if not using topology\n",
 				__func__, "SET_MODULE_PARAMS_32");
-			return -EINVAL;
-		}
-
-		if (!arg) {
-			dev_err(rtd->dev,
-				"%s: %s: No Param data to set\n",
-				__func__, "SET_MODULE_PARAMS_32");
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		if (copy_from_user(&p_data_32, arg,
@@ -2569,7 +2750,8 @@
 				"%s: %s: copy_from_user failed, size = %zd\n",
 				__func__, "SET_MODULE_PARAMS_32",
 				sizeof(p_data_32));
-			return -EFAULT;
+			err = -EFAULT;
+			goto done;
 		}
 
 		p_data.params = compat_ptr(p_data_32.params);
@@ -2581,7 +2763,8 @@
 				"%s: %s: Invalid num_params %d\n",
 				__func__, "SET_MODULE_PARAMS_32",
 				p_data.num_params);
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		if (p_data.data_size !=
@@ -2590,21 +2773,25 @@
 				"%s: %s: Invalid size %d\n",
 				__func__, "SET_MODULE_PARAMS_32",
 				p_data.data_size);
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		p_size = sizeof(struct lsm_params_info_32) *
 			 p_data.num_params;
 
 		params32 = kzalloc(p_size, GFP_KERNEL);
-		if (!params32)
-			return -ENOMEM;
+		if (!params32) {
+			err = -ENOMEM;
+			goto done;
+		}
 
 		p_size = sizeof(struct lsm_params_info) * p_data.num_params;
 		params = kzalloc(p_size, GFP_KERNEL);
 		if (!params) {
 			kfree(params32);
-			return -ENOMEM;
+			err = -ENOMEM;
+			goto done;
 		}
 
 		if (copy_from_user(params32, p_data.params,
@@ -2614,7 +2801,8 @@
 				__func__, "params32", p_data.data_size);
 			kfree(params32);
 			kfree(params);
-			return -EFAULT;
+			err = -EFAULT;
+			goto done;
 		}
 
 		p_info_32 = (struct lsm_params_info_32 *) params32;
@@ -2640,6 +2828,19 @@
 		kfree(params32);
 		break;
 	}
+	case SNDRV_LSM_REG_SND_MODEL_V2:
+	case SNDRV_LSM_SET_PARAMS:
+	case SNDRV_LSM_SET_MODULE_PARAMS:
+		/*
+		 * In ideal cases, the compat_ioctl should never be called
+		 * with the above unlocked ioctl commands. Print error
+		 * and return error if it does.
+		 */
+		dev_err(rtd->dev,
+			"%s: Invalid cmd for compat_ioctl\n",
+			__func__);
+		err = -EINVAL;
+		break;
 	default:
 		err = msm_cpe_lsm_ioctl_shared(substream, cmd, arg);
 		break;
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 081f8b4..755b62a 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -506,6 +506,33 @@
 	},
 	{
 		.playback = {
+			.stream_name = "SLIMBUS7_HOSTLESS Playback",
+			.aif_name = "SLIM7_DL_HL",
+			.rates = SNDRV_PCM_RATE_8000_384000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE),
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =     8000,
+			.rate_max =     384000,
+		},
+		.capture = {
+			.stream_name = "SLIMBUS7_HOSTLESS Capture",
+			.aif_name = "SLIM7_UL_HL",
+			.rates = SNDRV_PCM_RATE_8000_384000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE),
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =     8000,
+			.rate_max =     384000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "SLIMBUS7_HOSTLESS",
+		.probe = fe_dai_probe,
+	},
+	{
+		.playback = {
 			.stream_name = "SLIMBUS8_HOSTLESS Playback",
 			.aif_name = "SLIM8_DL_HL",
 			.rates = SNDRV_PCM_RATE_8000_384000,
@@ -583,6 +610,49 @@
 	},
 	{
 		.playback = {
+			.stream_name = "USBAUDIO_HOSTLESS Playback",
+			.aif_name = "USBAUDIO_DL_HL",
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+				SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+				SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+				SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+				SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_352800 |
+				SNDRV_PCM_RATE_384000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S24_LE |
+				SNDRV_PCM_FMTBIT_S24_3LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =     8000,
+			.rate_max =     384000,
+		},
+		.capture = {
+			.stream_name = "USBAUDIO_HOSTLESS Capture",
+			.aif_name = "USBAUDIO_UL_HL",
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+				SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+				SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+				SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+				SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_352800 |
+				SNDRV_PCM_RATE_384000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S24_LE |
+				SNDRV_PCM_FMTBIT_S24_3LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =     8000,
+			.rate_max =     384000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "USBAUDIO_HOSTLESS",
+		.probe = fe_dai_probe,
+	},
+	{
+		.playback = {
 			.stream_name = "AFE Playback",
 			.aif_name = "PCM_RX",
 			.rates = (SNDRV_PCM_RATE_8000 |
@@ -894,7 +964,7 @@
 			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
 				    SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
-			.channels_max = 2,
+			.channels_max = 4,
 			.rate_min =     8000,
 			.rate_max =    192000,
 		},
@@ -902,6 +972,22 @@
 		.name = "INT4_MI2S_RX_HOSTLESS",
 		.probe = fe_dai_probe,
 	},
+	{
+		.capture = {
+			.stream_name = "INT3 MI2S_TX Hostless Capture",
+			.aif_name = "INT3_MI2S_UL_HL",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE),
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min = 8000,
+			.rate_max = 48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "INT3_MI2S_TX_HOSTLESS",
+		.probe = fe_dai_probe,
+	},
 	/* TDM Hostless */
 	{
 		.capture = {
@@ -2117,12 +2203,14 @@
 		.capture = {
 			.stream_name = "Listen 1 Audio Service Capture",
 			.aif_name = "LSM1_UL_HL",
-			.rates = SNDRV_PCM_RATE_16000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rates = (SNDRV_PCM_RATE_16000 |
+				  SNDRV_PCM_RATE_48000),
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
-			.channels_max = 1,
+			.channels_max = 4,
 			.rate_min = 16000,
-			.rate_max = 16000,
+			.rate_max = 48000,
 		},
 		.ops = &msm_fe_dai_ops,
 		.name = "LSM1",
@@ -2132,12 +2220,14 @@
 		.capture = {
 			.stream_name = "Listen 2 Audio Service Capture",
 			.aif_name = "LSM2_UL_HL",
-			.rates = SNDRV_PCM_RATE_16000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rates = (SNDRV_PCM_RATE_16000 |
+				  SNDRV_PCM_RATE_48000),
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
-			.channels_max = 1,
+			.channels_max = 4,
 			.rate_min = 16000,
-			.rate_max = 16000,
+			.rate_max = 48000,
 		},
 		.ops = &msm_fe_dai_ops,
 		.name = "LSM2",
@@ -2147,12 +2237,14 @@
 		.capture = {
 			.stream_name = "Listen 3 Audio Service Capture",
 			.aif_name = "LSM3_UL_HL",
-			.rates = SNDRV_PCM_RATE_16000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rates = (SNDRV_PCM_RATE_16000 |
+				  SNDRV_PCM_RATE_48000),
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
-			.channels_max = 1,
+			.channels_max = 4,
 			.rate_min = 16000,
-			.rate_max = 16000,
+			.rate_max = 48000,
 		},
 		.ops = &msm_fe_dai_ops,
 		.name = "LSM3",
@@ -2162,12 +2254,14 @@
 		.capture = {
 			.stream_name = "Listen 4 Audio Service Capture",
 			.aif_name = "LSM4_UL_HL",
-			.rates = SNDRV_PCM_RATE_16000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rates = (SNDRV_PCM_RATE_16000 |
+				  SNDRV_PCM_RATE_48000),
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
-			.channels_max = 1,
+			.channels_max = 4,
 			.rate_min = 16000,
-			.rate_max = 16000,
+			.rate_max = 48000,
 		},
 		.ops = &msm_fe_dai_ops,
 		.name = "LSM4",
@@ -2177,12 +2271,14 @@
 		.capture = {
 			.stream_name = "Listen 5 Audio Service Capture",
 			.aif_name = "LSM5_UL_HL",
-			.rates = SNDRV_PCM_RATE_16000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rates = (SNDRV_PCM_RATE_16000 |
+				  SNDRV_PCM_RATE_48000),
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
-			.channels_max = 1,
+			.channels_max = 4,
 			.rate_min = 16000,
-			.rate_max = 16000,
+			.rate_max = 48000,
 		},
 		.ops = &msm_fe_dai_ops,
 		.name = "LSM5",
@@ -2192,12 +2288,14 @@
 		.capture = {
 			.stream_name = "Listen 6 Audio Service Capture",
 			.aif_name = "LSM6_UL_HL",
-			.rates = SNDRV_PCM_RATE_16000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rates = (SNDRV_PCM_RATE_16000 |
+				  SNDRV_PCM_RATE_48000),
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
-			.channels_max = 1,
+			.channels_max = 4,
 			.rate_min = 16000,
-			.rate_max = 16000,
+			.rate_max = 48000,
 		},
 		.ops = &msm_fe_dai_ops,
 		.name = "LSM6",
@@ -2207,12 +2305,14 @@
 		.capture = {
 			.stream_name = "Listen 7 Audio Service Capture",
 			.aif_name = "LSM7_UL_HL",
-			.rates = SNDRV_PCM_RATE_16000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rates = (SNDRV_PCM_RATE_16000 |
+				  SNDRV_PCM_RATE_48000),
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
-			.channels_max = 1,
+			.channels_max = 4,
 			.rate_min = 16000,
-			.rate_max = 16000,
+			.rate_max = 48000,
 		},
 		.ops = &msm_fe_dai_ops,
 		.name = "LSM7",
@@ -2222,12 +2322,14 @@
 		.capture = {
 			.stream_name = "Listen 8 Audio Service Capture",
 			.aif_name = "LSM8_UL_HL",
-			.rates = SNDRV_PCM_RATE_16000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rates = (SNDRV_PCM_RATE_16000 |
+				  SNDRV_PCM_RATE_48000),
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
-			.channels_max = 1,
+			.channels_max = 4,
 			.rate_min = 16000,
-			.rate_max = 16000,
+			.rate_max = 48000,
 		},
 		.ops = &msm_fe_dai_ops,
 		.name = "LSM8",
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index 73755ed..51c27b7 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -159,6 +159,21 @@
 	u32 index;
 };
 
+enum pinctrl_pin_state {
+	STATE_DISABLE = 0, /* All pins are in sleep state */
+	STATE_MI2S_ACTIVE,  /* IS2 = active, TDM = sleep */
+	STATE_TDM_ACTIVE,  /* IS2 = sleep, TDM = active */
+};
+
+struct msm_pinctrl_info {
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *mi2s_disable;
+	struct pinctrl_state *tdm_disable;
+	struct pinctrl_state *mi2s_active;
+	struct pinctrl_state *tdm_active;
+	enum pinctrl_pin_state curr_state;
+};
+
 struct msm_asoc_mach_data {
 	u32 mclk_freq;
 	int us_euro_gpio; /* used by gpio driver API */
@@ -166,6 +181,7 @@
 	struct device_node *hph_en1_gpio_p; /* used by pinctrl API */
 	struct device_node *hph_en0_gpio_p; /* used by pinctrl API */
 	struct snd_info_entry *codec_root;
+	struct msm_pinctrl_info pinctrl_info;
 };
 
 struct msm_asoc_wcd93xx_codec {
@@ -174,6 +190,9 @@
 	void (*mbhc_hs_detect_exit)(struct snd_soc_codec *codec);
 };
 
+static const char *const pin_states[] = {"sleep", "i2s-active",
+					 "tdm-active"};
+
 enum {
 	TDM_0 = 0,
 	TDM_1,
@@ -402,7 +421,8 @@
 					"KHZ_88P2", "KHZ_96", "KHZ_176P4",
 					"KHZ_192", "KHZ_352P8", "KHZ_384"};
 static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96",
-						  "KHZ_192"};
+					"KHZ_192", "KHZ_32", "KHZ_44P1",
+					"KHZ_88P2", "KHZ_176P4"};
 static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four",
 				    "Five", "Six", "Seven", "Eight"};
 static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
@@ -514,6 +534,9 @@
 	.key_code[7] = 0,
 	.linein_th = 5000,
 	.moisture_en = true,
+	.mbhc_micbias = MIC_BIAS_2,
+	.anc_micbias = MIC_BIAS_2,
+	.enable_anc_mic_detect = false,
 };
 
 static struct snd_soc_dapm_route wcd_audio_paths_tasha[] = {
@@ -1479,6 +1502,22 @@
 		return idx;
 
 	switch (ext_disp_rx_cfg[idx].sample_rate) {
+	case SAMPLING_RATE_176P4KHZ:
+		sample_rate_val = 6;
+		break;
+
+	case SAMPLING_RATE_88P2KHZ:
+		sample_rate_val = 5;
+		break;
+
+	case SAMPLING_RATE_44P1KHZ:
+		sample_rate_val = 4;
+		break;
+
+	case SAMPLING_RATE_32KHZ:
+		sample_rate_val = 3;
+		break;
+
 	case SAMPLING_RATE_192KHZ:
 		sample_rate_val = 2;
 		break;
@@ -1509,6 +1548,18 @@
 		return idx;
 
 	switch (ucontrol->value.integer.value[0]) {
+	case 6:
+		ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_176P4KHZ;
+		break;
+	case 5:
+		ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_88P2KHZ;
+		break;
+	case 4:
+		ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_44P1KHZ;
+		break;
+	case 3:
+		ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_32KHZ;
+		break;
 	case 2:
 		ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_192KHZ;
 		break;
@@ -3321,6 +3372,18 @@
 					    134, 135, 136, 137, 138, 139,
 					    140, 141, 142, 143};
 
+	/* Tavil Codec SLIMBUS configuration
+	 * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8
+	 * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+	 * TX14, TX15, TX16
+	 */
+	unsigned int rx_ch_tavil[WCD934X_RX_MAX] = {144, 145, 146, 147, 148,
+						    149, 150, 151};
+	unsigned int tx_ch_tavil[WCD934X_TX_MAX] = {128, 129, 130, 131, 132,
+						    133, 134, 135, 136, 137,
+						    138, 139, 140, 141, 142,
+						    143};
+
 	pr_info("%s: dev_name%s\n", __func__, dev_name(cpu_dai->dev));
 
 	rtd->pmdown_time = 0;
@@ -3369,20 +3432,27 @@
 	snd_soc_dapm_ignore_suspend(dapm, "HPHR");
 	snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI");
 	snd_soc_dapm_ignore_suspend(dapm, "VIINPUT");
+	snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL");
+	snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
 
 	if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) {
 		snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3");
 		snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4");
-		snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL");
-		snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
 		snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1");
 		snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2");
 	}
 
 	snd_soc_dapm_sync(dapm);
 
-	snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
-				    tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+	if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
+		snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch_tavil),
+					tx_ch_tavil, ARRAY_SIZE(rx_ch_tavil),
+					rx_ch_tavil);
+	} else {
+		snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+					tx_ch, ARRAY_SIZE(rx_ch),
+					rx_ch);
+	}
 
 	if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
 		msm_codec_fn.get_afe_config_fn = tavil_get_afe_config;
@@ -3978,6 +4048,275 @@
 	return ret;
 }
 
+static int msm_set_pinctrl(struct msm_pinctrl_info *pinctrl_info,
+				enum pinctrl_pin_state new_state)
+{
+	int ret = 0;
+	int curr_state = 0;
+
+	if (pinctrl_info == NULL) {
+		pr_err("%s: pinctrl_info is NULL\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+	curr_state = pinctrl_info->curr_state;
+	pinctrl_info->curr_state = new_state;
+	pr_debug("%s: curr_state = %s new_state = %s\n", __func__,
+		 pin_states[curr_state], pin_states[pinctrl_info->curr_state]);
+
+	if (curr_state == pinctrl_info->curr_state) {
+		pr_debug("%s: Already in same state\n", __func__);
+		goto err;
+	}
+
+	if (curr_state != STATE_DISABLE &&
+		pinctrl_info->curr_state != STATE_DISABLE) {
+		pr_debug("%s: state already active cannot switch\n", __func__);
+		ret = -EIO;
+		goto err;
+	}
+
+	switch (pinctrl_info->curr_state) {
+	case STATE_MI2S_ACTIVE:
+		ret = pinctrl_select_state(pinctrl_info->pinctrl,
+					pinctrl_info->mi2s_active);
+		if (ret) {
+			pr_err("%s: MI2S state select failed with %d\n",
+				__func__, ret);
+			ret = -EIO;
+			goto err;
+		}
+		break;
+	case STATE_TDM_ACTIVE:
+		ret = pinctrl_select_state(pinctrl_info->pinctrl,
+					pinctrl_info->tdm_active);
+		if (ret) {
+			pr_err("%s: TDM state select failed with %d\n",
+				__func__, ret);
+			ret = -EIO;
+			goto err;
+		}
+		break;
+	case STATE_DISABLE:
+		if (curr_state == STATE_MI2S_ACTIVE) {
+			ret = pinctrl_select_state(pinctrl_info->pinctrl,
+					pinctrl_info->mi2s_disable);
+		} else {
+			ret = pinctrl_select_state(pinctrl_info->pinctrl,
+					pinctrl_info->tdm_disable);
+		}
+		if (ret) {
+			pr_err("%s:  state disable failed with %d\n",
+				__func__, ret);
+			ret = -EIO;
+			goto err;
+		}
+		break;
+	default:
+		pr_err("%s: TLMM pin state is invalid\n", __func__);
+		return -EINVAL;
+	}
+
+err:
+	return ret;
+}
+
+static void msm_release_pinctrl(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+
+	if (pinctrl_info->pinctrl) {
+		devm_pinctrl_put(pinctrl_info->pinctrl);
+		pinctrl_info->pinctrl = NULL;
+	}
+}
+
+static int msm_get_pinctrl(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_pinctrl_info *pinctrl_info = NULL;
+	struct pinctrl *pinctrl;
+	int ret;
+
+	pinctrl_info = &pdata->pinctrl_info;
+
+	if (pinctrl_info == NULL) {
+		pr_err("%s: pinctrl_info is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	pinctrl = devm_pinctrl_get(&pdev->dev);
+	if (IS_ERR_OR_NULL(pinctrl)) {
+		pr_err("%s: Unable to get pinctrl handle\n", __func__);
+		return -EINVAL;
+	}
+	pinctrl_info->pinctrl = pinctrl;
+
+	/* get all the states handles from Device Tree */
+	pinctrl_info->mi2s_disable = pinctrl_lookup_state(pinctrl,
+						"quat-mi2s-sleep");
+	if (IS_ERR(pinctrl_info->mi2s_disable)) {
+		pr_err("%s: could not get mi2s_disable pinstate\n", __func__);
+		goto err;
+	}
+	pinctrl_info->mi2s_active = pinctrl_lookup_state(pinctrl,
+						"quat-mi2s-active");
+	if (IS_ERR(pinctrl_info->mi2s_active)) {
+		pr_err("%s: could not get mi2s_active pinstate\n", __func__);
+		goto err;
+	}
+	pinctrl_info->tdm_disable = pinctrl_lookup_state(pinctrl,
+						"quat-tdm-sleep");
+	if (IS_ERR(pinctrl_info->tdm_disable)) {
+		pr_err("%s: could not get tdm_disable pinstate\n", __func__);
+		goto err;
+	}
+	pinctrl_info->tdm_active = pinctrl_lookup_state(pinctrl,
+						"quat-tdm-active");
+	if (IS_ERR(pinctrl_info->tdm_active)) {
+		pr_err("%s: could not get tdm_active pinstate\n",
+			__func__);
+		goto err;
+	}
+	/* Reset the TLMM pins to a default state */
+	ret = pinctrl_select_state(pinctrl_info->pinctrl,
+					pinctrl_info->mi2s_disable);
+	if (ret != 0) {
+		pr_err("%s: Disable TLMM pins failed with %d\n",
+			__func__, ret);
+		ret = -EIO;
+		goto err;
+	}
+	pinctrl_info->curr_state = STATE_DISABLE;
+
+	return 0;
+
+err:
+	devm_pinctrl_put(pinctrl);
+	pinctrl_info->pinctrl = NULL;
+	return -EINVAL;
+}
+
+static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+				      struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	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);
+
+	if (cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX) {
+		channels->min = channels->max =
+				tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			       tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format);
+		rate->min = rate->max =
+				tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate;
+	} else if (cpu_dai->id == AFE_PORT_ID_SECONDARY_TDM_RX) {
+		channels->min = channels->max =
+				tdm_rx_cfg[TDM_SEC][TDM_0].channels;
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			       tdm_rx_cfg[TDM_SEC][TDM_0].bit_format);
+		rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate;
+	} else {
+		pr_err("%s: dai id 0x%x not supported\n",
+			__func__, cpu_dai->id);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: dai id = 0x%x channels = %d rate = %d format = 0x%x\n",
+		__func__, cpu_dai->id, channels->max, rate->max,
+		params_format(params));
+
+	return 0;
+}
+
+static int msm8998_tdm_snd_hw_params(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	int channels, slot_width, slots;
+	unsigned int slot_mask;
+	unsigned int slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
+
+	pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
+
+	slots = tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+	/*2 slot config - bits 0 and 1 set for the first two slots */
+	slot_mask = 0x0000FFFF >> (16-slots);
+	slot_width = 32;
+	channels = slots;
+
+	pr_debug("%s: slot_width %d slots %d\n", __func__, slot_width, slots);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_debug("%s: slot_width %d\n", __func__, slot_width);
+		ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
+			slots, slot_width);
+		if (ret < 0) {
+			pr_err("%s: failed to set tdm slot, err:%d\n",
+				__func__, ret);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai,
+			0, NULL, channels, slot_offset);
+		if (ret < 0) {
+			pr_err("%s: failed to set channel map, err:%d\n",
+				__func__, ret);
+			goto end;
+		}
+	} else {
+		pr_err("%s: invalid use case, err:%d\n",
+			__func__, ret);
+	}
+
+end:
+	return ret;
+}
+
+static int msm8998_tdm_snd_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 msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+
+	ret = msm_set_pinctrl(pinctrl_info, STATE_TDM_ACTIVE);
+	if (ret)
+		pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+			__func__, ret);
+
+	return ret;
+}
+
+static void msm8998_tdm_snd_shutdown(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 msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+
+	ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+	if (ret)
+		pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+			__func__, ret);
+
+}
+
+static struct snd_soc_ops msm8998_tdm_be_ops = {
+	.hw_params = msm8998_tdm_snd_hw_params,
+	.startup = msm8998_tdm_snd_startup,
+	.shutdown = msm8998_tdm_snd_shutdown
+};
+
 static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
 {
 	int ret = 0;
@@ -3985,6 +4324,9 @@
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	int index = cpu_dai->id;
 	unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+	struct snd_soc_card *card = rtd->card;
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
 
 	dev_dbg(rtd->card->dev,
 		"%s: substream = %s  stream = %d, dai name %s, dai ID %d\n",
@@ -3998,6 +4340,15 @@
 			__func__, cpu_dai->id);
 		goto done;
 	}
+	if (index == QUAT_MI2S) {
+		ret = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
+		if (ret) {
+			pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+				__func__, ret);
+			goto done;
+		}
+	}
+
 	/*
 	 * Muxtex protection in case the same MI2S
 	 * interface using for both TX and RX  so
@@ -4050,6 +4401,9 @@
 	int ret;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	int index = rtd->cpu_dai->id;
+	struct snd_soc_card *card = rtd->card;
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
 
 	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
 		 substream->name, substream->stream);
@@ -4068,6 +4422,13 @@
 		}
 	}
 	mutex_unlock(&mi2s_intf_conf[index].lock);
+
+	if (index == QUAT_MI2S) {
+		ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+		if (ret)
+			pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+				__func__, ret);
+	}
 }
 
 static struct snd_soc_ops msm_mi2s_be_ops = {
@@ -4952,6 +5313,42 @@
 	},
 };
 
+static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = {
+	{
+		.name = MSM_DAILINK_NAME(ASM Loopback),
+		.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,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+	},
+	{
+		.name = "USB Audio Hostless",
+		.stream_name = "USB Audio Hostless",
+		.cpu_dai_name = "USBAUDIO_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",
+	},
+};
+
 static struct snd_soc_dai_link msm_common_be_dai_links[] = {
 	/* Backend AFE DAI Links */
 	{
@@ -5159,8 +5556,8 @@
 		.no_pcm = 1,
 		.dpcm_playback = 1,
 		.id = MSM_BACKEND_DAI_QUAT_TDM_RX_0,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ops = &msm_tdm_be_ops,
+		.be_hw_params_fixup = msm_tdm_be_hw_params_fixup,
+		.ops = &msm8998_tdm_be_ops,
 		.ignore_suspend = 1,
 	},
 	{
@@ -5334,6 +5731,22 @@
 		.ignore_pmdown_time = 1,
 		.ignore_suspend = 1,
 	},
+	/* Slimbus VI Recording */
+	{
+		.name = LPASS_BE_SLIMBUS_TX_VI,
+		.stream_name = "Slimbus4 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16393",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tasha_codec",
+		.codec_dai_name = "tasha_vifeedback",
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+		.ignore_suspend = 1,
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.ignore_pmdown_time = 1,
+	},
 };
 
 static struct snd_soc_dai_link msm_tavil_be_dai_links[] = {
@@ -5506,6 +5919,22 @@
 		.ignore_pmdown_time = 1,
 		.ignore_suspend = 1,
 	},
+	/* Slimbus VI Recording */
+	{
+		.name = LPASS_BE_SLIMBUS_TX_VI,
+		.stream_name = "Slimbus4 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16393",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tavil_codec",
+		.codec_dai_name = "tavil_vifeedback",
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+		.ignore_suspend = 1,
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.ignore_pmdown_time = 1,
+	},
 };
 
 static struct snd_soc_dai_link msm_wcn_be_dai_links[] = {
@@ -5842,6 +6271,7 @@
 static struct snd_soc_dai_link msm_tasha_dai_links[
 			 ARRAY_SIZE(msm_common_dai_links) +
 			 ARRAY_SIZE(msm_tasha_fe_dai_links) +
+			 ARRAY_SIZE(msm_common_misc_fe_dai_links) +
 			 ARRAY_SIZE(msm_common_be_dai_links) +
 			 ARRAY_SIZE(msm_tasha_be_dai_links) +
 			 ARRAY_SIZE(msm_wcn_be_dai_links) +
@@ -5852,6 +6282,7 @@
 static struct snd_soc_dai_link msm_tavil_dai_links[
 			 ARRAY_SIZE(msm_common_dai_links) +
 			 ARRAY_SIZE(msm_tavil_fe_dai_links) +
+			 ARRAY_SIZE(msm_common_misc_fe_dai_links) +
 			 ARRAY_SIZE(msm_common_be_dai_links) +
 			 ARRAY_SIZE(msm_tavil_be_dai_links) +
 			 ARRAY_SIZE(msm_wcn_be_dai_links) +
@@ -6185,7 +6616,7 @@
 {
 	struct snd_soc_card *card = NULL;
 	struct snd_soc_dai_link *dailink;
-	int len_1, len_2, len_3;
+	int len_1, len_2, len_3, len_4;
 	int total_links;
 	const struct of_device_id *match;
 
@@ -6200,8 +6631,9 @@
 		card = &snd_soc_card_tasha_msm;
 		len_1 = ARRAY_SIZE(msm_common_dai_links);
 		len_2 = len_1 + ARRAY_SIZE(msm_tasha_fe_dai_links);
-		len_3 = len_2 + ARRAY_SIZE(msm_common_be_dai_links);
-		total_links = len_3 + ARRAY_SIZE(msm_tasha_be_dai_links);
+		len_3 = len_2 + ARRAY_SIZE(msm_common_misc_fe_dai_links);
+		len_4 = len_3 + ARRAY_SIZE(msm_common_be_dai_links);
+		total_links = len_4 + ARRAY_SIZE(msm_tasha_be_dai_links);
 		memcpy(msm_tasha_dai_links,
 		       msm_common_dai_links,
 		       sizeof(msm_common_dai_links));
@@ -6209,9 +6641,12 @@
 		       msm_tasha_fe_dai_links,
 		       sizeof(msm_tasha_fe_dai_links));
 		memcpy(msm_tasha_dai_links + len_2,
+		       msm_common_misc_fe_dai_links,
+		       sizeof(msm_common_misc_fe_dai_links));
+		memcpy(msm_tasha_dai_links + len_3,
 		       msm_common_be_dai_links,
 		       sizeof(msm_common_be_dai_links));
-		memcpy(msm_tasha_dai_links + len_3,
+		memcpy(msm_tasha_dai_links + len_4,
 		       msm_tasha_be_dai_links,
 		       sizeof(msm_tasha_be_dai_links));
 
@@ -6252,8 +6687,9 @@
 		card = &snd_soc_card_tavil_msm;
 		len_1 = ARRAY_SIZE(msm_common_dai_links);
 		len_2 = len_1 + ARRAY_SIZE(msm_tavil_fe_dai_links);
-		len_3 = len_2 + ARRAY_SIZE(msm_common_be_dai_links);
-		total_links = len_3 + ARRAY_SIZE(msm_tavil_be_dai_links);
+		len_3 = len_2 + ARRAY_SIZE(msm_common_misc_fe_dai_links);
+		len_4 = len_3 + ARRAY_SIZE(msm_common_be_dai_links);
+		total_links = len_4 + ARRAY_SIZE(msm_tavil_be_dai_links);
 		memcpy(msm_tavil_dai_links,
 		       msm_common_dai_links,
 		       sizeof(msm_common_dai_links));
@@ -6261,9 +6697,12 @@
 		       msm_tavil_fe_dai_links,
 		       sizeof(msm_tavil_fe_dai_links));
 		memcpy(msm_tavil_dai_links + len_2,
+		       msm_common_misc_fe_dai_links,
+		       sizeof(msm_common_misc_fe_dai_links));
+		memcpy(msm_tavil_dai_links + len_3,
 		       msm_common_be_dai_links,
 		       sizeof(msm_common_be_dai_links));
-		memcpy(msm_tavil_dai_links + len_3,
+		memcpy(msm_tavil_dai_links + len_4,
 		       msm_tavil_be_dai_links,
 		       sizeof(msm_tavil_be_dai_links));
 
@@ -6751,14 +7190,19 @@
 			pdev->dev.of_node->full_name);
 		dev_dbg(&pdev->dev, "Jack type properties set to default");
 	} else {
-		if (!strcmp(mbhc_audio_jack_type, "4-pole-jack"))
+		if (!strcmp(mbhc_audio_jack_type, "4-pole-jack")) {
+			wcd_mbhc_cfg.enable_anc_mic_detect = false;
 			dev_dbg(&pdev->dev, "This hardware has 4 pole jack");
-		else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack"))
+		} else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack")) {
+			wcd_mbhc_cfg.enable_anc_mic_detect = true;
 			dev_dbg(&pdev->dev, "This hardware has 5 pole jack");
-		else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack"))
+		} else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack")) {
+			wcd_mbhc_cfg.enable_anc_mic_detect = true;
 			dev_dbg(&pdev->dev, "This hardware has 6 pole jack");
-		else
+		} else {
+			wcd_mbhc_cfg.enable_anc_mic_detect = false;
 			dev_dbg(&pdev->dev, "Unknown value, set to default");
+		}
 	}
 	/*
 	 * Parse US-Euro gpio info from DT. Report no error if us-euro
@@ -6784,6 +7228,17 @@
 		dev_dbg(&pdev->dev, "msm_prepare_us_euro failed (%d)\n",
 			ret);
 
+	/* Parse pinctrl info from devicetree */
+	ret = msm_get_pinctrl(pdev);
+	if (!ret) {
+		pr_debug("%s: pinctrl parsing successful\n", __func__);
+	} else {
+		dev_dbg(&pdev->dev,
+			"%s: Parsing pinctrl failed with %d. Cannot use Ports\n",
+			__func__, ret);
+		ret = 0;
+	}
+
 	i2s_auxpcm_init(pdev);
 
 	is_initial_boot = true;
@@ -6801,6 +7256,7 @@
 		gpio_free(pdata->us_euro_gpio);
 		pdata->us_euro_gpio = 0;
 	}
+	msm_release_pinctrl(pdev);
 	devm_kfree(&pdev->dev, pdata);
 	return ret;
 }
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index 469ab1a..d4db55f 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -10,7 +10,6 @@
 				 msm-dai-stub-v2.o
 obj-$(CONFIG_SND_HWDEP) += msm-pcm-routing-devdep.o
 obj-$(CONFIG_DTS_EAGLE) += msm-dts-eagle.o
-obj-$(CONFIG_DOLBY_DAP) += msm-dolby-dap-config.o
 obj-$(CONFIG_DOLBY_DS2) += msm-ds2-dap-config.o
 obj-$(CONFIG_DOLBY_LICENSE) += msm-ds2-dap-config.o
 obj-$(CONFIG_DTS_SRS_TM) += msm-dts-srs-tm-config.o
diff --git a/sound/soc/msm/qdsp6v2/audio_cal_utils.c b/sound/soc/msm/qdsp6v2/audio_cal_utils.c
index f88087b..5d4a0ba 100644
--- a/sound/soc/msm/qdsp6v2/audio_cal_utils.c
+++ b/sound/soc/msm/qdsp6v2/audio_cal_utils.c
@@ -119,6 +119,9 @@
 	case AFE_SIDETONE_CAL_TYPE:
 		size = sizeof(struct audio_cal_info_sidetone);
 		break;
+	case AFE_SIDETONE_IIR_CAL_TYPE:
+		size = sizeof(struct audio_cal_info_sidetone_iir);
+		break;
 	case LSM_CUST_TOPOLOGY_CAL_TYPE:
 		size = 0;
 		break;
@@ -265,6 +268,9 @@
 	case AFE_SIDETONE_CAL_TYPE:
 		size = sizeof(struct audio_cal_type_sidetone);
 		break;
+	case AFE_SIDETONE_IIR_CAL_TYPE:
+		size = sizeof(struct audio_cal_type_sidetone_iir);
+		break;
 	case LSM_CUST_TOPOLOGY_CAL_TYPE:
 		size = sizeof(struct audio_cal_type_basic);
 		break;
@@ -598,7 +604,6 @@
 		goto done;
 
 	INIT_LIST_HEAD(&cal_block->list);
-	list_add_tail(&cal_block->list, &cal_type->cal_blocks);
 
 	cal_block->map_data.ion_map_handle = basic_cal->cal_data.mem_handle;
 	if (basic_cal->cal_data.mem_handle > 0) {
@@ -630,6 +635,7 @@
 		goto err;
 	}
 	cal_block->buffer_number = basic_cal->cal_hdr.buffer_number;
+	list_add_tail(&cal_block->list, &cal_type->cal_blocks);
 	pr_debug("%s: created block for cal type %d, buf num %d, map handle %d, map size %zd paddr 0x%pK!\n",
 		__func__, cal_type->info.reg.cal_type,
 		cal_block->buffer_number,
@@ -639,6 +645,8 @@
 done:
 	return cal_block;
 err:
+	kfree(cal_block->cal_info);
+	kfree(cal_block->client_info);
 	kfree(cal_block);
 	cal_block = NULL;
 	return cal_block;
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 48f58f1..e8e4e04 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -56,8 +56,8 @@
 #define FLAC_BLK_SIZE_LIMIT		65535
 
 /* Timestamp mode payload offsets */
-#define TS_LSW_OFFSET			6
-#define TS_MSW_OFFSET			7
+#define CAPTURE_META_DATA_TS_OFFSET_LSW	6
+#define CAPTURE_META_DATA_TS_OFFSET_MSW	7
 
 /* decoder parameter length */
 #define DDP_DEC_MAX_NUM_PARAM		18
@@ -100,7 +100,7 @@
 
 static unsigned int supported_sample_rates[] = {
 	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000,
-	88200, 96000, 176400, 192000, 352800, 384000, 2822400, 5644800
+	88200, 96000, 128000, 176400, 192000, 352800, 384000, 2822400, 5644800
 };
 
 struct msm_compr_pdata {
@@ -160,6 +160,10 @@
 	uint32_t stream_available;
 	uint32_t next_stream;
 
+	uint32_t run_mode;
+	uint32_t start_delay_lsw;
+	uint32_t start_delay_msw;
+
 	uint64_t marker_timestamp;
 
 	struct msm_compr_gapless_state gapless_state;
@@ -215,6 +219,99 @@
 				     struct msm_compr_dec_params *dec_params,
 				     int stream_id);
 
+static int msm_compr_set_render_mode(struct msm_compr_audio *prtd,
+				     uint32_t render_mode) {
+	int ret = -EINVAL;
+	struct audio_client *ac = prtd->audio_client;
+
+	pr_debug("%s, got render mode %u\n", __func__, render_mode);
+
+	if (render_mode == SNDRV_COMPRESS_RENDER_MODE_AUDIO_MASTER) {
+		render_mode = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT;
+	} else if (render_mode == SNDRV_COMPRESS_RENDER_MODE_STC_MASTER) {
+		render_mode = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC;
+		prtd->run_mode = ASM_SESSION_CMD_RUN_STARTIME_RUN_WITH_DELAY;
+	} else {
+		pr_err("%s, Invalid render mode %u\n", __func__,
+			render_mode);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	ret = q6asm_send_mtmx_strtr_render_mode(ac, render_mode);
+	if (ret) {
+		pr_err("%s, Render mode can't be set error %d\n", __func__,
+			ret);
+	}
+exit:
+	return ret;
+}
+
+static int msm_compr_set_clk_rec_mode(struct audio_client *ac,
+				     uint32_t clk_rec_mode) {
+	int ret = -EINVAL;
+
+	pr_debug("%s, got clk rec mode %u\n", __func__, clk_rec_mode);
+
+	if (clk_rec_mode == SNDRV_COMPRESS_CLK_REC_MODE_NONE) {
+		clk_rec_mode = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE;
+	} else if (clk_rec_mode == SNDRV_COMPRESS_CLK_REC_MODE_AUTO) {
+		clk_rec_mode = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO;
+	} else {
+		pr_err("%s, Invalid clk rec_mode mode %u\n", __func__,
+			clk_rec_mode);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	ret = q6asm_send_mtmx_strtr_clk_rec_mode(ac, clk_rec_mode);
+	if (ret) {
+		pr_err("%s, clk rec mode can't be set, error %d\n", __func__,
+			ret);
+	}
+
+exit:
+	return ret;
+}
+
+static int msm_compr_set_render_window(struct audio_client *ac,
+		uint32_t ws_lsw, uint32_t ws_msw,
+		uint32_t we_lsw, uint32_t we_msw)
+{
+	int ret = -EINVAL;
+	struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window;
+	uint32_t param_id;
+
+	pr_debug("%s, ws_lsw 0x%x ws_msw 0x%x we_lsw 0x%x we_ms 0x%x\n",
+		 __func__, ws_lsw, ws_msw, we_lsw, we_msw);
+
+	memset(&asm_mtmx_strtr_window, 0,
+	       sizeof(struct asm_session_mtmx_strtr_param_window_v2_t));
+	asm_mtmx_strtr_window.window_lsw = ws_lsw;
+	asm_mtmx_strtr_window.window_msw = ws_msw;
+	param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_START_V2;
+	ret = q6asm_send_mtmx_strtr_window(ac, &asm_mtmx_strtr_window,
+					   param_id);
+	if (ret) {
+		pr_err("%s, start window can't be set error %d\n", __func__,
+			ret);
+		goto exit;
+	}
+
+	asm_mtmx_strtr_window.window_lsw = we_lsw;
+	asm_mtmx_strtr_window.window_msw = we_msw;
+	param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_END_V2;
+	ret = q6asm_send_mtmx_strtr_window(ac, &asm_mtmx_strtr_window,
+					   param_id);
+	if (ret) {
+		pr_err("%s, end window can't be set error %d\n", __func__,
+			ret);
+	}
+
+exit:
+	return ret;
+}
+
 static int msm_compr_set_volume(struct snd_compr_stream *cstream,
 				uint32_t volume_l, uint32_t volume_r)
 {
@@ -314,6 +411,7 @@
 	int buffer_length;
 	uint64_t bytes_available;
 	struct audio_aio_write_param param;
+	struct snd_codec_metadata *buff_addr;
 
 	if (!atomic_read(&prtd->start)) {
 		pr_err("%s: stream is not in started state\n", __func__);
@@ -347,23 +445,34 @@
 	}
 
 	if (buffer_length) {
-		param.paddr	= prtd->buffer_paddr + prtd->byte_offset;
+		param.paddr = prtd->buffer_paddr + prtd->byte_offset;
 		WARN(prtd->byte_offset % 32 != 0, "offset %x not multiple of 32\n",
 		prtd->byte_offset);
 	} else {
-		param.paddr	= prtd->buffer_paddr;
+		param.paddr = prtd->buffer_paddr;
 	}
-
 	param.len	= buffer_length;
-	param.msw_ts	= 0;
-	param.lsw_ts	= 0;
-	param.flags	= NO_TIMESTAMP;
+	if (prtd->ts_header_offset) {
+		buff_addr = (struct snd_codec_metadata *)
+					(prtd->buffer + prtd->byte_offset);
+		param.len = buff_addr->length;
+		param.msw_ts = (uint32_t)
+			((buff_addr->timestamp & 0xFFFFFFFF00000000LL) >> 32);
+		param.lsw_ts = (uint32_t) (buff_addr->timestamp & 0xFFFFFFFFLL);
+		param.paddr += prtd->ts_header_offset;
+		param.flags = SET_TIMESTAMP;
+		param.metadata_len = prtd->ts_header_offset;
+	} else {
+		param.msw_ts = 0;
+		param.lsw_ts = 0;
+		param.flags = NO_TIMESTAMP;
+		param.metadata_len = 0;
+	}
 	param.uid	= buffer_length;
-	param.metadata_len = 0;
 	param.last_buffer = prtd->last_buffer;
 
 	pr_debug("%s: sending %d bytes to DSP byte_offset = %d\n",
-		__func__, buffer_length, prtd->byte_offset);
+		__func__, param.len, prtd->byte_offset);
 	if (q6asm_async_write(prtd->audio_client, &param) < 0) {
 		pr_err("%s:q6asm_async_write failed\n", __func__);
 	} else {
@@ -482,9 +591,21 @@
 		 * written to ADSP in the last write, update offset and
 		 * total copied data accordingly.
 		 */
-
-		prtd->byte_offset += token;
-		prtd->copied_total += token;
+		if (prtd->ts_header_offset) {
+			/* Always assume that the data will be sent to DSP on
+			 * frame boundary.
+			 * i.e, one frame of userspace write will result in
+			 * one kernel write to DSP. This is needed as
+			 * timestamp will be sent per frame.
+			 */
+			prtd->byte_offset +=
+					prtd->codec_param.buffer.fragment_size;
+			prtd->copied_total +=
+					prtd->codec_param.buffer.fragment_size;
+		} else {
+			prtd->byte_offset += token;
+			prtd->copied_total += token;
+		}
 		if (prtd->byte_offset >= prtd->buffer_size)
 			prtd->byte_offset -= prtd->buffer_size;
 
@@ -539,10 +660,10 @@
 			*buff_addr = prtd->ts_header_offset;
 			buff_addr++;
 			/* Write the TS LSW */
-			*buff_addr = payload[TS_LSW_OFFSET];
+			*buff_addr = payload[CAPTURE_META_DATA_TS_OFFSET_LSW];
 			buff_addr++;
 			/* Write the TS MSW */
-			*buff_addr = payload[TS_MSW_OFFSET];
+			*buff_addr = payload[CAPTURE_META_DATA_TS_OFFSET_MSW];
 		}
 		/* Always assume read_size is same as fragment_size */
 		read_size = prtd->codec_param.buffer.fragment_size;
@@ -760,7 +881,7 @@
 			COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
 	prtd->compr_cap.max_fragments =
 			COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
-	prtd->compr_cap.num_codecs = 14;
+	prtd->compr_cap.num_codecs = 15;
 	prtd->compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
 	prtd->compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
 	prtd->compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
@@ -775,6 +896,7 @@
 	prtd->compr_cap.codecs[11] = SND_AUDIOCODEC_APE;
 	prtd->compr_cap.codecs[12] = SND_AUDIOCODEC_DTS;
 	prtd->compr_cap.codecs[13] = SND_AUDIOCODEC_DSD;
+	prtd->compr_cap.codecs[14] = SND_AUDIOCODEC_APTX;
 }
 
 static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
@@ -794,6 +916,7 @@
 	struct asm_alac_cfg alac_cfg;
 	struct asm_ape_cfg ape_cfg;
 	struct asm_dsd_cfg dsd_cfg;
+	struct aptx_dec_bt_addr_cfg aptx_cfg;
 	union snd_codec_options *codec_options;
 
 	int ret = 0;
@@ -869,6 +992,9 @@
 		if (prtd->codec_param.codec.format ==
 					SND_AUDIOSTREAMFORMAT_MP4ADTS)
 			aac_cfg.format = 0x0;
+		else if (prtd->codec_param.codec.format ==
+					SND_AUDIOSTREAMFORMAT_MP4LATM)
+			aac_cfg.format = 0x04;
 		else
 			aac_cfg.format = 0x03;
 		aac_cfg.ch_cfg = prtd->num_channels;
@@ -1025,6 +1151,24 @@
 			pr_err("%s: CMD DSD Format block failed ret %d\n",
 				__func__, ret);
 		break;
+	case FORMAT_APTX:
+		pr_debug("SND_AUDIOCODEC_APTX\n");
+		memset(&aptx_cfg, 0x0, sizeof(struct aptx_dec_bt_addr_cfg));
+		ret = q6asm_stream_media_format_block_aptx_dec(
+							prtd->audio_client,
+							prtd->sample_rate,
+							stream_id);
+		if (ret >= 0) {
+			aptx_cfg.nap = codec_options->aptx_dec.nap;
+			aptx_cfg.uap = codec_options->aptx_dec.uap;
+			aptx_cfg.lap = codec_options->aptx_dec.lap;
+			q6asm_set_aptx_dec_bt_addr(prtd->audio_client,
+							&aptx_cfg);
+		} else {
+			pr_err("%s: CMD Format block failed ret %d\n",
+					 __func__, ret);
+		}
+		break;
 	default:
 		pr_debug("%s, unsupported format, skip", __func__);
 		break;
@@ -1206,6 +1350,12 @@
 	prtd->buffer_paddr = ac->port[dir].buf[0].phys;
 	prtd->buffer_size  = runtime->fragments * runtime->fragment_size;
 
+	/* Bit-0 of flags represent timestamp mode */
+	if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG)
+		prtd->ts_header_offset = sizeof(struct snd_codec_metadata);
+	else
+		prtd->ts_header_offset = 0;
+
 	ret = msm_compr_send_media_format_block(cstream, ac->stream_id, false);
 	if (ret < 0)
 		pr_err("%s, failed to send media format block\n", __func__);
@@ -1247,8 +1397,13 @@
 	pr_debug("%s: stream_id %d bits_per_sample %d\n",
 			__func__, ac->stream_id, bits_per_sample);
 
-	ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM,
-		bits_per_sample);
+	if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG) {
+		ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM,
+			bits_per_sample, true);
+	} else {
+		ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM,
+			bits_per_sample, false);
+	}
 	if (ret < 0) {
 		pr_err("%s: q6asm_open_read failed:%d\n", __func__, ret);
 		return ret;
@@ -1563,6 +1718,7 @@
 	kfree(pdata->dec_params[soc_prtd->dai_link->id]);
 	pdata->dec_params[soc_prtd->dai_link->id] = NULL;
 	kfree(prtd);
+	runtime->private_data = NULL;
 
 	return 0;
 }
@@ -1622,6 +1778,7 @@
 	q6asm_audio_client_free(ac);
 
 	kfree(prtd);
+	runtime->private_data = NULL;
 
 	return 0;
 }
@@ -1791,6 +1948,12 @@
 		break;
 	}
 
+	case SND_AUDIOCODEC_APTX: {
+		pr_debug("%s: SND_AUDIOCODEC_APTX\n", __func__);
+		prtd->codec = FORMAT_APTX;
+		break;
+	}
+
 	default:
 		pr_err("codec not supported, id =%d\n", params->codec.id);
 		return -EINVAL;
@@ -1935,7 +2098,8 @@
 			msm_compr_read_buffer(prtd);
 		}
 		/* issue RUN command for the stream */
-		q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		q6asm_run_nowait(prtd->audio_client, prtd->run_mode,
+				 prtd->start_delay_msw, prtd->start_delay_lsw);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		spin_lock_irqsave(&prtd->lock, flags);
@@ -2019,7 +2183,8 @@
 				   prtd->gapless_state.gapless_transition);
 		if (!prtd->gapless_state.gapless_transition) {
 			atomic_set(&prtd->start, 1);
-			q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+			q6asm_run_nowait(prtd->audio_client, prtd->run_mode,
+					 0, 0);
 		}
 		break;
 	case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
@@ -2664,6 +2829,7 @@
 	case SND_AUDIOCODEC_DTS:
 		break;
 	case SND_AUDIOCODEC_DSD:
+	case SND_AUDIOCODEC_APTX:
 		break;
 	default:
 		pr_err("%s: Unsupported audio codec %d\n",
@@ -2690,11 +2856,14 @@
 		return -EINVAL;
 	}
 
-	if (prtd->compr_passthr != LEGACY_PCM) {
+	if (((metadata->key == SNDRV_COMPRESS_ENCODER_PADDING) ||
+	     (metadata->key == SNDRV_COMPRESS_ENCODER_DELAY)) &&
+	     (prtd->compr_passthr != LEGACY_PCM)) {
 		pr_debug("%s: No trailing silence for compress_type[%d]\n",
 			__func__, prtd->compr_passthr);
 		return 0;
 	}
+
 	ac = prtd->audio_client;
 	if (metadata->key == SNDRV_COMPRESS_ENCODER_PADDING) {
 		pr_debug("%s, got encoder padding %u",
@@ -2704,11 +2873,63 @@
 		pr_debug("%s, got encoder delay %u",
 			 __func__, metadata->value[0]);
 		prtd->gapless_state.initial_samples_drop = metadata->value[0];
+	} else if (metadata->key == SNDRV_COMPRESS_RENDER_MODE) {
+		return msm_compr_set_render_mode(prtd, metadata->value[0]);
+	} else if (metadata->key == SNDRV_COMPRESS_CLK_REC_MODE) {
+		return msm_compr_set_clk_rec_mode(ac, metadata->value[0]);
+	} else if (metadata->key == SNDRV_COMPRESS_RENDER_WINDOW) {
+		return msm_compr_set_render_window(
+				ac,
+				metadata->value[0],
+				metadata->value[1],
+				metadata->value[2],
+				metadata->value[3]);
+	} else if (metadata->key == SNDRV_COMPRESS_START_DELAY) {
+		prtd->start_delay_lsw = metadata->value[0];
+		prtd->start_delay_msw = metadata->value[1];
 	}
 
 	return 0;
 }
 
+static int msm_compr_get_metadata(struct snd_compr_stream *cstream,
+				struct snd_compr_metadata *metadata)
+{
+	struct msm_compr_audio *prtd;
+	struct audio_client *ac;
+	int ret = -EINVAL;
+
+	pr_debug("%s\n", __func__);
+
+	if (!metadata || !cstream || !cstream->runtime)
+		return ret;
+
+	if (metadata->key != SNDRV_COMPRESS_PATH_DELAY) {
+		pr_err("%s, unsupported key %d\n", __func__, metadata->key);
+		return ret;
+	}
+
+	prtd = cstream->runtime->private_data;
+	if (!prtd || !prtd->audio_client) {
+		pr_err("%s: prtd or audio client is NULL\n", __func__);
+		return ret;
+	}
+
+	ac = prtd->audio_client;
+	ret = q6asm_get_path_delay(prtd->audio_client);
+	if (ret) {
+		pr_err("%s: get_path_delay failed, ret=%d\n", __func__, ret);
+		return ret;
+	}
+
+	pr_debug("%s, path delay(in us) %u\n", __func__, ac->path_delay);
+
+	metadata->value[0] = ac->path_delay;
+
+	return ret;
+}
+
+
 static int msm_compr_set_next_track_param(struct snd_compr_stream *cstream,
 				union snd_codec_options *codec_options)
 {
@@ -3078,6 +3299,7 @@
 	switch (prtd->codec) {
 	case FORMAT_MP3:
 	case FORMAT_MPEG4_AAC:
+	case FORMAT_APTX:
 		pr_debug("%s: no runtime parameters for codec: %d\n", __func__,
 			 prtd->codec);
 		break;
@@ -3144,6 +3366,7 @@
 	case FORMAT_APE:
 	case FORMAT_DTS:
 	case FORMAT_DSD:
+	case FORMAT_APTX:
 		pr_debug("%s: no runtime parameters for codec: %d\n", __func__,
 			 prtd->codec);
 		break;
@@ -3194,48 +3417,45 @@
 				      struct snd_ctl_elem_value *ucontrol)
 {
 	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_RX;
+	int be_id = ucontrol->value.integer.value[3];
+	int ret = 0;
 	int app_type;
 	int acdb_dev_id;
 	int sample_rate = 48000;
 
-	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
-	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
-		pr_err("%s Received out of bounds fe_id %llu\n",
-			__func__, fe_id);
-		return -EINVAL;
-	}
-
 	app_type = ucontrol->value.integer.value[0];
 	acdb_dev_id = ucontrol->value.integer.value[1];
 	if (ucontrol->value.integer.value[2] != 0)
 		sample_rate = ucontrol->value.integer.value[2];
-	pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
-		__func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_RX);
-	msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
-			acdb_dev_id, sample_rate, SESSION_TYPE_RX);
+	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+		__func__, fe_id, session_type, be_id,
+		app_type, acdb_dev_id, sample_rate);
+	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+						      be_id, app_type,
+						      acdb_dev_id, sample_rate);
+	if (ret < 0)
+		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+			__func__, ret);
 
-	return 0;
+	return ret;
 }
 
 static int msm_compr_playback_app_type_cfg_get(struct snd_kcontrol *kcontrol,
 				      struct snd_ctl_elem_value *ucontrol)
 {
 	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_RX;
+	int be_id = ucontrol->value.integer.value[3];
 	int ret = 0;
 	int app_type;
 	int acdb_dev_id;
 	int sample_rate;
 
-	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
-	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
-		pr_err("%s Received out of bounds fe_id %llu\n",
-			__func__, fe_id);
-		ret = -EINVAL;
-		goto done;
-	}
-
-	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_RX,
-		&app_type, &acdb_dev_id, &sample_rate);
+	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+						      be_id, &app_type,
+						      &acdb_dev_id,
+						      &sample_rate);
 	if (ret < 0) {
 		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
@@ -3245,8 +3465,8 @@
 	ucontrol->value.integer.value[0] = app_type;
 	ucontrol->value.integer.value[1] = acdb_dev_id;
 	ucontrol->value.integer.value[2] = sample_rate;
-	pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
-		__func__, fe_id, SESSION_TYPE_RX,
+	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+		__func__, fe_id, session_type, be_id,
 		app_type, acdb_dev_id, sample_rate);
 done:
 	return ret;
@@ -3256,48 +3476,45 @@
 					struct snd_ctl_elem_value *ucontrol)
 {
 	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_TX;
+	int be_id = ucontrol->value.integer.value[3];
+	int ret = 0;
 	int app_type;
 	int acdb_dev_id;
 	int sample_rate = 48000;
 
-	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
-	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
-		pr_err("%s Received out of bounds fe_id %llu\n",
-			__func__, fe_id);
-		return -EINVAL;
-	}
-
 	app_type = ucontrol->value.integer.value[0];
 	acdb_dev_id = ucontrol->value.integer.value[1];
 	if (ucontrol->value.integer.value[2] != 0)
 		sample_rate = ucontrol->value.integer.value[2];
-	pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
-		__func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
-	msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
-		acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+		__func__, fe_id, session_type, be_id,
+		app_type, acdb_dev_id, sample_rate);
+	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+						      be_id, app_type,
+						      acdb_dev_id, sample_rate);
+	if (ret < 0)
+		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+			__func__, ret);
 
-	return 0;
+	return ret;
 }
 
 static int msm_compr_capture_app_type_cfg_get(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol)
 {
 	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_TX;
+	int be_id = ucontrol->value.integer.value[3];
 	int ret = 0;
 	int app_type;
 	int acdb_dev_id;
 	int sample_rate;
 
-	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
-	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
-		pr_err("%s Received out of bounds fe_id %llu\n",
-			__func__, fe_id);
-		ret = -EINVAL;
-		goto done;
-	}
-
-	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
-		&app_type, &acdb_dev_id, &sample_rate);
+	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+						      be_id, &app_type,
+						      &acdb_dev_id,
+						      &sample_rate);
 	if (ret < 0) {
 		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
@@ -3307,8 +3524,8 @@
 	ucontrol->value.integer.value[0] = app_type;
 	ucontrol->value.integer.value[1] = acdb_dev_id;
 	ucontrol->value.integer.value[2] = sample_rate;
-	pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
-		__func__, fe_id, SESSION_TYPE_TX,
+	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+		__func__, fe_id, session_type, be_id,
 		app_type, acdb_dev_id, sample_rate);
 done:
 	return ret;
@@ -3860,6 +4077,7 @@
 	.pointer		= msm_compr_pointer,
 	.set_params		= msm_compr_set_params,
 	.set_metadata		= msm_compr_set_metadata,
+	.get_metadata		= msm_compr_get_metadata,
 	.set_next_track_param	= msm_compr_set_next_track_param,
 	.ack			= msm_compr_ack,
 	.copy			= msm_compr_copy,
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
index dffac45..9b072ea 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
@@ -124,6 +124,45 @@
 	SOC_ENUM_SINGLE_EXT(2, hdmi_format),
 };
 
+static int msm_dai_q6_ext_disp_drift_info(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = sizeof(struct afe_param_id_dev_timing_stats);
+
+	return 0;
+}
+
+static int msm_dai_q6_ext_disp_drift_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	int ret = -EINVAL;
+	struct afe_param_id_dev_timing_stats timing_stats;
+	struct snd_soc_dai *dai = kcontrol->private_data;
+	struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+	if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+		pr_err("%s:  afe port not started. status_mask = %ld\n",
+			__func__, *dai_data->status_mask);
+		goto done;
+	}
+
+	memset(&timing_stats, 0, sizeof(struct afe_param_id_dev_timing_stats));
+	ret = afe_get_av_dev_drift(&timing_stats, dai->id);
+	if (ret) {
+		pr_err("%s: Error getting AFE Drift for port %d, err=%d\n",
+			__func__, dai->id, ret);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	memcpy(ucontrol->value.bytes.data, (void *)&timing_stats,
+	       sizeof(struct afe_param_id_dev_timing_stats));
+done:
+	return ret;
+}
+
 static const struct snd_kcontrol_new hdmi_config_controls[] = {
 	SOC_ENUM_EXT("HDMI RX Format", hdmi_config_enum[0],
 				 msm_dai_q6_ext_disp_format_get,
@@ -132,6 +171,13 @@
 				 HDMI_RX_CA_MAX, 0, 1,
 				 msm_dai_q6_ext_disp_ca_get,
 				 msm_dai_q6_ext_disp_ca_put),
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface	= SNDRV_CTL_ELEM_IFACE_PCM,
+		.name	= "HDMI RX Drift",
+		.info	= msm_dai_q6_ext_disp_drift_info,
+		.get	= msm_dai_q6_ext_disp_drift_get,
+	},
 };
 
 static const struct snd_kcontrol_new display_port_config_controls[] = {
@@ -142,6 +188,13 @@
 				 HDMI_RX_CA_MAX, 0, 1,
 				 msm_dai_q6_ext_disp_ca_get,
 				 msm_dai_q6_ext_disp_ca_put),
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface	= SNDRV_CTL_ELEM_IFACE_PCM,
+		.name	= "DISPLAY Port RX Drift",
+		.info	= msm_dai_q6_ext_disp_drift_info,
+		.get	= msm_dai_q6_ext_disp_drift_get,
+	},
 };
 
 /* Current implementation assumes hw_param is called once
@@ -297,6 +350,10 @@
 		kcontrol = &hdmi_config_controls[1];
 		rc = snd_ctl_add(dai->component->card->snd_card,
 				 snd_ctl_new1(kcontrol, dai_data));
+
+		kcontrol = &hdmi_config_controls[2];
+		rc = snd_ctl_add(dai->component->card->snd_card,
+				 snd_ctl_new1(kcontrol, dai));
 	} else if (dai->driver->id == DISPLAY_PORT_RX) {
 		kcontrol = &display_port_config_controls[0];
 		rc = snd_ctl_add(dai->component->card->snd_card,
@@ -305,6 +362,10 @@
 		kcontrol = &display_port_config_controls[1];
 		rc = snd_ctl_add(dai->component->card->snd_card,
 				 snd_ctl_new1(kcontrol, dai_data));
+
+		kcontrol = &display_port_config_controls[2];
+		rc = snd_ctl_add(dai->component->card->snd_card,
+				snd_ctl_new1(kcontrol, dai));
 	} else {
 		dev_err(dai->dev, "%s: Invalid id:%d\n",
 			__func__, dai->driver->id);
@@ -370,8 +431,10 @@
 	.playback = {
 		.stream_name = "HDMI Playback",
 		.aif_name = "HDMI",
-		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
-		 SNDRV_PCM_RATE_192000,
+		.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+			 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+			 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+			 SNDRV_PCM_RATE_192000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
 		.channels_min = 2,
 		.channels_max = 8,
@@ -389,7 +452,9 @@
 		.playback = {
 			.stream_name = "Display Port Playback",
 			.aif_name = "DISPLAY_PORT",
-			.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+			.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+				 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+				 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
 				 SNDRV_PCM_RATE_192000,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
 				   SNDRV_PCM_FMTBIT_S24_LE,
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 52c2296..0c46763 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -51,6 +51,11 @@
 	ENC_FMT_APTX_HD = ASM_MEDIA_FMT_APTX_HD,
 };
 
+enum {
+	SPKR_1,
+	SPKR_2,
+};
+
 static const struct afe_clk_set lpass_clk_set_default = {
 	AFE_API_VERSION_CLOCK_SET,
 	Q6AFE_LPASS_CLK_ID_PRI_PCM_IBIT,
@@ -175,6 +180,7 @@
 	u16 afe_in_bitformat;
 	struct afe_enc_config enc_config;
 	union afe_port_config port_config;
+	u16 vi_feed_mono;
 };
 
 struct msm_dai_q6_spdif_dai_data {
@@ -212,6 +218,7 @@
 	u32 rate;
 	u32 channels;
 	u32 bitwidth;
+	u32 num_group_ports;
 	struct afe_clk_set clk_set; /* hold LPASS clock config. */
 	union afe_port_group_config group_cfg; /* hold tdm group config */
 	struct afe_tdm_port_config port_cfg; /* hold tdm config */
@@ -230,8 +237,14 @@
 	"Compr-60958"
 };
 
+static const char *const mi2s_vi_feed_mono[] = {
+	"Left",
+	"Right",
+};
+
 static const struct soc_enum mi2s_config_enum[] = {
 	SOC_ENUM_SINGLE_EXT(4, mi2s_format),
+	SOC_ENUM_SINGLE_EXT(2, mi2s_vi_feed_mono),
 };
 
 static const char *const sb_format[] = {
@@ -247,6 +260,7 @@
 static const char *const tdm_data_format[] = {
 	"LPCM",
 	"Compr",
+	"Gen Compr"
 };
 
 static const char *const tdm_header_type[] = {
@@ -256,8 +270,8 @@
 };
 
 static const struct soc_enum tdm_config_enum[] = {
-	SOC_ENUM_SINGLE_EXT(2, tdm_data_format),
-	SOC_ENUM_SINGLE_EXT(3, tdm_header_type),
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tdm_data_format), tdm_data_format),
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tdm_header_type), tdm_header_type),
 };
 
 static DEFINE_MUTEX(tdm_mutex);
@@ -285,6 +299,8 @@
 	0xFF,
 };
 
+static u32 num_tdm_group_ports;
+
 static struct afe_clk_set tdm_clk_set = {
 	AFE_API_VERSION_CLOCK_SET,
 	Q6AFE_LPASS_CLK_ID_QUAD_TDM_EBIT,
@@ -1882,6 +1898,11 @@
 			pr_err("%s: rx slot not found\n", __func__);
 			return -EINVAL;
 		}
+		if (rx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
+			pr_err("%s: invalid rx num %d\n", __func__, rx_num);
+			return -EINVAL;
+		}
+
 		for (i = 0; i < rx_num; i++) {
 			dai_data->port_config.slim_sch.shared_ch_mapping[i] =
 			    rx_slot[i];
@@ -1914,6 +1935,11 @@
 			pr_err("%s: tx slot not found\n", __func__);
 			return -EINVAL;
 		}
+		if (tx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
+			pr_err("%s: invalid tx num %d\n", __func__, tx_num);
+			return -EINVAL;
+		}
+
 		for (i = 0; i < tx_num; i++) {
 			dai_data->port_config.slim_sch.shared_ch_mapping[i] =
 			    tx_slot[i];
@@ -2046,6 +2072,42 @@
 	return 0;
 }
 
+static int msm_dai_q6_usb_audio_endian_cfg_put(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+	u32 val = ucontrol->value.integer.value[0];
+
+	if (dai_data) {
+		dai_data->port_config.usb_audio.endian = val;
+		pr_debug("%s: endian = 0x%x\n",  __func__,
+				 dai_data->port_config.usb_audio.endian);
+	} else {
+		pr_err("%s: dai_data is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int msm_dai_q6_usb_audio_endian_cfg_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+	if (dai_data) {
+		ucontrol->value.integer.value[0] =
+			 dai_data->port_config.usb_audio.endian;
+		pr_debug("%s: endian = 0x%x\n",  __func__,
+				 dai_data->port_config.usb_audio.endian);
+	} else {
+		pr_err("%s: dai_data is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int  msm_dai_q6_afe_enc_cfg_info(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_info *uinfo)
 {
@@ -2293,9 +2355,15 @@
 	SOC_SINGLE_EXT("USB_AUDIO_RX dev_token", 0, 0, UINT_MAX, 0,
 			msm_dai_q6_usb_audio_cfg_get,
 			msm_dai_q6_usb_audio_cfg_put),
+	SOC_SINGLE_EXT("USB_AUDIO_RX endian", 0, 0, 1, 0,
+			msm_dai_q6_usb_audio_endian_cfg_get,
+			msm_dai_q6_usb_audio_endian_cfg_put),
 	SOC_SINGLE_EXT("USB_AUDIO_TX dev_token", 0, 0, UINT_MAX, 0,
 			msm_dai_q6_usb_audio_cfg_get,
 			msm_dai_q6_usb_audio_cfg_put),
+	SOC_SINGLE_EXT("USB_AUDIO_TX endian", 0, 0, 1, 0,
+			msm_dai_q6_usb_audio_endian_cfg_get,
+			msm_dai_q6_usb_audio_endian_cfg_put),
 };
 
 static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
@@ -2360,10 +2428,16 @@
 		rc = snd_ctl_add(dai->component->card->snd_card,
 				 snd_ctl_new1(&usb_audio_cfg_controls[0],
 				 dai_data));
+		rc = snd_ctl_add(dai->component->card->snd_card,
+				 snd_ctl_new1(&usb_audio_cfg_controls[1],
+				 dai_data));
 		break;
 	case AFE_PORT_ID_USB_TX:
 		rc = snd_ctl_add(dai->component->card->snd_card,
-				 snd_ctl_new1(&usb_audio_cfg_controls[1],
+				 snd_ctl_new1(&usb_audio_cfg_controls[2],
+				 dai_data));
+		rc = snd_ctl_add(dai->component->card->snd_card,
+				 snd_ctl_new1(&usb_audio_cfg_controls[3],
 				 dai_data));
 		break;
 	}
@@ -3308,6 +3382,26 @@
 	return 0;
 }
 
+static int msm_dai_q6_mi2s_vi_feed_mono_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+	int value = ucontrol->value.integer.value[0];
+
+	dai_data->vi_feed_mono = value;
+	pr_debug("%s: value = %d\n", __func__, value);
+	return 0;
+}
+
+static int msm_dai_q6_mi2s_vi_feed_mono_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+	ucontrol->value.integer.value[0] = dai_data->vi_feed_mono;
+	return 0;
+}
+
 static const struct snd_kcontrol_new mi2s_config_controls[] = {
 	SOC_ENUM_EXT("PRI MI2S RX Format", mi2s_config_enum[0],
 		     msm_dai_q6_mi2s_format_get,
@@ -3342,6 +3436,15 @@
 	SOC_ENUM_EXT("SENARY MI2S TX Format", mi2s_config_enum[0],
 		     msm_dai_q6_mi2s_format_get,
 		     msm_dai_q6_mi2s_format_put),
+	SOC_ENUM_EXT("INT5 MI2S TX Format", mi2s_config_enum[0],
+		     msm_dai_q6_mi2s_format_get,
+		     msm_dai_q6_mi2s_format_put),
+};
+
+static const struct snd_kcontrol_new mi2s_vi_feed_controls[] = {
+	SOC_ENUM_EXT("INT5 MI2S VI MONO", mi2s_config_enum[1],
+		     msm_dai_q6_mi2s_vi_feed_mono_get,
+		     msm_dai_q6_mi2s_vi_feed_mono_put),
 };
 
 static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
@@ -3353,6 +3456,7 @@
 	struct snd_kcontrol *kcontrol = NULL;
 	int rc = 0;
 	const struct snd_kcontrol_new *ctrl = NULL;
+	const struct snd_kcontrol_new *vi_feed_ctrl = NULL;
 
 	dai->id = mi2s_pdata->intf_id;
 
@@ -3394,6 +3498,8 @@
 			ctrl = &mi2s_config_controls[9];
 		if (dai->id == MSM_SENARY_MI2S)
 			ctrl = &mi2s_config_controls[10];
+		if (dai->id == MSM_INT5_MI2S)
+			ctrl = &mi2s_config_controls[11];
 	}
 
 	if (ctrl) {
@@ -3408,6 +3514,21 @@
 				__func__, dai->name);
 		}
 	}
+
+	if (dai->id == MSM_INT5_MI2S)
+		vi_feed_ctrl = &mi2s_vi_feed_controls[0];
+
+	if (vi_feed_ctrl) {
+		rc = snd_ctl_add(dai->component->card->snd_card,
+				snd_ctl_new1(vi_feed_ctrl,
+				&mi2s_dai_data->tx_dai.mi2s_dai_data));
+
+		if (rc < 0) {
+			dev_err(dai->dev, "%s: err add TX vi feed channel ctl DAI = %s\n",
+				__func__, dai->name);
+		}
+	}
+
 	rc = msm_dai_q6_dai_add_route(dai);
 rtn:
 	return rc;
@@ -3654,8 +3775,12 @@
 		case AFE_PORT_I2S_QUAD01:
 		case AFE_PORT_I2S_6CHS:
 		case AFE_PORT_I2S_8CHS:
-			dai_data->port_config.i2s.channel_mode =
-						AFE_PORT_I2S_SD0;
+			if (dai_data->vi_feed_mono == SPKR_1)
+				dai_data->port_config.i2s.channel_mode =
+							AFE_PORT_I2S_SD0;
+			else
+				dai_data->port_config.i2s.channel_mode =
+							AFE_PORT_I2S_SD1;
 			break;
 		case AFE_PORT_I2S_QUAD23:
 			dai_data->port_config.i2s.channel_mode =
@@ -4812,7 +4937,6 @@
 static int msm_dai_tdm_q6_probe(struct platform_device *pdev)
 {
 	int rc = 0;
-	u32 num_ports = 0;
 	const uint32_t *port_id_array = NULL;
 	uint32_t array_length = 0;
 	int i = 0;
@@ -4835,18 +4959,19 @@
 
 	rc = of_property_read_u32(pdev->dev.of_node,
 		"qcom,msm-cpudai-tdm-group-num-ports",
-		&num_ports);
+		&num_tdm_group_ports);
 	if (rc) {
 		dev_err(&pdev->dev, "%s: Group Num Ports from DT file %s\n",
 			__func__, "qcom,msm-cpudai-tdm-group-num-ports");
 		goto rtn;
 	}
 	dev_dbg(&pdev->dev, "%s: Group Num Ports from DT file 0x%x\n",
-		__func__, num_ports);
+		__func__, num_tdm_group_ports);
 
-	if (num_ports > AFE_GROUP_DEVICE_NUM_PORTS) {
+	if (num_tdm_group_ports > AFE_GROUP_DEVICE_NUM_PORTS) {
 		dev_err(&pdev->dev, "%s Group Num Ports %d greater than Max %d\n",
-			__func__, num_ports, AFE_GROUP_DEVICE_NUM_PORTS);
+			__func__, num_tdm_group_ports,
+			AFE_GROUP_DEVICE_NUM_PORTS);
 		rc = -EINVAL;
 		goto rtn;
 	}
@@ -4860,18 +4985,19 @@
 		rc = -EINVAL;
 		goto rtn;
 	}
-	if (array_length != sizeof(uint32_t) * num_ports) {
+	if (array_length != sizeof(uint32_t) * num_tdm_group_ports) {
 		dev_err(&pdev->dev, "%s array_length is %d, expected is %zd\n",
-			__func__, array_length, sizeof(uint32_t) * num_ports);
+			__func__, array_length,
+			sizeof(uint32_t) * num_tdm_group_ports);
 		rc = -EINVAL;
 		goto rtn;
 	}
 
-	for (i = 0; i < num_ports; i++)
+	for (i = 0; i < num_tdm_group_ports; i++)
 		tdm_group_cfg.port_id[i] =
 			(u16)be32_to_cpu(port_id_array[i]);
 	/* Unused index should be filled with 0 or AFE_PORT_INVALID */
-	for (i = num_ports; i < AFE_GROUP_DEVICE_NUM_PORTS; i++)
+	for (i = num_tdm_group_ports; i < AFE_GROUP_DEVICE_NUM_PORTS; i++)
 		tdm_group_cfg.port_id[i] =
 			AFE_PORT_INVALID;
 
@@ -4938,7 +5064,20 @@
 	struct msm_dai_q6_tdm_dai_data *dai_data = kcontrol->private_data;
 	int value = ucontrol->value.integer.value[0];
 
-	dai_data->port_cfg.tdm.data_format = value;
+	switch (value) {
+	case 0:
+		dai_data->port_cfg.tdm.data_format = AFE_LINEAR_PCM_DATA;
+		break;
+	case 1:
+		dai_data->port_cfg.tdm.data_format = AFE_NON_LINEAR_DATA;
+		break;
+	case 2:
+		dai_data->port_cfg.tdm.data_format = AFE_GENERIC_COMPRESSED;
+		break;
+	default:
+		pr_err("%s: data_format invalid\n", __func__);
+		break;
+	}
 	pr_debug("%s: data_format = %d\n",
 		__func__, dai_data->port_cfg.tdm.data_format);
 	return 0;
@@ -5875,6 +6014,9 @@
 
 	/* HW only supports 16 and 8 slots configuration */
 	switch (slots) {
+	case 2:
+		cap_mask = 0x03;
+		break;
 	case 8:
 		cap_mask = 0xFF;
 		break;
@@ -6295,17 +6437,25 @@
 					__func__, dai->id);
 				goto rtn;
 			}
-			rc = afe_port_group_enable(group_id,
-				&dai_data->group_cfg, true);
-			if (rc < 0) {
-				dev_err(dai->dev, "%s: fail to enable AFE group 0x%x\n",
+
+			/*
+			 * if only one port, don't do group enable as there
+			 * is no group need for only one port
+			 */
+			if (dai_data->num_group_ports > 1) {
+				rc = afe_port_group_enable(group_id,
+					&dai_data->group_cfg, true);
+				if (rc < 0) {
+					dev_err(dai->dev,
+					"%s: fail to enable AFE group 0x%x\n",
 					__func__, group_id);
-				goto rtn;
+					goto rtn;
+				}
 			}
 		}
 
 		rc = afe_tdm_port_start(dai->id, &dai_data->port_cfg,
-			dai_data->rate);
+			dai_data->rate, dai_data->num_group_ports);
 		if (rc < 0) {
 			if (atomic_read(group_ref) == 0) {
 				afe_port_group_enable(group_id,
@@ -6399,13 +6549,15 @@
 			.stream_name = "Primary TDM0 Playback",
 			.aif_name = "PRI_TDM_RX_0",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_RX,
@@ -6417,13 +6569,15 @@
 			.stream_name = "Primary TDM1 Playback",
 			.aif_name = "PRI_TDM_RX_1",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_RX_1,
@@ -6435,13 +6589,15 @@
 			.stream_name = "Primary TDM2 Playback",
 			.aif_name = "PRI_TDM_RX_2",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_RX_2,
@@ -6453,13 +6609,15 @@
 			.stream_name = "Primary TDM3 Playback",
 			.aif_name = "PRI_TDM_RX_3",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_RX_3,
@@ -6471,13 +6629,15 @@
 			.stream_name = "Primary TDM4 Playback",
 			.aif_name = "PRI_TDM_RX_4",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_RX_4,
@@ -6489,13 +6649,15 @@
 			.stream_name = "Primary TDM5 Playback",
 			.aif_name = "PRI_TDM_RX_5",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_RX_5,
@@ -6507,13 +6669,15 @@
 			.stream_name = "Primary TDM6 Playback",
 			.aif_name = "PRI_TDM_RX_6",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_RX_6,
@@ -6525,13 +6689,15 @@
 			.stream_name = "Primary TDM7 Playback",
 			.aif_name = "PRI_TDM_RX_7",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_RX_7,
@@ -6543,13 +6709,15 @@
 			.stream_name = "Primary TDM0 Capture",
 			.aif_name = "PRI_TDM_TX_0",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_TX,
@@ -6561,13 +6729,15 @@
 			.stream_name = "Primary TDM1 Capture",
 			.aif_name = "PRI_TDM_TX_1",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_TX_1,
@@ -6579,13 +6749,15 @@
 			.stream_name = "Primary TDM2 Capture",
 			.aif_name = "PRI_TDM_TX_2",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_TX_2,
@@ -6597,13 +6769,15 @@
 			.stream_name = "Primary TDM3 Capture",
 			.aif_name = "PRI_TDM_TX_3",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_TX_3,
@@ -6615,13 +6789,15 @@
 			.stream_name = "Primary TDM4 Capture",
 			.aif_name = "PRI_TDM_TX_4",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_TX_4,
@@ -6633,13 +6809,15 @@
 			.stream_name = "Primary TDM5 Capture",
 			.aif_name = "PRI_TDM_TX_5",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_TX_5,
@@ -6651,13 +6829,15 @@
 			.stream_name = "Primary TDM6 Capture",
 			.aif_name = "PRI_TDM_TX_6",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_TX_6,
@@ -6669,13 +6849,15 @@
 			.stream_name = "Primary TDM7 Capture",
 			.aif_name = "PRI_TDM_TX_7",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_PRIMARY_TDM_TX_7,
@@ -6687,13 +6869,15 @@
 			.stream_name = "Secondary TDM0 Playback",
 			.aif_name = "SEC_TDM_RX_0",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_RX,
@@ -6705,13 +6889,15 @@
 			.stream_name = "Secondary TDM1 Playback",
 			.aif_name = "SEC_TDM_RX_1",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_RX_1,
@@ -6723,13 +6909,15 @@
 			.stream_name = "Secondary TDM2 Playback",
 			.aif_name = "SEC_TDM_RX_2",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_RX_2,
@@ -6741,13 +6929,15 @@
 			.stream_name = "Secondary TDM3 Playback",
 			.aif_name = "SEC_TDM_RX_3",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_RX_3,
@@ -6759,13 +6949,15 @@
 			.stream_name = "Secondary TDM4 Playback",
 			.aif_name = "SEC_TDM_RX_4",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_RX_4,
@@ -6777,13 +6969,15 @@
 			.stream_name = "Secondary TDM5 Playback",
 			.aif_name = "SEC_TDM_RX_5",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_RX_5,
@@ -6795,13 +6989,15 @@
 			.stream_name = "Secondary TDM6 Playback",
 			.aif_name = "SEC_TDM_RX_6",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_RX_6,
@@ -6813,13 +7009,15 @@
 			.stream_name = "Secondary TDM7 Playback",
 			.aif_name = "SEC_TDM_RX_7",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_RX_7,
@@ -6831,13 +7029,15 @@
 			.stream_name = "Secondary TDM0 Capture",
 			.aif_name = "SEC_TDM_TX_0",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_TX,
@@ -6849,13 +7049,15 @@
 			.stream_name = "Secondary TDM1 Capture",
 			.aif_name = "SEC_TDM_TX_1",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_TX_1,
@@ -6867,13 +7069,15 @@
 			.stream_name = "Secondary TDM2 Capture",
 			.aif_name = "SEC_TDM_TX_2",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_TX_2,
@@ -6885,13 +7089,15 @@
 			.stream_name = "Secondary TDM3 Capture",
 			.aif_name = "SEC_TDM_TX_3",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_TX_3,
@@ -6903,13 +7109,15 @@
 			.stream_name = "Secondary TDM4 Capture",
 			.aif_name = "SEC_TDM_TX_4",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_TX_4,
@@ -6921,13 +7129,15 @@
 			.stream_name = "Secondary TDM5 Capture",
 			.aif_name = "SEC_TDM_TX_5",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_TX_5,
@@ -6939,13 +7149,15 @@
 			.stream_name = "Secondary TDM6 Capture",
 			.aif_name = "SEC_TDM_TX_6",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_TX_6,
@@ -6957,13 +7169,15 @@
 			.stream_name = "Secondary TDM7 Capture",
 			.aif_name = "SEC_TDM_TX_7",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_SECONDARY_TDM_TX_7,
@@ -6975,13 +7189,15 @@
 			.stream_name = "Tertiary TDM0 Playback",
 			.aif_name = "TERT_TDM_RX_0",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_RX,
@@ -6993,13 +7209,15 @@
 			.stream_name = "Tertiary TDM1 Playback",
 			.aif_name = "TERT_TDM_RX_1",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_RX_1,
@@ -7011,13 +7229,15 @@
 			.stream_name = "Tertiary TDM2 Playback",
 			.aif_name = "TERT_TDM_RX_2",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_RX_2,
@@ -7029,13 +7249,15 @@
 			.stream_name = "Tertiary TDM3 Playback",
 			.aif_name = "TERT_TDM_RX_3",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_RX_3,
@@ -7047,13 +7269,15 @@
 			.stream_name = "Tertiary TDM4 Playback",
 			.aif_name = "TERT_TDM_RX_4",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_RX_4,
@@ -7065,13 +7289,15 @@
 			.stream_name = "Tertiary TDM5 Playback",
 			.aif_name = "TERT_TDM_RX_5",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_RX_5,
@@ -7083,13 +7309,15 @@
 			.stream_name = "Tertiary TDM6 Playback",
 			.aif_name = "TERT_TDM_RX_6",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_RX_6,
@@ -7101,13 +7329,15 @@
 			.stream_name = "Tertiary TDM7 Playback",
 			.aif_name = "TERT_TDM_RX_7",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_RX_7,
@@ -7119,13 +7349,15 @@
 			.stream_name = "Tertiary TDM0 Capture",
 			.aif_name = "TERT_TDM_TX_0",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_TX,
@@ -7137,13 +7369,15 @@
 			.stream_name = "Tertiary TDM1 Capture",
 			.aif_name = "TERT_TDM_TX_1",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_TX_1,
@@ -7155,13 +7389,15 @@
 			.stream_name = "Tertiary TDM2 Capture",
 			.aif_name = "TERT_TDM_TX_2",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_TX_2,
@@ -7173,13 +7409,15 @@
 			.stream_name = "Tertiary TDM3 Capture",
 			.aif_name = "TERT_TDM_TX_3",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_TX_3,
@@ -7191,13 +7429,15 @@
 			.stream_name = "Tertiary TDM4 Capture",
 			.aif_name = "TERT_TDM_TX_4",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_TX_4,
@@ -7209,13 +7449,15 @@
 			.stream_name = "Tertiary TDM5 Capture",
 			.aif_name = "TERT_TDM_TX_5",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_TX_5,
@@ -7227,13 +7469,15 @@
 			.stream_name = "Tertiary TDM6 Capture",
 			.aif_name = "TERT_TDM_TX_6",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_TX_6,
@@ -7245,13 +7489,15 @@
 			.stream_name = "Tertiary TDM7 Capture",
 			.aif_name = "TERT_TDM_TX_7",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_TERTIARY_TDM_TX_7,
@@ -7263,13 +7509,15 @@
 			.stream_name = "Quaternary TDM0 Playback",
 			.aif_name = "QUAT_TDM_RX_0",
 			.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
-				SNDRV_PCM_RATE_16000,
+				SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_RX,
@@ -7281,13 +7529,15 @@
 			.stream_name = "Quaternary TDM1 Playback",
 			.aif_name = "QUAT_TDM_RX_1",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_RX_1,
@@ -7299,13 +7549,15 @@
 			.stream_name = "Quaternary TDM2 Playback",
 			.aif_name = "QUAT_TDM_RX_2",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_RX_2,
@@ -7317,13 +7569,15 @@
 			.stream_name = "Quaternary TDM3 Playback",
 			.aif_name = "QUAT_TDM_RX_3",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_RX_3,
@@ -7335,13 +7589,15 @@
 			.stream_name = "Quaternary TDM4 Playback",
 			.aif_name = "QUAT_TDM_RX_4",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_RX_4,
@@ -7353,13 +7609,15 @@
 			.stream_name = "Quaternary TDM5 Playback",
 			.aif_name = "QUAT_TDM_RX_5",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_RX_5,
@@ -7371,13 +7629,15 @@
 			.stream_name = "Quaternary TDM6 Playback",
 			.aif_name = "QUAT_TDM_RX_6",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_RX_6,
@@ -7389,13 +7649,15 @@
 			.stream_name = "Quaternary TDM7 Playback",
 			.aif_name = "QUAT_TDM_RX_7",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_RX_7,
@@ -7407,13 +7669,15 @@
 			.stream_name = "Quaternary TDM0 Capture",
 			.aif_name = "QUAT_TDM_TX_0",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_TX,
@@ -7425,13 +7689,15 @@
 			.stream_name = "Quaternary TDM1 Capture",
 			.aif_name = "QUAT_TDM_TX_1",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_TX_1,
@@ -7443,13 +7709,15 @@
 			.stream_name = "Quaternary TDM2 Capture",
 			.aif_name = "QUAT_TDM_TX_2",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_TX_2,
@@ -7461,13 +7729,15 @@
 			.stream_name = "Quaternary TDM3 Capture",
 			.aif_name = "QUAT_TDM_TX_3",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_TX_3,
@@ -7479,13 +7749,15 @@
 			.stream_name = "Quaternary TDM4 Capture",
 			.aif_name = "QUAT_TDM_TX_4",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_TX_4,
@@ -7497,13 +7769,15 @@
 			.stream_name = "Quaternary TDM5 Capture",
 			.aif_name = "QUAT_TDM_TX_5",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_TX_5,
@@ -7515,13 +7789,15 @@
 			.stream_name = "Quaternary TDM6 Capture",
 			.aif_name = "QUAT_TDM_TX_6",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_TX_6,
@@ -7533,13 +7809,15 @@
 			.stream_name = "Quaternary TDM7 Capture",
 			.aif_name = "QUAT_TDM_TX_7",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE,
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min = 8000,
-			.rate_max = 48000,
+			.rate_max = 352800,
 		},
 		.ops = &msm_dai_q6_tdm_ops,
 		.id = AFE_PORT_ID_QUATERNARY_TDM_TX_7,
@@ -7732,6 +8010,9 @@
 	dai_data->clk_set = tdm_clk_set;
 	/* copy static group cfg per parent node */
 	dai_data->group_cfg.tdm_cfg = tdm_group_cfg;
+	/* copy static num group ports per parent node */
+	dai_data->num_group_ports = num_tdm_group_ports;
+
 
 	dev_set_drvdata(&pdev->dev, dai_data);
 
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-slim.c b/sound/soc/msm/qdsp6v2/msm-dai-slim.c
index 77fb8d4..779a2e6 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-slim.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-slim.c
@@ -313,7 +313,7 @@
 	struct msm_slim_dai_data *dai_data = NULL;
 	struct slim_ch prop;
 	int rc;
-	u8 i, j;
+	u8 i;
 
 	dai_data = msm_slim_get_dai_data(drv_data, dai);
 	if (!dai_data) {
@@ -330,6 +330,13 @@
 		return -EINVAL;
 	}
 
+	if (dai_data->status & DAI_STATE_PREPARED) {
+		dev_dbg(dai->dev,
+			"%s: dai id (%d) has already prepared.\n",
+			__func__, dai->id);
+		return 0;
+	}
+
 	dma_data = &dai_data->dma_data;
 	snd_soc_dai_set_dma_data(dai, substream, dma_data);
 
@@ -343,6 +350,10 @@
 		}
 	}
 
+	/* To decrement the channel ref count*/
+	for (i = 0; i < dai_data->ch_cnt; i++)
+		slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[i]);
+
 	prop.prot = SLIM_AUTO_ISO;
 	prop.baser = SLIM_RATE_4000HZ;
 	prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
@@ -366,8 +377,6 @@
 
 error_define_chan:
 error_chan_query:
-	for (j = 0; j < i; j++)
-		slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[j]);
 	return rc;
 }
 
@@ -377,7 +386,6 @@
 	struct msm_dai_slim_drv_data *drv_data = dev_get_drvdata(dai->dev);
 	struct msm_slim_dma_data *dma_data = NULL;
 	struct msm_slim_dai_data *dai_data;
-	int i, rc = 0;
 
 	dai_data = msm_slim_get_dai_data(drv_data, dai);
 	dma_data = snd_soc_dai_get_dma_data(dai, stream);
@@ -396,15 +404,6 @@
 		return;
 	}
 
-	for (i = 0; i < dai_data->ch_cnt; i++) {
-		rc = slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[i]);
-		if (rc) {
-			dev_err(dai->dev,
-				"%s: dealloc_ch failed, err = %d\n",
-				__func__, rc);
-		}
-	}
-
 	snd_soc_dai_set_dma_data(dai, stream, NULL);
 	/* clear prepared state for the dai */
 	CLR_DAI_STATE(dai_data->status, DAI_STATE_PREPARED);
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
deleted file mode 100644
index 29a1b3d..0000000
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ /dev/null
@@ -1,1071 +0,0 @@
-/* Copyright (c) 2013-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/err.h>
-#include <linux/module.h>
-#include <linux/bitops.h>
-#include <sound/control.h>
-#include <sound/q6adm-v2.h>
-#include <sound/q6core.h>
-
-#include "msm-dolby-dap-config.h"
-
-/* dolby endp based parameters */
-struct dolby_dap_endp_params_s {
-	int device;
-	int device_ch_caps;
-	int dap_device;
-	int params_id[DOLBY_NUM_ENDP_DEPENDENT_PARAMS];
-	int params_len[DOLBY_NUM_ENDP_DEPENDENT_PARAMS];
-	int params_offset[DOLBY_NUM_ENDP_DEPENDENT_PARAMS];
-	int params_val[DOLBY_ENDDEP_PARAM_LENGTH];
-};
-
-const struct dolby_dap_endp_params_s
-			dolby_dap_endp_params[NUM_DOLBY_ENDP_DEVICE] = {
-	{EARPIECE, 2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{SPEAKER, 2, DOLBY_ENDP_INT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{WIRED_HEADSET,	2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{WIRED_HEADPHONE, 2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{BLUETOOTH_SCO,	2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{BLUETOOTH_SCO_HEADSET,	2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{BLUETOOTH_SCO_CARKIT, 2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{BLUETOOTH_A2DP, 2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{BLUETOOTH_A2DP_HEADPHONES, 2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{BLUETOOTH_A2DP_SPEAKER, 2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{AUX_DIGITAL, 2, DOLBY_ENDP_HDMI,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-496, -496, 0}
-	},
-	{AUX_DIGITAL, 6, DOLBY_ENDP_HDMI,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-496, -496, 0}
-	},
-	{AUX_DIGITAL, 8, DOLBY_ENDP_HDMI,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-496, -496, 0}
-	},
-	{ANLG_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{DGTL_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{USB_ACCESSORY,	2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{USB_DEVICE, 2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{REMOTE_SUBMIX,	2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{PROXY,	2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{PROXY,	6, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{FM, 2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-	{FM_TX,	2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
-		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
-		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
-		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
-		{-320, -320, 144}
-	},
-};
-
-/* dolby param ids to/from dsp */
-static uint32_t	dolby_dap_params_id[ALL_DOLBY_PARAMS] = {
-	DOLBY_PARAM_ID_VDHE, DOLBY_PARAM_ID_VSPE, DOLBY_PARAM_ID_DSSF,
-	DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLE,
-	DOLBY_PARAM_ID_DVMC, DOLBY_PARAM_ID_DVME, DOLBY_PARAM_ID_IENB,
-	DOLBY_PARAM_ID_IEBF, DOLBY_PARAM_ID_IEON, DOLBY_PARAM_ID_DEON,
-	DOLBY_PARAM_ID_NGON, DOLBY_PARAM_ID_GEON, DOLBY_PARAM_ID_GENB,
-	DOLBY_PARAM_ID_GEBF, DOLBY_PARAM_ID_AONB, DOLBY_PARAM_ID_AOBF,
-	DOLBY_PARAM_ID_AOBG, DOLBY_PARAM_ID_AOON, DOLBY_PARAM_ID_ARNB,
-	DOLBY_PARAM_ID_ARBF, DOLBY_PARAM_ID_PLB,  DOLBY_PARAM_ID_PLMD,
-	DOLBY_PARAM_ID_DHSB, DOLBY_PARAM_ID_DHRG, DOLBY_PARAM_ID_DSSB,
-	DOLBY_PARAM_ID_DSSA, DOLBY_PARAM_ID_DVLA, DOLBY_PARAM_ID_IEBT,
-	DOLBY_PARAM_ID_IEA,  DOLBY_PARAM_ID_DEA,  DOLBY_PARAM_ID_DED,
-	DOLBY_PARAM_ID_GEBG, DOLBY_PARAM_ID_AOCC, DOLBY_PARAM_ID_ARBI,
-	DOLBY_PARAM_ID_ARBL, DOLBY_PARAM_ID_ARBH, DOLBY_PARAM_ID_AROD,
-	DOLBY_PARAM_ID_ARTP, DOLBY_PARAM_ID_VMON, DOLBY_PARAM_ID_VMB,
-	DOLBY_PARAM_ID_VCNB, DOLBY_PARAM_ID_VCBF, DOLBY_PARAM_ID_PREG,
-	DOLBY_PARAM_ID_VEN,  DOLBY_PARAM_ID_PSTG, DOLBY_COMMIT_ALL_TO_DSP,
-	DOLBY_COMMIT_TO_DSP, DOLBY_USE_CACHE, DOLBY_AUTO_ENDP,
-	DOLBY_AUTO_ENDDEP_PARAMS
-};
-
-/* modifed state:	0x00000000 - Not updated
- *			> 0x00000000 && < 0x00010000
- *				Updated and not committed to DSP
- *			0x00010001 - Updated and committed to DSP
- *			> 0x00010001 - Modified the committed value
- */
-static int dolby_dap_params_modified[MAX_DOLBY_PARAMS] = { 0 };
-/* param offset */
-static uint32_t	dolby_dap_params_offset[MAX_DOLBY_PARAMS] = {
-	DOLBY_PARAM_VDHE_OFFSET, DOLBY_PARAM_VSPE_OFFSET,
-	DOLBY_PARAM_DSSF_OFFSET, DOLBY_PARAM_DVLI_OFFSET,
-	DOLBY_PARAM_DVLO_OFFSET, DOLBY_PARAM_DVLE_OFFSET,
-	DOLBY_PARAM_DVMC_OFFSET, DOLBY_PARAM_DVME_OFFSET,
-	DOLBY_PARAM_IENB_OFFSET, DOLBY_PARAM_IEBF_OFFSET,
-	DOLBY_PARAM_IEON_OFFSET, DOLBY_PARAM_DEON_OFFSET,
-	DOLBY_PARAM_NGON_OFFSET, DOLBY_PARAM_GEON_OFFSET,
-	DOLBY_PARAM_GENB_OFFSET, DOLBY_PARAM_GEBF_OFFSET,
-	DOLBY_PARAM_AONB_OFFSET, DOLBY_PARAM_AOBF_OFFSET,
-	DOLBY_PARAM_AOBG_OFFSET, DOLBY_PARAM_AOON_OFFSET,
-	DOLBY_PARAM_ARNB_OFFSET, DOLBY_PARAM_ARBF_OFFSET,
-	DOLBY_PARAM_PLB_OFFSET,  DOLBY_PARAM_PLMD_OFFSET,
-	DOLBY_PARAM_DHSB_OFFSET, DOLBY_PARAM_DHRG_OFFSET,
-	DOLBY_PARAM_DSSB_OFFSET, DOLBY_PARAM_DSSA_OFFSET,
-	DOLBY_PARAM_DVLA_OFFSET, DOLBY_PARAM_IEBT_OFFSET,
-	DOLBY_PARAM_IEA_OFFSET,  DOLBY_PARAM_DEA_OFFSET,
-	DOLBY_PARAM_DED_OFFSET,  DOLBY_PARAM_GEBG_OFFSET,
-	DOLBY_PARAM_AOCC_OFFSET, DOLBY_PARAM_ARBI_OFFSET,
-	DOLBY_PARAM_ARBL_OFFSET, DOLBY_PARAM_ARBH_OFFSET,
-	DOLBY_PARAM_AROD_OFFSET, DOLBY_PARAM_ARTP_OFFSET,
-	DOLBY_PARAM_VMON_OFFSET, DOLBY_PARAM_VMB_OFFSET,
-	DOLBY_PARAM_VCNB_OFFSET, DOLBY_PARAM_VCBF_OFFSET,
-	DOLBY_PARAM_PREG_OFFSET, DOLBY_PARAM_VEN_OFFSET,
-	DOLBY_PARAM_PSTG_OFFSET
-};
-/* param_length */
-static uint32_t	dolby_dap_params_length[MAX_DOLBY_PARAMS] = {
-	DOLBY_PARAM_VDHE_LENGTH, DOLBY_PARAM_VSPE_LENGTH,
-	DOLBY_PARAM_DSSF_LENGTH, DOLBY_PARAM_DVLI_LENGTH,
-	DOLBY_PARAM_DVLO_LENGTH, DOLBY_PARAM_DVLE_LENGTH,
-	DOLBY_PARAM_DVMC_LENGTH, DOLBY_PARAM_DVME_LENGTH,
-	DOLBY_PARAM_IENB_LENGTH, DOLBY_PARAM_IEBF_LENGTH,
-	DOLBY_PARAM_IEON_LENGTH, DOLBY_PARAM_DEON_LENGTH,
-	DOLBY_PARAM_NGON_LENGTH, DOLBY_PARAM_GEON_LENGTH,
-	DOLBY_PARAM_GENB_LENGTH, DOLBY_PARAM_GEBF_LENGTH,
-	DOLBY_PARAM_AONB_LENGTH, DOLBY_PARAM_AOBF_LENGTH,
-	DOLBY_PARAM_AOBG_LENGTH, DOLBY_PARAM_AOON_LENGTH,
-	DOLBY_PARAM_ARNB_LENGTH, DOLBY_PARAM_ARBF_LENGTH,
-	DOLBY_PARAM_PLB_LENGTH,  DOLBY_PARAM_PLMD_LENGTH,
-	DOLBY_PARAM_DHSB_LENGTH, DOLBY_PARAM_DHRG_LENGTH,
-	DOLBY_PARAM_DSSB_LENGTH, DOLBY_PARAM_DSSA_LENGTH,
-	DOLBY_PARAM_DVLA_LENGTH, DOLBY_PARAM_IEBT_LENGTH,
-	DOLBY_PARAM_IEA_LENGTH,  DOLBY_PARAM_DEA_LENGTH,
-	DOLBY_PARAM_DED_LENGTH,  DOLBY_PARAM_GEBG_LENGTH,
-	DOLBY_PARAM_AOCC_LENGTH, DOLBY_PARAM_ARBI_LENGTH,
-	DOLBY_PARAM_ARBL_LENGTH, DOLBY_PARAM_ARBH_LENGTH,
-	DOLBY_PARAM_AROD_LENGTH, DOLBY_PARAM_ARTP_LENGTH,
-	DOLBY_PARAM_VMON_LENGTH, DOLBY_PARAM_VMB_LENGTH,
-	DOLBY_PARAM_VCNB_LENGTH, DOLBY_PARAM_VCBF_LENGTH,
-	DOLBY_PARAM_PREG_LENGTH, DOLBY_PARAM_VEN_LENGTH,
-	DOLBY_PARAM_PSTG_LENGTH
-};
-
-/* param_value */
-static uint32_t	dolby_dap_params_value[TOTAL_LENGTH_DOLBY_PARAM] = {0};
-
-struct dolby_dap_params_get_s {
-	int32_t  port_id;
-	uint32_t device_id;
-	uint32_t param_id;
-	uint32_t offset;
-	uint32_t length;
-};
-
-struct dolby_dap_params_states_s {
-	bool use_cache;
-	bool auto_endp;
-	bool enddep_params;
-	int  port_id[AFE_MAX_PORTS];
-	int  copp_idx[AFE_MAX_PORTS];
-	int  port_open_count;
-	int  port_ids_dolby_can_be_enabled;
-	int  device;
-};
-
-static struct dolby_dap_params_get_s dolby_dap_params_get = {-1, DEVICE_OUT_ALL,
-							     0, 0, 0};
-static struct dolby_dap_params_states_s dolby_dap_params_states = { true, true,
-						true, {DOLBY_INVALID_PORT_ID},
-						{-1}, 0, DEVICE_OUT_ALL, 0 };
-/*
- * port_ids_dolby_can_be_enabled is set to 0x7FFFFFFF.
- * this needs to be removed after interface validation
- */
-
-static int msm_dolby_dap_map_device_to_dolby_endpoint(int device)
-{
-	int i, dolby_dap_device = DOLBY_ENDP_EXT_SPEAKERS;
-
-	for (i = 0; i < NUM_DOLBY_ENDP_DEVICE; i++) {
-		if (dolby_dap_endp_params[i].device == device) {
-			dolby_dap_device = dolby_dap_endp_params[i].dap_device;
-			break;
-		}
-	}
-	/* default the endpoint to speaker if corresponding device entry */
-	/* not found */
-	if (i >= NUM_DOLBY_ENDP_DEVICE)
-		dolby_dap_params_states.device = SPEAKER;
-	return dolby_dap_device;
-}
-
-static int msm_dolby_dap_send_end_point(int port_id, int copp_idx)
-{
-	int rc = 0;
-	char *params_value;
-	int *update_params_value;
-	uint32_t params_length = (DOLBY_PARAM_INT_ENDP_LENGTH +
-				DOLBY_PARAM_PAYLOAD_SIZE) * sizeof(uint32_t);
-
-	pr_debug("%s\n", __func__);
-	params_value = kzalloc(params_length, GFP_KERNEL);
-	if (!params_value) {
-		pr_err("%s, params memory alloc failed", __func__);
-		return -ENOMEM;
-	}
-	update_params_value = (int *)params_value;
-	*update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
-	*update_params_value++ = DOLBY_PARAM_ID_INIT_ENDP;
-	*update_params_value++ = DOLBY_PARAM_INT_ENDP_LENGTH * sizeof(uint32_t);
-	*update_params_value++ =
-		 msm_dolby_dap_map_device_to_dolby_endpoint(
-						dolby_dap_params_states.device);
-	rc = adm_dolby_dap_send_params(port_id, copp_idx, params_value,
-				       params_length);
-	if (rc) {
-		pr_err("%s: send dolby params failed\n", __func__);
-		rc = -EINVAL;
-	}
-	kfree(params_value);
-	return rc;
-}
-
-static int msm_dolby_dap_send_enddep_params(int port_id, int copp_idx,
-					    int device_channels)
-{
-	int i, j, rc = 0, idx, offset;
-	char *params_value;
-	int *update_params_value;
-	uint32_t params_length = (DOLBY_ENDDEP_PARAM_LENGTH +
-					DOLBY_NUM_ENDP_DEPENDENT_PARAMS *
-					DOLBY_PARAM_PAYLOAD_SIZE) *
-				sizeof(uint32_t);
-
-	pr_debug("%s\n", __func__);
-	params_value = kzalloc(params_length, GFP_KERNEL);
-	if (!params_value) {
-		pr_err("%s, params memory alloc failed", __func__);
-		return -ENOMEM;
-	}
-	update_params_value = (int *)params_value;
-	for (idx = 0; idx < NUM_DOLBY_ENDP_DEVICE; idx++) {
-		if (dolby_dap_endp_params[idx].device ==
-			dolby_dap_params_states.device) {
-			if (dolby_dap_params_states.device == AUX_DIGITAL ||
-			    dolby_dap_params_states.device == PROXY) {
-				if (dolby_dap_endp_params[idx].device_ch_caps ==
-					device_channels)
-					break;
-			} else {
-				break;
-			}
-		}
-	}
-	if (idx >= NUM_DOLBY_ENDP_DEVICE) {
-		pr_err("%s: device is not set accordingly\n", __func__);
-		kfree(params_value);
-		return -EINVAL;
-	}
-	for (i = 0; i < DOLBY_ENDDEP_PARAM_LENGTH; i++) {
-		*update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
-		*update_params_value++ =
-				dolby_dap_endp_params[idx].params_id[i];
-		*update_params_value++ =
-			dolby_dap_endp_params[idx].params_len[i] *
-				sizeof(uint32_t);
-		offset = dolby_dap_endp_params[idx].params_offset[i];
-		for (j = 0; j < dolby_dap_endp_params[idx].params_len[i]; j++)
-			*update_params_value++ =
-				dolby_dap_endp_params[idx].params_val[offset+j];
-	}
-	rc = adm_dolby_dap_send_params(port_id, copp_idx, params_value,
-				       params_length);
-	if (rc) {
-		pr_err("%s: send dolby params failed\n", __func__);
-		rc = -EINVAL;
-	}
-	kfree(params_value);
-	return rc;
-}
-
-static int msm_dolby_dap_send_cached_params(int port_id, int copp_idx,
-					    int commit)
-{
-	char *params_value;
-	int *update_params_value, rc = 0;
-	uint32_t index_offset, i, j;
-	uint32_t params_length = (TOTAL_LENGTH_DOLBY_PARAM +
-				MAX_DOLBY_PARAMS * DOLBY_PARAM_PAYLOAD_SIZE) *
-				sizeof(uint32_t);
-
-	params_value = kzalloc(params_length, GFP_KERNEL);
-	if (!params_value)
-		return -ENOMEM;
-
-	update_params_value = (int *)params_value;
-	params_length = 0;
-	for (i = 0; i < MAX_DOLBY_PARAMS; i++) {
-		if ((dolby_dap_params_modified[i] == 0) ||
-		    ((commit) &&
-		     ((dolby_dap_params_modified[i] & 0x00010000) &&
-		     ((dolby_dap_params_modified[i] & 0x0000FFFF) <= 1))))
-			continue;
-		*update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
-		*update_params_value++ = dolby_dap_params_id[i];
-		*update_params_value++ = dolby_dap_params_length[i] *
-						sizeof(uint32_t);
-		index_offset = dolby_dap_params_offset[i];
-		for (j = 0; j < dolby_dap_params_length[i]; j++) {
-			*update_params_value++ =
-					dolby_dap_params_value[index_offset+j];
-		}
-		params_length += (DOLBY_PARAM_PAYLOAD_SIZE +
-				dolby_dap_params_length[i]) * sizeof(uint32_t);
-	}
-	pr_debug("%s, valid param length: %d", __func__, params_length);
-	if (params_length) {
-		rc = adm_dolby_dap_send_params(port_id, copp_idx, params_value,
-						params_length);
-		if (rc) {
-			pr_err("%s: send dolby params failed\n", __func__);
-			kfree(params_value);
-			return -EINVAL;
-		}
-		for (i = 0; i < MAX_DOLBY_PARAMS; i++) {
-			if ((dolby_dap_params_modified[i] == 0) ||
-			    ((commit) &&
-			     ((dolby_dap_params_modified[i] & 0x00010000) &&
-			     ((dolby_dap_params_modified[i] & 0x0000FFFF) <= 1))
-			    ))
-				continue;
-			dolby_dap_params_modified[i] = 0x00010001;
-		}
-	}
-	kfree(params_value);
-	return 0;
-}
-
-int msm_dolby_dap_init(int port_id, int copp_idx, int channels,
-		       bool is_custom_stereo_on)
-{
-	int ret = 0;
-	int index = adm_validate_and_get_port_index(port_id);
-
-	if (index < 0) {
-		pr_err("%s: Invalid port idx %d port_id %#x\n", __func__, index,
-			port_id);
-		return -EINVAL;
-	}
-	if ((port_id != DOLBY_INVALID_PORT_ID) &&
-	    (port_id & dolby_dap_params_states.port_ids_dolby_can_be_enabled)) {
-		dolby_dap_params_states.port_id[index] = port_id;
-		dolby_dap_params_states.copp_idx[index] = copp_idx;
-		dolby_dap_params_states.port_open_count++;
-		if (dolby_dap_params_states.auto_endp) {
-			ret = msm_dolby_dap_send_end_point(port_id, copp_idx);
-			if (ret) {
-				pr_err("%s: err sending endppoint\n", __func__);
-				return ret;
-			}
-		}
-		if (dolby_dap_params_states.use_cache) {
-			ret = msm_dolby_dap_send_cached_params(port_id,
-							       copp_idx, 0);
-			if (ret) {
-				pr_err("%s: err sending cached params\n",
-					__func__);
-				return ret;
-			}
-		}
-		if (dolby_dap_params_states.enddep_params) {
-			msm_dolby_dap_send_enddep_params(port_id, copp_idx,
-							 channels);
-			if (ret) {
-				pr_err("%s: err sending endp dependent params\n",
-					__func__);
-				return ret;
-			}
-		}
-		if (is_custom_stereo_on)
-			dolby_dap_set_custom_stereo_onoff(port_id, copp_idx,
-							  is_custom_stereo_on);
-	}
-	return ret;
-}
-
-void msm_dolby_dap_deinit(int port_id)
-{
-	int index = adm_validate_and_get_port_index(port_id);
-
-	if (index < 0) {
-		pr_err("%s: Invalid port idx %d port_id %#x\n", __func__, index,
-			port_id);
-		return;
-	}
-	dolby_dap_params_states.port_open_count--;
-	if ((dolby_dap_params_states.port_id[index] == port_id) &&
-		(!dolby_dap_params_states.port_open_count)) {
-		dolby_dap_params_states.port_id[index] = DOLBY_INVALID_PORT_ID;
-		dolby_dap_params_states.copp_idx[index] = -1;
-	}
-}
-
-static int msm_dolby_dap_set_vspe_vdhe(int port_id, int copp_idx,
-				       bool is_custom_stereo_enabled)
-{
-	char *params_value;
-	int *update_params_value, rc = 0;
-	uint32_t index_offset, i, j;
-	uint32_t params_length = (TOTAL_LENGTH_DOLBY_PARAM +
-				2 * DOLBY_PARAM_PAYLOAD_SIZE) *
-				sizeof(uint32_t);
-	if (port_id == DOLBY_INVALID_PORT_ID) {
-		pr_err("%s: Not a Dolby topology. Do not set custom stereo mixing\n",
-			__func__);
-		return -EINVAL;
-	}
-	params_value = kzalloc(params_length, GFP_KERNEL);
-	if (!params_value)
-		return -ENOMEM;
-
-	update_params_value = (int *)params_value;
-	params_length = 0;
-	/* for VDHE and VSPE DAP params at index 0 and 1 in table */
-	for (i = 0; i < 2; i++) {
-		*update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
-		*update_params_value++ = dolby_dap_params_id[i];
-		*update_params_value++ = dolby_dap_params_length[i] *
-					sizeof(uint32_t);
-		index_offset = dolby_dap_params_offset[i];
-		for (j = 0; j < dolby_dap_params_length[i]; j++) {
-			if (is_custom_stereo_enabled)
-				*update_params_value++ = 0;
-			else
-				*update_params_value++ =
-					dolby_dap_params_value[index_offset+j];
-		}
-		params_length += (DOLBY_PARAM_PAYLOAD_SIZE +
-				dolby_dap_params_length[i]) * sizeof(uint32_t);
-	}
-	pr_debug("%s, valid param length: %d", __func__, params_length);
-	if (params_length) {
-		rc = adm_dolby_dap_send_params(port_id, copp_idx, params_value,
-					       params_length);
-		if (rc) {
-			pr_err("%s: send vdhe/vspe params failed with rc=%d\n",
-				__func__, rc);
-			kfree(params_value);
-			return -EINVAL;
-		}
-	}
-	kfree(params_value);
-	return 0;
-}
-
-int dolby_dap_set_custom_stereo_onoff(int port_id, int copp_idx,
-				      bool is_custom_stereo_enabled)
-{
-	char *params_value;
-	int *update_params_value, rc = 0;
-	uint32_t params_length = (TOTAL_LENGTH_DOLBY_PARAM +
-				DOLBY_PARAM_PAYLOAD_SIZE) *
-				sizeof(uint32_t);
-	if (port_id == DOLBY_INVALID_PORT_ID)
-		return -EINVAL;
-
-	msm_dolby_dap_set_vspe_vdhe(port_id, copp_idx,
-				    is_custom_stereo_enabled);
-	params_value = kzalloc(params_length, GFP_KERNEL);
-	if (!params_value) {
-		pr_err("%s, params memory alloc failed\n", __func__);
-		return -ENOMEM;
-	}
-	update_params_value = (int *)params_value;
-	params_length = 0;
-	*update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
-	*update_params_value++ = DOLBY_ENABLE_CUSTOM_STEREO;
-	*update_params_value++ = sizeof(uint32_t);
-	if (is_custom_stereo_enabled)
-		*update_params_value++ = 1;
-	else
-		*update_params_value++ = 0;
-	params_length += (DOLBY_PARAM_PAYLOAD_SIZE + 1) * sizeof(uint32_t);
-	pr_debug("%s, valid param length: %d", __func__, params_length);
-	if (params_length) {
-		rc = adm_dolby_dap_send_params(port_id, copp_idx, params_value,
-					       params_length);
-		if (rc) {
-			pr_err("%s: setting ds1 custom stereo param failed with rc=%d\n",
-				__func__, rc);
-			kfree(params_value);
-			return -EINVAL;
-		}
-	}
-	kfree(params_value);
-	return 0;
-}
-
-static int msm_dolby_dap_map_device_to_port_id(int device)
-{
-	int port_id = SLIMBUS_0_RX;
-
-	device = DEVICE_OUT_ALL;
-	/*update the device when single stream to multiple device is handled*/
-	if (device == DEVICE_OUT_ALL) {
-		port_id = PRIMARY_I2S_RX | SLIMBUS_0_RX | HDMI_RX |
-				INT_BT_SCO_RX | INT_FM_RX |
-				RT_PROXY_PORT_001_RX |
-				AFE_PORT_ID_PRIMARY_PCM_RX |
-				MI2S_RX | SECONDARY_I2S_RX |
-				SLIMBUS_1_RX | SLIMBUS_4_RX | SLIMBUS_3_RX |
-				AFE_PORT_ID_SECONDARY_MI2S_RX;
-	} else {
-		/* update port_id based on the device */
-	}
-	return port_id;
-}
-
-int msm_dolby_dap_param_to_set_control_get(struct snd_kcontrol *kcontrol,
-					   struct snd_ctl_elem_value *ucontrol)
-{
-	/* not used while setting the parameters */
-	return 0;
-}
-
-int msm_dolby_dap_param_to_set_control_put(struct snd_kcontrol *kcontrol,
-					   struct snd_ctl_elem_value *ucontrol)
-{
-	int rc = 0, port_id, copp_idx;
-	uint32_t idx, j;
-	uint32_t device = ucontrol->value.integer.value[0];
-	uint32_t param_id = ucontrol->value.integer.value[1];
-	uint32_t offset = ucontrol->value.integer.value[2];
-	uint32_t length = ucontrol->value.integer.value[3];
-
-	dolby_dap_params_states.port_ids_dolby_can_be_enabled =
-				msm_dolby_dap_map_device_to_port_id(device);
-	for (idx = 0; idx < ALL_DOLBY_PARAMS; idx++) {
-		/*paramid from user space*/
-		if (param_id == dolby_dap_params_id[idx])
-			break;
-	}
-	if (idx > ALL_DOLBY_PARAMS-1) {
-		pr_err("%s: invalid param id 0x%x to set\n", __func__,
-			param_id);
-		return -EINVAL;
-	}
-	switch (idx) {
-		case DOLBY_COMMIT_ALL_IDX: {
-			/* COMIIT ALL: Send all parameters to DSP */
-			pr_debug("%s: COMMIT_ALL recvd\n", __func__);
-			for (idx = 0; idx < AFE_MAX_PORTS; idx++) {
-				port_id = dolby_dap_params_states.port_id[idx];
-				copp_idx =
-					dolby_dap_params_states.copp_idx[idx];
-				if ((copp_idx > 0) &&
-				    (copp_idx < MAX_COPPS_PER_PORT) &&
-				    (port_id != DOLBY_INVALID_PORT_ID))
-					rc |= msm_dolby_dap_send_cached_params(
-								      port_id,
-								      copp_idx,
-								      0);
-			}
-		}
-		break;
-		case DOLBY_COMMIT_IDX: {
-			pr_debug("%s: COMMIT recvd\n", __func__);
-			/* COMMIT: Send only modified parameters to DSP */
-			for (idx = 0; idx < AFE_MAX_PORTS; idx++) {
-				port_id = dolby_dap_params_states.port_id[idx];
-				copp_idx =
-					dolby_dap_params_states.copp_idx[idx];
-				if ((copp_idx > 0) &&
-				    (copp_idx < MAX_COPPS_PER_PORT) &&
-				    (port_id == DOLBY_INVALID_PORT_ID))
-					rc |= msm_dolby_dap_send_cached_params(
-								      port_id,
-								      copp_idx,
-								      1);
-			}
-		}
-		break;
-		case DOLBY_USE_CACHE_IDX: {
-			pr_debug("%s: USE CACHE recvd val: %ld\n", __func__,
-				ucontrol->value.integer.value[4]);
-			dolby_dap_params_states.use_cache =
-				ucontrol->value.integer.value[4];
-		}
-		break;
-		case DOLBY_AUTO_ENDP_IDX: {
-			pr_debug("%s: AUTO_ENDP recvd val: %ld\n", __func__,
-				ucontrol->value.integer.value[4]);
-			dolby_dap_params_states.auto_endp =
-				ucontrol->value.integer.value[4];
-		}
-		break;
-		case DOLBY_AUTO_ENDDEP_IDX: {
-			pr_debug("%s: USE_ENDDEP_PARAMS recvd val: %ld\n",
-				__func__, ucontrol->value.integer.value[4]);
-			dolby_dap_params_states.enddep_params =
-				ucontrol->value.integer.value[4];
-		}
-		break;
-		default: {
-			/* cache the parameters */
-			dolby_dap_params_modified[idx] += 1;
-			dolby_dap_params_length[idx] = length;
-			pr_debug("%s: param recvd deviceId=0x%x paramId=0x%x offset=%d length=%d\n",
-				__func__, device, param_id, offset, length);
-			for (j = 0; j < length; j++) {
-				dolby_dap_params_value[
-					dolby_dap_params_offset[idx] +
-					offset + j]
-				= ucontrol->value.integer.value[4+j];
-				pr_debug("value[%d]: %ld\n", j,
-					ucontrol->value.integer.value[4+j]);
-			}
-		}
-	}
-
-	return rc;
-}
-
-int msm_dolby_dap_param_to_get_control_get(struct snd_kcontrol *kcontrol,
-					   struct snd_ctl_elem_value *ucontrol)
-{
-	int rc = 0, i, index;
-	char *params_value;
-	int *update_params_value;
-	uint32_t params_length = DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM *
-					sizeof(uint32_t);
-	uint32_t param_payload_len =
-			DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
-	int port_id = dolby_dap_params_get.port_id, copp_idx;
-
-	if (port_id == DOLBY_INVALID_PORT_ID) {
-		pr_err("%s, port_id not set, do not query ADM\n", __func__);
-		return -EINVAL;
-	}
-	index = adm_validate_and_get_port_index(port_id);
-	if (index < 0) {
-		pr_err("%s: Invalid port idx %d port_id %#x\n", __func__, index,
-			port_id);
-		return -EINVAL;
-	}
-	copp_idx = dolby_dap_params_states.copp_idx[index];
-	if ((copp_idx < 0) || (copp_idx >= MAX_COPPS_PER_PORT)) {
-		pr_debug("%s: get params called before copp open.copp_idx:%d\n",
-			 __func__, copp_idx);
-		return -EINVAL;
-	}
-	params_value = kzalloc(params_length, GFP_KERNEL);
-	if (!params_value)
-		return -ENOMEM;
-
-	if (dolby_dap_params_get.param_id == DOLBY_PARAM_ID_VER) {
-		rc = adm_get_params(port_id, copp_idx,
-				    DOLBY_BUNDLE_MODULE_ID, DOLBY_PARAM_ID_VER,
-				    params_length + param_payload_len,
-				    params_value);
-	} else {
-		for (i = 0; i < MAX_DOLBY_PARAMS; i++)
-			if (dolby_dap_params_id[i] ==
-				dolby_dap_params_get.param_id)
-				break;
-		if (i > MAX_DOLBY_PARAMS-1) {
-			pr_err("%s: invalid param id to set", __func__);
-			rc = -EINVAL;
-		} else {
-			params_length = (dolby_dap_params_length[i] +
-						DOLBY_PARAM_PAYLOAD_SIZE) *
-						sizeof(uint32_t);
-			rc = adm_get_params(port_id, copp_idx,
-					    DOLBY_BUNDLE_MODULE_ID,
-					    dolby_dap_params_id[i],
-					    params_length + param_payload_len,
-					    params_value);
-		}
-	}
-	if (rc) {
-		pr_err("%s: get parameters failed rc:%d\n", __func__, rc);
-		kfree(params_value);
-		return -EINVAL;
-	}
-	update_params_value = (int *)params_value;
-	ucontrol->value.integer.value[0] = dolby_dap_params_get.device_id;
-	ucontrol->value.integer.value[1] = dolby_dap_params_get.param_id;
-	ucontrol->value.integer.value[2] = dolby_dap_params_get.offset;
-	ucontrol->value.integer.value[3] = dolby_dap_params_get.length;
-
-	pr_debug("%s: FROM DSP value[0] 0x%x value[1] %d value[2] 0x%x\n",
-			__func__, update_params_value[0],
-			update_params_value[1], update_params_value[2]);
-	for (i = 0; i < dolby_dap_params_get.length; i++) {
-		ucontrol->value.integer.value[DOLBY_PARAM_PAYLOAD_SIZE+i] =
-			update_params_value[i];
-		pr_debug("value[%d]:%d\n", i, update_params_value[i]);
-	}
-	pr_debug("%s: Returning param_id=0x%x offset=%d length=%d\n",
-			__func__, dolby_dap_params_get.param_id,
-			dolby_dap_params_get.offset,
-			dolby_dap_params_get.length);
-	kfree(params_value);
-	return 0;
-}
-
-int msm_dolby_dap_param_to_get_control_put(struct snd_kcontrol *kcontrol,
-					   struct snd_ctl_elem_value *ucontrol)
-{
-	int port_id, idx, copp_idx;
-
-	dolby_dap_params_get.device_id = ucontrol->value.integer.value[0];
-	port_id = msm_dolby_dap_map_device_to_port_id(
-						dolby_dap_params_get.device_id);
-	for (idx = 0; idx < AFE_MAX_PORTS; idx++) {
-		port_id = dolby_dap_params_states.port_id[idx];
-		copp_idx = dolby_dap_params_states.copp_idx[idx];
-		if ((copp_idx < 0) ||
-		    (copp_idx >= MAX_COPPS_PER_PORT) ||
-		    (port_id == DOLBY_INVALID_PORT_ID))
-			continue;
-		else
-			break;
-	}
-	if (idx == AFE_MAX_PORTS)
-		port_id = SLIMBUS_0_RX;
-	dolby_dap_params_get.port_id = port_id;
-	dolby_dap_params_get.param_id = ucontrol->value.integer.value[1];
-	dolby_dap_params_get.offset = ucontrol->value.integer.value[2];
-	dolby_dap_params_get.length = ucontrol->value.integer.value[3];
-	pr_debug("%s: param_id=0x%x offset=%d length=%d\n", __func__,
-		dolby_dap_params_get.param_id, dolby_dap_params_get.offset,
-		dolby_dap_params_get.length);
-	return 0;
-}
-
-int msm_dolby_dap_param_visualizer_control_get(struct snd_kcontrol *kcontrol,
-					   struct snd_ctl_elem_value *ucontrol)
-{
-	uint32_t length = dolby_dap_params_value[DOLBY_PARAM_VCNB_OFFSET];
-	char *visualizer_data;
-	int i, rc;
-	int *update_visualizer_data;
-	uint32_t offset, params_length =
-		(2*length + DOLBY_VIS_PARAM_HEADER_SIZE)*sizeof(uint32_t);
-	uint32_t param_payload_len =
-		DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
-	int port_id, copp_idx, idx;
-
-	for (idx = 0; idx < AFE_MAX_PORTS; idx++) {
-		port_id = dolby_dap_params_states.port_id[idx];
-		copp_idx = dolby_dap_params_states.copp_idx[idx];
-		if ((copp_idx < 0) ||
-		    (copp_idx >= MAX_COPPS_PER_PORT) ||
-		    (port_id == DOLBY_INVALID_PORT_ID))
-			continue;
-		else
-			break;
-	}
-	if (idx == AFE_MAX_PORTS) {
-		pr_debug("%s, port_id not set, returning error", __func__);
-		ucontrol->value.integer.value[0] = 0;
-		return -EINVAL;
-	}
-	visualizer_data = kzalloc(params_length, GFP_KERNEL);
-	if (!visualizer_data)
-		return -ENOMEM;
-
-	offset = 0;
-	params_length = length * sizeof(uint32_t);
-	rc = adm_get_params(port_id, copp_idx, DOLBY_BUNDLE_MODULE_ID,
-			    DOLBY_PARAM_ID_VCBG,
-			    params_length + param_payload_len,
-			    visualizer_data + offset);
-	if (rc) {
-		pr_err("%s: get parameters failed\n", __func__);
-		kfree(visualizer_data);
-		return -EINVAL;
-	}
-
-	offset = length * sizeof(uint32_t);
-	rc = adm_get_params(port_id, copp_idx, DOLBY_BUNDLE_MODULE_ID,
-			    DOLBY_PARAM_ID_VCBE,
-			    params_length + param_payload_len,
-			    visualizer_data + offset);
-	if (rc) {
-		pr_err("%s: get parameters failed\n", __func__);
-		kfree(visualizer_data);
-		return -EINVAL;
-	}
-
-	ucontrol->value.integer.value[0] = 2*length;
-	pr_debug("%s: visualizer data length %ld\n", __func__,
-			ucontrol->value.integer.value[0]);
-	update_visualizer_data = (int *)visualizer_data;
-	for (i = 0; i < 2*length; i++) {
-		ucontrol->value.integer.value[1+i] = update_visualizer_data[i];
-		pr_debug("value[%d] %d\n", i, update_visualizer_data[i]);
-	}
-	kfree(visualizer_data);
-	return 0;
-}
-
-int msm_dolby_dap_param_visualizer_control_put(struct snd_kcontrol *kcontrol,
-					   struct snd_ctl_elem_value *ucontrol)
-{
-	/* not used while getting the visualizer data */
-	return 0;
-}
-
-int msm_dolby_dap_endpoint_control_get(struct snd_kcontrol *kcontrol,
-				       struct snd_ctl_elem_value *ucontrol)
-{
-	/* not used while setting the endpoint */
-	return 0;
-}
-
-int msm_dolby_dap_endpoint_control_put(struct snd_kcontrol *kcontrol,
-				       struct snd_ctl_elem_value *ucontrol)
-{
-	int device = ucontrol->value.integer.value[0];
-
-	dolby_dap_params_states.device = device;
-	return 0;
-}
-
-int msm_dolby_dap_security_control_get(struct snd_kcontrol *kcontrol,
-				       struct snd_ctl_elem_value *ucontrol)
-{
-	/* not used while setting the manfr id*/
-	return 0;
-}
-
-int msm_dolby_dap_security_control_put(struct snd_kcontrol *kcontrol,
-				       struct snd_ctl_elem_value *ucontrol)
-{
-	int manufacturer_id = ucontrol->value.integer.value[0];
-
-	core_set_dolby_manufacturer_id(manufacturer_id);
-	return 0;
-}
-
-int msm_dolby_dap_license_control_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	ucontrol->value.integer.value[0] =
-			core_get_license_status(DOLBY_DS1_LICENSE_ID);
-	return 0;
-}
-
-int msm_dolby_dap_license_control_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	return core_set_license(ucontrol->value.integer.value[0],
-						DOLBY_DS1_LICENSE_ID);
-}
-
-static const struct snd_kcontrol_new dolby_license_controls[] = {
-	SOC_SINGLE_MULTI_EXT("DS1 License", SND_SOC_NOPM, 0,
-	0xFFFFFFFF, 0, 1, msm_dolby_dap_license_control_get,
-	msm_dolby_dap_license_control_put),
-};
-
-static const struct snd_kcontrol_new dolby_security_controls[] = {
-	SOC_SINGLE_MULTI_EXT("DS1 Security", SND_SOC_NOPM, 0,
-	0xFFFFFFFF, 0, 1, msm_dolby_dap_security_control_get,
-	msm_dolby_dap_security_control_put),
-};
-
-static const struct snd_kcontrol_new dolby_dap_param_to_set_controls[] = {
-	SOC_SINGLE_MULTI_EXT("DS1 DAP Set Param", SND_SOC_NOPM, 0, 0xFFFFFFFF,
-	0, 128, msm_dolby_dap_param_to_set_control_get,
-	msm_dolby_dap_param_to_set_control_put),
-};
-
-static const struct snd_kcontrol_new dolby_dap_param_to_get_controls[] = {
-	SOC_SINGLE_MULTI_EXT("DS1 DAP Get Param", SND_SOC_NOPM, 0, 0xFFFFFFFF,
-	0, 128, msm_dolby_dap_param_to_get_control_get,
-	msm_dolby_dap_param_to_get_control_put),
-};
-
-static const struct snd_kcontrol_new dolby_dap_param_visualizer_controls[] = {
-	SOC_SINGLE_MULTI_EXT("DS1 DAP Get Visualizer", SND_SOC_NOPM, 0,
-	0xFFFFFFFF, 0, 41, msm_dolby_dap_param_visualizer_control_get,
-	msm_dolby_dap_param_visualizer_control_put),
-};
-
-static const struct snd_kcontrol_new dolby_dap_param_end_point_controls[] = {
-	SOC_SINGLE_MULTI_EXT("DS1 DAP Endpoint", SND_SOC_NOPM, 0,
-	0xFFFFFFFF, 0, 1, msm_dolby_dap_endpoint_control_get,
-	msm_dolby_dap_endpoint_control_put),
-};
-
-void msm_dolby_dap_add_controls(struct snd_soc_platform *platform)
-{
-	snd_soc_add_platform_controls(platform,
-				dolby_license_controls,
-			ARRAY_SIZE(dolby_license_controls));
-
-	snd_soc_add_platform_controls(platform,
-				dolby_security_controls,
-			ARRAY_SIZE(dolby_security_controls));
-
-	snd_soc_add_platform_controls(platform,
-				dolby_dap_param_to_set_controls,
-			ARRAY_SIZE(dolby_dap_param_to_set_controls));
-
-	snd_soc_add_platform_controls(platform,
-				dolby_dap_param_to_get_controls,
-			ARRAY_SIZE(dolby_dap_param_to_get_controls));
-
-	snd_soc_add_platform_controls(platform,
-				dolby_dap_param_visualizer_controls,
-			ARRAY_SIZE(dolby_dap_param_visualizer_controls));
-
-	snd_soc_add_platform_controls(platform,
-				dolby_dap_param_end_point_controls,
-			ARRAY_SIZE(dolby_dap_param_end_point_controls));
-}
diff --git a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c
index 0ba1661..b7e69fa 100644
--- a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c
@@ -198,7 +198,8 @@
 	uint32_t param_payload_len = PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
 	int rc = 0;
 
-	update_params_value = kzalloc(params_length, GFP_KERNEL);
+	update_params_value = kzalloc(params_length + param_payload_len,
+				      GFP_KERNEL);
 	if (!update_params_value)
 		goto end;
 
@@ -999,6 +1000,20 @@
 							copp_idx, rc);
 					}
 				}
+				/* Turn on qti modules */
+				for (j = 1; j < mod_list[0]; j++) {
+					if (!msm_ds2_dap_can_enable_module(
+						mod_list[j]) ||
+						mod_list[j] ==
+						DS2_MODULE_ID)
+						continue;
+					pr_debug("%s: param enable %d\n",
+						__func__, mod_list[j]);
+					adm_param_enable(port_id, copp_idx,
+							 mod_list[j],
+							 MODULE_ENABLE);
+				}
+
 				/* Add adm api to resend calibration on port */
 				rc = msm_ds2_dap_send_cal_data(i);
 				if (rc < 0) {
@@ -1642,6 +1657,7 @@
 		ret = 0;
 		dolby_data->length = 0;
 		pr_err("%s Incorrect VCNB length", __func__);
+		return -EINVAL;
 	}
 
 	params_length = (2*length + DOLBY_VIS_PARAM_HEADER_SIZE) *
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index d19c346..37dd31f 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-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
@@ -35,7 +35,7 @@
 
 #define CAPTURE_MIN_NUM_PERIODS     2
 #define CAPTURE_MAX_NUM_PERIODS     8
-#define CAPTURE_MAX_PERIOD_SIZE     4096
+#define CAPTURE_MAX_PERIOD_SIZE     61440
 #define CAPTURE_MIN_PERIOD_SIZE     320
 #define LISTEN_MAX_STATUS_PAYLOAD_SIZE 256
 
@@ -47,12 +47,14 @@
 				SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				SNDRV_PCM_INFO_INTERLEAVED |
 				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
-	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
-	.rates =                SNDRV_PCM_RATE_16000,
+	.formats =              (SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S24_LE),
+	.rates =		(SNDRV_PCM_RATE_16000 |
+				SNDRV_PCM_RATE_48000),
 	.rate_min =             16000,
-	.rate_max =             16000,
+	.rate_max =             48000,
 	.channels_min =         1,
-	.channels_max =         1,
+	.channels_max =         4,
 	.buffer_bytes_max =     CAPTURE_MAX_NUM_PERIODS *
 				CAPTURE_MAX_PERIOD_SIZE,
 	.period_bytes_min =	CAPTURE_MIN_PERIOD_SIZE,
@@ -64,7 +66,7 @@
 
 /* Conventional and unconventional sample rate supported */
 static unsigned int supported_sample_rates[] = {
-	16000,
+	16000, 48000,
 };
 
 static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
@@ -76,7 +78,7 @@
 struct lsm_priv {
 	struct snd_pcm_substream *substream;
 	struct lsm_client *lsm_client;
-	struct snd_lsm_event_status *event_status;
+	struct snd_lsm_event_status_v3 *event_status;
 	spinlock_t event_lock;
 	wait_queue_head_t event_wait;
 	unsigned long event_avail;
@@ -84,10 +86,16 @@
 	atomic_t buf_count;
 	atomic_t read_abort;
 	wait_queue_head_t period_wait;
+	struct mutex lsm_api_lock;
 	int appl_cnt;
 	int dma_write;
 };
 
+enum { /* lsm session states */
+	IDLE = 0,
+	RUNNING,
+};
+
 static int msm_lsm_queue_lab_buffer(struct lsm_priv *prtd, int i)
 {
 	int rc = 0;
@@ -193,10 +201,12 @@
 	struct lsm_priv *prtd = priv;
 	struct snd_pcm_substream *substream = prtd->substream;
 	struct snd_soc_pcm_runtime *rtd;
-	struct snd_lsm_event_status *temp;
+	struct snd_lsm_event_status_v3 *temp;
 	uint16_t status = 0;
 	uint16_t payload_size = 0;
 	uint16_t index = 0;
+	uint32_t event_ts_lsw = 0;
+	uint32_t event_ts_msw = 0;
 
 	if (!substream || !substream->private_data) {
 		pr_err("%s: Invalid %s\n", __func__,
@@ -271,25 +281,45 @@
 			"%s: event detect status = %d payload size = %d\n",
 			__func__, status, payload_size);
 		break;
+
+	case LSM_SESSION_EVENT_DETECTION_STATUS_V3:
+		event_ts_lsw = ((uint32_t *)payload)[0];
+		event_ts_msw = ((uint32_t *)payload)[1];
+		status = (uint16_t)((uint8_t *)payload)[8];
+		payload_size = (uint16_t)((uint8_t *)payload)[9];
+		index = 10;
+		dev_dbg(rtd->dev,
+			"%s: ts_msw = %u, ts_lsw = %u, event detect status = %d payload size = %d\n",
+			__func__, event_ts_msw, event_ts_lsw, status,
+			payload_size);
+		break;
+
 	default:
 		break;
 	}
 
 	if (opcode == LSM_SESSION_EVENT_DETECTION_STATUS ||
-		opcode == LSM_SESSION_EVENT_DETECTION_STATUS_V2) {
+		opcode == LSM_SESSION_EVENT_DETECTION_STATUS_V2 ||
+		opcode == LSM_SESSION_EVENT_DETECTION_STATUS_V3) {
 		spin_lock_irqsave(&prtd->event_lock, flags);
 		temp = krealloc(prtd->event_status,
-				sizeof(struct snd_lsm_event_status) +
+				sizeof(struct snd_lsm_event_status_v3) +
 				payload_size, GFP_ATOMIC);
 		if (!temp) {
 			dev_err(rtd->dev, "%s: no memory for event status\n",
 				__func__);
 			return;
 		}
-
+		/*
+		 * event status timestamp will be non-zero and valid if
+		 * opcode is LSM_SESSION_EVENT_DETECTION_STATUS_V3
+		 */
 		prtd->event_status = temp;
+		prtd->event_status->timestamp_lsw = event_ts_lsw;
+		prtd->event_status->timestamp_msw = event_ts_msw;
 		prtd->event_status->status = status;
 		prtd->event_status->payload_size = payload_size;
+
 		if (likely(prtd->event_status)) {
 			memcpy(prtd->event_status->payload,
 			       &((uint8_t *)payload)[index],
@@ -641,6 +671,54 @@
 	return rc;
 }
 
+static int msm_lsm_set_poll_enable(struct snd_pcm_substream *substream,
+		struct lsm_params_info *p_info)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct lsm_priv *prtd = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_lsm_poll_enable poll_enable;
+	int rc = 0;
+
+	if (p_info->param_size != sizeof(poll_enable)) {
+		dev_err(rtd->dev,
+			"%s: Invalid param_size %d\n",
+			__func__, p_info->param_size);
+		rc = -EINVAL;
+		goto done;
+	}
+
+	if (copy_from_user(&poll_enable, p_info->param_data,
+			   sizeof(poll_enable))) {
+		dev_err(rtd->dev,
+			"%s: copy_from_user failed, size = %zd\n",
+			__func__, sizeof(poll_enable));
+		rc = -EFAULT;
+		goto done;
+	}
+
+	if (prtd->lsm_client->poll_enable == poll_enable.poll_en) {
+		dev_dbg(rtd->dev,
+			"%s: Polling for session %d already %s\n",
+			__func__, prtd->lsm_client->session,
+			(poll_enable.poll_en ? "enabled" : "disabled"));
+		rc = 0;
+		goto done;
+	}
+
+	rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
+				 &poll_enable, LSM_POLLING_ENABLE);
+	if (!rc) {
+		prtd->lsm_client->poll_enable = poll_enable.poll_en;
+	} else {
+		dev_err(rtd->dev,
+			"%s: Failed to set poll enable, err = %d\n",
+			__func__, rc);
+	}
+done:
+	return rc;
+}
+
 static int msm_lsm_process_params(struct snd_pcm_substream *substream,
 		struct snd_lsm_module_params *p_data,
 		void *params)
@@ -681,6 +759,9 @@
 		case LSM_CUSTOM_PARAMS:
 			rc = msm_lsm_set_custom(substream, p_info);
 			break;
+		case LSM_POLLING_ENABLE:
+			rc = msm_lsm_set_poll_enable(substream, p_info);
+			break;
 		default:
 			dev_err(rtd->dev,
 				"%s: Invalid param_type %d\n",
@@ -710,10 +791,8 @@
 	struct snd_lsm_session_data session_data;
 	int rc = 0;
 	int xchg = 0;
-	u32 size = 0;
 	struct snd_pcm_runtime *runtime;
 	struct lsm_priv *prtd;
-	struct snd_lsm_event_status *user = arg;
 	struct snd_lsm_detection_params det_params;
 	uint8_t *confidence_level = NULL;
 
@@ -730,8 +809,13 @@
 	switch (cmd) {
 	case SNDRV_LSM_SET_SESSION_DATA:
 		dev_dbg(rtd->dev, "%s: set session data\n", __func__);
-		memcpy(&session_data, arg,
-		       sizeof(struct snd_lsm_session_data));
+		if (copy_from_user(&session_data, arg,
+				   sizeof(session_data))) {
+			dev_err(rtd->dev, "%s: %s: copy_from_user failed\n",
+				__func__, "LSM_SET_SESSION_DATA");
+			return -EFAULT;
+		}
+
 		if (session_data.app_id != LSM_VOICE_WAKEUP_APP_ID_V2) {
 			dev_err(rtd->dev,
 				"%s:Invalid App id %d for Listen client\n",
@@ -820,13 +904,6 @@
 		break;
 
 	case SNDRV_LSM_SET_PARAMS:
-		if (!arg) {
-			dev_err(rtd->dev,
-				"%s: %s Invalid argument\n",
-				__func__, "SNDRV_LSM_SET_PARAMS");
-			return -EINVAL;
-		}
-
 		dev_dbg(rtd->dev, "%s: set_params\n", __func__);
 		memcpy(&det_params, arg,
 			sizeof(det_params));
@@ -872,21 +949,36 @@
 		break;
 
 	case SNDRV_LSM_EVENT_STATUS:
+	case SNDRV_LSM_EVENT_STATUS_V3: {
+		uint32_t ts_lsw, ts_msw;
+		uint16_t status = 0, payload_size = 0;
+
 		dev_dbg(rtd->dev, "%s: Get event status\n", __func__);
 		atomic_set(&prtd->event_wait_stop, 0);
+
+		/*
+		 * Release the api lock before wait to allow
+		 * other IOCTLs to be invoked while waiting
+		 * for event
+		 */
+		mutex_unlock(&prtd->lsm_api_lock);
 		rc = wait_event_freezable(prtd->event_wait,
 				(cmpxchg(&prtd->event_avail, 1, 0) ||
 				 (xchg = atomic_cmpxchg(&prtd->event_wait_stop,
 							1, 0))));
+		mutex_lock(&prtd->lsm_api_lock);
 		dev_dbg(rtd->dev, "%s: wait_event_freezable %d event_wait_stop %d\n",
 			 __func__, rc, xchg);
 		if (!rc && !xchg) {
 			dev_dbg(rtd->dev, "%s: New event available %ld\n",
 				__func__, prtd->event_avail);
 			spin_lock_irqsave(&prtd->event_lock, flags);
+
 			if (prtd->event_status) {
-				size = sizeof(*(prtd->event_status)) +
-				prtd->event_status->payload_size;
+				payload_size = prtd->event_status->payload_size;
+				ts_lsw = prtd->event_status->timestamp_lsw;
+				ts_msw = prtd->event_status->timestamp_msw;
+				status = prtd->event_status->status;
 				spin_unlock_irqrestore(&prtd->event_lock,
 						       flags);
 			} else {
@@ -898,15 +990,43 @@
 					__func__);
 				break;
 			}
-			if (user->payload_size <
-			    prtd->event_status->payload_size) {
-				dev_dbg(rtd->dev,
-					"%s: provided %d bytes isn't enough, needs %d bytes\n",
-					__func__, user->payload_size,
-					prtd->event_status->payload_size);
-				rc = -ENOMEM;
+
+			if (cmd == SNDRV_LSM_EVENT_STATUS) {
+				struct snd_lsm_event_status *user = arg;
+
+				if (user->payload_size < payload_size) {
+					dev_dbg(rtd->dev,
+						"%s: provided %d bytes isn't enough, needs %d bytes\n",
+						__func__, user->payload_size,
+						payload_size);
+					rc = -ENOMEM;
+				} else {
+					user->status = status;
+					user->payload_size = payload_size;
+					memcpy(user->payload,
+						prtd->event_status->payload,
+						payload_size);
+				}
 			} else {
-				memcpy(user, prtd->event_status, size);
+				struct snd_lsm_event_status_v3 *user_v3 = arg;
+
+				if (user_v3->payload_size < payload_size) {
+					dev_dbg(rtd->dev,
+						"%s: provided %d bytes isn't enough, needs %d bytes\n",
+						__func__, user_v3->payload_size,
+						payload_size);
+					rc = -ENOMEM;
+				} else {
+					user_v3->timestamp_lsw = ts_lsw;
+					user_v3->timestamp_msw = ts_msw;
+					user_v3->status = status;
+					user_v3->payload_size = payload_size;
+					memcpy(user_v3->payload,
+						prtd->event_status->payload,
+						payload_size);
+				}
+			}
+			if (!rc) {
 				if (prtd->lsm_client->lab_enable
 					&& !prtd->lsm_client->lab_started
 					&& prtd->event_status->status ==
@@ -931,6 +1051,7 @@
 			rc = 0;
 		}
 		break;
+	}
 
 	case SNDRV_LSM_ABORT_EVENT:
 		dev_dbg(rtd->dev, "%s: Aborting event status wait\n",
@@ -978,46 +1099,43 @@
 		break;
 	}
 	case SNDRV_LSM_LAB_CONTROL: {
-		u32 *enable = NULL;
+		u32 enable;
 
-		if (!arg) {
-			dev_err(rtd->dev,
-				"%s: Invalid param arg for ioctl %s session %d\n",
-				__func__, "SNDRV_LSM_LAB_CONTROL",
-				prtd->lsm_client->session);
-			rc = -EINVAL;
-			break;
+		if (copy_from_user(&enable, arg, sizeof(enable))) {
+			dev_err(rtd->dev, "%s: %s: copy_frm_user failed\n",
+				__func__, "LSM_LAB_CONTROL");
+			return -EFAULT;
 		}
-		enable = (int *)arg;
+
 		dev_dbg(rtd->dev, "%s: ioctl %s, enable = %d\n",
-			 __func__, "SNDRV_LSM_LAB_CONTROL", *enable);
+			 __func__, "SNDRV_LSM_LAB_CONTROL", enable);
 		if (!prtd->lsm_client->started) {
-			if (prtd->lsm_client->lab_enable == *enable) {
+			if (prtd->lsm_client->lab_enable == enable) {
 				dev_dbg(rtd->dev,
 					"%s: Lab for session %d already %s\n",
 					__func__, prtd->lsm_client->session,
-					((*enable) ? "enabled" : "disabled"));
+					enable ? "enabled" : "disabled");
 				rc = 0;
 				break;
 			}
-			rc = q6lsm_lab_control(prtd->lsm_client, *enable);
+			rc = q6lsm_lab_control(prtd->lsm_client, enable);
 			if (rc) {
 				dev_err(rtd->dev,
 					"%s: ioctl %s failed rc %d to %s lab for session %d\n",
 					__func__, "SNDRV_LAB_CONTROL", rc,
-					((*enable) ? "enable" : "disable"),
+					enable ? "enable" : "disable",
 					prtd->lsm_client->session);
 			} else {
 				rc = msm_lsm_lab_buffer_alloc(prtd,
-					((*enable) ? LAB_BUFFER_ALLOC
-					: LAB_BUFFER_DEALLOC));
+					enable ? LAB_BUFFER_ALLOC
+					: LAB_BUFFER_DEALLOC);
 				if (rc)
 					dev_err(rtd->dev,
 						"%s: msm_lsm_lab_buffer_alloc failed rc %d for %s",
 						__func__, rc,
-					((*enable) ? "ALLOC" : "DEALLOC"));
+						enable ? "ALLOC" : "DEALLOC");
 				if (!rc)
-					prtd->lsm_client->lab_enable = *enable;
+					prtd->lsm_client->lab_enable = enable;
 			}
 		} else {
 			dev_err(rtd->dev, "%s: ioctl %s issued after start",
@@ -1040,6 +1158,43 @@
 			prtd->lsm_client->lab_started = false;
 		}
 	break;
+
+	case SNDRV_LSM_SET_PORT:
+		dev_dbg(rtd->dev, "%s: set LSM port\n", __func__);
+		rc = q6lsm_set_port_connected(prtd->lsm_client);
+		break;
+
+	case SNDRV_LSM_SET_FWK_MODE_CONFIG: {
+		u32 *mode = NULL;
+
+		if (!arg) {
+			dev_err(rtd->dev,
+				"%s: Invalid param arg for ioctl %s session %d\n",
+				__func__, "SNDRV_LSM_SET_FWK_MODE_CONFIG",
+				prtd->lsm_client->session);
+			rc = -EINVAL;
+			break;
+		}
+		mode = (u32 *)arg;
+		if (prtd->lsm_client->event_mode == *mode) {
+			dev_dbg(rtd->dev,
+				"%s: mode for %d already set to %d\n",
+				__func__, prtd->lsm_client->session, *mode);
+			rc = 0;
+		} else {
+			dev_dbg(rtd->dev, "%s: Event mode = %d\n",
+				 __func__, *mode);
+			rc = q6lsm_set_fwk_mode_cfg(prtd->lsm_client, *mode);
+			if (!rc)
+				prtd->lsm_client->event_mode = *mode;
+			else
+				dev_err(rtd->dev,
+					"%s: set event mode failed %d\n",
+					__func__, rc);
+		}
+		break;
+	}
+
 	default:
 		dev_dbg(rtd->dev,
 			"%s: Falling into default snd_lib_ioctl cmd 0x%x\n",
@@ -1058,12 +1213,21 @@
 	return rc;
 }
 #ifdef CONFIG_COMPAT
+
 struct snd_lsm_event_status32 {
 	u16 status;
 	u16 payload_size;
 	u8 payload[0];
 };
 
+struct snd_lsm_event_status_v3_32 {
+	u32 timestamp_lsw;
+	u32 timestamp_msw;
+	u16 status;
+	u16 payload_size;
+	u8 payload[0];
+};
+
 struct snd_lsm_sound_model_v2_32 {
 	compat_uptr_t data;
 	compat_uptr_t confidence_level;
@@ -1085,7 +1249,7 @@
 	u32 param_id;
 	u32 param_size;
 	compat_uptr_t param_data;
-	enum LSM_PARAM_TYPE param_type;
+	uint32_t param_type;
 };
 
 struct snd_lsm_module_params_32 {
@@ -1095,14 +1259,14 @@
 };
 
 enum {
-	SNDRV_LSM_EVENT_STATUS32 =
-		_IOW('U', 0x02, struct snd_lsm_event_status32),
 	SNDRV_LSM_REG_SND_MODEL_V2_32 =
 		_IOW('U', 0x07, struct snd_lsm_sound_model_v2_32),
 	SNDRV_LSM_SET_PARAMS_32 =
 		_IOW('U', 0x0A, struct snd_lsm_detection_params_32),
 	SNDRV_LSM_SET_MODULE_PARAMS_32 =
 		_IOW('U', 0x0B, struct snd_lsm_module_params_32),
+	SNDRV_LSM_EVENT_STATUS_V3_32 =
+		_IOW('U', 0x0F, struct snd_lsm_event_status_v3_32),
 };
 
 static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
@@ -1126,15 +1290,18 @@
 	rtd = substream->private_data;
 	prtd = runtime->private_data;
 
+	mutex_lock(&prtd->lsm_api_lock);
+
 	switch (cmd) {
-	case SNDRV_LSM_EVENT_STATUS32: {
-		struct snd_lsm_event_status32 userarg32, *user32 = NULL;
-		struct snd_lsm_event_status *user = NULL;
+	case SNDRV_LSM_EVENT_STATUS: {
+		struct snd_lsm_event_status *user = NULL, userarg32;
+		struct snd_lsm_event_status *user32 = NULL;
 
 		if (copy_from_user(&userarg32, arg, sizeof(userarg32))) {
 			dev_err(rtd->dev, "%s: err copyuser ioctl %s\n",
-				__func__, "SNDRV_LSM_EVENT_STATUS32");
-			return -EFAULT;
+				__func__, "SNDRV_LSM_EVENT_STATUS");
+			err = -EFAULT;
+			goto done;
 		}
 
 		if (userarg32.payload_size >
@@ -1142,7 +1309,8 @@
 			pr_err("%s: payload_size %d is invalid, max allowed = %d\n",
 				__func__, userarg32.payload_size,
 				LISTEN_MAX_STATUS_PAYLOAD_SIZE);
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		size = sizeof(*user) + userarg32.payload_size;
@@ -1151,7 +1319,8 @@
 			dev_err(rtd->dev,
 				"%s: Allocation failed event status size %d\n",
 				__func__, size);
-			return -EFAULT;
+			err = -EFAULT;
+			goto done;
 		} else {
 			cmd = SNDRV_LSM_EVENT_STATUS;
 			user->payload_size = userarg32.payload_size;
@@ -1193,6 +1362,73 @@
 		break;
 	}
 
+	case SNDRV_LSM_EVENT_STATUS_V3_32: {
+		struct snd_lsm_event_status_v3_32 userarg32, *user32 = NULL;
+		struct snd_lsm_event_status_v3 *user = NULL;
+
+		if (copy_from_user(&userarg32, arg, sizeof(userarg32))) {
+			dev_err(rtd->dev, "%s: err copyuser ioctl %s\n",
+				__func__, "SNDRV_LSM_EVENT_STATUS_V3_32");
+			return -EFAULT;
+		}
+
+		if (userarg32.payload_size >
+		    LISTEN_MAX_STATUS_PAYLOAD_SIZE) {
+			pr_err("%s: payload_size %d is invalid, max allowed = %d\n",
+				__func__, userarg32.payload_size,
+				LISTEN_MAX_STATUS_PAYLOAD_SIZE);
+			return -EINVAL;
+		}
+
+		size = sizeof(*user) + userarg32.payload_size;
+		user = kmalloc(size, GFP_KERNEL);
+		if (!user) {
+			dev_err(rtd->dev,
+				"%s: Allocation failed event status size %d\n",
+				__func__, size);
+			return -EFAULT;
+		}
+		cmd = SNDRV_LSM_EVENT_STATUS_V3;
+		user->payload_size = userarg32.payload_size;
+		err = msm_lsm_ioctl_shared(substream, cmd, user);
+
+		/* Update size with actual payload size */
+		size = sizeof(userarg32) + user->payload_size;
+		if (!err && !access_ok(VERIFY_WRITE, arg, size)) {
+			dev_err(rtd->dev,
+				"%s: write verify failed size %d\n",
+				__func__, size);
+			err = -EFAULT;
+		}
+		if (!err) {
+			user32 = kmalloc(size, GFP_KERNEL);
+			if (!user32) {
+				dev_err(rtd->dev,
+					"%s: Allocation event user status size %d\n",
+					__func__, size);
+				err = -EFAULT;
+			} else {
+				user32->timestamp_lsw = user->timestamp_lsw;
+				user32->timestamp_msw = user->timestamp_msw;
+				user32->status = user->status;
+				user32->payload_size = user->payload_size;
+				memcpy(user32->payload,
+				user->payload, user32->payload_size);
+			}
+		}
+		if (!err && (copy_to_user(arg, user32, size))) {
+			dev_err(rtd->dev, "%s: failed to copy payload %d",
+				__func__, size);
+			err = -EFAULT;
+		}
+		kfree(user);
+		kfree(user32);
+		if (err)
+			dev_err(rtd->dev, "%s: lsmevent failed %d",
+				__func__, err);
+		break;
+	}
+
 	case SNDRV_LSM_REG_SND_MODEL_V2_32: {
 		struct snd_lsm_sound_model_v2_32 snd_modelv232;
 		struct snd_lsm_sound_model_v2 snd_modelv2;
@@ -1201,7 +1437,8 @@
 			dev_err(rtd->dev,
 				"%s: %s: not supported if using topology\n",
 				__func__, "REG_SND_MODEL_V2");
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		if (copy_from_user(&snd_modelv232, arg,
@@ -1242,7 +1479,7 @@
 			dev_err(rtd->dev,
 				"%s: %s: not supported if using topology\n",
 				__func__, "SET_PARAMS_32");
-			return -EINVAL;
+			err = -EINVAL;
 		}
 
 		if (copy_from_user(&det_params32, arg,
@@ -1285,14 +1522,8 @@
 			dev_err(rtd->dev,
 				"%s: %s: not supported if not using topology\n",
 				__func__, "SET_MODULE_PARAMS_32");
-			return -EINVAL;
-		}
-
-		if (!arg) {
-			dev_err(rtd->dev,
-				"%s: %s: No Param data to set\n",
-				__func__, "SET_MODULE_PARAMS_32");
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		if (copy_from_user(&p_data_32, arg,
@@ -1301,7 +1532,8 @@
 				"%s: %s: copy_from_user failed, size = %zd\n",
 				__func__, "SET_MODULE_PARAMS_32",
 				sizeof(p_data_32));
-			return -EFAULT;
+			err = -EFAULT;
+			goto done;
 		}
 
 		p_data.params = compat_ptr(p_data_32.params);
@@ -1313,7 +1545,8 @@
 				"%s: %s: Invalid num_params %d\n",
 				__func__, "SET_MODULE_PARAMS_32",
 				p_data.num_params);
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		if (p_data.data_size !=
@@ -1322,15 +1555,18 @@
 				"%s: %s: Invalid size %d\n",
 				__func__, "SET_MODULE_PARAMS_32",
 				p_data.data_size);
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		p_size = sizeof(struct lsm_params_info_32) *
 			 p_data.num_params;
 
 		params32 = kzalloc(p_size, GFP_KERNEL);
-		if (!params32)
-			return -ENOMEM;
+		if (!params32) {
+			err = -ENOMEM;
+			goto done;
+		}
 
 		p_size = sizeof(struct lsm_params_info) * p_data.num_params;
 		params = kzalloc(p_size, GFP_KERNEL);
@@ -1339,7 +1575,8 @@
 				"%s: no memory for params, size = %zd\n",
 				__func__, p_size);
 			kfree(params32);
-			return -ENOMEM;
+			err = -ENOMEM;
+			goto done;
 		}
 
 		if (copy_from_user(params32, p_data.params,
@@ -1349,7 +1586,8 @@
 				__func__, "params32", p_data.data_size);
 			kfree(params32);
 			kfree(params);
-			return -EFAULT;
+			err = -EFAULT;
+			goto done;
 		}
 
 		p_info_32 = (struct lsm_params_info_32 *) params32;
@@ -1375,10 +1613,25 @@
 		kfree(params32);
 		break;
 	}
+	case SNDRV_LSM_REG_SND_MODEL_V2:
+	case SNDRV_LSM_SET_PARAMS:
+	case SNDRV_LSM_SET_MODULE_PARAMS:
+		/*
+		 * In ideal cases, the compat_ioctl should never be called
+		 * with the above unlocked ioctl commands. Print error
+		 * and return error if it does.
+		 */
+		dev_err(rtd->dev,
+			"%s: Invalid cmd for compat_ioctl\n",
+			__func__);
+		err = -EINVAL;
+		break;
 	default:
 		err = msm_lsm_ioctl_shared(substream, cmd, arg);
 		break;
 	}
+done:
+	mutex_unlock(&prtd->lsm_api_lock);
 	return err;
 }
 #else
@@ -1390,7 +1643,6 @@
 {
 	int err = 0;
 	u32 size = 0;
-	struct snd_lsm_session_data session_data;
 	struct snd_pcm_runtime *runtime;
 	struct snd_soc_pcm_runtime *rtd;
 	struct lsm_priv *prtd;
@@ -1404,27 +1656,8 @@
 	prtd = runtime->private_data;
 	rtd = substream->private_data;
 
+	mutex_lock(&prtd->lsm_api_lock);
 	switch (cmd) {
-	case SNDRV_LSM_SET_SESSION_DATA:
-		dev_dbg(rtd->dev,
-			"%s: SNDRV_LSM_SET_SESSION_DATA\n",
-			__func__);
-		if (copy_from_user(&session_data, (void *)arg,
-				   sizeof(struct snd_lsm_session_data))) {
-			err = -EFAULT;
-			dev_err(rtd->dev,
-				"%s: copy from user failed, size %zd\n",
-				__func__, sizeof(struct snd_lsm_session_data));
-			break;
-		}
-		if (!err)
-			err = msm_lsm_ioctl_shared(substream,
-						   cmd, &session_data);
-		if (err)
-			dev_err(rtd->dev,
-				"%s REG_SND_MODEL failed err %d\n",
-				__func__, err);
-		break;
 	case SNDRV_LSM_REG_SND_MODEL_V2: {
 		struct snd_lsm_sound_model_v2 snd_model_v2;
 
@@ -1432,14 +1665,10 @@
 			dev_err(rtd->dev,
 				"%s: %s: not supported if using topology\n",
 				__func__, "REG_SND_MODEL_V2");
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
-		if (!arg) {
-			dev_err(rtd->dev,
-				"%s: Invalid params snd_model\n", __func__);
-			return -EINVAL;
-		}
 		if (copy_from_user(&snd_model_v2, arg, sizeof(snd_model_v2))) {
 			err = -EFAULT;
 			dev_err(rtd->dev,
@@ -1464,16 +1693,11 @@
 			dev_err(rtd->dev,
 				"%s: %s: not supported if using topology\n",
 				__func__, "SET_PARAMS");
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		pr_debug("%s: SNDRV_LSM_SET_PARAMS\n", __func__);
-		if (!arg) {
-			dev_err(rtd->dev,
-				"%s: %s, Invalid params\n",
-				__func__, "SNDRV_LSM_SET_PARAMS");
-			return -EINVAL;
-		}
 
 		if (copy_from_user(&det_params, arg,
 				   sizeof(det_params))) {
@@ -1491,7 +1715,8 @@
 			dev_err(rtd->dev,
 				"%s: LSM_SET_PARAMS failed, err %d\n",
 				__func__, err);
-		return err;
+
+		goto done;
 	}
 
 	case SNDRV_LSM_SET_MODULE_PARAMS: {
@@ -1503,14 +1728,8 @@
 			dev_err(rtd->dev,
 				"%s: %s: not supported if not using topology\n",
 				__func__, "SET_MODULE_PARAMS");
-			return -EINVAL;
-		}
-
-		if (!arg) {
-			dev_err(rtd->dev,
-				"%s: %s: No Param data to set\n",
-				__func__, "SET_MODULE_PARAMS");
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		if (copy_from_user(&p_data, arg,
@@ -1518,7 +1737,8 @@
 			dev_err(rtd->dev,
 				"%s: %s: copy_from_user failed, size = %zd\n",
 				__func__, "p_data", sizeof(p_data));
-			return -EFAULT;
+			err = -EFAULT;
+			goto done;
 		}
 
 		if (p_data.num_params > LSM_PARAMS_MAX) {
@@ -1526,7 +1746,8 @@
 				"%s: %s: Invalid num_params %d\n",
 				__func__, "SET_MODULE_PARAMS",
 				p_data.num_params);
-			return -EINVAL;
+			err = -EINVAL;
+			goto done;
 		}
 
 		p_size = p_data.num_params *
@@ -1537,12 +1758,15 @@
 				"%s: %s: Invalid size %zd\n",
 				__func__, "SET_MODULE_PARAMS", p_size);
 
-			return -EFAULT;
+			err = -EFAULT;
+			goto done;
 		}
 
 		params = kzalloc(p_size, GFP_KERNEL);
-		if (!params)
-			return -ENOMEM;
+		if (!params) {
+			err = -ENOMEM;
+			goto done;
+		}
 
 		if (copy_from_user(params, p_data.params,
 				   p_data.data_size)) {
@@ -1550,7 +1774,8 @@
 				"%s: %s: copy_from_user failed, size = %d\n",
 				__func__, "params", p_data.data_size);
 			kfree(params);
-			return -EFAULT;
+			err = -EFAULT;
+			goto done;
 		}
 
 		err = msm_lsm_process_params(substream, &p_data, params);
@@ -1567,15 +1792,72 @@
 
 		dev_dbg(rtd->dev,
 			"%s: SNDRV_LSM_EVENT_STATUS\n", __func__);
+		if (copy_from_user(&userarg, arg, sizeof(userarg))) {
+			dev_err(rtd->dev,
+				"%s: err copyuser event_status\n",
+				__func__);
+			err = -EFAULT;
+			goto done;
+		}
+
+		if (userarg.payload_size >
+		    LISTEN_MAX_STATUS_PAYLOAD_SIZE) {
+			pr_err("%s: payload_size %d is invalid, max allowed = %d\n",
+				__func__, userarg.payload_size,
+				LISTEN_MAX_STATUS_PAYLOAD_SIZE);
+			err = -EINVAL;
+			goto done;
+		}
+
+		size = sizeof(struct snd_lsm_event_status) +
+		userarg.payload_size;
+		user = kmalloc(size, GFP_KERNEL);
+		if (!user) {
+			dev_err(rtd->dev,
+				"%s: Allocation failed event status size %d\n",
+				__func__, size);
+			err = -EFAULT;
+			goto done;
+		}
+		user->payload_size = userarg.payload_size;
+		err = msm_lsm_ioctl_shared(substream, cmd, user);
+
+		/* Update size with actual payload size */
+		size = sizeof(*user) + user->payload_size;
+		if (!err && !access_ok(VERIFY_WRITE, arg, size)) {
+			dev_err(rtd->dev,
+				"%s: write verify failed size %d\n",
+				__func__, size);
+			err = -EFAULT;
+		}
+		if (!err && (copy_to_user(arg, user, size))) {
+			dev_err(rtd->dev,
+				"%s: failed to copy payload %d",
+				__func__, size);
+			err = -EFAULT;
+		}
+		kfree(user);
+		if (err)
+			dev_err(rtd->dev,
+				"%s: lsmevent failed %d", __func__, err);
+		goto done;
+	}
+
+	case SNDRV_LSM_EVENT_STATUS_V3: {
+		struct snd_lsm_event_status_v3 *user = NULL;
+		struct snd_lsm_event_status_v3 userarg;
+
+		dev_dbg(rtd->dev,
+			"%s: SNDRV_LSM_EVENT_STATUS_V3\n", __func__);
 		if (!arg) {
 			dev_err(rtd->dev,
-				"%s: Invalid params event status\n",
+				"%s: Invalid params event_status_v3\n",
 				__func__);
 			return -EINVAL;
 		}
 		if (copy_from_user(&userarg, arg, sizeof(userarg))) {
 			dev_err(rtd->dev,
-				"%s: err copyuser event_status\n",
+				"%s: err copyuser event_status_v3\n",
 				__func__);
 			return -EFAULT;
 		}
@@ -1588,8 +1870,8 @@
 			return -EINVAL;
 		}
 
-		size = sizeof(struct snd_lsm_event_status) +
-		userarg.payload_size;
+		size = sizeof(struct snd_lsm_event_status_v3) +
+			userarg.payload_size;
 		user = kmalloc(size, GFP_KERNEL);
 		if (!user) {
 			dev_err(rtd->dev,
@@ -1617,13 +1899,16 @@
 		kfree(user);
 		if (err)
 			dev_err(rtd->dev,
-				"%s: lsmevent failed %d", __func__, err);
-		return err;
+				"%s: lsm_event_v3 failed %d", __func__, err);
+		break;
 	}
+
 	default:
 		err = msm_lsm_ioctl_shared(substream, cmd, arg);
 	break;
 	}
+done:
+	mutex_unlock(&prtd->lsm_api_lock);
 	return err;
 }
 
@@ -1640,6 +1925,7 @@
 		       __func__);
 		return -ENOMEM;
 	}
+	mutex_init(&prtd->lsm_api_lock);
 	spin_lock_init(&prtd->event_lock);
 	init_waitqueue_head(&prtd->event_wait);
 	init_waitqueue_head(&prtd->period_wait);
@@ -1687,6 +1973,11 @@
 		return -ENOMEM;
 	}
 	prtd->lsm_client->opened = false;
+	prtd->lsm_client->session_state = IDLE;
+	prtd->lsm_client->poll_enable = true;
+	prtd->lsm_client->perf_mode = 0;
+	prtd->lsm_client->event_mode = LSM_EVENT_NON_TIME_STAMP_MODE;
+
 	return 0;
 }
 
@@ -1695,6 +1986,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd = runtime->private_data;
 	struct snd_soc_pcm_runtime *rtd;
+	int ret = 0;
 
 	if (!substream->private_data) {
 		pr_err("%s: Invalid private_data", __func__);
@@ -1708,9 +2000,30 @@
 			"%s: LSM client data ptr is NULL\n", __func__);
 		return -EINVAL;
 	}
+
+	if (q6lsm_set_media_fmt_params(prtd->lsm_client))
+		dev_dbg(rtd->dev,
+			"%s: failed to set lsm media fmt params\n", __func__);
+
+	if (prtd->lsm_client->session_state == IDLE) {
+		ret = msm_pcm_routing_reg_phy_compr_stream(
+				rtd->dai_link->id,
+				prtd->lsm_client->perf_mode,
+				prtd->lsm_client->session,
+				SNDRV_PCM_STREAM_CAPTURE,
+				LISTEN);
+		if (ret) {
+			dev_err(rtd->dev,
+				"%s: register phy compr stream failed %d\n",
+					__func__, ret);
+			return ret;
+		}
+	}
+
+	prtd->lsm_client->session_state = RUNNING;
 	prtd->lsm_client->started = false;
 	runtime->private_data = prtd;
-	return 0;
+	return ret;
 }
 
 static int msm_lsm_close(struct snd_pcm_substream *substream)
@@ -1759,6 +2072,9 @@
 				 __func__);
 	}
 
+	msm_pcm_routing_dereg_phy_stream(rtd->dai_link->id,
+					SNDRV_PCM_STREAM_CAPTURE);
+
 	if (prtd->lsm_client->opened) {
 		q6lsm_close(prtd->lsm_client);
 		prtd->lsm_client->opened = false;
@@ -1769,6 +2085,7 @@
 	kfree(prtd->event_status);
 	prtd->event_status = NULL;
 	spin_unlock_irqrestore(&prtd->event_lock, flags);
+	mutex_destroy(&prtd->lsm_api_lock);
 	kfree(prtd);
 	runtime->private_data = NULL;
 
@@ -1780,7 +2097,7 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd = runtime->private_data;
-	struct lsm_lab_hw_params *hw_params = NULL;
+	struct lsm_hw_params *hw_params = NULL;
 	struct snd_soc_pcm_runtime *rtd;
 
 	if (!substream->private_data) {
@@ -1796,25 +2113,36 @@
 		return -EINVAL;
 	}
 	hw_params = &prtd->lsm_client->hw_params;
-	hw_params->sample_rate = params_rate(params);
-	hw_params->sample_size =
-	(params_format(params) == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 0;
+	hw_params->num_chs = params_channels(params);
 	hw_params->period_count = params_periods(params);
-	if (hw_params->sample_rate != 16000 || hw_params->sample_size != 16 ||
-		hw_params->period_count == 0) {
+	hw_params->sample_rate = params_rate(params);
+	if (((hw_params->sample_rate != 16000) &&
+		(hw_params->sample_rate != 48000)) ||
+		(hw_params->period_count == 0)) {
 		dev_err(rtd->dev,
-			"%s: Invalid params sample rate %d sample size %d period count %d",
+			"%s: Invalid Params sample rate %d period count %d\n",
 			__func__, hw_params->sample_rate,
-			hw_params->sample_size,
-		hw_params->period_count);
+			hw_params->period_count);
 		return -EINVAL;
 	}
+
+	if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE) {
+		hw_params->sample_size = 16;
+	} else if (params_format(params) == SNDRV_PCM_FORMAT_S24_LE) {
+		hw_params->sample_size = 24;
+	} else {
+		dev_err(rtd->dev, "%s: Invalid Format 0x%x\n",
+			__func__, params_format(params));
+		return -EINVAL;
+	}
+
 	hw_params->buf_sz = params_buffer_bytes(params) /
-	hw_params->period_count;
+			hw_params->period_count;
 	dev_dbg(rtd->dev,
-		"%s: sample rate %d sample size %d buffer size %d period count %d\n",
-		__func__, hw_params->sample_rate, hw_params->sample_size,
-		hw_params->buf_sz, hw_params->period_count);
+		"%s: channels %d sample rate %d sample size %d buffer size %d period count %d\n",
+		__func__, hw_params->num_chs, hw_params->sample_rate,
+		hw_params->sample_size, hw_params->buf_sz,
+		hw_params->period_count);
 	return 0;
 }
 
@@ -1910,6 +2238,105 @@
 	return 0;
 }
 
+static int msm_lsm_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_TX;
+	int be_id = ucontrol->value.integer.value[3];
+	int ret = 0;
+	int app_type;
+	int acdb_dev_id;
+	int sample_rate;
+
+	app_type = ucontrol->value.integer.value[0];
+	acdb_dev_id = ucontrol->value.integer.value[1];
+	sample_rate = ucontrol->value.integer.value[2];
+
+	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+		__func__, fe_id, session_type, be_id,
+		app_type, acdb_dev_id, sample_rate);
+	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+						      be_id, app_type,
+						      acdb_dev_id, sample_rate);
+	if (ret < 0)
+		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+			__func__, ret);
+
+	return 0;
+}
+
+static int msm_lsm_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_TX;
+	int be_id = ucontrol->value.integer.value[3];
+	int ret = 0;
+	int app_type;
+	int acdb_dev_id;
+	int sample_rate;
+
+	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+						      be_id, &app_type,
+						      &acdb_dev_id,
+						      &sample_rate);
+	if (ret < 0) {
+		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	ucontrol->value.integer.value[0] = app_type;
+	ucontrol->value.integer.value[1] = acdb_dev_id;
+	ucontrol->value.integer.value[2] = sample_rate;
+	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+		__func__, fe_id, session_type, be_id,
+		app_type, acdb_dev_id, sample_rate);
+done:
+	return ret;
+}
+
+static int msm_lsm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm *pcm = rtd->pcm;
+	struct snd_pcm_usr *app_type_info;
+	struct snd_kcontrol *kctl;
+	const char *mixer_ctl_name	= "Listen Stream";
+	const char *deviceNo		= "NN";
+	const char *suffix		= "App Type Cfg";
+	int ctl_len, ret = 0;
+
+	ctl_len = strlen(mixer_ctl_name) + 1 +
+			strlen(deviceNo) + 1 + strlen(suffix) + 1;
+	pr_debug("%s: Listen app type cntrl add\n", __func__);
+	ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
+				NULL, 1, ctl_len, rtd->dai_link->id,
+				&app_type_info);
+	if (ret < 0) {
+		pr_err("%s: Listen app type cntrl add failed: %d\n",
+			__func__, ret);
+		return ret;
+	}
+	kctl = app_type_info->kctl;
+	snprintf(kctl->id.name, ctl_len, "%s %d %s",
+		mixer_ctl_name, rtd->pcm->device, suffix);
+	kctl->put = msm_lsm_app_type_cfg_ctl_put;
+	kctl->get = msm_lsm_app_type_cfg_ctl_get;
+	return 0;
+}
+
+static int msm_lsm_add_controls(struct snd_soc_pcm_runtime *rtd)
+{
+	int ret = 0;
+
+	ret = msm_lsm_add_app_type_controls(rtd);
+	if (ret)
+		pr_err("%s, add  app type controls failed:%d\n", __func__, ret);
+
+	return ret;
+}
+
 static const struct snd_pcm_ops msm_lsm_ops = {
 	.open           = msm_lsm_open,
 	.close          = msm_lsm_close,
@@ -1924,11 +2351,16 @@
 static int msm_asoc_lsm_new(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
 
 	if (!card->dev->coherent_dma_mask)
 		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-	return 0;
+	ret = msm_lsm_add_controls(rtd);
+	if (ret)
+		pr_err("%s, kctl add failed:%d\n", __func__, ret);
+
+	return ret;
 }
 
 static int msm_asoc_lsm_probe(struct snd_soc_platform *platform)
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index 8d43186..ab9b310 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -682,6 +682,7 @@
 	mutex_unlock(&prtd->lock);
 	prtd->prepared--;
 	kfree(prtd);
+	runtime->private_data = NULL;
 	return 0;
 }
 static int msm_afe_prepare(struct snd_pcm_substream *substream)
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
index 15809ce..f668e95 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
@@ -25,6 +25,7 @@
 #include <sound/control.h>
 #include <sound/tlv.h>
 #include <asm/dma.h>
+#include <sound/q6audio-v2.h>
 
 #include "msm-pcm-routing-v2.h"
 
@@ -67,6 +68,10 @@
 
 static u32 hfp_tx_mute;
 
+struct msm_pcm_pdata {
+	int perf_mode;
+};
+
 static void stop_pcm(struct msm_pcm_loopback *pcm);
 static int msm_pcm_loopback_get_session(struct snd_soc_pcm_runtime *rtd,
 					struct msm_pcm_loopback **pcm);
@@ -245,6 +250,7 @@
 	struct msm_pcm_routing_evt event;
 	struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window;
 	uint32_t param_id;
+	struct msm_pcm_pdata *pdata;
 
 	ret =  msm_pcm_loopback_get_session(rtd, &pcm);
 	if (ret)
@@ -270,6 +276,15 @@
 		if (pcm->audio_client != NULL)
 			stop_pcm(pcm);
 
+		pdata = (struct msm_pcm_pdata *)
+			dev_get_drvdata(rtd->platform->dev);
+		if (!pdata) {
+			dev_err(rtd->platform->dev,
+				"%s: platform data not populated\n", __func__);
+			mutex_unlock(&pcm->lock);
+			return -EINVAL;
+		}
+
 		pcm->audio_client = q6asm_audio_client_alloc(
 				(app_cb)msm_pcm_loopback_event_handler, pcm);
 		if (!pcm->audio_client) {
@@ -279,7 +294,7 @@
 			return -ENOMEM;
 		}
 		pcm->session_id = pcm->audio_client->session;
-		pcm->audio_client->perf_mode = false;
+		pcm->audio_client->perf_mode = pdata->perf_mode;
 		ret = q6asm_open_loopback_v2(pcm->audio_client,
 					     bits_per_sample);
 		if (ret < 0) {
@@ -542,48 +557,45 @@
 					struct snd_ctl_elem_value *ucontrol)
 {
 	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_RX;
+	int be_id = ucontrol->value.integer.value[3];
+	int ret = 0;
 	int app_type;
 	int acdb_dev_id;
 	int sample_rate = 48000;
 
-	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
-	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
-		pr_err("%s: Received out of bounds fe_id %llu\n",
-			__func__, fe_id);
-		return -EINVAL;
-	}
-
 	app_type = ucontrol->value.integer.value[0];
 	acdb_dev_id = ucontrol->value.integer.value[1];
 	if (ucontrol->value.integer.value[2] != 0)
 		sample_rate = ucontrol->value.integer.value[2];
-	pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
-		__func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_RX);
-	msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
-			acdb_dev_id, sample_rate, SESSION_TYPE_RX);
+	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+		__func__, fe_id, session_type, be_id,
+		app_type, acdb_dev_id, sample_rate);
+	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+						      be_id, app_type,
+						      acdb_dev_id, sample_rate);
+	if (ret < 0)
+		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+			__func__, ret);
 
-	return 0;
+	return ret;
 }
 
 static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol)
 {
 	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_RX;
+	int be_id = ucontrol->value.integer.value[3];
 	int ret = 0;
 	int app_type;
 	int acdb_dev_id;
 	int sample_rate;
 
-	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
-	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
-		pr_err("%s: Received out of bounds fe_id %llu\n",
-			__func__, fe_id);
-		ret = -EINVAL;
-		goto done;
-	}
-
-	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_RX,
-		&app_type, &acdb_dev_id, &sample_rate);
+	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+						      be_id, &app_type,
+						      &acdb_dev_id,
+						      &sample_rate);
 	if (ret < 0) {
 		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
@@ -593,8 +605,8 @@
 	ucontrol->value.integer.value[0] = app_type;
 	ucontrol->value.integer.value[1] = acdb_dev_id;
 	ucontrol->value.integer.value[2] = sample_rate;
-	pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
-		__func__, fe_id, SESSION_TYPE_RX,
+	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+		__func__, fe_id, session_type, be_id,
 		app_type, acdb_dev_id, sample_rate);
 done:
 	return ret;
@@ -604,48 +616,45 @@
 					struct snd_ctl_elem_value *ucontrol)
 {
 	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_TX;
+	int be_id = ucontrol->value.integer.value[3];
+	int ret = 0;
 	int app_type;
 	int acdb_dev_id;
 	int sample_rate = 48000;
 
-	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
-	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
-		pr_err("%s: Received out of bounds fe_id %llu\n",
-			__func__, fe_id);
-		return -EINVAL;
-	}
-
 	app_type = ucontrol->value.integer.value[0];
 	acdb_dev_id = ucontrol->value.integer.value[1];
 	if (ucontrol->value.integer.value[2] != 0)
 		sample_rate = ucontrol->value.integer.value[2];
-	pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
-		__func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
-	msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
-			acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+		__func__, fe_id, session_type, be_id,
+		app_type, acdb_dev_id, sample_rate);
+	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+						      be_id, app_type,
+						      acdb_dev_id, sample_rate);
+	if (ret < 0)
+		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+			__func__, ret);
 
-	return 0;
+	return ret;
 }
 
 static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol)
 {
 	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_TX;
+	int be_id = ucontrol->value.integer.value[3];
 	int ret = 0;
 	int app_type;
 	int acdb_dev_id;
 	int sample_rate;
 
-	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
-	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
-		pr_err("%s: Received out of bounds fe_id %llu\n",
-			__func__, fe_id);
-		ret = -EINVAL;
-		goto done;
-	}
-
-	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
-		&app_type, &acdb_dev_id, &sample_rate);
+	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+						      be_id, &app_type,
+						      &acdb_dev_id,
+						      &sample_rate);
 	if (ret < 0) {
 		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
@@ -655,8 +664,8 @@
 	ucontrol->value.integer.value[0] = app_type;
 	ucontrol->value.integer.value[1] = acdb_dev_id;
 	ucontrol->value.integer.value[2] = sample_rate;
-	pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
-		__func__, fe_id, SESSION_TYPE_TX,
+	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+		__func__, fe_id, session_type, be_id,
 		app_type, acdb_dev_id, sample_rate);
 done:
 	return ret;
@@ -746,9 +755,23 @@
 
 static int msm_pcm_probe(struct platform_device *pdev)
 {
+	struct msm_pcm_pdata *pdata;
+
 	dev_dbg(&pdev->dev, "%s: dev name %s\n",
 		__func__, dev_name(&pdev->dev));
 
+	pdata = kzalloc(sizeof(struct msm_pcm_pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	if (of_property_read_bool(pdev->dev.of_node,
+				"qcom,msm-pcm-loopback-low-latency"))
+		pdata->perf_mode = LOW_LATENCY_PCM_MODE;
+	else
+		pdata->perf_mode = LEGACY_PCM_MODE;
+
+	dev_set_drvdata(&pdev->dev, pdata);
+
 	return snd_soc_register_platform(&pdev->dev,
 				   &msm_soc_platform);
 }
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
index ecf194f..9b7c6fb 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
@@ -139,6 +139,17 @@
 	.mask = 0,
 };
 
+static unsigned long msm_pcm_fe_topology[MSM_FRONTEND_DAI_MAX];
+
+/* default value is DTS (i.e read from device tree) */
+static char const *msm_pcm_fe_topology_text[] = {
+	"DTS", "ULL", "ULL_PP", "LL" };
+
+static const struct soc_enum msm_pcm_fe_topology_enum[] = {
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(msm_pcm_fe_topology_text),
+			    msm_pcm_fe_topology_text),
+};
+
 static void event_handler(uint32_t opcode,
 		uint32_t token, uint32_t *payload, void *priv)
 {
@@ -258,6 +269,8 @@
 	uint16_t bits_per_sample;
 	int ret;
 	int dir = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? IN : OUT;
+	unsigned long topology;
+	int perf_mode;
 
 	pdata = (struct msm_plat_data *)
 		dev_get_drvdata(soc_prtd->platform->dev);
@@ -268,11 +281,24 @@
 		return ret;
 	}
 
+	topology = msm_pcm_fe_topology[soc_prtd->dai_link->id];
+
+	if (!strcmp(msm_pcm_fe_topology_text[topology], "ULL_PP"))
+		perf_mode = ULL_POST_PROCESSING_PCM_MODE;
+	else if (!strcmp(msm_pcm_fe_topology_text[topology], "ULL"))
+		perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+	else if (!strcmp(msm_pcm_fe_topology_text[topology], "LL"))
+		perf_mode = LOW_LATENCY_PCM_MODE;
+	else
+		/* use the default from the device tree */
+		perf_mode = pdata->perf_mode;
+
+
 	/* need to set LOW_LATENCY_PCM_MODE for capture since
 	 * push mode does not support ULL
 	 */
 	prtd->audio_client->perf_mode = (dir == IN) ?
-					pdata->perf_mode :
+					perf_mode :
 					LOW_LATENCY_PCM_MODE;
 
 	/* rate and channels are sent to audio driver */
@@ -544,6 +570,8 @@
 					 SNDRV_PCM_STREAM_PLAYBACK :
 					 SNDRV_PCM_STREAM_CAPTURE);
 	kfree(prtd);
+	runtime->private_data = NULL;
+
 	return 0;
 }
 
@@ -721,6 +749,269 @@
 	return 0;
 }
 
+static int msm_pcm_fe_topology_info(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_info *uinfo)
+{
+	const struct soc_enum *e = &msm_pcm_fe_topology_enum[0];
+
+	return snd_ctl_enum_info(uinfo, 1, e->items, e->texts);
+}
+
+static int msm_pcm_fe_topology_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned long fe_id = kcontrol->private_value;
+
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: %lu topology %s\n", __func__, fe_id,
+		 msm_pcm_fe_topology_text[msm_pcm_fe_topology[fe_id]]);
+	ucontrol->value.enumerated.item[0] = msm_pcm_fe_topology[fe_id];
+	return 0;
+}
+
+static int msm_pcm_fe_topology_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned long fe_id = kcontrol->private_value;
+	unsigned int item;
+
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id);
+		return -EINVAL;
+	}
+
+	item = ucontrol->value.enumerated.item[0];
+	if (item >= ARRAY_SIZE(msm_pcm_fe_topology_text)) {
+		pr_err("%s Received out of bound topology %lu\n", __func__,
+		       fe_id);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: %lu new topology %s\n", __func__, fe_id,
+		 msm_pcm_fe_topology_text[item]);
+	msm_pcm_fe_topology[fe_id] = item;
+	return 0;
+}
+
+static int msm_pcm_add_fe_topology_control(struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = "PCM_Dev";
+	const char *deviceNo       = "NN";
+	const char *topo_text      = "Topology";
+	char *mixer_str = NULL;
+	int ctl_len;
+	int ret;
+	struct snd_kcontrol_new topology_control[1] = {
+		{
+			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+			.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+			.name =  "?",
+			.info =  msm_pcm_fe_topology_info,
+			.get = msm_pcm_fe_topology_get,
+			.put = msm_pcm_fe_topology_put,
+			.private_value = 0,
+		},
+	};
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 +
+		  strlen(topo_text) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+
+	if (!mixer_str)
+		return -ENOMEM;
+
+	snprintf(mixer_str, ctl_len, "%s %d %s", mixer_ctl_name,
+		 rtd->pcm->device, topo_text);
+
+	topology_control[0].name = mixer_str;
+	topology_control[0].private_value = rtd->dai_link->id;
+	ret = snd_soc_add_platform_controls(rtd->platform, topology_control,
+					    ARRAY_SIZE(topology_control));
+	msm_pcm_fe_topology[rtd->dai_link->id] = 0;
+	kfree(mixer_str);
+	return ret;
+}
+
+static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_RX;
+	int be_id = ucontrol->value.integer.value[3];
+	int ret = 0;
+	int app_type;
+	int acdb_dev_id;
+	int sample_rate = 48000;
+
+	app_type = ucontrol->value.integer.value[0];
+	acdb_dev_id = ucontrol->value.integer.value[1];
+	if (ucontrol->value.integer.value[2] != 0)
+		sample_rate = ucontrol->value.integer.value[2];
+
+	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+						      be_id, app_type,
+						      acdb_dev_id, sample_rate);
+	if (ret < 0)
+		pr_err("%s: msm_pcm_playback_app_type_cfg_ctl_put failed, err %d\n",
+			__func__, ret);
+
+	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+		__func__, fe_id, session_type, be_id,
+		app_type, acdb_dev_id, sample_rate);
+	return ret;
+}
+
+static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_RX;
+	int be_id = ucontrol->value.integer.value[3];
+	int ret = 0;
+	int app_type;
+	int acdb_dev_id;
+	int sample_rate;
+
+	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+						      be_id, &app_type,
+						      &acdb_dev_id,
+						      &sample_rate);
+	if (ret < 0) {
+		pr_err("%s: msm_pcm_playback_app_type_cfg_ctl_get failed, err: %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	ucontrol->value.integer.value[0] = app_type;
+	ucontrol->value.integer.value[1] = acdb_dev_id;
+	ucontrol->value.integer.value[2] = sample_rate;
+
+	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+		__func__, fe_id, session_type, be_id,
+		app_type, acdb_dev_id, sample_rate);
+done:
+	return ret;
+}
+
+static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_TX;
+	int be_id = ucontrol->value.integer.value[3];
+	int ret = 0;
+	int app_type;
+	int acdb_dev_id;
+	int sample_rate = 48000;
+
+	app_type = ucontrol->value.integer.value[0];
+	acdb_dev_id = ucontrol->value.integer.value[1];
+	if (ucontrol->value.integer.value[2] != 0)
+		sample_rate = ucontrol->value.integer.value[2];
+
+	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+						      be_id, app_type,
+						      acdb_dev_id, sample_rate);
+	if (ret < 0)
+		pr_err("%s: msm_pcm_capture_app_type_cfg_ctl_put failed, err: %d\n",
+			__func__, ret);
+
+	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+		__func__, fe_id, session_type, be_id,
+		app_type, acdb_dev_id, sample_rate);
+
+	return ret;
+}
+
+static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_TX;
+	int be_id = ucontrol->value.integer.value[3];
+	int ret = 0;
+	int app_type;
+	int acdb_dev_id;
+	int sample_rate;
+
+	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+						      be_id, &app_type,
+						      &acdb_dev_id,
+						      &sample_rate);
+	if (ret < 0) {
+		pr_err("%s: msm_pcm_capture_app_type_cfg_ctl_get failed, err: %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	ucontrol->value.integer.value[0] = app_type;
+	ucontrol->value.integer.value[1] = acdb_dev_id;
+	ucontrol->value.integer.value[2] = sample_rate;
+	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+		__func__, fe_id, session_type, be_id,
+		app_type, acdb_dev_id, sample_rate);
+done:
+	return ret;
+}
+
+static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm *pcm = rtd->pcm;
+	struct snd_pcm_usr *app_type_info;
+	struct snd_kcontrol *kctl;
+	const char *playback_mixer_ctl_name = "Audio Stream";
+	const char *capture_mixer_ctl_name = "Audio Stream Capture";
+	const char *deviceNo = "NN";
+	const char *suffix = "App Type Cfg";
+	int ctl_len, ret = 0;
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+		ctl_len = strlen(playback_mixer_ctl_name) + 1 +
+				strlen(deviceNo) + 1 +
+				strlen(suffix) + 1;
+		pr_debug("%s: Playback app type cntrl add\n", __func__);
+		ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				NULL, 1, ctl_len, rtd->dai_link->id,
+				&app_type_info);
+		if (ret < 0) {
+			pr_err("%s: playback app type cntrl add failed, err: %d\n",
+				__func__, ret);
+			return ret;
+		}
+		kctl = app_type_info->kctl;
+		snprintf(kctl->id.name, ctl_len, "%s %d %s",
+			     playback_mixer_ctl_name, rtd->pcm->device, suffix);
+		kctl->put = msm_pcm_playback_app_type_cfg_ctl_put;
+		kctl->get = msm_pcm_playback_app_type_cfg_ctl_get;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+		ctl_len = strlen(capture_mixer_ctl_name) + 1 +
+				strlen(deviceNo) + 1 + strlen(suffix) + 1;
+		pr_debug("%s: Capture app type cntrl add\n", __func__);
+		ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
+				NULL, 1, ctl_len, rtd->dai_link->id,
+				&app_type_info);
+		if (ret < 0) {
+			pr_err("%s: capture app type cntrl add failed, err: %d\n",
+				__func__, ret);
+			return ret;
+		}
+		kctl = app_type_info->kctl;
+		snprintf(kctl->id.name, ctl_len, "%s %d %s",
+		 capture_mixer_ctl_name, rtd->pcm->device, suffix);
+		kctl->put = msm_pcm_capture_app_type_cfg_ctl_put;
+		kctl->get = msm_pcm_capture_app_type_cfg_ctl_get;
+	}
+
+	return 0;
+}
+
+
 static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_card *card = rtd->card->snd_card;
@@ -741,6 +1032,19 @@
 		pr_err("%s: Could not add pcm Volume Control %d\n",
 			__func__, ret);
 	}
+
+	ret = msm_pcm_add_fe_topology_control(rtd);
+	if (ret) {
+		pr_err("%s: Could not add pcm topology control %d\n",
+			__func__, ret);
+	}
+
+	ret = msm_pcm_add_app_type_controls(rtd);
+	if (ret) {
+		pr_err("%s: Could not add app type controls failed %d\n",
+			__func__, ret);
+	}
+
 	pcm->nonatomic = true;
 exit:
 	return ret;
@@ -778,8 +1082,12 @@
 
 		rc = of_property_read_string(pdev->dev.of_node,
 			"qcom,latency-level", &latency_level);
-		if (!rc && !strcmp(latency_level, "ultra"))
-			perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+		if (!rc) {
+			if (!strcmp(latency_level, "ultra"))
+				perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+			else if (!strcmp(latency_level, "ull-pp"))
+				perf_mode = ULL_POST_PROCESSING_PCM_MODE;
+		}
 	}
 
 	pdata = devm_kzalloc(&pdev->dev,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index e899f5e..1799d0d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -110,7 +110,7 @@
 /* Conventional and unconventional sample rate supported */
 static unsigned int supported_sample_rates[] = {
 	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
-	88200, 96000, 176400, 192000, 384000
+	88200, 96000, 176400, 192000, 352800, 384000
 };
 
 static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
@@ -286,6 +286,7 @@
 	struct msm_plat_data *pdata;
 	struct snd_pcm_hw_params *params;
 	int ret;
+	uint32_t fmt_type = FORMAT_LINEAR_PCM;
 	uint16_t bits_per_sample;
 	uint16_t sample_word_size;
 
@@ -334,38 +335,67 @@
 		sample_word_size = 16;
 		break;
 	}
+	if (prtd->compress_enable) {
+		fmt_type = FORMAT_GEN_COMPR;
+		pr_debug("%s: Compressed enabled!\n", __func__);
+		ret = q6asm_open_write_compressed(prtd->audio_client, fmt_type,
+				COMPRESSED_PASSTHROUGH_GEN);
+		if (ret < 0) {
+			pr_err("%s: q6asm_open_write_compressed failed (%d)\n",
+			__func__, ret);
+			q6asm_audio_client_free(prtd->audio_client);
+			prtd->audio_client = NULL;
+			return -ENOMEM;
+		}
+	} else {
+		ret = q6asm_open_write_v4(prtd->audio_client,
+			fmt_type, bits_per_sample);
 
-	ret = q6asm_open_write_v4(prtd->audio_client,
-				  FORMAT_LINEAR_PCM, bits_per_sample);
+		if (ret < 0) {
+			pr_err("%s: q6asm_open_write_v4 failed (%d)\n",
+			__func__, ret);
+			q6asm_audio_client_free(prtd->audio_client);
+			prtd->audio_client = NULL;
+			return -ENOMEM;
+		}
 
-	if (ret < 0) {
-		pr_err("%s: q6asm_open_write_v2 failed\n", __func__);
-		q6asm_audio_client_free(prtd->audio_client);
-		prtd->audio_client = NULL;
-		return -ENOMEM;
+		ret = q6asm_send_cal(prtd->audio_client);
+		if (ret < 0)
+			pr_debug("%s : Send cal failed : %d", __func__, ret);
 	}
-
-	ret = q6asm_send_cal(prtd->audio_client);
-	if (ret < 0)
-		pr_debug("%s : Send cal failed : %d", __func__, ret);
-
 	pr_debug("%s: session ID %d\n", __func__,
 			prtd->audio_client->session);
 	prtd->session_id = prtd->audio_client->session;
-	ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->id,
+
+	if (prtd->compress_enable) {
+		ret = msm_pcm_routing_reg_phy_compr_stream(
+				soc_prtd->dai_link->id,
+				prtd->audio_client->perf_mode,
+				prtd->session_id,
+				SNDRV_PCM_STREAM_PLAYBACK,
+				COMPRESSED_PASSTHROUGH_GEN);
+	} else {
+		ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->id,
 			prtd->audio_client->perf_mode,
 			prtd->session_id, substream->stream);
+	}
 	if (ret) {
 		pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
 		return ret;
 	}
-
-	ret = q6asm_media_format_block_multi_ch_pcm_v4(
+	if (prtd->compress_enable) {
+		ret = q6asm_media_format_block_gen_compr(
+			prtd->audio_client, runtime->rate,
+			runtime->channels, !prtd->set_channel_map,
+			prtd->channel_map, bits_per_sample);
+	} else {
+		ret = q6asm_media_format_block_multi_ch_pcm_v4(
 				prtd->audio_client, runtime->rate,
 				runtime->channels, !prtd->set_channel_map,
 				prtd->channel_map, bits_per_sample,
 				sample_word_size, ASM_LITTLE_ENDIAN,
 				DEFAULT_QF);
+	}
 	if (ret < 0)
 		pr_info("%s: CMD Format block failed\n", __func__);
 
@@ -424,7 +454,7 @@
 				prtd->audio_client->perf_mode);
 
 		ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM,
-				bits_per_sample);
+				bits_per_sample, false);
 		if (ret < 0) {
 			pr_err("%s: q6asm_open_read failed\n", __func__);
 			q6asm_audio_client_free(prtd->audio_client);
@@ -774,6 +804,8 @@
 	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
 						SNDRV_PCM_STREAM_PLAYBACK);
 	kfree(prtd);
+	runtime->private_data = NULL;
+
 	return 0;
 }
 
@@ -879,6 +911,7 @@
 	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
 		SNDRV_PCM_STREAM_CAPTURE);
 	kfree(prtd);
+	runtime->private_data = NULL;
 
 	return 0;
 }
@@ -1091,6 +1124,136 @@
 	return 0;
 }
 
+static int msm_pcm_compress_ctl_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0x2000;
+	return 0;
+}
+
+static int msm_pcm_compress_ctl_get(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+	struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+	struct snd_pcm_substream *substream;
+	struct msm_audio *prtd;
+
+	if (!pdata) {
+		pr_err("%s pdata is NULL\n", __func__);
+		return -ENODEV;
+	}
+	substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+	if (!substream) {
+		pr_err("%s substream not found\n", __func__);
+		return -EINVAL;
+	}
+	if (!substream->runtime) {
+		pr_err("%s substream runtime not found\n", __func__);
+		return 0;
+	}
+	prtd = substream->runtime->private_data;
+	if (prtd)
+		ucontrol->value.integer.value[0] = prtd->compress_enable;
+	return 0;
+}
+
+static int msm_pcm_compress_ctl_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+	struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+	struct snd_pcm_substream *substream;
+	struct msm_audio *prtd;
+	int compress = ucontrol->value.integer.value[0];
+
+	if (!pdata) {
+		pr_err("%s pdata is NULL\n", __func__);
+		return -ENODEV;
+	}
+	substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+	pr_debug("%s: compress : 0x%x\n", __func__, compress);
+	if (!substream) {
+		pr_err("%s substream not found\n", __func__);
+		return -EINVAL;
+	}
+	if (!substream->runtime) {
+		pr_err("%s substream runtime not found\n", __func__);
+		return 0;
+	}
+	prtd = substream->runtime->private_data;
+	if (prtd) {
+		pr_debug("%s: setting compress flag to 0x%x\n",
+		__func__, compress);
+		prtd->compress_enable = compress;
+	}
+	return rc;
+}
+
+static int msm_pcm_add_compress_control(struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = "Playback ";
+	const char *mixer_ctl_end_name = " Compress";
+	const char *deviceNo = "NN";
+	char *mixer_str = NULL;
+	int ctl_len;
+	int ret = 0;
+	struct msm_plat_data *pdata;
+	struct snd_kcontrol_new pcm_compress_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_pcm_compress_ctl_info,
+		.get = msm_pcm_compress_ctl_get,
+		.put = msm_pcm_compress_ctl_put,
+		.private_value = 0,
+		}
+	};
+
+	if (!rtd) {
+		pr_err("%s: NULL rtd\n", __func__);
+		return -EINVAL;
+	}
+
+	ctl_len = strlen(mixer_ctl_name) + strlen(deviceNo) +
+		  strlen(mixer_ctl_end_name) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+
+	if (!mixer_str)
+		return -ENOMEM;
+
+	snprintf(mixer_str, ctl_len, "%s%d%s", mixer_ctl_name,
+			rtd->pcm->device, mixer_ctl_end_name);
+
+	pcm_compress_control[0].name = mixer_str;
+	pcm_compress_control[0].private_value = rtd->dai_link->id;
+	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+	pdata = dev_get_drvdata(rtd->platform->dev);
+	if (pdata) {
+		if (!pdata->pcm) {
+			pdata->pcm = rtd->pcm;
+			snd_soc_add_platform_controls(rtd->platform,
+						      pcm_compress_control,
+						      ARRAY_SIZE
+						      (pcm_compress_control));
+			pr_debug("%s: add control success plt = %pK\n",
+				 __func__, rtd->platform);
+		}
+	} else {
+		pr_err("%s: NULL pdata\n", __func__);
+		ret = -EINVAL;
+	}
+	kfree(mixer_str);
+	return ret;
+}
+
 static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -1182,48 +1345,45 @@
 					struct snd_ctl_elem_value *ucontrol)
 {
 	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_RX;
+	int be_id = ucontrol->value.integer.value[3];
+	int ret = 0;
 	int app_type;
 	int acdb_dev_id;
 	int sample_rate = 48000;
 
-	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
-	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
-		pr_err("%s Received out of bounds fe_id %llu\n",
-			__func__, fe_id);
-		return -EINVAL;
-	}
-
 	app_type = ucontrol->value.integer.value[0];
 	acdb_dev_id = ucontrol->value.integer.value[1];
 	if (ucontrol->value.integer.value[2] != 0)
 		sample_rate = ucontrol->value.integer.value[2];
-	pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
-		__func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_RX);
-	msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
-			acdb_dev_id, sample_rate, SESSION_TYPE_RX);
+	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+		__func__, fe_id, session_type, be_id,
+		app_type, acdb_dev_id, sample_rate);
+	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+						      be_id, app_type,
+						      acdb_dev_id, sample_rate);
+	if (ret < 0)
+		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+			__func__, ret);
 
-	return 0;
+	return ret;
 }
 
 static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol)
 {
 	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_RX;
+	int be_id = ucontrol->value.integer.value[3];
 	int ret = 0;
 	int app_type;
 	int acdb_dev_id;
 	int sample_rate;
 
-	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
-	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
-		pr_err("%s Received out of bounds fe_id %llu\n",
-			__func__, fe_id);
-		ret = -EINVAL;
-		goto done;
-	}
-
-	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_RX,
-		&app_type, &acdb_dev_id, &sample_rate);
+	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+						      be_id, &app_type,
+						      &acdb_dev_id,
+						      &sample_rate);
 	if (ret < 0) {
 		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
@@ -1233,8 +1393,8 @@
 	ucontrol->value.integer.value[0] = app_type;
 	ucontrol->value.integer.value[1] = acdb_dev_id;
 	ucontrol->value.integer.value[2] = sample_rate;
-	pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
-		__func__, fe_id, SESSION_TYPE_RX,
+	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+		__func__, fe_id, session_type, be_id,
 		app_type, acdb_dev_id, sample_rate);
 done:
 	return ret;
@@ -1244,48 +1404,45 @@
 					struct snd_ctl_elem_value *ucontrol)
 {
 	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_TX;
+	int be_id = ucontrol->value.integer.value[3];
+	int ret = 0;
 	int app_type;
 	int acdb_dev_id;
 	int sample_rate = 48000;
 
-	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
-	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
-		pr_err("%s: Received out of bounds fe_id %llu\n",
-			__func__, fe_id);
-		return -EINVAL;
-	}
-
 	app_type = ucontrol->value.integer.value[0];
 	acdb_dev_id = ucontrol->value.integer.value[1];
 	if (ucontrol->value.integer.value[2] != 0)
 		sample_rate = ucontrol->value.integer.value[2];
-	pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
-		__func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
-	msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
-			acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+		__func__, fe_id, session_type, be_id,
+		app_type, acdb_dev_id, sample_rate);
+	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+						      be_id, app_type,
+						      acdb_dev_id, sample_rate);
+	if (ret < 0)
+		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+			__func__, ret);
 
-	return 0;
+	return ret;
 }
 
 static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol)
 {
 	u64 fe_id = kcontrol->private_value;
+	int session_type = SESSION_TYPE_TX;
+	int be_id = ucontrol->value.integer.value[3];
 	int ret = 0;
 	int app_type;
 	int acdb_dev_id;
 	int sample_rate;
 
-	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
-	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
-		pr_err("%s: Received out of bounds fe_id %llu\n",
-			__func__, fe_id);
-		ret = -EINVAL;
-		goto done;
-	}
-
-	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
-		&app_type, &acdb_dev_id, &sample_rate);
+	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+						      be_id, &app_type,
+						      &acdb_dev_id,
+						      &sample_rate);
 	if (ret < 0) {
 		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
@@ -1295,8 +1452,8 @@
 	ucontrol->value.integer.value[0] = app_type;
 	ucontrol->value.integer.value[1] = acdb_dev_id;
 	ucontrol->value.integer.value[2] = sample_rate;
-	pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
-		__func__, fe_id, SESSION_TYPE_TX,
+	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+		__func__, fe_id, session_type, be_id,
 		app_type, acdb_dev_id, sample_rate);
 done:
 	return ret;
@@ -1388,6 +1545,11 @@
 		pr_err("%s: Could not add pcm Volume Control %d\n",
 			__func__, ret);
 
+	ret = msm_pcm_add_compress_control(rtd);
+	if (ret)
+		pr_err("%s: Could not add pcm Compress Control %d\n",
+			__func__, ret);
+
 	return ret;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
index 5290d34..3b3f048 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -109,6 +109,7 @@
 	int cmd_interrupt;
 	bool meta_data_mode;
 	uint32_t volume;
+	bool compress_enable;
 	/* array of frame info */
 	struct msm_audio_in_frame_info in_frame_info[CAPTURE_MAX_NUM_PERIODS];
 };
@@ -123,6 +124,7 @@
 
 struct msm_plat_data {
 	int perf_mode;
+	struct snd_pcm *pcm;
 };
 
 #endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 3d13932..465634b 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -56,22 +56,26 @@
 #define DS2_ADM_COPP_TOPOLOGY_ID 0xFFFFFFFF
 #endif
 
-static int get_cal_path(int path_type);
-
 static struct mutex routing_lock;
 
 static struct cal_type_data *cal_data;
 
 static int fm_switch_enable;
 static int hfp_switch_enable;
+static int int0_mi2s_switch_enable;
+static int int4_mi2s_switch_enable;
 static int pri_mi2s_switch_enable;
 static int sec_mi2s_switch_enable;
 static int tert_mi2s_switch_enable;
 static int quat_mi2s_switch_enable;
 static int fm_pcmrx_switch_enable;
-static int lsm_mux_slim_port;
+static int usb_switch_enable;
+static int lsm_port_index;
 static int slim0_rx_aanc_fb_port;
 static int msm_route_ec_ref_rx;
+static int msm_ec_ref_ch = 4;
+static int msm_ec_ref_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+static int msm_ec_ref_sampling_rate = 48000;
 static uint32_t voc_session_id = ALL_SESSION_VSID;
 static int msm_route_ext_ec_ref;
 static bool is_custom_stereo_on;
@@ -85,6 +89,8 @@
 	MADSWAUDIO,
 };
 
+#define ADM_LSM_PORT_INDEX 9
+
 #define SLIMBUS_0_TX_TEXT "SLIMBUS_0_TX"
 #define SLIMBUS_1_TX_TEXT "SLIMBUS_1_TX"
 #define SLIMBUS_2_TX_TEXT "SLIMBUS_2_TX"
@@ -92,12 +98,17 @@
 #define SLIMBUS_4_TX_TEXT "SLIMBUS_4_TX"
 #define SLIMBUS_5_TX_TEXT "SLIMBUS_5_TX"
 #define TERT_MI2S_TX_TEXT "TERT_MI2S_TX"
+#define QUAT_MI2S_TX_TEXT "QUAT_MI2S_TX"
+#define ADM_LSM_TX_TEXT "ADM_LSM_TX"
+#define INT3_MI2S_TX_TEXT "INT3_MI2S_TX"
+
 #define LSM_FUNCTION_TEXT "LSM Function"
-static const char * const mad_audio_mux_text[] = {
+static const char * const lsm_port_text[] = {
 	"None",
 	SLIMBUS_0_TX_TEXT, SLIMBUS_1_TX_TEXT, SLIMBUS_2_TX_TEXT,
 	SLIMBUS_3_TX_TEXT, SLIMBUS_4_TX_TEXT, SLIMBUS_5_TX_TEXT,
-	TERT_MI2S_TX_TEXT
+	TERT_MI2S_TX_TEXT, QUAT_MI2S_TX_TEXT, ADM_LSM_TX_TEXT,
+	INT3_MI2S_TX_TEXT
 };
 
 struct msm_pcm_route_bdai_pp_params {
@@ -113,6 +124,18 @@
 	{DISPLAY_PORT_RX, 0, 0, 0},
 };
 
+/*
+ * The be_dai_name_table is passed to HAL so that it can specify the
+ * BE ID for the BE it wants to enable based on the name. Thus there
+ * is a matching table and structure in HAL that need to be updated
+ * if any changes to these are made.
+ */
+struct msm_pcm_route_bdai_name {
+	unsigned int be_id;
+	char be_name[LPASS_BE_NAME_MAX_LENGTH];
+};
+static struct msm_pcm_route_bdai_name be_dai_name_table[MSM_BACKEND_DAI_MAX];
+
 static int msm_routing_send_device_pp_params(int port_id,  int copp_idx);
 
 static int msm_routing_get_bit_width(unsigned int format)
@@ -120,6 +143,9 @@
 	int bit_width;
 
 	switch (format) {
+	case SNDRV_PCM_FORMAT_S32_LE:
+		bit_width = 32;
+		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
 	case SNDRV_PCM_FORMAT_S24_3LE:
 		bit_width = 24;
@@ -265,253 +291,261 @@
 
 #define SLIMBUS_EXTPROC_RX AFE_PORT_INVALID
 struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = {
-	{ PRIMARY_I2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_PRI_I2S_RX},
-	{ PRIMARY_I2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_PRI_I2S_TX},
-	{ SLIMBUS_0_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_0_RX},
-	{ SLIMBUS_0_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_0_TX},
-	{ HDMI_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_HDMI},
-	{ INT_BT_SCO_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_SCO_RX},
-	{ INT_BT_SCO_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_SCO_TX},
-	{ INT_FM_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_FM_RX},
-	{ INT_FM_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_FM_TX},
-	{ RT_PROXY_PORT_001_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_AFE_PCM_RX},
-	{ RT_PROXY_PORT_001_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_AFE_PCM_TX},
-	{ AFE_PORT_ID_PRIMARY_PCM_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ PRIMARY_I2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_PRI_I2S_RX},
+	{ PRIMARY_I2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_PRI_I2S_TX},
+	{ SLIMBUS_0_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_0_RX},
+	{ SLIMBUS_0_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_0_TX},
+	{ HDMI_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_HDMI},
+	{ INT_BT_SCO_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_SCO_RX},
+	{ INT_BT_SCO_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_SCO_TX},
+	{ INT_FM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_FM_RX},
+	{ INT_FM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_FM_TX},
+	{ RT_PROXY_PORT_001_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	  LPASS_BE_AFE_PCM_RX},
+	{ RT_PROXY_PORT_001_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	  LPASS_BE_AFE_PCM_TX},
+	{ AFE_PORT_ID_PRIMARY_PCM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_AUXPCM_RX},
-	{ AFE_PORT_ID_PRIMARY_PCM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_PCM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_AUXPCM_TX},
-	{ VOICE_PLAYBACK_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ VOICE_PLAYBACK_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_VOICE_PLAYBACK_TX},
-	{ VOICE2_PLAYBACK_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ VOICE2_PLAYBACK_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_VOICE2_PLAYBACK_TX},
-	{ VOICE_RECORD_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_INCALL_RECORD_RX},
-	{ VOICE_RECORD_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_INCALL_RECORD_TX},
-	{ MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_MI2S_RX},
-	{ MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_MI2S_TX},
-	{ SECONDARY_I2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SEC_I2S_RX},
-	{ SLIMBUS_1_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_1_RX},
-	{ SLIMBUS_1_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_1_TX},
-	{ SLIMBUS_2_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_2_RX},
-	{ SLIMBUS_2_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_2_TX},
-	{ SLIMBUS_3_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_3_RX},
-	{ SLIMBUS_3_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_3_TX},
-	{ SLIMBUS_4_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_RX},
-	{ SLIMBUS_4_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_TX},
-	{ SLIMBUS_5_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_5_RX},
-	{ SLIMBUS_5_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_5_TX},
-	{ SLIMBUS_6_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_RX},
-	{ SLIMBUS_6_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_TX},
-	{ SLIMBUS_7_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_RX},
-	{ SLIMBUS_7_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_TX},
-	{ SLIMBUS_8_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_RX},
-	{ SLIMBUS_8_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_TX},
-	{ SLIMBUS_EXTPROC_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_STUB_RX},
-	{ SLIMBUS_EXTPROC_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_STUB_TX},
-	{ SLIMBUS_EXTPROC_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_STUB_1_TX},
-	{ AFE_PORT_ID_QUATERNARY_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ VOICE_RECORD_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	  LPASS_BE_INCALL_RECORD_RX},
+	{ VOICE_RECORD_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	  LPASS_BE_INCALL_RECORD_TX},
+	{ MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_MI2S_RX},
+	{ MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_MI2S_TX},
+	{ SECONDARY_I2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SEC_I2S_RX},
+	{ SLIMBUS_1_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_1_RX},
+	{ SLIMBUS_1_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_1_TX},
+	{ SLIMBUS_2_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_2_RX},
+	{ SLIMBUS_2_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_2_TX},
+	{ SLIMBUS_3_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_3_RX},
+	{ SLIMBUS_3_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_3_TX},
+	{ SLIMBUS_4_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_RX},
+	{ SLIMBUS_4_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_TX},
+	{ SLIMBUS_5_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_5_RX},
+	{ SLIMBUS_5_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_5_TX},
+	{ SLIMBUS_6_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_RX},
+	{ SLIMBUS_6_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_TX},
+	{ SLIMBUS_7_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_RX},
+	{ SLIMBUS_7_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_TX},
+	{ SLIMBUS_8_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_RX},
+	{ SLIMBUS_8_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_TX},
+	{ SLIMBUS_EXTPROC_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_STUB_RX},
+	{ SLIMBUS_EXTPROC_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_STUB_TX},
+	{ SLIMBUS_EXTPROC_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_STUB_1_TX},
+	{ AFE_PORT_ID_QUATERNARY_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_MI2S_RX},
-	{ AFE_PORT_ID_QUATERNARY_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_MI2S_TX},
-	{ AFE_PORT_ID_SECONDARY_MI2S_RX,  0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_MI2S_RX,  0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_MI2S_RX},
-	{ AFE_PORT_ID_SECONDARY_MI2S_TX,  0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_MI2S_TX,  0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_MI2S_TX},
-	{ AFE_PORT_ID_PRIMARY_MI2S_RX,    0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_MI2S_RX,    0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_MI2S_RX},
-	{ AFE_PORT_ID_PRIMARY_MI2S_TX,    0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_MI2S_TX,    0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_MI2S_TX},
-	{ AFE_PORT_ID_TERTIARY_MI2S_RX,   0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_MI2S_RX,   0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_MI2S_RX},
-	{ AFE_PORT_ID_TERTIARY_MI2S_TX,   0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_MI2S_TX,   0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_MI2S_TX},
-	{ AUDIO_PORT_ID_I2S_RX,           0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AUDIO_PORT_ID_I2S_RX,           0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_AUDIO_I2S_RX},
-	{ AFE_PORT_ID_SECONDARY_PCM_RX,	  0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_PCM_RX,	  0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_AUXPCM_RX},
-	{ AFE_PORT_ID_SECONDARY_PCM_TX,   0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_PCM_TX,   0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_AUXPCM_TX},
-	{ AFE_PORT_ID_SPDIF_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SPDIF_RX},
-	{ AFE_PORT_ID_SECONDARY_MI2S_RX_SD1, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SPDIF_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SPDIF_RX},
+	{ AFE_PORT_ID_SECONDARY_MI2S_RX_SD1, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_MI2S_RX_SD1},
-	{ AFE_PORT_ID_QUINARY_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUINARY_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUIN_MI2S_RX},
-	{ AFE_PORT_ID_QUINARY_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUINARY_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUIN_MI2S_TX},
-	{ AFE_PORT_ID_SENARY_MI2S_TX,   0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SENARY_MI2S_TX,   0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SENARY_MI2S_TX},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_RX_0},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_TX_0},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_RX_1},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_TX_1},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_RX_2},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_TX_2},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_RX_3},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_TX_3},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_RX_4},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_TX_4},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_RX_5},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_TX_5},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_RX_6},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_TX_6},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_RX_7},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_PRI_TDM_TX_7},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_RX_0},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_TX_0},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_RX_1},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_TX_1},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_RX_2},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_TX_2},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_RX_3},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_TX_3},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_RX_4},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_TX_4},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_RX_5},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_TX_5},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_RX_6},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_TX_6},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_RX_7},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_SEC_TDM_TX_7},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_RX_0},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_TX_0},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_RX_1},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_TX_1},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_RX_2},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_TX_2},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_RX_3},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_TX_3},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_RX_4},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_TX_4},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_RX_5},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_TX_5},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_RX_6},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_TX_6},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_RX_7},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_TDM_TX_7},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_RX_0},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_TX_0},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_RX_1},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX_1, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_TX_1},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_RX_2},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX_2, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_TX_2},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_RX_3},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX_3, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_TX_3},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_RX_4},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX_4, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_TX_4},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_RX_5},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX_5, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_TX_5},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_RX_6},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX_6, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_TX_6},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_RX_7},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX_7, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_TDM_TX_7},
-	{ INT_BT_A2DP_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_A2DP_RX},
-	{ AFE_PORT_ID_USB_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_USB_AUDIO_RX},
-	{ AFE_PORT_ID_USB_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_USB_AUDIO_TX},
-	{ DISPLAY_PORT_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_DISPLAY_PORT},
-	{ AFE_PORT_ID_TERTIARY_PCM_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ INT_BT_A2DP_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_A2DP_RX},
+	{ AFE_PORT_ID_USB_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	  LPASS_BE_USB_AUDIO_RX},
+	{ AFE_PORT_ID_USB_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	  LPASS_BE_USB_AUDIO_TX},
+	{ DISPLAY_PORT_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_DISPLAY_PORT},
+	{ AFE_PORT_ID_TERTIARY_PCM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_AUXPCM_RX},
-	{ AFE_PORT_ID_TERTIARY_PCM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_PCM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_TERT_AUXPCM_TX},
-	{ AFE_PORT_ID_QUATERNARY_PCM_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_PCM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_AUXPCM_RX},
-	{ AFE_PORT_ID_QUATERNARY_PCM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_PCM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_QUAT_AUXPCM_TX},
-	{ AFE_PORT_ID_INT0_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT0_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_INT0_MI2S_RX},
-	{ AFE_PORT_ID_INT0_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT0_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_INT0_MI2S_TX},
-	{ AFE_PORT_ID_INT1_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT1_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_INT1_MI2S_RX},
-	{ AFE_PORT_ID_INT1_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT1_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_INT1_MI2S_TX},
-	{ AFE_PORT_ID_INT2_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT2_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_INT2_MI2S_RX},
-	{ AFE_PORT_ID_INT2_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT2_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_INT2_MI2S_TX},
-	{ AFE_PORT_ID_INT3_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT3_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_INT3_MI2S_RX},
-	{ AFE_PORT_ID_INT3_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT3_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_INT3_MI2S_TX},
-	{ AFE_PORT_ID_INT4_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT4_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_INT4_MI2S_RX},
-	{ AFE_PORT_ID_INT4_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT4_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_INT4_MI2S_TX},
-	{ AFE_PORT_ID_INT5_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT5_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_INT5_MI2S_RX},
-	{ AFE_PORT_ID_INT5_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT5_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_INT5_MI2S_TX},
-	{ AFE_PORT_ID_INT6_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT6_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_INT6_MI2S_RX},
-	{ AFE_PORT_ID_INT6_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT6_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
 	  LPASS_BE_INT6_MI2S_TX},
 };
 
-/* Track ASM playback & capture sessions of DAI */
+/* Track ASM playback & capture sessions of DAI
+ * Track LSM listen sessions
+ */
 static struct msm_pcm_routing_fdai_data
-	fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
+	fe_dai_map[MSM_FRONTEND_DAI_MAX][2] = {
 	/* MULTIMEDIA1 */
 	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
 	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
@@ -569,13 +603,80 @@
 	/* MULTIMEDIA19 */
 	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
 	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* CS_VOICE */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* VOIP */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* AFE_RX */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* AFE_TX */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* VOICE_STUB */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* VOLTE */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* DTMF_RX */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* VOICE2 */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* QCHAT */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* VOLTE_STUB */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* LSM1 */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* LSM2 */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* LSM3 */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* LSM4 */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* LSM5 */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* LSM6 */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* LSM7 */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* LSM8 */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* VOICE2_STUB */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* VOWLAN */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* VOICEMMODE1 */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* VOICEMMODE2 */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
 };
 
-static unsigned long session_copp_map[MSM_FRONTEND_DAI_MM_SIZE][2]
+static unsigned long session_copp_map[MSM_FRONTEND_DAI_MAX][2]
 				     [MSM_BACKEND_DAI_MAX];
 static struct msm_pcm_routing_app_type_data app_type_cfg[MAX_APP_TYPES];
+static struct msm_pcm_routing_app_type_data lsm_app_type_cfg[MAX_APP_TYPES];
 static struct msm_pcm_stream_app_type_cfg
-			 fe_dai_app_type_cfg[MSM_FRONTEND_DAI_MM_SIZE][2];
+	fe_dai_app_type_cfg[MSM_FRONTEND_DAI_MAX][2][MSM_BACKEND_DAI_MAX];
 
 /* The caller of this should aqcuire routing lock */
 void msm_pcm_routing_get_bedai_info(int be_idx,
@@ -618,44 +719,89 @@
 	return 0;
 }
 
-void msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int app_type,
-	int acdb_dev_id, int sample_rate, int session_type)
+static int msm_pcm_routing_get_lsm_app_type_idx(int app_type)
 {
-	pr_debug("%s: fedai_id %d, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
-		__func__, fedai_id, session_type, app_type,
-		acdb_dev_id, sample_rate);
-	if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+	int idx;
+
+	pr_debug("%s: app_type: %d\n", __func__, app_type);
+	for (idx = 0; idx < MAX_APP_TYPES; idx++) {
+		if (lsm_app_type_cfg[idx].app_type == app_type)
+			return idx;
+	}
+	pr_debug("%s: App type not available, fallback to default\n", __func__);
+	return 0;
+}
+
+static bool is_mm_lsm_fe_id(int fe_id)
+{
+	bool rc = true;
+
+	if (fe_id > MSM_FRONTEND_DAI_MM_MAX_ID &&
+		((fe_id < MSM_FRONTEND_DAI_LSM1) ||
+		 (fe_id > MSM_FRONTEND_DAI_LSM8))) {
+		rc = false;
+	}
+	return rc;
+}
+
+int msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int session_type,
+					    int be_id, int app_type,
+					    int acdb_dev_id, int sample_rate)
+{
+	int ret = 0;
+
+	pr_debug("%s: fedai_id %d, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+		__func__, fedai_id, session_type, be_id,
+		app_type, acdb_dev_id, sample_rate);
+
+	if (!is_mm_lsm_fe_id(fedai_id)) {
 		pr_err("%s: Invalid machine driver ID %d\n",
 			__func__, fedai_id);
-		return;
+		ret = -EINVAL;
+		goto done;
 	}
 	if (session_type != SESSION_TYPE_RX &&
 		session_type != SESSION_TYPE_TX) {
 		pr_err("%s: Invalid session type %d\n",
 			__func__, session_type);
-		return;
+		ret = -EINVAL;
+		goto done;
 	}
-	fe_dai_app_type_cfg[fedai_id][session_type].app_type = app_type;
-	fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id = acdb_dev_id;
-	fe_dai_app_type_cfg[fedai_id][session_type].sample_rate = sample_rate;
+	if (be_id < 0 || be_id >= MSM_BACKEND_DAI_MAX) {
+		pr_err("%s: Received out of bounds be_id %d\n",
+			__func__, be_id);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	fe_dai_app_type_cfg[fedai_id][session_type][be_id].app_type = app_type;
+	fe_dai_app_type_cfg[fedai_id][session_type][be_id].acdb_dev_id =
+		acdb_dev_id;
+	fe_dai_app_type_cfg[fedai_id][session_type][be_id].sample_rate =
+		sample_rate;
+
+done:
+	return ret;
 }
 
 /**
  * msm_pcm_routing_get_stream_app_type_cfg
  *
- * Receives fedai_id, session_type and populates app_type, acdb_dev_id, &
- * sample rate. Returns 0 on success. On failure returns
+ * Receives fedai_id, session_type, be_id, and populates app_type,
+ * acdb_dev_id, & sample rate. Returns 0 on success. On failure returns
  * -EINVAL and does not alter passed values.
  *
  * fedai_id - Passed value, front end ID for which app type config is wanted
  * session_type - Passed value, session type for which app type config
  *                is wanted
+ * be_id - Passed value, back end device id for which app type config is wanted
  * app_type - Returned value, app type used by app type config
  * acdb_dev_id - Returned value, ACDB device ID used by app type config
  * sample_rate - Returned value, sample rate used by app type config
  */
 int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type,
-	int *app_type, int *acdb_dev_id, int *sample_rate)
+					    int be_id, int *app_type,
+					    int *acdb_dev_id, int *sample_rate)
 {
 	int ret = 0;
 
@@ -671,24 +817,31 @@
 		pr_err("%s: NULL pointer sent for sample rate\n", __func__);
 		ret = -EINVAL;
 		goto done;
-	} else if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+	} else if (!is_mm_lsm_fe_id(fedai_id)) {
 		pr_err("%s: Invalid FE ID %d\n",
 			__func__, fedai_id);
 		ret = -EINVAL;
 		goto done;
 	} else if (session_type != SESSION_TYPE_RX &&
-		session_type != SESSION_TYPE_TX) {
+		   session_type != SESSION_TYPE_TX) {
 		pr_err("%s: Invalid session type %d\n",
 			__func__, session_type);
 		ret = -EINVAL;
 		goto done;
+	} else if (be_id < 0 || be_id >= MSM_BACKEND_DAI_MAX) {
+		pr_err("%s: Received out of bounds be_id %d\n",
+			__func__, be_id);
+		return -EINVAL;
 	}
-	*app_type = fe_dai_app_type_cfg[fedai_id][session_type].app_type;
-	*acdb_dev_id = fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
-	*sample_rate = fe_dai_app_type_cfg[fedai_id][session_type].sample_rate;
 
-	pr_debug("%s: fedai_id %d, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
-		__func__, fedai_id, session_type,
+	*app_type = fe_dai_app_type_cfg[fedai_id][session_type][be_id].app_type;
+	*acdb_dev_id =
+		fe_dai_app_type_cfg[fedai_id][session_type][be_id].acdb_dev_id;
+	*sample_rate =
+		fe_dai_app_type_cfg[fedai_id][session_type][be_id].sample_rate;
+
+	pr_debug("%s: fedai_id %d, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+		__func__, fedai_id, session_type, be_id,
 		*app_type, *acdb_dev_id, *sample_rate);
 done:
 	return ret;
@@ -719,8 +872,7 @@
 
 static struct cal_block_data *msm_routing_find_topology(int path,
 							int app_type,
-							int acdb_id,
-							int sample_rate)
+							int acdb_id)
 {
 	struct list_head *ptr, *next;
 	struct cal_block_data *cal_block = NULL;
@@ -738,37 +890,37 @@
 			cal_block->cal_info;
 		if ((cal_info->path == path)  &&
 			(cal_info->app_type == app_type) &&
-			(cal_info->acdb_id == acdb_id) &&
-			(cal_info->sample_rate == sample_rate)) {
+			(cal_info->acdb_id == acdb_id)) {
 			return cal_block;
 		}
 	}
-	pr_debug("%s: Can't find topology for path %d, app %d, acdb_id %d sample_rate %d defaulting to search by path\n",
-		__func__, path, app_type, acdb_id, sample_rate);
+	pr_debug("%s: Can't find topology for path %d, app %d, acdb_id %d defaulting to search by path\n",
+		__func__, path, app_type, acdb_id);
 	return msm_routing_find_topology_by_path(path);
 }
 
-static int msm_routing_get_adm_topology(int path, int fedai_id,
-					int session_type)
+static int msm_routing_get_adm_topology(int fedai_id, int session_type,
+					int be_id)
 {
 	int topology = NULL_COPP_TOPOLOGY;
 	struct cal_block_data *cal_block = NULL;
-	int app_type = 0, acdb_dev_id = 0, sample_rate = 0;
+	int app_type = 0, acdb_dev_id = 0;
 
-	pr_debug("%s\n", __func__);
 
-	path = get_cal_path(path);
+	pr_debug("%s: fedai_id %d, session_type %d, be_id %d\n",
+	       __func__, fedai_id, session_type, be_id);
+
 	if (cal_data == NULL)
 		goto done;
 
 	mutex_lock(&cal_data->lock);
 
-	app_type = fe_dai_app_type_cfg[fedai_id][session_type].app_type;
-	acdb_dev_id = fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
-	sample_rate = fe_dai_app_type_cfg[fedai_id][session_type].sample_rate;
+	app_type = fe_dai_app_type_cfg[fedai_id][session_type][be_id].app_type;
+	acdb_dev_id =
+		fe_dai_app_type_cfg[fedai_id][session_type][be_id].acdb_dev_id;
 
-	cal_block = msm_routing_find_topology(path, app_type,
-					      acdb_dev_id, sample_rate);
+	cal_block = msm_routing_find_topology(session_type, app_type,
+					      acdb_dev_id);
 	if (cal_block == NULL)
 		goto unlock;
 
@@ -792,20 +944,21 @@
 }
 
 static void msm_pcm_routing_build_matrix(int fedai_id, int sess_type,
-					 int path_type, int perf_mode)
+					 int path_type, int perf_mode,
+					 uint32_t passthr_mode)
 {
 	int i, port_type, j, num_copps = 0;
 	struct route_payload payload;
 
-	port_type = ((path_type == ADM_PATH_PLAYBACK  ||
-		     path_type == ADM_PATH_COMPRESSED_RX) ?
+	port_type = ((path_type == ADM_PATH_PLAYBACK ||
+		      path_type == ADM_PATH_COMPRESSED_RX) ?
 		MSM_AFE_PORT_TYPE_RX : MSM_AFE_PORT_TYPE_TX);
 
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
 		if (!is_be_dai_extproc(i) &&
 		   (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
 		   (msm_bedais[i].active) &&
-		   (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
+		   (test_bit(fedai_id, &msm_bedais[i].fe_sessions[0]))) {
 			for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
 				unsigned long copp =
 				      session_copp_map[fedai_id][sess_type][i];
@@ -813,6 +966,18 @@
 					payload.port_id[num_copps] =
 							msm_bedais[i].port_id;
 					payload.copp_idx[num_copps] = j;
+					payload.app_type[num_copps] =
+						fe_dai_app_type_cfg
+							[fedai_id][sess_type][i]
+								.app_type;
+					payload.acdb_dev_id[num_copps] =
+						fe_dai_app_type_cfg
+							[fedai_id][sess_type][i]
+								.acdb_dev_id;
+					payload.sample_rate[num_copps] =
+						fe_dai_app_type_cfg
+							[fedai_id][sess_type][i]
+								.sample_rate;
 					num_copps++;
 				}
 			}
@@ -822,13 +987,7 @@
 	if (num_copps) {
 		payload.num_copps = num_copps;
 		payload.session_id = fe_dai_map[fedai_id][sess_type].strm_id;
-		payload.app_type =
-			fe_dai_app_type_cfg[fedai_id][sess_type].app_type;
-		payload.acdb_dev_id =
-			fe_dai_app_type_cfg[fedai_id][sess_type].acdb_dev_id;
-		payload.sample_rate =
-			fe_dai_app_type_cfg[fedai_id][sess_type].sample_rate;
-		adm_matrix_map(path_type, payload, perf_mode);
+		adm_matrix_map(path_type, payload, perf_mode, passthr_mode);
 		msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
 	}
 }
@@ -862,7 +1021,7 @@
 		if (!is_be_dai_extproc(i) &&
 		    (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
 		    (msm_bedais[i].active) &&
-		    (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
+		    (test_bit(fedai_id, &msm_bedais[i].fe_sessions[0]))) {
 			mode = afe_get_port_type(msm_bedais[i].port_id);
 			adm_connect_afe_port(mode, dspst_id,
 					     msm_bedais[i].port_id);
@@ -872,28 +1031,52 @@
 	mutex_unlock(&routing_lock);
 }
 
+static bool route_check_fe_id_adm_support(int fe_id)
+{
+	bool rc = true;
+
+	if ((fe_id >= MSM_FRONTEND_DAI_LSM1) &&
+		 (fe_id <= MSM_FRONTEND_DAI_LSM8)) {
+		/* fe id is listen while port is set to afe */
+		if (lsm_port_index != ADM_LSM_PORT_INDEX) {
+			pr_debug("%s: fe_id %d, lsm mux slim port %d\n",
+				__func__, fe_id, lsm_port_index);
+			rc = false;
+		}
+	}
+
+	return rc;
+}
+
 int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode,
 					  int dspst_id, int stream_type,
-					  uint32_t compr_passthr_mode)
+					  uint32_t passthr_mode)
 {
-	int i, j, session_type, path_type, port_type, topology, num_copps = 0;
+	int i, j, session_type, path_type, port_type, topology;
+	int num_copps = 0;
 	struct route_payload payload;
 	u32 channels, sample_rate;
 	u16 bit_width = 16;
+	bool is_lsm;
 
 	pr_debug("%s:fe_id[%d] perf_mode[%d] id[%d] stream_type[%d] passt[%d]",
 		 __func__, fe_id, perf_mode, dspst_id,
-		 stream_type, compr_passthr_mode);
-
-	if (fe_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+		 stream_type, passthr_mode);
+	if (!is_mm_lsm_fe_id(fe_id)) {
 		/* bad ID assigned in machine driver */
 		pr_err("%s: bad MM ID %d\n", __func__, fe_id);
 		return -EINVAL;
 	}
 
+	if (!route_check_fe_id_adm_support(fe_id)) {
+		/* ignore adm open if not supported for fe_id */
+		pr_debug("%s: No ADM support for fe id %d\n", __func__, fe_id);
+		return 0;
+	}
+
 	if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
 		session_type = SESSION_TYPE_RX;
-		if (compr_passthr_mode != LEGACY_PCM)
+		if (passthr_mode != LEGACY_PCM)
 			path_type = ADM_PATH_COMPRESSED_RX;
 		else
 			path_type = ADM_PATH_PLAYBACK;
@@ -907,6 +1090,8 @@
 		return -EINVAL;
 	}
 
+	is_lsm = (fe_id >= MSM_FRONTEND_DAI_LSM1) &&
+			 (fe_id <= MSM_FRONTEND_DAI_LSM8);
 	mutex_lock(&routing_lock);
 
 	payload.num_copps = 0; /* only RX needs to use payload */
@@ -914,14 +1099,14 @@
 	/* re-enable EQ if active */
 	msm_qti_pp_send_eq_values(fe_id);
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
-		if (test_bit(fe_id, &msm_bedais[i].fe_sessions))
-			msm_bedais[i].compr_passthr_mode = compr_passthr_mode;
+		if (test_bit(fe_id, &msm_bedais[i].fe_sessions[0]))
+			msm_bedais[i].passthr_mode = passthr_mode;
 
 		if (!is_be_dai_extproc(i) &&
 			(afe_get_port_type(msm_bedais[i].port_id) ==
 			port_type) &&
 			(msm_bedais[i].active) &&
-			(test_bit(fe_id, &msm_bedais[i].fe_sessions))) {
+			(test_bit(fe_id, &msm_bedais[i].fe_sessions[0]))) {
 			int app_type, app_type_idx, copp_idx, acdb_dev_id;
 
 			/*
@@ -936,25 +1121,36 @@
 			bit_width = msm_routing_get_bit_width(
 						msm_bedais[i].format);
 			app_type =
-			fe_dai_app_type_cfg[fe_id][session_type].app_type;
-			if (app_type) {
+			fe_dai_app_type_cfg[fe_id][session_type][i].app_type;
+			if (app_type && is_lsm) {
+				app_type_idx =
+				msm_pcm_routing_get_lsm_app_type_idx(app_type);
+				sample_rate =
+				fe_dai_app_type_cfg[fe_id][session_type][i]
+					.sample_rate;
+				bit_width =
+				lsm_app_type_cfg[app_type_idx].bit_width;
+			} else if (app_type) {
 				app_type_idx =
 					msm_pcm_routing_get_app_type_idx(
 						app_type);
 				sample_rate =
-			fe_dai_app_type_cfg[fe_id][session_type].sample_rate;
+			fe_dai_app_type_cfg[fe_id][session_type][i].sample_rate;
 				bit_width =
 					app_type_cfg[app_type_idx].bit_width;
 			} else {
 				sample_rate = msm_bedais[i].sample_rate;
 			}
 			acdb_dev_id =
-			fe_dai_app_type_cfg[fe_id][session_type].acdb_dev_id;
-			topology = msm_routing_get_adm_topology(path_type,
-						fe_id, session_type);
-			if (compr_passthr_mode == COMPRESSED_PASSTHROUGH_DSD)
-				topology = COMPRESS_PASSTHROUGH_NONE_TOPOLOGY;
-			pr_err("%s: Before adm open topology %d\n", __func__,
+			fe_dai_app_type_cfg[fe_id][session_type][i].acdb_dev_id;
+			topology = msm_routing_get_adm_topology(fe_id,
+								session_type,
+								i);
+			if ((passthr_mode == COMPRESSED_PASSTHROUGH_DSD)
+			     || (passthr_mode ==
+			     COMPRESSED_PASSTHROUGH_GEN))
+				topology = COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY;
+			pr_debug("%s: Before adm open topology %d\n", __func__,
 				topology);
 
 			copp_idx =
@@ -988,10 +1184,24 @@
 					payload.port_id[num_copps] =
 					msm_bedais[i].port_id;
 					payload.copp_idx[num_copps] = j;
+					payload.app_type[num_copps] =
+						fe_dai_app_type_cfg
+							[fe_id][session_type][i]
+								.app_type;
+					payload.acdb_dev_id[num_copps] =
+						fe_dai_app_type_cfg
+							[fe_id][session_type][i]
+								.acdb_dev_id;
+					payload.sample_rate[num_copps] =
+						fe_dai_app_type_cfg
+							[fe_id][session_type][i]
+								.sample_rate;
 					num_copps++;
 				}
 			}
-			if (compr_passthr_mode != COMPRESSED_PASSTHROUGH_DSD) {
+			if (passthr_mode != COMPRESSED_PASSTHROUGH_DSD
+			    && passthr_mode !=
+			    COMPRESSED_PASSTHROUGH_GEN) {
 				msm_routing_send_device_pp_params(
 				msm_bedais[i].port_id,
 				copp_idx);
@@ -1001,11 +1211,7 @@
 	if (num_copps) {
 		payload.num_copps = num_copps;
 		payload.session_id = fe_dai_map[fe_id][session_type].strm_id;
-		payload.app_type =
-			fe_dai_app_type_cfg[fe_id][session_type].app_type;
-		payload.acdb_dev_id =
-			fe_dai_app_type_cfg[fe_id][session_type].acdb_dev_id;
-		adm_matrix_map(path_type, payload, perf_mode);
+		adm_matrix_map(path_type, payload, perf_mode, passthr_mode);
 		msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
 	}
 	mutex_unlock(&routing_lock);
@@ -1056,6 +1262,7 @@
 	struct route_payload payload;
 	u32 channels, sample_rate;
 	uint16_t bits_per_sample = 16;
+	uint32_t passthr_mode = LEGACY_PCM;
 
 	if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
 		/* bad ID assigned in machine driver */
@@ -1085,7 +1292,7 @@
 		if (!is_be_dai_extproc(i) &&
 		   (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
 		   (msm_bedais[i].active) &&
-		   (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
+		   (test_bit(fedai_id, &msm_bedais[i].fe_sessions[0]))) {
 			int app_type, app_type_idx, copp_idx, acdb_dev_id;
 			/*
 			 * check if ADM needs to be configured with different
@@ -1095,29 +1302,31 @@
 				channels = msm_bedais[i].channel;
 			else
 				channels = msm_bedais[i].adm_override_ch;
-			msm_bedais[i].compr_passthr_mode =
+			msm_bedais[i].passthr_mode =
 				LEGACY_PCM;
 
 			bits_per_sample = msm_routing_get_bit_width(
 						msm_bedais[i].format);
 
 			app_type =
-			fe_dai_app_type_cfg[fedai_id][session_type].app_type;
+			fe_dai_app_type_cfg[fedai_id][session_type][i].app_type;
 			if (app_type) {
 				app_type_idx =
 				msm_pcm_routing_get_app_type_idx(app_type);
 				sample_rate =
-				fe_dai_app_type_cfg[fedai_id][session_type].
-					sample_rate;
+				fe_dai_app_type_cfg[fedai_id][session_type][i]
+					.sample_rate;
 				bits_per_sample =
 					app_type_cfg[app_type_idx].bit_width;
 			} else
 				sample_rate = msm_bedais[i].sample_rate;
 
 			acdb_dev_id =
-			fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
-			topology = msm_routing_get_adm_topology(path_type,
-						fedai_id, session_type);
+			fe_dai_app_type_cfg[fedai_id][session_type][i]
+				.acdb_dev_id;
+			topology = msm_routing_get_adm_topology(fedai_id,
+								session_type,
+								i);
 			copp_idx = adm_open(msm_bedais[i].port_id, path_type,
 					    sample_rate, channels, topology,
 					    perf_mode, bits_per_sample,
@@ -1148,11 +1357,23 @@
 					payload.port_id[num_copps] =
 							msm_bedais[i].port_id;
 					payload.copp_idx[num_copps] = j;
+					payload.app_type[num_copps] =
+						fe_dai_app_type_cfg
+							[fedai_id][session_type]
+							[i].app_type;
+					payload.acdb_dev_id[num_copps] =
+						fe_dai_app_type_cfg
+							[fedai_id][session_type]
+							[i].acdb_dev_id;
+					payload.sample_rate[num_copps] =
+						fe_dai_app_type_cfg
+							[fedai_id][session_type]
+							[i].sample_rate;
 					num_copps++;
 				}
 			}
 			if ((perf_mode == LEGACY_PCM_MODE) &&
-				(msm_bedais[i].compr_passthr_mode ==
+				(msm_bedais[i].passthr_mode ==
 				LEGACY_PCM))
 				msm_pcm_routing_cfg_pp(msm_bedais[i].port_id,
 						       copp_idx, topology,
@@ -1162,13 +1383,7 @@
 	if (num_copps) {
 		payload.num_copps = num_copps;
 		payload.session_id = fe_dai_map[fedai_id][session_type].strm_id;
-		payload.app_type =
-			fe_dai_app_type_cfg[fedai_id][session_type].app_type;
-		payload.acdb_dev_id =
-			fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
-		payload.sample_rate =
-			fe_dai_app_type_cfg[fedai_id][session_type].sample_rate;
-		adm_matrix_map(path_type, payload, perf_mode);
+		adm_matrix_map(path_type, payload, perf_mode, passthr_mode);
 		msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
 	}
 	mutex_unlock(&routing_lock);
@@ -1197,7 +1412,7 @@
 	int i, port_type, session_type, path_type, topology;
 	struct msm_pcm_routing_fdai_data *fdai;
 
-	if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+	if (!is_mm_lsm_fe_id(fedai_id)) {
 		/* bad ID assigned in machine driver */
 		pr_err("%s: bad MM ID\n", __func__);
 		return;
@@ -1218,7 +1433,7 @@
 		if (!is_be_dai_extproc(i) &&
 		   (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
 		   (msm_bedais[i].active) &&
-		   (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
+		   (test_bit(fedai_id, &msm_bedais[i].fe_sessions[0]))) {
 			int idx;
 			unsigned long copp =
 				session_copp_map[fedai_id][session_type][i];
@@ -1243,7 +1458,7 @@
 			if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID ||
 				topology == DS2_ADM_COPP_TOPOLOGY_ID) &&
 			    (fdai->perf_mode == LEGACY_PCM_MODE) &&
-			    (msm_bedais[i].compr_passthr_mode ==
+			    (msm_bedais[i].passthr_mode ==
 					LEGACY_PCM))
 				msm_pcm_routing_deinit_pp(msm_bedais[i].port_id,
 							  topology);
@@ -1260,13 +1475,13 @@
 {
 	bool rc = false;
 
-	if (fe_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+	if (!is_mm_lsm_fe_id(fe_id)) {
 		/* recheck FE ID in the mixer control defined in this file */
 		pr_err("%s: bad MM ID\n", __func__);
 		return rc;
 	}
 
-	if (test_bit(fe_id, &msm_bedais[be_id].fe_sessions))
+	if (test_bit(fe_id, &msm_bedais[be_id].fe_sessions[0]))
 		rc = true;
 
 	return rc;
@@ -1278,19 +1493,27 @@
 	u32 channels, sample_rate;
 	uint16_t bits_per_sample = 16;
 	struct msm_pcm_routing_fdai_data *fdai;
+	uint32_t passthr_mode = msm_bedais[reg].passthr_mode;
+	bool is_lsm;
 
 	pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
 
-	if (val > MSM_FRONTEND_DAI_MM_MAX_ID) {
+	if (!is_mm_lsm_fe_id(val)) {
 		/* recheck FE ID in the mixer control defined in this file */
 		pr_err("%s: bad MM ID\n", __func__);
 		return;
 	}
 
+	if (!route_check_fe_id_adm_support(val)) {
+		/* ignore adm open if not supported for fe_id */
+		pr_debug("%s: No ADM support for fe id %d\n", __func__, val);
+		return;
+	}
+
 	if (afe_get_port_type(msm_bedais[reg].port_id) ==
 		MSM_AFE_PORT_TYPE_RX) {
 		session_type = SESSION_TYPE_RX;
-		if (msm_bedais[reg].compr_passthr_mode != LEGACY_PCM)
+		if (passthr_mode != LEGACY_PCM)
 			path_type = ADM_PATH_COMPRESSED_RX;
 		else
 			path_type = ADM_PATH_PLAYBACK;
@@ -1298,15 +1521,17 @@
 		session_type = SESSION_TYPE_TX;
 		path_type = ADM_PATH_LIVE_REC;
 	}
+	is_lsm = (val >= MSM_FRONTEND_DAI_LSM1) &&
+			 (val <= MSM_FRONTEND_DAI_LSM8);
 
 	mutex_lock(&routing_lock);
 	if (set) {
-		if (!test_bit(val, &msm_bedais[reg].fe_sessions) &&
+		if (!test_bit(val, &msm_bedais[reg].fe_sessions[0]) &&
 			((msm_bedais[reg].port_id == VOICE_PLAYBACK_TX) ||
 			(msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
 			voc_start_playback(set, msm_bedais[reg].port_id);
 
-		set_bit(val, &msm_bedais[reg].fe_sessions);
+		set_bit(val, &msm_bedais[reg].fe_sessions[0]);
 		fdai = &fe_dai_map[val][session_type];
 		if (msm_bedais[reg].active && fdai->strm_id !=
 			INVALID_SESSION) {
@@ -1336,22 +1561,31 @@
 						msm_bedais[reg].format);
 
 			app_type =
-				fe_dai_app_type_cfg[val][session_type].app_type;
-			if (app_type) {
+			fe_dai_app_type_cfg[val][session_type][reg].app_type;
+			if (app_type && is_lsm) {
+				app_type_idx =
+				msm_pcm_routing_get_lsm_app_type_idx(app_type);
+				sample_rate =
+				fe_dai_app_type_cfg[val][session_type][reg]
+					.sample_rate;
+				bits_per_sample =
+				lsm_app_type_cfg[app_type_idx].bit_width;
+			} else if (app_type) {
 				app_type_idx =
 				msm_pcm_routing_get_app_type_idx(app_type);
 				sample_rate =
-				fe_dai_app_type_cfg[val][session_type].
-					sample_rate;
+				fe_dai_app_type_cfg[val][session_type][reg]
+					.sample_rate;
 				bits_per_sample =
 					app_type_cfg[app_type_idx].bit_width;
 			} else
 				sample_rate = msm_bedais[reg].sample_rate;
 
-			topology = msm_routing_get_adm_topology(path_type, val,
-						session_type);
+			topology = msm_routing_get_adm_topology(val,
+								session_type,
+								reg);
 			acdb_dev_id =
-			fe_dai_app_type_cfg[val][session_type].acdb_dev_id;
+			fe_dai_app_type_cfg[val][session_type][reg].acdb_dev_id;
 			copp_idx = adm_open(msm_bedais[reg].port_id, path_type,
 					    sample_rate, channels, topology,
 					    fdai->perf_mode, bits_per_sample,
@@ -1382,20 +1616,20 @@
 
 			msm_pcm_routing_build_matrix(val, session_type,
 						     path_type,
-						     fdai->perf_mode);
+						     fdai->perf_mode,
+						     passthr_mode);
 			if ((fdai->perf_mode == LEGACY_PCM_MODE) &&
-				(msm_bedais[reg].compr_passthr_mode ==
-					LEGACY_PCM))
+				(passthr_mode == LEGACY_PCM))
 				msm_pcm_routing_cfg_pp(msm_bedais[reg].port_id,
 						       copp_idx, topology,
 						       channels);
 		}
 	} else {
-		if (test_bit(val, &msm_bedais[reg].fe_sessions) &&
+		if (test_bit(val, &msm_bedais[reg].fe_sessions[0]) &&
 			((msm_bedais[reg].port_id == VOICE_PLAYBACK_TX) ||
 			(msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
 			voc_start_playback(set, msm_bedais[reg].port_id);
-		clear_bit(val, &msm_bedais[reg].fe_sessions);
+		clear_bit(val, &msm_bedais[reg].fe_sessions[0]);
 		fdai = &fe_dai_map[val][session_type];
 		if (msm_bedais[reg].active && fdai->strm_id !=
 			INVALID_SESSION) {
@@ -1420,14 +1654,14 @@
 			if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID ||
 				topology == DS2_ADM_COPP_TOPOLOGY_ID) &&
 			    (fdai->perf_mode == LEGACY_PCM_MODE) &&
-			    (msm_bedais[reg].compr_passthr_mode ==
-				LEGACY_PCM))
+			    (passthr_mode == LEGACY_PCM))
 				msm_pcm_routing_deinit_pp(
 						msm_bedais[reg].port_id,
 						topology);
 			msm_pcm_routing_build_matrix(val, session_type,
 						     path_type,
-						     fdai->perf_mode);
+						     fdai->perf_mode,
+						     passthr_mode);
 		}
 	}
 	if ((msm_bedais[reg].port_id == VOICE_RECORD_RX)
@@ -1443,7 +1677,7 @@
 	struct soc_mixer_control *mc =
 	(struct soc_mixer_control *)kcontrol->private_value;
 
-	if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
+	if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0]))
 		ucontrol->value.integer.value[0] = 1;
 	else
 		ucontrol->value.integer.value[0] = 0;
@@ -1479,6 +1713,51 @@
 	return 1;
 }
 
+static int msm_routing_get_listen_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+	(struct soc_mixer_control *)kcontrol->private_value;
+
+	if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0]))
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+		ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int msm_routing_put_listen_mixer(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_dapm_update *update = NULL;
+
+	pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+		ucontrol->value.integer.value[0]);
+
+	if (ucontrol->value.integer.value[0]) {
+		if (msm_pcm_routing_route_is_set(mc->reg, mc->shift) == false)
+			msm_pcm_routing_process_audio(mc->reg, mc->shift, 1);
+		snd_soc_dapm_mixer_update_power(widget->dapm,
+						kcontrol, 1, update);
+	} else if (!ucontrol->value.integer.value[0]) {
+		if (msm_pcm_routing_route_is_set(mc->reg, mc->shift) == true)
+			msm_pcm_routing_process_audio(mc->reg, mc->shift, 0);
+		snd_soc_dapm_mixer_update_power(widget->dapm,
+						kcontrol, 0, update);
+	}
+
+	return 1;
+}
+
 static void msm_pcm_routing_process_voice(u16 reg, u16 val, int set)
 {
 	u32 session_id = 0;
@@ -1495,9 +1774,9 @@
 	mutex_lock(&routing_lock);
 
 	if (set)
-		set_bit(val, &msm_bedais[reg].fe_sessions);
+		set_bit(val, &msm_bedais[reg].fe_sessions[0]);
 	else
-		clear_bit(val, &msm_bedais[reg].fe_sessions);
+		clear_bit(val, &msm_bedais[reg].fe_sessions[0]);
 
 	if (val == MSM_FRONTEND_DAI_DTMF_RX &&
 	    afe_get_port_type(msm_bedais[reg].port_id) ==
@@ -1556,7 +1835,7 @@
 
 	mutex_lock(&routing_lock);
 
-	if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
+	if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0]))
 		ucontrol->value.integer.value[0] = 1;
 	else
 		ucontrol->value.integer.value[0] = 0;
@@ -1600,7 +1879,7 @@
 
 	mutex_lock(&routing_lock);
 
-	if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
+	if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0]))
 		ucontrol->value.integer.value[0] = 1;
 	else
 		ucontrol->value.integer.value[0] = 0;
@@ -1625,14 +1904,14 @@
 
 	if (ucontrol->value.integer.value[0]) {
 		mutex_lock(&routing_lock);
-		set_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions);
+		set_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0]);
 		mutex_unlock(&routing_lock);
 
 		snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1,
 						update);
 	} else {
 		mutex_lock(&routing_lock);
-		clear_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions);
+		clear_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0]);
 		mutex_unlock(&routing_lock);
 
 		snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0,
@@ -1645,6 +1924,68 @@
 	return 1;
 }
 
+/*
+ * Return the mapping between port ID and backend ID to enable the AFE callback
+ * to determine the acdb_dev_id from the port id
+ */
+int msm_pcm_get_be_id_from_port_id(int port_id)
+{
+	int i;
+	int be_id = -EINVAL;
+
+	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+		if (msm_bedais[i].port_id == port_id) {
+			be_id = i;
+			break;
+		}
+	}
+
+	return be_id;
+}
+
+/*
+ * Return the registered dev_acdb_id given a port ID to enable identifying the
+ * correct AFE calibration information by comparing the header information.
+ */
+static int msm_pcm_get_dev_acdb_id_by_port_id(int port_id)
+{
+	int acdb_id = -EINVAL;
+	int i = 0;
+	int session;
+	int port_type = afe_get_port_type(port_id);
+	int be_id = msm_pcm_get_be_id_from_port_id(port_id);
+
+	pr_debug("%s:port_id %d be_id %d, port_type 0x%x\n",
+		  __func__, port_id, be_id, port_type);
+
+	if (port_type == MSM_AFE_PORT_TYPE_TX) {
+		session = SESSION_TYPE_TX;
+	} else if (port_type == MSM_AFE_PORT_TYPE_RX) {
+		session = SESSION_TYPE_RX;
+	} else {
+		pr_err("%s: Invalid port type %d\n", __func__, port_type);
+		acdb_id = -EINVAL;
+		goto exit;
+	}
+
+	if (be_id < 0) {
+		pr_err("%s: Error getting backend id %d\n", __func__, be_id);
+		goto exit;
+	}
+
+	mutex_lock(&routing_lock);
+	i = find_first_bit(&msm_bedais[be_id].fe_sessions[0],
+			   MSM_FRONTEND_DAI_MAX);
+	if (i < MSM_FRONTEND_DAI_MAX)
+		acdb_id = fe_dai_app_type_cfg[i][session][be_id].acdb_dev_id;
+
+	pr_debug("%s: FE[%d] session[%d] BE[%d] acdb_id(%d)\n",
+		 __func__, i, session, be_id, acdb_id);
+	mutex_unlock(&routing_lock);
+exit:
+	return acdb_id;
+}
+
 static int msm_routing_get_switch_mixer(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -1703,6 +2044,93 @@
 	return 1;
 }
 
+static int msm_routing_get_int0_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = int0_mi2s_switch_enable;
+	pr_debug("%s: INT0 MI2S Switch enable %ld\n", __func__,
+		ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int msm_routing_put_int0_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_dapm_update *update = NULL;
+
+	pr_debug("%s: INT0 MI2S Switch enable %ld\n", __func__,
+			ucontrol->value.integer.value[0]);
+	if (ucontrol->value.integer.value[0])
+		snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1,
+						update);
+	else
+		snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0,
+						update);
+	int0_mi2s_switch_enable = ucontrol->value.integer.value[0];
+	return 1;
+}
+
+static int msm_routing_get_int4_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = int4_mi2s_switch_enable;
+	pr_debug("%s: INT4 MI2S Switch enable %ld\n", __func__,
+		ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int msm_routing_put_int4_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_dapm_update *update = NULL;
+
+	pr_debug("%s: INT4 MI2S Switch enable %ld\n", __func__,
+			ucontrol->value.integer.value[0]);
+	if (ucontrol->value.integer.value[0])
+		snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1,
+						update);
+	else
+		snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0,
+						update);
+	int4_mi2s_switch_enable = ucontrol->value.integer.value[0];
+	return 1;
+}
+
+static int msm_routing_get_usb_switch_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = usb_switch_enable;
+	pr_debug("%s: HFP Switch enable %ld\n", __func__,
+		ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int msm_routing_put_usb_switch_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_dapm_update *update = NULL;
+
+	pr_debug("%s: USB Switch enable %ld\n", __func__,
+			ucontrol->value.integer.value[0]);
+	if (ucontrol->value.integer.value[0])
+		snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol,
+						1, update);
+	else
+		snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol,
+						0, update);
+	usb_switch_enable = ucontrol->value.integer.value[0];
+	return 1;
+}
+
 static int msm_routing_get_pri_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -1852,23 +2280,24 @@
 	return 1;
 }
 
-static int msm_routing_lsm_mux_get(struct snd_kcontrol *kcontrol,
+static int msm_routing_lsm_port_get(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
-	ucontrol->value.integer.value[0] = lsm_mux_slim_port;
+	ucontrol->value.integer.value[0] = lsm_port_index;
 	return 0;
 }
 
-static int msm_routing_lsm_mux_put(struct snd_kcontrol *kcontrol,
+static int msm_routing_lsm_port_put(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist =
-					dapm_kcontrol_get_wlist(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	int mux = ucontrol->value.enumerated.item[0];
 	int lsm_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX;
-	struct snd_soc_dapm_update *update = NULL;
+
+	if (mux >= e->items) {
+		pr_err("%s: Invalid mux value %d\n", __func__, mux);
+		return -EINVAL;
+	}
 
 	pr_debug("%s: LSM enable %ld\n", __func__,
 			ucontrol->value.integer.value[0]);
@@ -1894,21 +2323,21 @@
 	case 7:
 		lsm_port = AFE_PORT_ID_TERTIARY_MI2S_TX;
 		break;
+	case 8:
+		lsm_port = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+		break;
+	case 9:
+		lsm_port = ADM_LSM_PORT_ID;
+		break;
+	case 10:
+		lsm_port = AFE_PORT_ID_INT3_MI2S_TX;
+		break;
 	default:
 		pr_err("Default lsm port");
 		break;
 	}
 	set_lsm_port(lsm_port);
-
-	if (ucontrol->value.integer.value[0]) {
-		lsm_mux_slim_port = ucontrol->value.integer.value[0];
-		snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, mux, e,
-						update);
-	} else {
-		snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, mux, e,
-						update);
-		lsm_mux_slim_port = ucontrol->value.integer.value[0];
-	}
+	lsm_port_index = ucontrol->value.integer.value[0];
 
 	return 0;
 }
@@ -1921,22 +2350,31 @@
 	enum afe_mad_type mad_type;
 
 	pr_debug("%s: enter\n", __func__);
-	for (i = 0; i < ARRAY_SIZE(mad_audio_mux_text); i++)
-		if (!strcmp(kcontrol->id.name, mad_audio_mux_text[i]))
+	for (i = 0; i < ARRAY_SIZE(lsm_port_text); i++)
+		if (!strnstr(kcontrol->id.name, lsm_port_text[i],
+			    strlen(lsm_port_text[i])))
 			break;
 
-	if (i-- == ARRAY_SIZE(mad_audio_mux_text)) {
+	if (i-- == ARRAY_SIZE(lsm_port_text)) {
 		WARN(1, "Invalid id name %s\n", kcontrol->id.name);
 		return -EINVAL;
 	}
 
-	/*Check for Tertiary TX port*/
-	if (!strcmp(kcontrol->id.name, mad_audio_mux_text[7])) {
-		ucontrol->value.integer.value[0] = MADSWAUDIO;
-		return 0;
-	}
-
 	port_id = i * 2 + 1 + SLIMBUS_0_RX;
+
+	/*Check for Tertiary/Quaternary/INT3 TX port*/
+	if (strnstr(kcontrol->id.name, lsm_port_text[7],
+			strlen(lsm_port_text[7])))
+		port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+
+	if (strnstr(kcontrol->id.name, lsm_port_text[8],
+			strlen(lsm_port_text[8])))
+		port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+
+	if (strnstr(kcontrol->id.name, lsm_port_text[10],
+			strlen(lsm_port_text[10])))
+		port_id = AFE_PORT_ID_INT3_MI2S_TX;
+
 	mad_type = afe_port_get_mad_type(port_id);
 	pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
 		 mad_type);
@@ -1971,11 +2409,12 @@
 	enum afe_mad_type mad_type;
 
 	pr_debug("%s: enter\n", __func__);
-	for (i = 0; i < ARRAY_SIZE(mad_audio_mux_text); i++)
-		if (!strcmp(kcontrol->id.name, mad_audio_mux_text[i]))
+	for (i = 0; i < ARRAY_SIZE(lsm_port_text); i++)
+		if (strnstr(kcontrol->id.name, lsm_port_text[i],
+			    strlen(lsm_port_text[i])))
 			break;
 
-	if (i-- == ARRAY_SIZE(mad_audio_mux_text)) {
+	if (i-- == ARRAY_SIZE(lsm_port_text)) {
 		WARN(1, "Invalid id name %s\n", kcontrol->id.name);
 		return -EINVAL;
 	}
@@ -2002,11 +2441,18 @@
 		return -EINVAL;
 	}
 
-	/*Check for Tertiary TX port*/
-	if (!strcmp(kcontrol->id.name, mad_audio_mux_text[7])) {
+	/*Check for Tertiary/Quaternary/INT3 TX port*/
+	if (strnstr(kcontrol->id.name, lsm_port_text[7],
+			strlen(lsm_port_text[7])))
 		port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
-		mad_type = MAD_SW_AUDIO;
-	}
+
+	if (strnstr(kcontrol->id.name, lsm_port_text[8],
+			strlen(lsm_port_text[8])))
+		port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+
+	if (strnstr(kcontrol->id.name, lsm_port_text[10],
+			strlen(lsm_port_text[10])))
+		port_id = AFE_PORT_ID_INT3_MI2S_TX;
 
 	pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
 		 mad_type);
@@ -2172,6 +2618,144 @@
 	return 1;
 }
 
+static int msm_ec_ref_ch_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = msm_ec_ref_ch;
+	pr_debug("%s: msm_ec_ref_ch = %ld\n", __func__,
+		ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int msm_ec_ref_ch_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	msm_ec_ref_ch = ucontrol->value.integer.value[0];
+	pr_debug("%s: msm_ec_ref_ch = %d\n", __func__, msm_ec_ref_ch);
+	adm_num_ec_ref_rx_chans(msm_ec_ref_ch);
+	return 0;
+}
+
+static const char *const ec_ref_ch_text[] = {"Zero", "One", "Two", "Three",
+	"Four", "Five", "Six", "Seven", "Eight"};
+
+static int msm_ec_ref_bit_format_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	switch (msm_ec_ref_bit_format) {
+	case SNDRV_PCM_FORMAT_S24_LE:
+		ucontrol->value.integer.value[0] = 2;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		ucontrol->value.integer.value[0] = 1;
+		break;
+	default:
+		ucontrol->value.integer.value[0] = 0;
+		break;
+	}
+	pr_debug("%s: msm_ec_ref_bit_format = %ld\n",
+		 __func__, ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int msm_ec_ref_bit_format_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	u16 bit_width = 0;
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 2:
+		msm_ec_ref_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+		break;
+	case 1:
+		msm_ec_ref_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+		break;
+	default:
+		msm_ec_ref_bit_format = 0;
+		break;
+	}
+
+	if (msm_ec_ref_bit_format == SNDRV_PCM_FORMAT_S16_LE)
+		bit_width = 16;
+	else if (msm_ec_ref_bit_format == SNDRV_PCM_FORMAT_S24_LE)
+		bit_width = 24;
+
+	pr_debug("%s: msm_ec_ref_bit_format = %d\n",
+		 __func__, msm_ec_ref_bit_format);
+	adm_ec_ref_rx_bit_width(bit_width);
+	return 0;
+}
+
+static char const *ec_ref_bit_format_text[] = {"0", "S16_LE", "S24_LE"};
+
+static int msm_ec_ref_rate_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = msm_ec_ref_sampling_rate;
+	pr_debug("%s: msm_ec_ref_sampling_rate = %ld\n",
+		 __func__, ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int msm_ec_ref_rate_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		msm_ec_ref_sampling_rate = 0;
+		break;
+	case 1:
+		msm_ec_ref_sampling_rate = 8000;
+		break;
+	case 2:
+		msm_ec_ref_sampling_rate = 16000;
+		break;
+	case 3:
+		msm_ec_ref_sampling_rate = 32000;
+		break;
+	case 4:
+		msm_ec_ref_sampling_rate = 44100;
+		break;
+	case 5:
+		msm_ec_ref_sampling_rate = 48000;
+		break;
+	case 6:
+		msm_ec_ref_sampling_rate = 96000;
+		break;
+	case 7:
+		msm_ec_ref_sampling_rate = 192000;
+		break;
+	case 8:
+		msm_ec_ref_sampling_rate = 384000;
+		break;
+	default:
+		msm_ec_ref_sampling_rate = 48000;
+		break;
+	}
+	pr_debug("%s: msm_ec_ref_sampling_rate = %d\n",
+		 __func__, msm_ec_ref_sampling_rate);
+	adm_ec_ref_rx_sampling_rate(msm_ec_ref_sampling_rate);
+	return 0;
+}
+
+static const char *const ec_ref_rate_text[] = {"0", "8000", "16000",
+	"32000", "44100", "48000", "96000", "192000", "384000"};
+
+static const struct soc_enum msm_route_ec_ref_params_enum[] = {
+	SOC_ENUM_SINGLE_EXT(9, ec_ref_ch_text),
+	SOC_ENUM_SINGLE_EXT(3, ec_ref_bit_format_text),
+	SOC_ENUM_SINGLE_EXT(9, ec_ref_rate_text),
+};
+
+static const struct snd_kcontrol_new ec_ref_param_controls[] = {
+	SOC_ENUM_EXT("EC Reference Channels", msm_route_ec_ref_params_enum[0],
+		msm_ec_ref_ch_get, msm_ec_ref_ch_put),
+	SOC_ENUM_EXT("EC Reference Bit Format", msm_route_ec_ref_params_enum[1],
+		msm_ec_ref_bit_format_get, msm_ec_ref_bit_format_put),
+	SOC_ENUM_EXT("EC Reference SampleRate", msm_route_ec_ref_params_enum[2],
+		msm_ec_ref_rate_get, msm_ec_ref_rate_put),
+};
+
 static int msm_routing_ec_ref_rx_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -2189,10 +2773,10 @@
 	struct snd_soc_dapm_widget_list *wlist =
 					dapm_kcontrol_get_wlist(kcontrol);
 	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-	int mux = ucontrol->value.enumerated.item[0];
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	struct snd_soc_dapm_update *update = NULL;
 
+
 	mutex_lock(&routing_lock);
 	switch (ucontrol->value.integer.value[0]) {
 	case 0:
@@ -2271,6 +2855,18 @@
 		msm_route_ec_ref_rx = 19;
 		ec_ref_port_id = AFE_PORT_ID_USB_RX;
 		break;
+	case 20:
+		msm_route_ec_ref_rx = 20;
+		ec_ref_port_id = AFE_PORT_ID_INT0_MI2S_RX;
+		break;
+	case 21:
+		msm_route_ec_ref_rx = 21;
+		ec_ref_port_id = AFE_PORT_ID_INT4_MI2S_RX;
+		break;
+	case 22:
+		msm_route_ec_ref_rx = 22;
+		ec_ref_port_id = AFE_PORT_ID_INT3_MI2S_TX;
+		break;
 	default:
 		msm_route_ec_ref_rx = 0; /* NONE */
 		pr_err("%s EC ref rx %ld not valid\n",
@@ -2282,7 +2878,8 @@
 	pr_debug("%s: msm_route_ec_ref_rx = %d\n",
 	    __func__, msm_route_ec_ref_rx);
 	mutex_unlock(&routing_lock);
-	snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, mux, e, update);
+	snd_soc_dapm_mux_update_power(widget->dapm, kcontrol,
+					msm_route_ec_ref_rx, e, update);
 	return 0;
 }
 
@@ -2291,7 +2888,8 @@
 	"TERT_MI2S_TX", "QUAT_MI2S_TX", "SEC_I2S_RX", "PROXY_RX",
 	"SLIM_5_RX", "SLIM_1_TX", "QUAT_TDM_TX_1",
 	"QUAT_TDM_RX_0", "QUAT_TDM_RX_1", "QUAT_TDM_RX_2", "SLIM_6_RX",
-	"TERT_MI2S_RX", "QUAT_MI2S_RX", "TERT_TDM_TX_0", "USB_AUDIO_RX"};
+	"TERT_MI2S_RX", "QUAT_MI2S_RX", "TERT_TDM_TX_0", "USB_AUDIO_RX",
+	"INT0_MI2S_RX", "INT4_MI2S_RX", "INT3_MI2S_TX"};
 
 static const struct soc_enum msm_route_ec_ref_rx_enum[] = {
 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ec_ref_rx), ec_ref_rx),
@@ -2376,6 +2974,11 @@
 	uint16_t ext_ec_ref_port_id;
 	struct snd_soc_dapm_update *update = NULL;
 
+	if (mux >= e->items) {
+		pr_err("%s: Invalid mux value %d\n", __func__, mux);
+		return -EINVAL;
+	}
+
 	mutex_lock(&routing_lock);
 	msm_route_ext_ec_ref = ucontrol->value.integer.value[0];
 
@@ -4061,6 +4664,159 @@
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new pri_tdm_rx_1_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new pri_tdm_rx_2_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new pri_tdm_rx_3_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new pri_tdm_tx_0_mixer_controls[] = {
 	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_TDM_TX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -4163,6 +4919,159 @@
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new sec_tdm_rx_1_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new sec_tdm_rx_2_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new sec_tdm_rx_3_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new sec_tdm_tx_0_mixer_controls[] = {
 	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_TDM_TX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -4788,6 +5697,30 @@
 	SOC_SINGLE_EXT("QUIN_MI2S_TX", MSM_BACKEND_DAI_QUINARY_MI2S_TX,
 		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
 		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
 	SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
 		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
 		msm_routing_put_audio_mixer),
@@ -4851,9 +5784,39 @@
 	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_SINGLE_EXT("QUIN_MI2S_TX", MSM_BACKEND_DAI_QUINARY_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
@@ -4926,6 +5889,30 @@
 	SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
@@ -4977,6 +5964,30 @@
 	SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
@@ -5058,6 +6069,30 @@
 	SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
@@ -5136,6 +6171,30 @@
 	SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
@@ -5205,6 +6264,30 @@
 	SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
@@ -5237,6 +6320,57 @@
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new mmul9_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new mmul17_mixer_controls[] = {
 	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
@@ -6064,6 +7198,12 @@
 	msm_routing_put_voice_mixer),
 };
 
+static const struct snd_kcontrol_new quat_tdm_rx_2_voice_mixer_controls[] = {
+	SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+	MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
 static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
 	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_EXTPROC_RX,
 	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
@@ -6329,6 +7469,9 @@
 	SOC_SINGLE_EXT("USB_AUDIO_TX_MMode1", MSM_BACKEND_DAI_USB_TX,
 	MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_0_MMode1",
+	MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_VOICEMMODE1,
+	1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new tx_voicemmode2_mixer_controls[] = {
@@ -6622,6 +7765,66 @@
 	msm_routing_put_voice_mixer),
 };
 
+static const struct snd_kcontrol_new int0_mi2s_rx_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_INT0_MI2S_RX,
+	MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_INT0_MI2S_RX,
+	MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_INT0_MI2S_RX,
+	MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_INT0_MI2S_RX,
+	MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT0_MI2S_RX,
+	MSM_BACKEND_DAI_INT3_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT0_MI2S_RX,
+	MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT0_MI2S_RX,
+	MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_INT0_MI2S_RX,
+	MSM_BACKEND_DAI_SLIMBUS_7_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_INT0_MI2S_RX,
+	MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new int4_mi2s_rx_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_INT4_MI2S_RX,
+	MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_INT4_MI2S_RX,
+	MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_INT4_MI2S_RX,
+	MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_INT4_MI2S_RX,
+	MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT4_MI2S_RX,
+	MSM_BACKEND_DAI_INT3_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT4_MI2S_RX,
+	MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT4_MI2S_RX,
+	MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_INT4_MI2S_RX,
+	MSM_BACKEND_DAI_SLIMBUS_7_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_INT4_MI2S_RX,
+	MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+};
+
 static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
 	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
 	MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
@@ -6884,6 +8087,12 @@
 	msm_routing_put_port_mixer),
 };
 
+static const struct snd_kcontrol_new usb_rx_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_RX,
+	MSM_BACKEND_DAI_USB_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+};
+
 static const struct snd_kcontrol_new quat_mi2s_rx_port_mixer_controls[] = {
 	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
 	MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
@@ -6908,6 +8117,542 @@
 	msm_routing_put_port_mixer),
 };
 
+static const struct snd_kcontrol_new pri_tdm_rx_0_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new pri_tdm_rx_1_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_1,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new pri_tdm_rx_2_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_2,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new pri_tdm_rx_3_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_3,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new sec_tdm_rx_0_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_SEC_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_SEC_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_SEC_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_SEC_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new sec_tdm_rx_1_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_SEC_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_SEC_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_SEC_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_SEC_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_1,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new sec_tdm_rx_2_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_SEC_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_SEC_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_SEC_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_SEC_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_2,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new sec_tdm_rx_3_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_INT_FM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_SEC_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_SEC_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_SEC_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_SEC_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_3,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+};
+
 static const struct snd_kcontrol_new tert_tdm_rx_0_port_mixer_controls[] = {
 	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0,
 		MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0,
@@ -7483,6 +9228,222 @@
 	msm_routing_put_port_mixer),
 };
 
+static const struct snd_kcontrol_new lsm1_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+};
+
+static const struct snd_kcontrol_new lsm2_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+};
+
+static const struct snd_kcontrol_new lsm3_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+};
+
+static const struct snd_kcontrol_new lsm4_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+};
+
+static const struct snd_kcontrol_new lsm5_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+};
+
+static const struct snd_kcontrol_new lsm6_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+};
+
+static const struct snd_kcontrol_new lsm7_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+};
+
+static const struct snd_kcontrol_new lsm8_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+	SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+		MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+		msm_routing_put_listen_mixer),
+};
+
 static const struct snd_kcontrol_new slim_fm_switch_mixer_controls =
 	SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
 	0, 1, 0, msm_routing_get_switch_mixer,
@@ -7513,6 +9474,16 @@
 	0, 1, 0, msm_routing_get_fm_pcmrx_switch_mixer,
 	msm_routing_put_fm_pcmrx_switch_mixer);
 
+static const struct snd_kcontrol_new int0_mi2s_rx_switch_mixer_controls =
+	SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+	0, 1, 0, msm_routing_get_int0_mi2s_switch_mixer,
+	msm_routing_put_int0_mi2s_switch_mixer);
+
+static const struct snd_kcontrol_new int4_mi2s_rx_switch_mixer_controls =
+	SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+	0, 1, 0, msm_routing_get_int4_mi2s_switch_mixer,
+	msm_routing_put_int4_mi2s_switch_mixer);
+
 static const struct snd_kcontrol_new pri_mi2s_rx_switch_mixer_controls =
 	SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
 	0, 1, 0, msm_routing_get_pri_mi2s_switch_mixer,
@@ -7548,53 +9519,27 @@
 	0, 1, 0, msm_routing_get_hfp_switch_mixer,
 	msm_routing_put_hfp_switch_mixer);
 
-static const struct soc_enum lsm_mux_enum =
-	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mad_audio_mux_text), mad_audio_mux_text);
+static const struct snd_kcontrol_new hfp_slim7_switch_mixer_controls =
+	SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+	0, 1, 0, msm_routing_get_hfp_switch_mixer,
+	msm_routing_put_hfp_switch_mixer);
 
-static const struct snd_kcontrol_new lsm1_mux =
-	SOC_DAPM_ENUM_EXT("LSM1 MUX", lsm_mux_enum,
-			  msm_routing_lsm_mux_get,
-			  msm_routing_lsm_mux_put);
+static const struct snd_kcontrol_new usb_switch_mixer_controls =
+	SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+	0, 1, 0, msm_routing_get_usb_switch_mixer,
+	msm_routing_put_usb_switch_mixer);
 
-static const struct snd_kcontrol_new lsm2_mux =
-	SOC_DAPM_ENUM_EXT("LSM2 MUX", lsm_mux_enum,
-			  msm_routing_lsm_mux_get,
-			  msm_routing_lsm_mux_put);
-static const struct snd_kcontrol_new lsm3_mux =
-	SOC_DAPM_ENUM_EXT("LSM3 MUX", lsm_mux_enum,
-			  msm_routing_lsm_mux_get,
-			  msm_routing_lsm_mux_put);
-
-static const struct snd_kcontrol_new lsm4_mux =
-	SOC_DAPM_ENUM_EXT("LSM4 MUX", lsm_mux_enum,
-			  msm_routing_lsm_mux_get,
-			  msm_routing_lsm_mux_put);
-static const struct snd_kcontrol_new lsm5_mux =
-	SOC_DAPM_ENUM_EXT("LSM5 MUX", lsm_mux_enum,
-			  msm_routing_lsm_mux_get,
-			  msm_routing_lsm_mux_put);
-
-static const struct snd_kcontrol_new lsm6_mux =
-	SOC_DAPM_ENUM_EXT("LSM6 MUX", lsm_mux_enum,
-			  msm_routing_lsm_mux_get,
-			  msm_routing_lsm_mux_put);
-static const struct snd_kcontrol_new lsm7_mux =
-	SOC_DAPM_ENUM_EXT("LSM7 MUX", lsm_mux_enum,
-			  msm_routing_lsm_mux_get,
-			  msm_routing_lsm_mux_put);
-
-static const struct snd_kcontrol_new lsm8_mux =
-	SOC_DAPM_ENUM_EXT("LSM8 MUX", lsm_mux_enum,
-			  msm_routing_lsm_mux_get,
-			  msm_routing_lsm_mux_put);
-
+static const struct soc_enum lsm_port_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lsm_port_text), lsm_port_text);
 
 static const char * const lsm_func_text[] = {
 	"None", "AUDIO", "BEACON", "ULTRASOUND", "SWAUDIO",
 };
 static const struct soc_enum lsm_func_enum =
 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lsm_func_text), lsm_func_text);
-static const struct snd_kcontrol_new lsm_function[] = {
+
+static const struct snd_kcontrol_new lsm_controls[] = {
+	/* kcontrol of lsm_function */
 	SOC_ENUM_EXT(SLIMBUS_0_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
 		     msm_routing_lsm_func_get, msm_routing_lsm_func_put),
 	SOC_ENUM_EXT(SLIMBUS_1_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
@@ -7609,6 +9554,35 @@
 		     msm_routing_lsm_func_get, msm_routing_lsm_func_put),
 	SOC_ENUM_EXT(TERT_MI2S_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
 		    msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+	SOC_ENUM_EXT(QUAT_MI2S_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+		    msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+	SOC_ENUM_EXT(INT3_MI2S_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+		    msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+	/* kcontrol of lsm_port */
+	SOC_ENUM_EXT("LSM1 Port", lsm_port_enum,
+			  msm_routing_lsm_port_get,
+			  msm_routing_lsm_port_put),
+	SOC_ENUM_EXT("LSM2 Port", lsm_port_enum,
+			  msm_routing_lsm_port_get,
+			  msm_routing_lsm_port_put),
+	SOC_ENUM_EXT("LSM3 Port", lsm_port_enum,
+			  msm_routing_lsm_port_get,
+			  msm_routing_lsm_port_put),
+	SOC_ENUM_EXT("LSM4 Port", lsm_port_enum,
+			  msm_routing_lsm_port_get,
+			  msm_routing_lsm_port_put),
+	SOC_ENUM_EXT("LSM5 Port", lsm_port_enum,
+			  msm_routing_lsm_port_get,
+			  msm_routing_lsm_port_put),
+	SOC_ENUM_EXT("LSM6 Port", lsm_port_enum,
+			  msm_routing_lsm_port_get,
+			  msm_routing_lsm_port_put),
+	SOC_ENUM_EXT("LSM7 Port", lsm_port_enum,
+			  msm_routing_lsm_port_get,
+			  msm_routing_lsm_port_put),
+	SOC_ENUM_EXT("LSM8 Port", lsm_port_enum,
+			  msm_routing_lsm_port_get,
+			  msm_routing_lsm_port_put),
 };
 
 static const char * const aanc_slim_0_rx_text[] = {
@@ -7662,10 +9636,11 @@
 			continue;
 		if ((port_id != SLIMBUS_0_RX) &&
 		     (port_id != RT_PROXY_PORT_001_RX) &&
-			(port_id != AFE_PORT_ID_PRIMARY_MI2S_RX))
+			(port_id != AFE_PORT_ID_PRIMARY_MI2S_RX) &&
+			(port_id != AFE_PORT_ID_INT4_MI2S_RX))
 			continue;
 
-		for_each_set_bit(i, &msm_bedais[be_index].fe_sessions,
+		for_each_set_bit(i, &msm_bedais[be_index].fe_sessions[0],
 				MSM_FRONTEND_DAI_MM_SIZE) {
 			if (fe_dai_map[i][SESSION_TYPE_RX].perf_mode !=
 			    LEGACY_PCM_MODE)
@@ -7771,6 +9746,45 @@
 	msm_routing_put_app_type_cfg_control),
 };
 
+static int msm_routing_get_lsm_app_type_cfg_control(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	return 0;
+}
+
+static int msm_routing_put_lsm_app_type_cfg_control(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int i = 0, j;
+	int num_app_types = ucontrol->value.integer.value[i++];
+
+	memset(lsm_app_type_cfg, 0, MAX_APP_TYPES*
+				sizeof(struct msm_pcm_routing_app_type_data));
+	if (num_app_types > MAX_APP_TYPES) {
+		pr_err("%s: number of app types exceed the max supported\n",
+			__func__);
+		return -EINVAL;
+	}
+	for (j = 0; j < num_app_types; j++) {
+		lsm_app_type_cfg[j].app_type =
+				ucontrol->value.integer.value[i++];
+		lsm_app_type_cfg[j].sample_rate =
+				ucontrol->value.integer.value[i++];
+		lsm_app_type_cfg[j].bit_width =
+				ucontrol->value.integer.value[i++];
+	}
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new lsm_app_type_cfg_controls[] = {
+	SOC_SINGLE_MULTI_EXT("Listen App Type Config", SND_SOC_NOPM, 0,
+	0xFFFFFFFF, 0, 128, msm_routing_get_lsm_app_type_cfg_control,
+	msm_routing_put_lsm_app_type_cfg_control),
+};
+
 static int msm_routing_get_use_ds1_or_ds2_control(
 					struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol)
@@ -7802,7 +9816,7 @@
 	uint32_t param_length = sizeof(uint32_t);
 	uint32_t param_payload_len = RMS_PAYLOAD_LEN * sizeof(uint32_t);
 
-	param_value = kzalloc(param_length, GFP_KERNEL);
+	param_value = kzalloc(param_length + param_payload_len, GFP_KERNEL);
 	if (!param_value)
 		return -ENOMEM;
 
@@ -7966,7 +9980,7 @@
 		goto done;
 	}
 
-	for_each_set_bit(i, &msm_bedais[be_idx].fe_sessions,
+	for_each_set_bit(i, &msm_bedais[be_idx].fe_sessions[0],
 			 MSM_FRONTEND_DAI_MM_SIZE) {
 		for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
 			copp = session_copp_map[i]
@@ -8010,6 +10024,9 @@
 	} else if (!strcmp(kcontrol->id.name + strlen(prefix),
 					"TERT_MI2S")) {
 		*port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+	} else if (!strcmp(kcontrol->id.name + strlen(prefix),
+					"INT3_MI2S")) {
+		*port_id = AFE_PORT_ID_INT3_MI2S_TX;
 	} else {
 		pr_err("%s: mixer ctl name=%s, could not derive valid port id\n",
 			__func__, kcontrol->id.name);
@@ -8214,6 +10231,36 @@
 		.info	= msm_source_tracking_info,
 		.get	= msm_audio_source_tracking_get,
 	},
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name	= "Sound Focus Voice Tx INT3_MI2S",
+		.info	= msm_sound_focus_info,
+		.get	= msm_voice_sound_focus_get,
+		.put	= msm_voice_sound_focus_put,
+	},
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name	= "Source Tracking Voice Tx INT3_MI2S",
+		.info	= msm_source_tracking_info,
+		.get	= msm_voice_source_tracking_get,
+	},
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name	= "Sound Focus Audio Tx INT3_MI2S",
+		.info	= msm_sound_focus_info,
+		.get	= msm_audio_sound_focus_get,
+		.put	= msm_audio_sound_focus_put,
+	},
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name	= "Source Tracking Audio Tx INT3_MI2S",
+		.info	= msm_source_tracking_info,
+		.get	= msm_audio_source_tracking_get,
+	},
 };
 
 static int spkr_prot_put_vi_lch_port(struct snd_kcontrol *kcontrol,
@@ -8319,6 +10366,14 @@
 	"ZERO", "SENARY_TX"
 };
 
+static const char * const int4_mi2s_rx_vi_fb_tx_mono_mux_text[] = {
+	"ZERO", "INT5_MI2S_TX"
+};
+
+static const char * const int4_mi2s_rx_vi_fb_tx_stereo_mux_text[] = {
+	"ZERO", "INT5_MI2S_TX"
+};
+
 static const int const slim0_rx_vi_fb_tx_lch_value[] = {
 	MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_SLIMBUS_4_TX
 };
@@ -8331,6 +10386,14 @@
 	MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_SENARY_MI2S_TX
 };
 
+static const int const int4_mi2s_rx_vi_fb_tx_mono_ch_value[] = {
+	MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_INT5_MI2S_TX
+};
+
+static const int const int4_mi2s_rx_vi_fb_tx_stereo_ch_value[] = {
+	MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_INT5_MI2S_TX
+};
+
 static const struct soc_enum slim0_rx_vi_fb_lch_mux_enum =
 	SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_SLIMBUS_0_RX, 0, 0,
 	ARRAY_SIZE(slim0_rx_vi_fb_tx_lch_mux_text),
@@ -8346,6 +10409,18 @@
 	ARRAY_SIZE(mi2s_rx_vi_fb_tx_mux_text),
 	mi2s_rx_vi_fb_tx_mux_text, mi2s_rx_vi_fb_tx_value);
 
+static const struct soc_enum int4_mi2s_rx_vi_fb_mono_ch_mux_enum =
+	SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_INT4_MI2S_RX, 0, 0,
+	ARRAY_SIZE(int4_mi2s_rx_vi_fb_tx_mono_mux_text),
+	int4_mi2s_rx_vi_fb_tx_mono_mux_text,
+	int4_mi2s_rx_vi_fb_tx_mono_ch_value);
+
+static const struct soc_enum int4_mi2s_rx_vi_fb_stereo_ch_mux_enum =
+	SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_INT4_MI2S_RX, 0, 0,
+	ARRAY_SIZE(int4_mi2s_rx_vi_fb_tx_stereo_mux_text),
+	int4_mi2s_rx_vi_fb_tx_stereo_mux_text,
+	int4_mi2s_rx_vi_fb_tx_stereo_ch_value);
+
 static const struct snd_kcontrol_new slim0_rx_vi_fb_lch_mux =
 	SOC_DAPM_ENUM_EXT("SLIM0_RX_VI_FB_LCH_MUX",
 	slim0_rx_vi_fb_lch_mux_enum, spkr_prot_get_vi_lch_port,
@@ -8361,6 +10436,16 @@
 	mi2s_rx_vi_fb_mux_enum, spkr_prot_get_vi_lch_port,
 	spkr_prot_put_vi_lch_port);
 
+static const struct snd_kcontrol_new int4_mi2s_rx_vi_fb_mono_ch_mux =
+	SOC_DAPM_ENUM_EXT("INT4_MI2S_RX_VI_FB_MONO_CH_MUX",
+	int4_mi2s_rx_vi_fb_mono_ch_mux_enum, spkr_prot_get_vi_lch_port,
+	spkr_prot_put_vi_lch_port);
+
+static const struct snd_kcontrol_new int4_mi2s_rx_vi_fb_stereo_ch_mux =
+	SOC_DAPM_ENUM_EXT("INT4_MI2S_RX_VI_FB_STEREO_CH_MUX",
+	int4_mi2s_rx_vi_fb_stereo_ch_mux_enum, spkr_prot_get_vi_rch_port,
+	spkr_prot_put_vi_rch_port);
+
 static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
 	/* Frontend AIF */
 	/* Widget name equals to Front-End DAI name<Need confirmation>,
@@ -8433,6 +10518,10 @@
 		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("SLIM6_UL_HL", "SLIMBUS6_HOSTLESS Capture",
 		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIM7_DL_HL", "SLIMBUS7_HOSTLESS Playback",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIM7_UL_HL", "SLIMBUS7_HOSTLESS Capture",
+		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SLIM8_DL_HL", "SLIMBUS8_HOSTLESS Playback",
 		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("SLIM8_UL_HL", "SLIMBUS8_HOSTLESS Capture",
@@ -8444,6 +10533,10 @@
 	SND_SOC_DAPM_AIF_IN("INTHFP_DL_HL", "INT_HFP_BT_HOSTLESS Playback",
 		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("INTHFP_UL_HL", "INT_HFP_BT_HOSTLESS Capture",
+	0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("USBAUDIO_DL_HL", "USBAUDIO_HOSTLESS Playback",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("USBAUDIO_UL_HL", "USBAUDIO_HOSTLESS Capture",
 		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("HDMI_DL_HL", "HDMI_HOSTLESS Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SEC_I2S_DL_HL", "SEC_I2S_RX_HOSTLESS Playback",
@@ -8473,6 +10566,9 @@
 		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MI2S_UL_HL", "MI2S_TX_HOSTLESS Capture",
 		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("INT3_MI2S_UL_HL",
+		"INT3 MI2S_TX Hostless Capture",
+		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("TERT_MI2S_UL_HL",
 		"Tertiary MI2S_TX Hostless Capture",
 		0, 0, 0, 0),
@@ -8909,6 +11005,8 @@
 				0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SENARY_TX", "Senary_mi2s Capture",
 				0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("INT5_MI2S_TX", "INT5 MI2S Capture",
+				0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SLIMBUS_5_TX", "Slimbus5 Capture", 0, 0, 0, 0),
 
 	SND_SOC_DAPM_AIF_OUT("AUX_PCM_RX", "AUX PCM Playback", 0, 0, 0, 0),
@@ -8965,6 +11063,10 @@
 				&slim6_fm_switch_mixer_controls),
 	SND_SOC_DAPM_SWITCH("PCM_RX_DL_HL", SND_SOC_NOPM, 0, 0,
 				&pcm_rx_switch_mixer_controls),
+	SND_SOC_DAPM_SWITCH("INT0_MI2S_RX_DL_HL", SND_SOC_NOPM, 0, 0,
+				&int0_mi2s_rx_switch_mixer_controls),
+	SND_SOC_DAPM_SWITCH("INT4_MI2S_RX_DL_HL", SND_SOC_NOPM, 0, 0,
+				&int4_mi2s_rx_switch_mixer_controls),
 	SND_SOC_DAPM_SWITCH("PRI_MI2S_RX_DL_HL", SND_SOC_NOPM, 0, 0,
 				&pri_mi2s_rx_switch_mixer_controls),
 	SND_SOC_DAPM_SWITCH("SEC_MI2S_RX_DL_HL", SND_SOC_NOPM, 0, 0,
@@ -8979,16 +11081,10 @@
 				&hfp_aux_switch_mixer_controls),
 	SND_SOC_DAPM_SWITCH("HFP_INT_UL_HL", SND_SOC_NOPM, 0, 0,
 				&hfp_int_switch_mixer_controls),
-
-	/* Mux Definitions */
-	SND_SOC_DAPM_MUX("LSM1 MUX", SND_SOC_NOPM, 0, 0, &lsm1_mux),
-	SND_SOC_DAPM_MUX("LSM2 MUX", SND_SOC_NOPM, 0, 0, &lsm2_mux),
-	SND_SOC_DAPM_MUX("LSM3 MUX", SND_SOC_NOPM, 0, 0, &lsm3_mux),
-	SND_SOC_DAPM_MUX("LSM4 MUX", SND_SOC_NOPM, 0, 0, &lsm4_mux),
-	SND_SOC_DAPM_MUX("LSM5 MUX", SND_SOC_NOPM, 0, 0, &lsm5_mux),
-	SND_SOC_DAPM_MUX("LSM6 MUX", SND_SOC_NOPM, 0, 0, &lsm6_mux),
-	SND_SOC_DAPM_MUX("LSM7 MUX", SND_SOC_NOPM, 0, 0, &lsm7_mux),
-	SND_SOC_DAPM_MUX("LSM8 MUX", SND_SOC_NOPM, 0, 0, &lsm8_mux),
+	SND_SOC_DAPM_SWITCH("HFP_SLIM7_UL_HL", SND_SOC_NOPM, 0, 0,
+				&hfp_slim7_switch_mixer_controls),
+	SND_SOC_DAPM_SWITCH("USB_DL_HL", SND_SOC_NOPM, 0, 0,
+				&usb_switch_mixer_controls),
 
 	/* Mixer definitions */
 	SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -9038,12 +11134,30 @@
 	SND_SOC_DAPM_MIXER("PRI_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
 				pri_tdm_rx_0_mixer_controls,
 				ARRAY_SIZE(pri_tdm_rx_0_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRI_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				pri_tdm_rx_1_mixer_controls,
+				ARRAY_SIZE(pri_tdm_rx_1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRI_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				pri_tdm_rx_2_mixer_controls,
+				ARRAY_SIZE(pri_tdm_rx_2_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRI_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				pri_tdm_rx_3_mixer_controls,
+				ARRAY_SIZE(pri_tdm_rx_3_mixer_controls)),
 	SND_SOC_DAPM_MIXER("PRI_TDM_TX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
 				pri_tdm_tx_0_mixer_controls,
 				ARRAY_SIZE(pri_tdm_tx_0_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SEC_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
 				sec_tdm_rx_0_mixer_controls,
 				ARRAY_SIZE(sec_tdm_rx_0_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				sec_tdm_rx_1_mixer_controls,
+				ARRAY_SIZE(sec_tdm_rx_1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				sec_tdm_rx_2_mixer_controls,
+				ARRAY_SIZE(sec_tdm_rx_2_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				sec_tdm_rx_3_mixer_controls,
+				ARRAY_SIZE(sec_tdm_rx_3_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SEC_TDM_TX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
 				sec_tdm_tx_0_mixer_controls,
 				ARRAY_SIZE(sec_tdm_tx_0_mixer_controls)),
@@ -9091,6 +11205,8 @@
 	mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia9 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul9_mixer_controls, ARRAY_SIZE(mmul9_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia17 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul17_mixer_controls, ARRAY_SIZE(mmul17_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia18 Mixer", SND_SOC_NOPM, 0, 0,
@@ -9195,6 +11311,10 @@
 				SND_SOC_NOPM, 0, 0,
 				quin_mi2s_rx_voice_mixer_controls,
 				ARRAY_SIZE(quin_mi2s_rx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUAT_TDM_RX_2_Voice Mixer",
+				SND_SOC_NOPM, 0, 0,
+				quat_tdm_rx_2_voice_mixer_controls,
+				ARRAY_SIZE(quat_tdm_rx_2_voice_mixer_controls)),
 	SND_SOC_DAPM_MIXER("Voice_Tx Mixer",
 				SND_SOC_NOPM, 0, 0, tx_voice_mixer_controls,
 				ARRAY_SIZE(tx_voice_mixer_controls)),
@@ -9302,6 +11422,30 @@
 	SND_SOC_DAPM_MIXER("QUAT_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
 	quat_mi2s_rx_port_mixer_controls,
 	ARRAY_SIZE(quat_mi2s_rx_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRI_TDM_RX_0 Port Mixer", SND_SOC_NOPM, 0, 0,
+	pri_tdm_rx_0_port_mixer_controls,
+	ARRAY_SIZE(pri_tdm_rx_0_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRI_TDM_RX_1 Port Mixer", SND_SOC_NOPM, 0, 0,
+	pri_tdm_rx_1_port_mixer_controls,
+	ARRAY_SIZE(pri_tdm_rx_1_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRI_TDM_RX_2 Port Mixer", SND_SOC_NOPM, 0, 0,
+	pri_tdm_rx_2_port_mixer_controls,
+	ARRAY_SIZE(pri_tdm_rx_2_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRI_TDM_RX_3 Port Mixer", SND_SOC_NOPM, 0, 0,
+	pri_tdm_rx_3_port_mixer_controls,
+	ARRAY_SIZE(pri_tdm_rx_3_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_TDM_RX_0 Port Mixer", SND_SOC_NOPM, 0, 0,
+	sec_tdm_rx_0_port_mixer_controls,
+	ARRAY_SIZE(sec_tdm_rx_0_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_TDM_RX_1 Port Mixer", SND_SOC_NOPM, 0, 0,
+	sec_tdm_rx_1_port_mixer_controls,
+	ARRAY_SIZE(sec_tdm_rx_1_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_TDM_RX_2 Port Mixer", SND_SOC_NOPM, 0, 0,
+	sec_tdm_rx_2_port_mixer_controls,
+	ARRAY_SIZE(sec_tdm_rx_2_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_TDM_RX_3 Port Mixer", SND_SOC_NOPM, 0, 0,
+	sec_tdm_rx_3_port_mixer_controls,
+	ARRAY_SIZE(sec_tdm_rx_3_port_mixer_controls)),
 	SND_SOC_DAPM_MIXER("TERT_TDM_RX_0 Port Mixer", SND_SOC_NOPM, 0, 0,
 	tert_tdm_rx_0_port_mixer_controls,
 	ARRAY_SIZE(tert_tdm_rx_0_port_mixer_controls)),
@@ -9326,12 +11470,38 @@
 	SND_SOC_DAPM_MIXER("QUAT_TDM_RX_3 Port Mixer", SND_SOC_NOPM, 0, 0,
 	quat_tdm_rx_3_port_mixer_controls,
 	ARRAY_SIZE(quat_tdm_rx_3_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("INT0_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+	int0_mi2s_rx_port_mixer_controls,
+	ARRAY_SIZE(int0_mi2s_rx_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("INT4_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+	int4_mi2s_rx_port_mixer_controls,
+	ARRAY_SIZE(int4_mi2s_rx_port_mixer_controls)),
 	SND_SOC_DAPM_MIXER("QCHAT_Tx Mixer",
 	SND_SOC_NOPM, 0, 0, tx_qchat_mixer_controls,
 	ARRAY_SIZE(tx_qchat_mixer_controls)),
 	SND_SOC_DAPM_MIXER("USB_AUDIO_RX_Voice Mixer",
 	SND_SOC_NOPM, 0, 0, usb_audio_rx_voice_mixer_controls,
 	ARRAY_SIZE(usb_audio_rx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("USB_AUDIO_RX Port Mixer",
+	SND_SOC_NOPM, 0, 0, usb_rx_port_mixer_controls,
+	ARRAY_SIZE(usb_rx_port_mixer_controls)),
+	/* lsm mixer definitions */
+	SND_SOC_DAPM_MIXER("LSM1 Mixer", SND_SOC_NOPM, 0, 0,
+	lsm1_mixer_controls, ARRAY_SIZE(lsm1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("LSM2 Mixer", SND_SOC_NOPM, 0, 0,
+	lsm2_mixer_controls, ARRAY_SIZE(lsm2_mixer_controls)),
+	SND_SOC_DAPM_MIXER("LSM3 Mixer", SND_SOC_NOPM, 0, 0,
+	lsm3_mixer_controls, ARRAY_SIZE(lsm3_mixer_controls)),
+	SND_SOC_DAPM_MIXER("LSM4 Mixer", SND_SOC_NOPM, 0, 0,
+	lsm4_mixer_controls, ARRAY_SIZE(lsm4_mixer_controls)),
+	SND_SOC_DAPM_MIXER("LSM5 Mixer", SND_SOC_NOPM, 0, 0,
+	lsm5_mixer_controls, ARRAY_SIZE(lsm5_mixer_controls)),
+	SND_SOC_DAPM_MIXER("LSM6 Mixer", SND_SOC_NOPM, 0, 0,
+	lsm6_mixer_controls, ARRAY_SIZE(lsm6_mixer_controls)),
+	SND_SOC_DAPM_MIXER("LSM7 Mixer", SND_SOC_NOPM, 0, 0,
+	lsm7_mixer_controls, ARRAY_SIZE(lsm7_mixer_controls)),
+	SND_SOC_DAPM_MIXER("LSM8 Mixer", SND_SOC_NOPM, 0, 0,
+	lsm8_mixer_controls, ARRAY_SIZE(lsm8_mixer_controls)),
 	/* Virtual Pins to force backends ON atm */
 	SND_SOC_DAPM_OUTPUT("BE_OUT"),
 	SND_SOC_DAPM_INPUT("BE_IN"),
@@ -9342,6 +11512,10 @@
 				&slim0_rx_vi_fb_rch_mux),
 	SND_SOC_DAPM_MUX("PRI_MI2S_RX_VI_FB_MUX", SND_SOC_NOPM, 0, 0,
 				&mi2s_rx_vi_fb_mux),
+	SND_SOC_DAPM_MUX("INT4_MI2S_RX_VI_FB_MONO_CH_MUX", SND_SOC_NOPM, 0, 0,
+				&int4_mi2s_rx_vi_fb_mono_ch_mux),
+	SND_SOC_DAPM_MUX("INT4_MI2S_RX_VI_FB_STEREO_CH_MUX", SND_SOC_NOPM, 0, 0,
+				&int4_mi2s_rx_vi_fb_stereo_ch_mux),
 
 	SND_SOC_DAPM_MUX("VOC_EXT_EC MUX", SND_SOC_NOPM, 0, 0,
 			 &voc_ext_ec_mux),
@@ -9550,10 +11724,14 @@
 	{"SLIMBUS_6_RX", NULL, "SLIMBUS_6_RX Audio Mixer"},
 
 	{"SLIMBUS_7_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"SLIMBUS_7_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"SLIMBUS_7_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"SLIMBUS_7_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"SLIMBUS_7_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"SLIMBUS_7_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"SLIMBUS_7_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+	{"SLIMBUS_7_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+	{"SLIMBUS_7_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
 	{"SLIMBUS_7_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
 	{"SLIMBUS_7_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
 	{"SLIMBUS_7_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
@@ -9604,6 +11782,7 @@
 	{"MultiMedia18 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"MultiMedia19 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"MultiMedia8 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
 	{"MultiMedia3 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia5 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
@@ -9769,6 +11948,60 @@
 	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
 	{"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Audio Mixer"},
 
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia6", "MM_DL6"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia7", "MM_DL7"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia8", "MM_DL8"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia9", "MM_DL9"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia10", "MM_DL10"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia11", "MM_DL11"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia12", "MM_DL12"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia13", "MM_DL13"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"PRI_TDM_RX_1", NULL, "PRI_TDM_RX_1 Audio Mixer"},
+
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia6", "MM_DL6"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia7", "MM_DL7"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia8", "MM_DL8"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia9", "MM_DL9"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia10", "MM_DL10"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia11", "MM_DL11"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia12", "MM_DL12"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia13", "MM_DL13"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"PRI_TDM_RX_2", NULL, "PRI_TDM_RX_2 Audio Mixer"},
+
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia6", "MM_DL6"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia7", "MM_DL7"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia8", "MM_DL8"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia9", "MM_DL9"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia10", "MM_DL10"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia11", "MM_DL11"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia12", "MM_DL12"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia13", "MM_DL13"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"PRI_TDM_RX_3", NULL, "PRI_TDM_RX_3 Audio Mixer"},
+
 	{"PRI_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"PRI_TDM_TX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"PRI_TDM_TX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -9805,6 +12038,60 @@
 	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
 	{"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Audio Mixer"},
 
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia6", "MM_DL6"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia7", "MM_DL7"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia8", "MM_DL8"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia9", "MM_DL9"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia10", "MM_DL10"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia11", "MM_DL11"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia12", "MM_DL12"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia13", "MM_DL13"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"SEC_TDM_RX_1", NULL, "SEC_TDM_RX_1 Audio Mixer"},
+
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia6", "MM_DL6"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia7", "MM_DL7"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia8", "MM_DL8"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia9", "MM_DL9"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia10", "MM_DL10"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia11", "MM_DL11"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia12", "MM_DL12"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia13", "MM_DL13"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"SEC_TDM_RX_2", NULL, "SEC_TDM_RX_2 Audio Mixer"},
+
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia6", "MM_DL6"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia7", "MM_DL7"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia8", "MM_DL8"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia9", "MM_DL9"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia10", "MM_DL10"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia11", "MM_DL11"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia12", "MM_DL12"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia13", "MM_DL13"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"SEC_TDM_RX_3", NULL, "SEC_TDM_RX_3 Audio Mixer"},
+
 	{"SEC_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"SEC_TDM_TX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"SEC_TDM_TX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -9931,6 +12218,42 @@
 	{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
 	{"QUAT_TDM_RX_0", NULL, "QUAT_TDM_RX_0 Audio Mixer"},
 
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Audio Mixer"},
+
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Audio Mixer"},
+
 	{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -10033,6 +12356,8 @@
 	{"MultiMedia3 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"},
 	{"MultiMedia5 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"},
 	{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia2 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"},
+	{"MultiMedia2 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia2 Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
 	{"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
 	{"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
@@ -10050,6 +12375,14 @@
 	{"MultiMedia6 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
 	{"MultiMedia6 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
 
+	{"MultiMedia1 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+	{"MultiMedia1 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+	{"MultiMedia1 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+	{"MultiMedia1 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+	{"MultiMedia1 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+	{"MultiMedia1 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+	{"MultiMedia1 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+	{"MultiMedia1 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
 	{"MultiMedia1 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
 	{"MultiMedia1 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
 	{"MultiMedia1 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
@@ -10059,6 +12392,14 @@
 	{"MultiMedia1 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
 	{"MultiMedia1 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
 
+	{"MultiMedia2 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+	{"MultiMedia2 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+	{"MultiMedia2 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+	{"MultiMedia2 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+	{"MultiMedia2 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+	{"MultiMedia2 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+	{"MultiMedia2 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+	{"MultiMedia2 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
 	{"MultiMedia2 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
 	{"MultiMedia2 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
 	{"MultiMedia2 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
@@ -10068,6 +12409,14 @@
 	{"MultiMedia2 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
 	{"MultiMedia2 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
 
+	{"MultiMedia3 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+	{"MultiMedia3 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+	{"MultiMedia3 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+	{"MultiMedia3 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+	{"MultiMedia3 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+	{"MultiMedia3 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+	{"MultiMedia3 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+	{"MultiMedia3 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
 	{"MultiMedia3 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
 	{"MultiMedia3 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
 	{"MultiMedia3 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
@@ -10077,6 +12426,14 @@
 	{"MultiMedia3 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
 	{"MultiMedia3 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
 
+	{"MultiMedia4 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+	{"MultiMedia4 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+	{"MultiMedia4 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+	{"MultiMedia4 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+	{"MultiMedia4 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+	{"MultiMedia4 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+	{"MultiMedia4 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+	{"MultiMedia4 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
 	{"MultiMedia4 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
 	{"MultiMedia4 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
 	{"MultiMedia4 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
@@ -10086,6 +12443,14 @@
 	{"MultiMedia4 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
 	{"MultiMedia4 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
 
+	{"MultiMedia5 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+	{"MultiMedia5 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+	{"MultiMedia5 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+	{"MultiMedia5 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+	{"MultiMedia5 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+	{"MultiMedia5 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+	{"MultiMedia5 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+	{"MultiMedia5 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
 	{"MultiMedia5 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
 	{"MultiMedia5 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
 	{"MultiMedia5 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
@@ -10095,6 +12460,14 @@
 	{"MultiMedia5 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
 	{"MultiMedia5 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
 
+	{"MultiMedia6 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+	{"MultiMedia6 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+	{"MultiMedia6 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+	{"MultiMedia6 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+	{"MultiMedia6 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+	{"MultiMedia6 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+	{"MultiMedia6 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+	{"MultiMedia6 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
 	{"MultiMedia6 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
 	{"MultiMedia6 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
 	{"MultiMedia6 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
@@ -10104,6 +12477,14 @@
 	{"MultiMedia6 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
 	{"MultiMedia6 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
 
+	{"MultiMedia8 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+	{"MultiMedia8 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+	{"MultiMedia8 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+	{"MultiMedia8 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+	{"MultiMedia8 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+	{"MultiMedia8 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+	{"MultiMedia8 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+	{"MultiMedia8 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
 	{"MultiMedia8 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
 	{"MultiMedia8 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
 	{"MultiMedia8 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
@@ -10113,6 +12494,15 @@
 	{"MultiMedia8 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
 	{"MultiMedia8 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
 
+	{"MultiMedia9 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+	{"MultiMedia9 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+	{"MultiMedia9 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+	{"MultiMedia9 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+	{"MultiMedia9 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+	{"MultiMedia9 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+	{"MultiMedia9 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+	{"MultiMedia9 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+
 	{"MultiMedia1 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
 	{"MultiMedia2 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
 	{"MultiMedia4 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
@@ -10227,6 +12617,7 @@
 	{"MM_UL5", NULL, "MultiMedia5 Mixer"},
 	{"MM_UL6", NULL, "MultiMedia6 Mixer"},
 	{"MM_UL8", NULL, "MultiMedia8 Mixer"},
+	{"MM_UL9", NULL, "MultiMedia9 Mixer"},
 	{"MM_UL17", NULL, "MultiMedia17 Mixer"},
 	{"MM_UL18", NULL, "MultiMedia18 Mixer"},
 	{"MM_UL19", NULL, "MultiMedia19 Mixer"},
@@ -10551,6 +12942,9 @@
 	{"QUIN_MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
 	{"QUIN_MI2S_RX", NULL, "QUIN_MI2S_RX_Voice Mixer"},
 
+	{"QUAT_TDM_RX_2_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+	{"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2_Voice Mixer"},
+
 	{"VOC_EXT_EC MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"VOC_EXT_EC MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
 	{"VOC_EXT_EC MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
@@ -10716,6 +13110,7 @@
 	{"VoiceMMode1_Tx Mixer", "SEC_AUX_PCM_TX_MMode1", "SEC_AUX_PCM_TX"},
 	{"VoiceMMode1_Tx Mixer", "TERT_AUX_PCM_TX_MMode1", "TERT_AUX_PCM_TX"},
 	{"VoiceMMode1_Tx Mixer", "QUAT_AUX_PCM_TX_MMode1", "QUAT_AUX_PCM_TX"},
+	{"VoiceMMode1_Tx Mixer", "QUAT_TDM_TX_0_MMode1", "QUAT_TDM_TX_0"},
 	{"VOICEMMODE1_UL", NULL, "VoiceMMode1_Tx Mixer"},
 
 	{"VoiceMMode2_Tx Mixer", "PRI_TX_MMode2", "PRI_I2S_TX"},
@@ -10768,70 +13163,81 @@
 	{"SLIM4_UL_HL", NULL, "SLIMBUS_4_TX"},
 	{"SLIM8_UL_HL", NULL, "SLIMBUS_8_TX"},
 
-	{"LSM1 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
-	{"LSM1 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
-	{"LSM1 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
-	{"LSM1 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
-	{"LSM1 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
-	{"LSM1 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
-	{"LSM1_UL_HL", NULL, "LSM1 MUX"},
+	{"LSM1 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM1 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM1 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM1 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM1 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM1 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+	{"LSM1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"LSM1 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+	{"LSM1_UL_HL", NULL, "LSM1 Mixer"},
 
-	{"LSM2 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
-	{"LSM2 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
-	{"LSM2 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
-	{"LSM2 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
-	{"LSM2 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
-	{"LSM2 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
-	{"LSM2_UL_HL", NULL, "LSM2 MUX"},
+	{"LSM2 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM2 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM2 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM2 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM2 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM2 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+	{"LSM2 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"LSM2 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+	{"LSM2_UL_HL", NULL, "LSM2 Mixer"},
 
 
-	{"LSM3 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
-	{"LSM3 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
-	{"LSM3 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
-	{"LSM3 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
-	{"LSM3 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
-	{"LSM3 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
-	{"LSM3_UL_HL", NULL, "LSM3 MUX"},
+	{"LSM3 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM3 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM3 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM3 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM3 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM3 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+	{"LSM3 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"LSM3 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+	{"LSM3_UL_HL", NULL, "LSM3 Mixer"},
 
 
-	{"LSM4 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
-	{"LSM4 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
-	{"LSM4 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
-	{"LSM4 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
-	{"LSM4 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
-	{"LSM4 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
-	{"LSM4_UL_HL", NULL, "LSM4 MUX"},
+	{"LSM4 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM4 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM4 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM4 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM4 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM4 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+	{"LSM4 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"LSM4 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+	{"LSM4_UL_HL", NULL, "LSM4 Mixer"},
 
-	{"LSM5 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
-	{"LSM5 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
-	{"LSM5 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
-	{"LSM5 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
-	{"LSM5 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
-	{"LSM5 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
-	{"LSM5_UL_HL", NULL, "LSM5 MUX"},
+	{"LSM5 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM5 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM5 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM5 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM5 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM5 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+	{"LSM5 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"LSM5 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+	{"LSM5_UL_HL", NULL, "LSM5 Mixer"},
 
-	{"LSM6 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
-	{"LSM6 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
-	{"LSM6 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
-	{"LSM6 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
-	{"LSM6 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
-	{"LSM6_UL_HL", NULL, "LSM6 MUX"},
+	{"LSM6 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM6 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM6 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM6 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM6 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM6 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"LSM6_UL_HL", NULL, "LSM6 Mixer"},
 
+	{"LSM7 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM7 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM7 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM7 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM7 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM7 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"LSM7_UL_HL", NULL, "LSM7 Mixer"},
 
-	{"LSM7 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
-	{"LSM7 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
-	{"LSM7 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
-	{"LSM7 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
-	{"LSM7 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
-	{"LSM7_UL_HL", NULL, "LSM7 MUX"},
-
-
-	{"LSM8 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
-	{"LSM8 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
-	{"LSM8 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
-	{"LSM8 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
-	{"LSM8 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
-	{"LSM8_UL_HL", NULL, "LSM8 MUX"},
+	{"LSM8 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM8 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM8 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM8 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM8 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM8 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"LSM8_UL_HL", NULL, "LSM8 Mixer"},
 
 
 	{"CPE_LSM_UL_HL", NULL, "BE_IN"},
@@ -10860,13 +13266,17 @@
 	{"HFP_AUX_UL_HL", "Switch", "SEC_AUX_PCM_TX"},
 	{"INTHFP_UL_HL", NULL, "HFP_INT_UL_HL"},
 	{"HFP_INT_UL_HL", "Switch", "INT_BT_SCO_TX"},
+	{"SLIM7_UL_HL", NULL, "HFP_SLIM7_UL_HL"},
+	{"HFP_SLIM7_UL_HL", "Switch", "SLIMBUS_7_TX"},
 	{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
 	{"AUXPCM_UL_HL", NULL, "AUX_PCM_TX"},
 	{"MI2S_RX", NULL, "MI2S_DL_HL"},
 	{"MI2S_UL_HL", NULL, "MI2S_TX"},
 	{"PCM_RX_DL_HL", "Switch", "SLIM0_DL_HL"},
 	{"PCM_RX", NULL, "PCM_RX_DL_HL"},
-	{"INT0_MI2S_RX_DL_HL", "Switch", "INT0_MI2S_DL_HL"},
+
+	/* connect to INT4_MI2S_DL_HL since same pcm_id */
+	{"INT0_MI2S_RX_DL_HL", "Switch", "INT4_MI2S_DL_HL"},
 	{"INT0_MI2S_RX", NULL, "INT0_MI2S_RX_DL_HL"},
 	{"INT4_MI2S_RX_DL_HL", "Switch", "INT4_MI2S_DL_HL"},
 	{"INT4_MI2S_RX", NULL, "INT4_MI2S_RX_DL_HL"},
@@ -10880,26 +13290,40 @@
 	{"QUAT_MI2S_RX_DL_HL", "Switch", "QUAT_MI2S_DL_HL"},
 	{"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX_DL_HL"},
 	{"MI2S_UL_HL", NULL, "TERT_MI2S_TX"},
+	{"INT3_MI2S_UL_HL", NULL, "INT3_MI2S_TX"},
 	{"TERT_MI2S_UL_HL", NULL, "TERT_MI2S_TX"},
 	{"SEC_I2S_RX", NULL, "SEC_I2S_DL_HL"},
 	{"PRI_MI2S_UL_HL", NULL, "PRI_MI2S_TX"},
+	{"SEC_MI2S_UL_HL", NULL, "SEC_MI2S_TX"},
 	{"SEC_MI2S_RX", NULL, "SEC_MI2S_DL_HL"},
 	{"PRI_MI2S_RX", NULL, "PRI_MI2S_DL_HL"},
 	{"TERT_MI2S_RX", NULL, "TERT_MI2S_DL_HL"},
 	{"QUAT_MI2S_UL_HL", NULL, "QUAT_MI2S_TX"},
 
 	{"PRI_TDM_TX_0_UL_HL", NULL, "PRI_TDM_TX_0"},
+	{"PRI_TDM_TX_1_UL_HL", NULL, "PRI_TDM_TX_1"},
+	{"PRI_TDM_TX_2_UL_HL", NULL, "PRI_TDM_TX_2"},
+	{"PRI_TDM_TX_3_UL_HL", NULL, "PRI_TDM_TX_3"},
 	{"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0_DL_HL"},
+	{"PRI_TDM_RX_1", NULL, "PRI_TDM_RX_1_DL_HL"},
+	{"PRI_TDM_RX_2", NULL, "PRI_TDM_RX_2_DL_HL"},
+	{"PRI_TDM_RX_3", NULL, "PRI_TDM_RX_3_DL_HL"},
 	{"SEC_TDM_TX_0_UL_HL", NULL, "SEC_TDM_TX_0"},
+	{"SEC_TDM_TX_1_UL_HL", NULL, "SEC_TDM_TX_1"},
+	{"SEC_TDM_TX_2_UL_HL", NULL, "SEC_TDM_TX_2"},
+	{"SEC_TDM_TX_3_UL_HL", NULL, "SEC_TDM_TX_3"},
 	{"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0_DL_HL"},
+	{"SEC_TDM_RX_1", NULL, "SEC_TDM_RX_1_DL_HL"},
+	{"SEC_TDM_RX_2", NULL, "SEC_TDM_RX_2_DL_HL"},
+	{"SEC_TDM_RX_3", NULL, "SEC_TDM_RX_3_DL_HL"},
 	{"TERT_TDM_TX_0_UL_HL", NULL, "TERT_TDM_TX_0"},
 	{"TERT_TDM_TX_1_UL_HL", NULL, "TERT_TDM_TX_1"},
 	{"TERT_TDM_TX_2_UL_HL", NULL, "TERT_TDM_TX_2"},
 	{"TERT_TDM_TX_3_UL_HL", NULL, "TERT_TDM_TX_3"},
 	{"TERT_TDM_RX_0", NULL, "TERT_TDM_RX_0_DL_HL"},
-	{"TERT_TDM_RX_1", NULL, "TERT_TDM_RX_0_DL_HL"},
-	{"TERT_TDM_RX_2", NULL, "TERT_TDM_RX_0_DL_HL"},
-	{"TERT_TDM_RX_3", NULL, "TERT_TDM_RX_0_DL_HL"},
+	{"TERT_TDM_RX_1", NULL, "TERT_TDM_RX_1_DL_HL"},
+	{"TERT_TDM_RX_2", NULL, "TERT_TDM_RX_2_DL_HL"},
+	{"TERT_TDM_RX_3", NULL, "TERT_TDM_RX_3_DL_HL"},
 	{"QUAT_TDM_TX_0_UL_HL", NULL, "QUAT_TDM_TX_0"},
 	{"QUAT_TDM_TX_1_UL_HL", NULL, "QUAT_TDM_TX_1"},
 	{"QUAT_TDM_TX_2_UL_HL", NULL, "QUAT_TDM_TX_2"},
@@ -10909,6 +13333,150 @@
 	{"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2_DL_HL"},
 	{"QUAT_TDM_RX_3", NULL, "QUAT_TDM_RX_3_DL_HL"},
 
+	{"PRI_TDM_RX_0 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"PRI_TDM_RX_0 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+	{"PRI_TDM_RX_0 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"PRI_TDM_RX_0 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"PRI_TDM_RX_0 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"PRI_TDM_RX_0 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+	{"PRI_TDM_RX_0 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+	{"PRI_TDM_RX_0 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+	{"PRI_TDM_RX_0 Port Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+	{"PRI_TDM_RX_0 Port Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+	{"PRI_TDM_RX_0 Port Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+	{"PRI_TDM_RX_0 Port Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+	{"PRI_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+	{"PRI_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+	{"PRI_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+	{"PRI_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+	{"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Port Mixer"},
+
+	{"PRI_TDM_RX_1 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"PRI_TDM_RX_1 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+	{"PRI_TDM_RX_1 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"PRI_TDM_RX_1 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"PRI_TDM_RX_1 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"PRI_TDM_RX_1 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+	{"PRI_TDM_RX_1 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+	{"PRI_TDM_RX_1 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+	{"PRI_TDM_RX_1 Port Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+	{"PRI_TDM_RX_1 Port Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+	{"PRI_TDM_RX_1 Port Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+	{"PRI_TDM_RX_1 Port Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+	{"PRI_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+	{"PRI_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+	{"PRI_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+	{"PRI_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+	{"PRI_TDM_RX_1", NULL, "PRI_TDM_RX_1 Port Mixer"},
+
+	{"PRI_TDM_RX_2 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"PRI_TDM_RX_2 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+	{"PRI_TDM_RX_2 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"PRI_TDM_RX_2 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"PRI_TDM_RX_2 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"PRI_TDM_RX_2 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+	{"PRI_TDM_RX_2 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+	{"PRI_TDM_RX_2 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+	{"PRI_TDM_RX_2 Port Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+	{"PRI_TDM_RX_2 Port Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+	{"PRI_TDM_RX_2 Port Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+	{"PRI_TDM_RX_2 Port Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+	{"PRI_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+	{"PRI_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+	{"PRI_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+	{"PRI_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+	{"PRI_TDM_RX_2", NULL, "PRI_TDM_RX_2 Port Mixer"},
+
+	{"PRI_TDM_RX_3 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"PRI_TDM_RX_3 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+	{"PRI_TDM_RX_3 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"PRI_TDM_RX_3 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"PRI_TDM_RX_3 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"PRI_TDM_RX_3 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+	{"PRI_TDM_RX_3 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+	{"PRI_TDM_RX_3 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+	{"PRI_TDM_RX_3 Port Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+	{"PRI_TDM_RX_3 Port Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+	{"PRI_TDM_RX_3 Port Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+	{"PRI_TDM_RX_3 Port Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+	{"PRI_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+	{"PRI_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+	{"PRI_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+	{"PRI_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+	{"PRI_TDM_RX_3", NULL, "PRI_TDM_RX_3 Port Mixer"},
+
+	{"SEC_TDM_RX_0 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"SEC_TDM_RX_0 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+	{"SEC_TDM_RX_0 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"SEC_TDM_RX_0 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"SEC_TDM_RX_0 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"SEC_TDM_RX_0 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+	{"SEC_TDM_RX_0 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+	{"SEC_TDM_RX_0 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+	{"SEC_TDM_RX_0 Port Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+	{"SEC_TDM_RX_0 Port Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+	{"SEC_TDM_RX_0 Port Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+	{"SEC_TDM_RX_0 Port Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+	{"SEC_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+	{"SEC_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+	{"SEC_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+	{"SEC_TDM_RX_0 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+	{"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Port Mixer"},
+
+	{"SEC_TDM_RX_1 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"SEC_TDM_RX_1 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+	{"SEC_TDM_RX_1 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"SEC_TDM_RX_1 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"SEC_TDM_RX_1 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"SEC_TDM_RX_1 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+	{"SEC_TDM_RX_1 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+	{"SEC_TDM_RX_1 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+	{"SEC_TDM_RX_1 Port Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+	{"SEC_TDM_RX_1 Port Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+	{"SEC_TDM_RX_1 Port Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+	{"SEC_TDM_RX_1 Port Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+	{"SEC_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+	{"SEC_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+	{"SEC_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+	{"SEC_TDM_RX_1 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+	{"SEC_TDM_RX_1", NULL, "SEC_TDM_RX_1 Port Mixer"},
+
+	{"SEC_TDM_RX_2 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"SEC_TDM_RX_2 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+	{"SEC_TDM_RX_2 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"SEC_TDM_RX_2 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"SEC_TDM_RX_2 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"SEC_TDM_RX_2 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+	{"SEC_TDM_RX_2 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+	{"SEC_TDM_RX_2 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+	{"SEC_TDM_RX_2 Port Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+	{"SEC_TDM_RX_2 Port Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+	{"SEC_TDM_RX_2 Port Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+	{"SEC_TDM_RX_2 Port Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+	{"SEC_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+	{"SEC_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+	{"SEC_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+	{"SEC_TDM_RX_2 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+	{"SEC_TDM_RX_2", NULL, "SEC_TDM_RX_2 Port Mixer"},
+
+	{"SEC_TDM_RX_3 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"SEC_TDM_RX_3 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+	{"SEC_TDM_RX_3 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"SEC_TDM_RX_3 Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"SEC_TDM_RX_3 Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"SEC_TDM_RX_3 Port Mixer", "AFE_PCM_TX", "PCM_TX"},
+	{"SEC_TDM_RX_3 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+	{"SEC_TDM_RX_3 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+	{"SEC_TDM_RX_3 Port Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+	{"SEC_TDM_RX_3 Port Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+	{"SEC_TDM_RX_3 Port Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+	{"SEC_TDM_RX_3 Port Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+	{"SEC_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+	{"SEC_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+	{"SEC_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+	{"SEC_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+	{"SEC_TDM_RX_3", NULL, "SEC_TDM_RX_3 Port Mixer"},
+
 	{"TERT_TDM_RX_0 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"TERT_TDM_RX_0 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
 	{"TERT_TDM_RX_0 Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
@@ -11053,6 +13621,28 @@
 	{"QUAT_TDM_RX_3 Port Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
 	{"QUAT_TDM_RX_3", NULL, "QUAT_TDM_RX_3 Port Mixer"},
 
+	{"INT0_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"INT0_MI2S_RX Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+	{"INT0_MI2S_RX Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+	{"INT0_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"INT0_MI2S_RX Port Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+	{"INT0_MI2S_RX Port Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
+	{"INT0_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
+	{"INT0_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"INT0_MI2S_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"INT0_MI2S_RX", NULL, "INT0_MI2S_RX Port Mixer"},
+
+	{"INT4_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"INT4_MI2S_RX Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+	{"INT4_MI2S_RX Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+	{"INT4_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"INT4_MI2S_RX Port Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+	{"INT4_MI2S_RX Port Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
+	{"INT4_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
+	{"INT4_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"INT4_MI2S_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"INT4_MI2S_RX", NULL, "INT4_MI2S_RX Port Mixer"},
+
 	{"SLIMBUS_0_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"SLIMBUS_0_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"SLIMBUS_0_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
@@ -11072,6 +13662,12 @@
 	{"AFE_PCM_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"AFE_PCM_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"PCM_RX", NULL, "AFE_PCM_RX Port Mixer"},
+	{"USB_AUDIO_RX Port Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
+	{"USB_AUDIO_RX", NULL, "USB_AUDIO_RX Port Mixer"},
+	{"USB_DL_HL", "Switch", "USBAUDIO_DL_HL"},
+	{"USB_AUDIO_RX", NULL, "USB_DL_HL"},
+	{"USBAUDIO_UL_HL", NULL, "USB_AUDIO_TX"},
+
 
 	{"AUX_PCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
 	{"AUX_PCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
@@ -11300,7 +13896,13 @@
 	{"BE_OUT", NULL, "VOICE_PLAYBACK_TX"},
 	{"BE_OUT", NULL, "VOICE2_PLAYBACK_TX"},
 	{"BE_OUT", NULL, "PRI_TDM_RX_0"},
+	{"BE_OUT", NULL, "PRI_TDM_RX_1"},
+	{"BE_OUT", NULL, "PRI_TDM_RX_2"},
+	{"BE_OUT", NULL, "PRI_TDM_RX_3"},
 	{"BE_OUT", NULL, "SEC_TDM_RX_0"},
+	{"BE_OUT", NULL, "SEC_TDM_RX_1"},
+	{"BE_OUT", NULL, "SEC_TDM_RX_2"},
+	{"BE_OUT", NULL, "SEC_TDM_RX_3"},
 	{"BE_OUT", NULL, "TERT_TDM_RX_0"},
 	{"BE_OUT", NULL, "TERT_TDM_RX_1"},
 	{"BE_OUT", NULL, "TERT_TDM_RX_2"},
@@ -11318,6 +13920,7 @@
 	{"TERT_MI2S_TX", NULL, "BE_IN"},
 	{"INT2_MI2S_TX", NULL, "BE_IN"},
 	{"INT3_MI2S_TX", NULL, "BE_IN"},
+	{"INT5_MI2S_TX", NULL, "BE_IN"},
 	{"SEC_MI2S_TX", NULL, "BE_IN"},
 	{"SENARY_MI2S_TX", NULL, "BE_IN" },
 	{"SLIMBUS_0_TX", NULL, "BE_IN" },
@@ -11346,11 +13949,21 @@
 	{"SLIM0_RX_VI_FB_LCH_MUX", "SLIM4_TX", "SLIMBUS_4_TX"},
 	{"SLIM0_RX_VI_FB_RCH_MUX", "SLIM4_TX", "SLIMBUS_4_TX"},
 	{"PRI_MI2S_RX_VI_FB_MUX", "SENARY_TX", "SENARY_TX"},
+	{"INT4_MI2S_RX_VI_FB_MONO_CH_MUX", "INT5_MI2S_TX", "INT5_MI2S_TX"},
+	{"INT4_MI2S_RX_VI_FB_STEREO_CH_MUX", "INT5_MI2S_TX", "INT5_MI2S_TX"},
 	{"SLIMBUS_0_RX", NULL, "SLIM0_RX_VI_FB_LCH_MUX"},
 	{"SLIMBUS_0_RX", NULL, "SLIM0_RX_VI_FB_RCH_MUX"},
 	{"PRI_MI2S_RX", NULL, "PRI_MI2S_RX_VI_FB_MUX"},
+	{"INT4_MI2S_RX", NULL, "INT4_MI2S_RX_VI_FB_MONO_CH_MUX"},
+	{"INT4_MI2S_RX", NULL, "INT4_MI2S_RX_VI_FB_STEREO_CH_MUX"},
 	{"PRI_TDM_TX_0", NULL, "BE_IN"},
+	{"PRI_TDM_TX_1", NULL, "BE_IN"},
+	{"PRI_TDM_TX_2", NULL, "BE_IN"},
+	{"PRI_TDM_TX_3", NULL, "BE_IN"},
 	{"SEC_TDM_TX_0", NULL, "BE_IN"},
+	{"SEC_TDM_TX_1", NULL, "BE_IN"},
+	{"SEC_TDM_TX_2", NULL, "BE_IN"},
+	{"SEC_TDM_TX_3", NULL, "BE_IN"},
 	{"TERT_TDM_TX_0", NULL, "BE_IN"},
 	{"TERT_TDM_TX_1", NULL, "BE_IN"},
 	{"TERT_TDM_TX_2", NULL, "BE_IN"},
@@ -11408,7 +14021,9 @@
 		path_type = ADM_PATH_LIVE_REC;
 
 	mutex_lock(&routing_lock);
-	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
+	for_each_set_bit(i, &bedai->fe_sessions[0], MSM_FRONTEND_DAI_MAX) {
+		if (!is_mm_lsm_fe_id(i))
+			continue;
 		fdai = &fe_dai_map[i][session_type];
 		if (fdai->strm_id != INVALID_SESSION) {
 			int idx;
@@ -11429,13 +14044,12 @@
 			clear_bit(idx,
 				  &session_copp_map[i][session_type][be_id]);
 			if ((fdai->perf_mode == LEGACY_PCM_MODE) &&
-				(bedai->compr_passthr_mode == LEGACY_PCM))
+				(bedai->passthr_mode == LEGACY_PCM))
 				msm_pcm_routing_deinit_pp(bedai->port_id,
 							  topology);
 		}
 	}
 
-	bedai->compr_passthr_mode = LEGACY_PCM;
 	bedai->active = 0;
 	bedai->sample_rate = 0;
 	bedai->channel = 0;
@@ -11455,6 +14069,7 @@
 	struct msm_pcm_routing_fdai_data *fdai;
 	u32 session_id;
 	struct media_format_info voc_be_media_format;
+	bool is_lsm;
 
 	pr_debug("%s: substream->pcm->id:%s\n",
 		 __func__, substream->pcm->id);
@@ -11467,7 +14082,7 @@
 	bedai = &msm_bedais[be_id];
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		if (bedai->compr_passthr_mode != LEGACY_PCM)
+		if (bedai->passthr_mode != LEGACY_PCM)
 			path_type = ADM_PATH_COMPRESSED_RX;
 		else
 			path_type = ADM_PATH_PLAYBACK;
@@ -11488,7 +14103,13 @@
 	 */
 	bedai->active = 1;
 
-	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
+	for_each_set_bit(i, &bedai->fe_sessions[0], MSM_FRONTEND_DAI_MAX) {
+		if (!(is_mm_lsm_fe_id(i) &&
+				route_check_fe_id_adm_support(i)))
+			continue;
+
+		is_lsm = (i >= MSM_FRONTEND_DAI_LSM1) &&
+				 (i <= MSM_FRONTEND_DAI_LSM8);
 		fdai = &fe_dai_map[i][session_type];
 		if (fdai->strm_id != INVALID_SESSION) {
 			int app_type, app_type_idx, copp_idx, acdb_dev_id;
@@ -11510,13 +14131,21 @@
 						bedai->format);
 
 			app_type =
-				fe_dai_app_type_cfg[i][session_type].app_type;
-			if (app_type) {
+			fe_dai_app_type_cfg[i][session_type][be_id].app_type;
+			if (app_type && is_lsm) {
+				app_type_idx =
+				msm_pcm_routing_get_lsm_app_type_idx(app_type);
+				sample_rate =
+				fe_dai_app_type_cfg[i][session_type][be_id]
+					.sample_rate;
+				bits_per_sample =
+				lsm_app_type_cfg[app_type_idx].bit_width;
+			} else if (app_type) {
 				app_type_idx =
 				msm_pcm_routing_get_app_type_idx(app_type);
 				sample_rate =
-					fe_dai_app_type_cfg[i][session_type].
-						sample_rate;
+					fe_dai_app_type_cfg[i][session_type]
+							   [be_id].sample_rate;
 				bits_per_sample =
 					app_type_cfg[app_type_idx].bit_width;
 			} else
@@ -11530,9 +14159,9 @@
 			else
 				channels = bedai->adm_override_ch;
 			acdb_dev_id =
-			fe_dai_app_type_cfg[i][session_type].acdb_dev_id;
-			topology = msm_routing_get_adm_topology(path_type, i,
-						session_type);
+			fe_dai_app_type_cfg[i][session_type][be_id].acdb_dev_id;
+			topology = msm_routing_get_adm_topology(i, session_type,
+								be_id);
 			copp_idx = adm_open(bedai->port_id, path_type,
 					    sample_rate, channels, topology,
 					    fdai->perf_mode, bits_per_sample,
@@ -11556,16 +14185,16 @@
 					bedai->sample_rate);
 
 			msm_pcm_routing_build_matrix(i, session_type, path_type,
-						     fdai->perf_mode);
+						     fdai->perf_mode,
+						     bedai->passthr_mode);
 			if ((fdai->perf_mode == LEGACY_PCM_MODE) &&
-				(bedai->compr_passthr_mode ==
-					LEGACY_PCM))
+				(bedai->passthr_mode == LEGACY_PCM))
 				msm_pcm_routing_cfg_pp(bedai->port_id, copp_idx,
 						       topology, channels);
 		}
 	}
 
-	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MAX) {
+	for_each_set_bit(i, &bedai->fe_sessions[0], MSM_FRONTEND_DAI_MAX) {
 		session_id = msm_pcm_routing_get_voc_sessionid(i);
 		if (session_id) {
 			pr_debug("%s voice session_id: 0x%x\n", __func__,
@@ -11630,6 +14259,7 @@
 	unsigned long pp_config = 0;
 	bool mute_on;
 	int latency;
+	bool compr_passthr_mode = true;
 
 	pr_debug("%s: port_id %d, copp_idx %d\n", __func__, port_id, copp_idx);
 
@@ -11666,14 +14296,16 @@
 		return -EINVAL;
 	}
 
+	if ((msm_bedais[be_idx].passthr_mode == LEGACY_PCM) ||
+		(msm_bedais[be_idx].passthr_mode == LISTEN))
+		compr_passthr_mode = false;
+
 	pp_config = msm_bedais_pp_params[index].pp_params_config;
 	if (test_bit(ADM_PP_PARAM_MUTE_BIT, &pp_config)) {
 		pr_debug("%s: ADM_PP_PARAM_MUTE\n", __func__);
 		clear_bit(ADM_PP_PARAM_MUTE_BIT, &pp_config);
 		mute_on = msm_bedais_pp_params[index].mute_on;
-		if ((msm_bedais[be_idx].active) &&
-			(msm_bedais[be_idx].compr_passthr_mode !=
-			 LEGACY_PCM))
+		if ((msm_bedais[be_idx].active) && compr_passthr_mode)
 			adm_send_compressed_device_mute(port_id,
 								copp_idx,
 								mute_on);
@@ -11683,9 +14315,7 @@
 		clear_bit(ADM_PP_PARAM_LATENCY_BIT,
 			  &pp_config);
 		latency = msm_bedais_pp_params[index].latency;
-		if ((msm_bedais[be_idx].active) &&
-			(msm_bedais[be_idx].compr_passthr_mode !=
-			 LEGACY_PCM))
+		if ((msm_bedais[be_idx].active) && compr_passthr_mode)
 			adm_send_compressed_device_latency(port_id,
 							   copp_idx,
 							   latency);
@@ -11701,6 +14331,7 @@
 	int index, be_idx, i, topo_id, idx;
 	bool mute;
 	int latency;
+	bool compr_passthr_mode = true;
 
 	pr_debug("%s: pp_id: 0x%x\n", __func__, pp_id);
 
@@ -11725,7 +14356,11 @@
 		return -EINVAL;
 	}
 
-	for_each_set_bit(i, &msm_bedais[be_idx].fe_sessions,
+	if ((msm_bedais[be_idx].passthr_mode == LEGACY_PCM) ||
+		(msm_bedais[be_idx].passthr_mode == LISTEN))
+		compr_passthr_mode = false;
+
+	for_each_set_bit(i, &msm_bedais[be_idx].fe_sessions[0],
 				MSM_FRONTEND_DAI_MM_SIZE) {
 		for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
 			unsigned long copp =
@@ -11739,7 +14374,7 @@
 				continue;
 		pr_debug("%s: port: 0x%x, copp %ld, be active: %d, passt: %d\n",
 			 __func__, port_id, copp, msm_bedais[be_idx].active,
-			 msm_bedais[be_idx].compr_passthr_mode);
+			 msm_bedais[be_idx].passthr_mode);
 		switch (pp_id) {
 		case ADM_PP_PARAM_MUTE_ID:
 			pr_debug("%s: ADM_PP_PARAM_MUTE\n", __func__);
@@ -11747,9 +14382,7 @@
 			msm_bedais_pp_params[index].mute_on = mute;
 			set_bit(ADM_PP_PARAM_MUTE_BIT,
 				&msm_bedais_pp_params[index].pp_params_config);
-			if ((msm_bedais[be_idx].active) &&
-				(msm_bedais[be_idx].compr_passthr_mode !=
-				LEGACY_PCM))
+			if ((msm_bedais[be_idx].active) && compr_passthr_mode)
 				adm_send_compressed_device_mute(port_id,
 					idx, mute);
 			break;
@@ -11761,9 +14394,7 @@
 				&msm_bedais_pp_params[index].pp_params_config);
 			latency = msm_bedais_pp_params[index].latency =
 				ucontrol->value.integer.value[1];
-			if ((msm_bedais[be_idx].active) &&
-				(msm_bedais[be_idx].compr_passthr_mode !=
-				LEGACY_PCM))
+			if ((msm_bedais[be_idx].active) && compr_passthr_mode)
 				adm_send_compressed_device_latency(port_id,
 					idx, latency);
 			break;
@@ -11790,6 +14421,92 @@
 	msm_routing_put_device_pp_params_mixer),
 };
 
+static int msm_aptx_dec_license_control_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+			core_get_license_status(ASM_MEDIA_FMT_APTX);
+	pr_debug("%s: status %ld\n", __func__,
+			ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int msm_aptx_dec_license_control_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int32_t status = 0;
+
+	status = core_set_license(ucontrol->value.integer.value[0],
+				APTX_CLASSIC_DEC_LICENSE_ID);
+	pr_debug("%s: status %d\n", __func__, status);
+	return status;
+}
+
+static const struct snd_kcontrol_new aptx_dec_license_controls[] = {
+	SOC_SINGLE_EXT("APTX Dec License", SND_SOC_NOPM, 0,
+	0xFFFF, 0, msm_aptx_dec_license_control_get,
+	msm_aptx_dec_license_control_put),
+};
+
+static int msm_routing_be_dai_name_table_info(struct snd_kcontrol *kcontrol,
+					      struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = sizeof(be_dai_name_table);
+	return 0;
+}
+
+static int msm_routing_be_dai_name_table_tlv_get(struct snd_kcontrol *kcontrol,
+						 unsigned int __user *bytes,
+						 unsigned int size)
+{
+	int i;
+	int ret;
+
+	if (size < sizeof(be_dai_name_table)) {
+		pr_err("%s: invalid size %d requested, returning\n",
+			__func__, size);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	/*
+	 * Fill be_dai_name_table from msm_bedais table to reduce code changes
+	 * needed when adding new backends
+	 */
+	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+		be_dai_name_table[i].be_id = i;
+		strlcpy(be_dai_name_table[i].be_name,
+			msm_bedais[i].name,
+			LPASS_BE_NAME_MAX_LENGTH);
+	}
+
+	ret = copy_to_user(bytes, &be_dai_name_table,
+			   sizeof(be_dai_name_table));
+	if (ret) {
+		pr_err("%s: failed to copy be_dai_name_table\n", __func__);
+		ret = -EFAULT;
+	}
+
+done:
+	return ret;
+}
+
+static const struct snd_kcontrol_new
+	msm_routing_be_dai_name_table_mixer_controls[] = {
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			  SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
+		.info = msm_routing_be_dai_name_table_info,
+		.name = "Backend DAI Name Table",
+		.tlv.c = snd_soc_bytes_tlv_callback,
+		.private_value = (unsigned long) &(struct soc_bytes_ext) {
+			.max = sizeof(be_dai_name_table),
+			.get = msm_routing_be_dai_name_table_tlv_get,
+		}
+	},
+};
+
 static const struct snd_pcm_ops msm_routing_pcm_ops = {
 	.hw_params	= msm_pcm_routing_hw_params,
 	.close          = msm_pcm_routing_close,
@@ -11806,8 +14523,8 @@
 
 	snd_soc_dapm_new_widgets(platform->component.dapm.card);
 
-	snd_soc_add_platform_controls(platform, lsm_function,
-				      ARRAY_SIZE(lsm_function));
+	snd_soc_add_platform_controls(platform, lsm_controls,
+				      ARRAY_SIZE(lsm_controls));
 
 	snd_soc_add_platform_controls(platform, aanc_slim_0_rx_mux,
 				      ARRAY_SIZE(aanc_slim_0_rx_mux));
@@ -11818,10 +14535,16 @@
 	snd_soc_add_platform_controls(platform, app_type_cfg_controls,
 				      ARRAY_SIZE(app_type_cfg_controls));
 
+	snd_soc_add_platform_controls(platform, lsm_app_type_cfg_controls,
+				      ARRAY_SIZE(lsm_app_type_cfg_controls));
+
 	snd_soc_add_platform_controls(platform,
 				stereo_to_custom_stereo_controls,
 			ARRAY_SIZE(stereo_to_custom_stereo_controls));
 
+	snd_soc_add_platform_controls(platform, ec_ref_param_controls,
+				ARRAY_SIZE(ec_ref_param_controls));
+
 	msm_qti_pp_add_controls(platform);
 
 	msm_dts_srs_tm_add_controls(platform);
@@ -11836,12 +14559,19 @@
 				device_pp_params_mixer_controls,
 				ARRAY_SIZE(device_pp_params_mixer_controls));
 
+	snd_soc_add_platform_controls(platform,
+		msm_routing_be_dai_name_table_mixer_controls,
+		ARRAY_SIZE(msm_routing_be_dai_name_table_mixer_controls));
+
 	msm_dts_eagle_add_controls(platform);
 
 	snd_soc_add_platform_controls(platform, msm_source_tracking_controls,
 				ARRAY_SIZE(msm_source_tracking_controls));
 	snd_soc_add_platform_controls(platform, adm_channel_config_controls,
 				ARRAY_SIZE(adm_channel_config_controls));
+
+	snd_soc_add_platform_controls(platform, aptx_dec_license_controls,
+					ARRAY_SIZE(aptx_dec_license_controls));
 	return 0;
 }
 
@@ -11902,21 +14632,12 @@
 		return 0;
 	}
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
-		if (test_bit(fedai_id, &msm_bedais[i].fe_sessions))
+		if (test_bit(fedai_id, &msm_bedais[i].fe_sessions[0]))
 			return msm_bedais[i].active;
 	}
 	return 0;
 }
 
-static int get_cal_path(int path_type)
-{
-	if (path_type == ADM_PATH_PLAYBACK ||
-	    path_type == ADM_PATH_COMPRESSED_RX)
-		return RX_DEVICE;
-	else
-		return TX_DEVICE;
-}
-
 static int msm_routing_set_cal(int32_t cal_type,
 					size_t data_size, void *data)
 {
@@ -11974,6 +14695,11 @@
 	if (msm_routing_init_cal_data())
 		pr_err("%s: could not init cal data!\n", __func__);
 
+	afe_set_routing_callback(
+		(routing_cb)msm_pcm_get_dev_acdb_id_by_port_id);
+
+	memset(&be_dai_name_table, 0, sizeof(be_dai_name_table));
+
 	return platform_driver_register(&msm_routing_pcm_driver);
 }
 module_init(msm_soc_routing_platform_init);
@@ -11981,6 +14707,8 @@
 static void __exit msm_soc_routing_platform_exit(void)
 {
 	msm_routing_delete_cal_data();
+	memset(&be_dai_name_table, 0, sizeof(be_dai_name_table));
+	mutex_destroy(&routing_lock);
 	platform_driver_unregister(&msm_routing_pcm_driver);
 }
 module_exit(msm_soc_routing_platform_exit);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index d64fd64..fcd155e 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -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
@@ -13,6 +13,12 @@
 #define _MSM_PCM_ROUTING_H
 #include <sound/apr_audio-v2.h>
 
+/*
+ * These names are used by HAL to specify the BE. If any changes are
+ * made to the string names or the max name length corresponding
+ * changes need to be made in the HAL to ensure they still match.
+ */
+#define LPASS_BE_NAME_MAX_LENGTH 24
 #define LPASS_BE_PRI_I2S_RX "PRIMARY_I2S_RX"
 #define LPASS_BE_PRI_I2S_TX "PRIMARY_I2S_TX"
 #define LPASS_BE_SLIMBUS_0_RX "SLIMBUS_0_RX"
@@ -64,6 +70,7 @@
 #define LPASS_BE_SLIMBUS_3_TX "SLIMBUS_3_TX"
 #define LPASS_BE_SLIMBUS_4_RX "SLIMBUS_4_RX"
 #define LPASS_BE_SLIMBUS_4_TX "SLIMBUS_4_TX"
+#define LPASS_BE_SLIMBUS_TX_VI "SLIMBUS_TX_VI"
 #define LPASS_BE_SLIMBUS_5_RX "SLIMBUS_5_RX"
 #define LPASS_BE_SLIMBUS_5_TX "SLIMBUS_5_TX"
 #define LPASS_BE_SLIMBUS_6_RX "SLIMBUS_6_RX"
@@ -390,6 +397,7 @@
 #define ADM_PP_PARAM_LATENCY_ID			1
 #define ADM_PP_PARAM_LATENCY_BIT		2
 #define BE_DAI_PORT_SESSIONS_IDX_MAX		4
+#define BE_DAI_FE_SESSIONS_IDX_MAX		2
 
 struct msm_pcm_routing_evt {
 	void (*event_func)(enum msm_pcm_routing_event, void *);
@@ -399,7 +407,9 @@
 struct msm_pcm_routing_bdai_data {
 	u16 port_id; /* AFE port ID */
 	u8 active; /* track if this backend is enabled */
-	unsigned long fe_sessions; /* Front-end sessions */
+
+	/* Front-end sessions */
+	unsigned long fe_sessions[BE_DAI_FE_SESSIONS_IDX_MAX];
 	/*
 	 * Track Tx BE ports -> Rx BE ports.
 	 * port_sessions[0] used to track BE 0 to BE 63.
@@ -413,7 +423,7 @@
 	unsigned int  channel;
 	unsigned int  format;
 	unsigned int  adm_override_ch;
-	u32 compr_passthr_mode;
+	u32 passthr_mode;
 	char *name;
 };
 
@@ -465,8 +475,10 @@
 void msm_pcm_routing_acquire_lock(void);
 void msm_pcm_routing_release_lock(void);
 
-void msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int app_type,
-			int acdb_dev_id, int sample_rate, int session_type);
+int msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int session_type,
+					     int be_id, int app_type,
+					     int acdb_dev_id, int sample_rate);
 int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type,
-			int *app_type, int *acdb_dev_id, int *sample_rate);
+					    int be_id, int *app_type,
+					    int *acdb_dev_id, int *sample_rate);
 #endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index fa71eea..e39e642 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, 2017 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
@@ -390,6 +390,32 @@
 	return ret;
 }
 
+static int msm_voice_sidetone_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int ret;
+	bool sidetone_enable = ucontrol->value.integer.value[0];
+	uint32_t session_id = ALL_SESSION_VSID;
+
+	if (sidetone_enable < 0) {
+		pr_err("%s: Invalid arguments sidetone enable %d\n",
+			 __func__, sidetone_enable);
+		ret = -EINVAL;
+		return ret;
+	}
+	ret = voc_set_afe_sidetone(session_id, sidetone_enable);
+	pr_debug("%s: AFE Sidetone enable=%d session_id=0x%x ret=%d\n",
+		 __func__, sidetone_enable, session_id, ret);
+	return ret;
+}
+
+static int msm_voice_sidetone_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = voc_get_afe_sidetone();
+	return 0;
+}
+
 static int msm_voice_gain_put(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
@@ -632,6 +658,8 @@
 		.info	= msm_voice_cvd_version_info,
 		.get	= msm_voice_cvd_version_get,
 	},
+	SOC_SINGLE_MULTI_EXT("Voice Sidetone Enable", SND_SOC_NOPM, 0, 1, 0, 1,
+			     msm_voice_sidetone_get, msm_voice_sidetone_put),
 };
 
 static const struct snd_pcm_ops msm_pcm_ops = {
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index 1a739a4..02225f0 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -815,20 +815,25 @@
 			if (prtd->mode == MODE_PCM) {
 				ret = copy_from_user(&buf_node->frame.voc_pkt,
 							buf, count);
+				if (ret) {
+					pr_err("%s: copy from user failed %d\n",
+					       __func__, ret);
+					return -EFAULT;
+				}
 				buf_node->frame.pktlen = count;
 			} else {
 				ret = copy_from_user(&buf_node->frame,
 							buf, count);
+				if (ret) {
+					pr_err("%s: copy from user failed %d\n",
+					       __func__, ret);
+					return -EFAULT;
+				}
 				if (buf_node->frame.pktlen >= count)
 					buf_node->frame.pktlen = count -
 					(sizeof(buf_node->frame.frm_hdr) +
 					 sizeof(buf_node->frame.pktlen));
 			}
-			if (ret) {
-				pr_err("%s: copy from user failed %d\n",
-				       __func__, ret);
-				return -EFAULT;
-			}
 			spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
 			list_add_tail(&buf_node->list, &prtd->in_queue);
 			spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
index 9276231..c60b27f 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
@@ -81,6 +81,10 @@
 static const DECLARE_TLV_DB_LINEAR(hfp_rx_vol_gain, 0,
 				INT_RX_VOL_MAX_STEPS);
 
+static int msm_route_icc_vol_control;
+static const DECLARE_TLV_DB_LINEAR(icc_rx_vol_gain, 0,
+				INT_RX_VOL_MAX_STEPS);
+
 static int msm_route_pri_auxpcm_lb_vol_ctrl;
 static const DECLARE_TLV_DB_LINEAR(pri_auxpcm_lb_vol_gain, 0,
 				INT_RX_VOL_MAX_STEPS);
@@ -89,6 +93,8 @@
 static const DECLARE_TLV_DB_LINEAR(sec_auxpcm_lb_vol_gain, 0,
 				INT_RX_VOL_MAX_STEPS);
 
+static int msm_multichannel_ec_primary_mic_ch;
+
 static void msm_qti_pp_send_eq_values_(int eq_idx)
 {
 	int result;
@@ -342,7 +348,7 @@
 	uint32_t param_payload_len = RMS_PAYLOAD_LEN * sizeof(uint32_t);
 	struct msm_pcm_routing_bdai_data msm_bedai;
 
-	param_value = kzalloc(param_length, GFP_KERNEL);
+	param_value = kzalloc(param_length + param_payload_len, GFP_KERNEL);
 	if (!param_value)
 		return -ENOMEM;
 
@@ -399,6 +405,7 @@
 static int msm_afe_sec_mi2s_lb_vol_ctrl;
 static int msm_afe_tert_mi2s_lb_vol_ctrl;
 static int msm_afe_quat_mi2s_lb_vol_ctrl;
+static int msm_afe_slimbus_7_lb_vol_ctrl;
 static int msm_afe_slimbus_8_lb_vol_ctrl;
 static const DECLARE_TLV_DB_LINEAR(fm_rx_vol_gain, 0, INT_RX_VOL_MAX_STEPS);
 static const DECLARE_TLV_DB_LINEAR(afe_lb_vol_gain, 0, INT_RX_VOL_MAX_STEPS);
@@ -471,6 +478,29 @@
 	return 0;
 }
 
+static int msm_qti_pp_get_slimbus_7_lb_vol_mixer(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = msm_afe_slimbus_7_lb_vol_ctrl;
+	return 0;
+}
+
+static int msm_qti_pp_set_slimbus_7_lb_vol_mixer(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	int ret = afe_loopback_gain(SLIMBUS_7_TX,
+				ucontrol->value.integer.value[0]);
+
+	if (ret)
+		pr_err("%s: failed to set LB vol for SLIMBUS_7_TX, err %d\n",
+			__func__, ret);
+	else
+		msm_afe_slimbus_7_lb_vol_ctrl =
+				ucontrol->value.integer.value[0];
+
+	return ret;
+}
+
 static int msm_qti_pp_get_slimbus_8_lb_vol_mixer(struct snd_kcontrol *kcontrol,
 				       struct snd_ctl_elem_value *ucontrol)
 {
@@ -495,6 +525,23 @@
 	return ret;
 }
 
+static int msm_qti_pp_get_icc_vol_mixer(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = msm_route_icc_vol_control;
+	return 0;
+}
+
+static int msm_qti_pp_set_icc_vol_mixer(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	adm_set_mic_gain(AFE_PORT_ID_QUATERNARY_TDM_TX,
+		adm_get_default_copp_idx(AFE_PORT_ID_QUATERNARY_TDM_TX),
+		ucontrol->value.integer.value[0]);
+	msm_route_icc_vol_control = ucontrol->value.integer.value[0];
+	return 0;
+}
+
 static int msm_qti_pp_get_quat_mi2s_fm_vol_mixer(struct snd_kcontrol *kcontrol,
 				       struct snd_ctl_elem_value *ucontrol)
 {
@@ -581,7 +628,7 @@
 static int msm_qti_pp_get_channel_map_mixer(struct snd_kcontrol *kcontrol,
 					    struct snd_ctl_elem_value *ucontrol)
 {
-	char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL];
+	char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL] = {0};
 	int i;
 
 	adm_get_multi_ch_map(channel_map, ADM_PATH_PLAYBACK);
@@ -774,6 +821,43 @@
 	return 0;
 }
 
+static int msm_multichannel_ec_primary_mic_ch_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int ret = 0;
+	int copp_idx = 0;
+	int port_id = AFE_PORT_ID_QUATERNARY_TDM_TX;
+
+	msm_multichannel_ec_primary_mic_ch = ucontrol->value.integer.value[0];
+	pr_debug("%s: msm_multichannel_ec_primary_mic_ch = %u\n",
+		__func__, msm_multichannel_ec_primary_mic_ch);
+	copp_idx = adm_get_default_copp_idx(port_id);
+	if ((copp_idx < 0) || (copp_idx > MAX_COPPS_PER_PORT)) {
+		pr_err("%s : no active copp to query multichannel ec copp_idx: %u\n",
+			__func__, copp_idx);
+		return -EINVAL;
+	}
+	adm_send_set_multichannel_ec_primary_mic_ch(port_id, copp_idx,
+		msm_multichannel_ec_primary_mic_ch);
+
+	return ret;
+}
+
+static int msm_multichannel_ec_primary_mic_ch_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = msm_multichannel_ec_primary_mic_ch;
+	pr_debug("%s: msm_multichannel_ec_primary_mic_ch = %lu\n",
+		__func__, ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static const struct  snd_kcontrol_new msm_multichannel_ec_controls[] = {
+	SOC_SINGLE_EXT("Multichannel EC Primary Mic Ch", SND_SOC_NOPM, 0,
+		0xFFFFFFFF, 0, msm_multichannel_ec_primary_mic_ch_get,
+		msm_multichannel_ec_primary_mic_ch_put),
+};
+
 static const struct snd_kcontrol_new int_fm_vol_mixer_controls[] = {
 	SOC_SINGLE_EXT_TLV("Internal FM RX Volume", SND_SOC_NOPM, 0,
 	INT_RX_VOL_GAIN, 0, msm_qti_pp_get_fm_vol_mixer,
@@ -801,6 +885,14 @@
 	msm_qti_pp_set_tert_mi2s_lb_vol_mixer, afe_lb_vol_gain),
 };
 
+static const struct snd_kcontrol_new slimbus_7_lb_vol_mixer_controls[] = {
+	SOC_SINGLE_EXT_TLV("SLIMBUS_7 LOOPBACK Volume", SND_SOC_NOPM, 0,
+				INT_RX_VOL_GAIN, 0,
+				msm_qti_pp_get_slimbus_7_lb_vol_mixer,
+				msm_qti_pp_set_slimbus_7_lb_vol_mixer,
+				afe_lb_vol_gain),
+};
+
 static const struct snd_kcontrol_new slimbus_8_lb_vol_mixer_controls[] = {
 	SOC_SINGLE_EXT_TLV("SLIMBUS_8 LOOPBACK Volume", SND_SOC_NOPM, 0,
 	INT_RX_VOL_GAIN, 0, msm_qti_pp_get_slimbus_8_lb_vol_mixer,
@@ -813,6 +905,12 @@
 	msm_qti_pp_set_hfp_vol_mixer, hfp_rx_vol_gain),
 };
 
+static const struct snd_kcontrol_new int_icc_vol_mixer_controls[] = {
+	SOC_SINGLE_EXT_TLV("Internal ICC Volume", SND_SOC_NOPM, 0,
+	INT_RX_VOL_GAIN, 0, msm_qti_pp_get_icc_vol_mixer,
+	msm_qti_pp_set_icc_vol_mixer, icc_rx_vol_gain),
+};
+
 static const struct snd_kcontrol_new pri_auxpcm_lb_vol_mixer_controls[] = {
 	SOC_SINGLE_EXT_TLV("PRI AUXPCM LOOPBACK Volume",
 	AFE_PORT_ID_PRIMARY_PCM_TX, 0, INT_RX_VOL_GAIN, 0,
@@ -999,12 +1097,18 @@
 	snd_soc_add_platform_controls(platform, tert_mi2s_lb_vol_mixer_controls,
 			ARRAY_SIZE(tert_mi2s_lb_vol_mixer_controls));
 
+	snd_soc_add_platform_controls(platform, slimbus_7_lb_vol_mixer_controls,
+			ARRAY_SIZE(slimbus_7_lb_vol_mixer_controls));
+
 	snd_soc_add_platform_controls(platform, slimbus_8_lb_vol_mixer_controls,
 			ARRAY_SIZE(slimbus_8_lb_vol_mixer_controls));
 
 	snd_soc_add_platform_controls(platform, int_hfp_vol_mixer_controls,
 			ARRAY_SIZE(int_hfp_vol_mixer_controls));
 
+	snd_soc_add_platform_controls(platform, int_icc_vol_mixer_controls,
+			ARRAY_SIZE(int_icc_vol_mixer_controls));
+
 	snd_soc_add_platform_controls(platform,
 			pri_auxpcm_lb_vol_mixer_controls,
 			ARRAY_SIZE(pri_auxpcm_lb_vol_mixer_controls));
@@ -1031,5 +1135,8 @@
 
 	snd_soc_add_platform_controls(platform, asphere_mixer_controls,
 			ARRAY_SIZE(asphere_mixer_controls));
+
+	snd_soc_add_platform_controls(platform, msm_multichannel_ec_controls,
+			ARRAY_SIZE(msm_multichannel_ec_controls));
 }
 #endif /* CONFIG_QTI_PP */
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 62e4a4d..90d640d 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -102,6 +102,9 @@
 
 	int set_custom_topology;
 	int ec_ref_rx;
+	int num_ec_ref_rx_chans;
+	int ec_ref_rx_bit_width;
+	int ec_ref_rx_sampling_rate;
 };
 
 static struct adm_ctl			this_adm;
@@ -986,9 +989,10 @@
 		      char *params, uint32_t client_id)
 {
 	struct adm_cmd_get_pp_params_v5 *adm_params = NULL;
-	int sz, rc = 0, i = 0;
+	int rc = 0, i = 0;
 	int port_idx, idx;
 	int *params_data = (int *)params;
+	uint64_t sz = 0;
 
 	port_id = afe_convert_virtual_to_portid(port_id);
 	port_idx = adm_validate_and_get_port_index(port_id);
@@ -997,7 +1001,16 @@
 		return -EINVAL;
 	}
 
-	sz = sizeof(struct adm_cmd_get_pp_params_v5) + params_length;
+	sz = (uint64_t)sizeof(struct adm_cmd_get_pp_params_v5) +
+				(uint64_t)params_length;
+	/*
+	 * Check if the value of "sz" (which is ultimately assigned to
+	 * "hdr.pkt_size") crosses U16_MAX.
+	 */
+	if (sz > U16_MAX) {
+		pr_err("%s: Invalid params_length\n", __func__);
+		return -EINVAL;
+	}
 	adm_params = kzalloc(sz, GFP_KERNEL);
 	if (!adm_params) {
 		pr_err("%s: adm params memory alloc failed", __func__);
@@ -1367,6 +1380,7 @@
 				 */
 			case ADM_CMD_DEVICE_OPEN_V5:
 			case ADM_CMD_DEVICE_CLOSE_V5:
+			case ADM_CMD_DEVICE_OPEN_V6:
 				pr_debug("%s: Basic callback received, wake up.\n",
 					__func__);
 				atomic_set(&this_adm.copp.stat[port_idx]
@@ -1462,7 +1476,8 @@
 		}
 
 		switch (data->opcode) {
-		case ADM_CMDRSP_DEVICE_OPEN_V5: {
+		case ADM_CMDRSP_DEVICE_OPEN_V5:
+		case ADM_CMDRSP_DEVICE_OPEN_V6: {
 			struct adm_cmd_rsp_device_open_v5 *open =
 			(struct adm_cmd_rsp_device_open_v5 *)data->payload;
 
@@ -2271,10 +2286,64 @@
 	return rc;
 }
 
+int adm_arrange_mch_ep2_map(struct adm_cmd_device_open_v6 *open_v6,
+			 int channel_mode)
+{
+	int rc = 0;
+
+	memset(open_v6->dev_channel_mapping_eid2, 0,
+	       PCM_FORMAT_MAX_NUM_CHANNEL);
+
+	if (channel_mode == 1)	{
+		open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FC;
+	} else if (channel_mode == 2) {
+		open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+		open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+	} else if (channel_mode == 3)	{
+		open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+		open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+		open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_FC;
+	} else if (channel_mode == 4) {
+		open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+		open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+		open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LS;
+		open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_RS;
+	} else if (channel_mode == 5) {
+		open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+		open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+		open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_FC;
+		open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_LS;
+		open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_RS;
+	} else if (channel_mode == 6) {
+		open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+		open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+		open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LFE;
+		open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_FC;
+		open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_LS;
+		open_v6->dev_channel_mapping_eid2[5] = PCM_CHANNEL_RS;
+	} else if (channel_mode == 8) {
+		open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+		open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+		open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LFE;
+		open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_FC;
+		open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_LS;
+		open_v6->dev_channel_mapping_eid2[5] = PCM_CHANNEL_RS;
+		open_v6->dev_channel_mapping_eid2[6] = PCM_CHANNEL_LB;
+		open_v6->dev_channel_mapping_eid2[7] = PCM_CHANNEL_RB;
+	} else {
+		pr_err("%s: invalid num_chan %d\n", __func__,
+			channel_mode);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
 int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
 	     int perf_mode, uint16_t bit_width, int app_type, int acdb_id)
 {
 	struct adm_cmd_device_open_v5	open;
+	struct adm_cmd_device_open_v6	open_v6;
 	int ret = 0;
 	int port_idx, copp_idx, flags;
 	int tmp_port = q6audio_get_port_id(port_id);
@@ -2409,6 +2478,7 @@
 				pr_err("%s: DTS_EAGLE mmap did not work!",
 					__func__);
 		}
+		memset(&open, 0, sizeof(struct adm_cmd_device_open_v5));
 		open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 						   APR_HDR_LEN(APR_HDR_SIZE),
 						   APR_PKT_VER);
@@ -2424,10 +2494,9 @@
 		open.flags = flags;
 		open.mode_of_operation = path;
 		open.endpoint_id_1 = tmp_port;
+		open.endpoint_id_2 = 0xFFFF;
 
-		if (this_adm.ec_ref_rx == -1) {
-			open.endpoint_id_2 = 0xFFFF;
-		} else if (this_adm.ec_ref_rx && (path != 1)) {
+		if (this_adm.ec_ref_rx && (path != 1)) {
 			open.endpoint_id_2 = this_adm.ec_ref_rx;
 			this_adm.ec_ref_rx = -1;
 		}
@@ -2451,7 +2520,49 @@
 
 		atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
 
-		ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+		if ((this_adm.num_ec_ref_rx_chans != 0) && (path != 1) &&
+			(open.endpoint_id_2 != 0xFFFF)) {
+			memset(&open_v6, 0,
+				sizeof(struct adm_cmd_device_open_v6));
+			memcpy(&open_v6, &open,
+				sizeof(struct adm_cmd_device_open_v5));
+			open_v6.hdr.opcode = ADM_CMD_DEVICE_OPEN_V6;
+			open_v6.hdr.pkt_size = sizeof(open_v6);
+			open_v6.dev_num_channel_eid2 =
+				this_adm.num_ec_ref_rx_chans;
+			this_adm.num_ec_ref_rx_chans = 0;
+
+			if (this_adm.ec_ref_rx_bit_width != 0) {
+				open_v6.bit_width_eid2 =
+					this_adm.ec_ref_rx_bit_width;
+				this_adm.ec_ref_rx_bit_width = 0;
+			} else {
+				open_v6.bit_width_eid2 = bit_width;
+			}
+
+			if (this_adm.ec_ref_rx_sampling_rate != 0) {
+				open_v6.sample_rate_eid2 =
+					this_adm.ec_ref_rx_sampling_rate;
+				this_adm.ec_ref_rx_sampling_rate = 0;
+			} else {
+				open_v6.sample_rate_eid2 = rate;
+			}
+
+			pr_debug("%s: eid2_channels=%d eid2_bit_width=%d eid2_rate=%d\n",
+				__func__, open_v6.dev_num_channel_eid2,
+				open_v6.bit_width_eid2,
+				open_v6.sample_rate_eid2);
+
+			ret = adm_arrange_mch_ep2_map(&open_v6,
+				open_v6.dev_num_channel_eid2);
+
+			if (ret)
+				return ret;
+
+			ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open_v6);
+		} else {
+			ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+		}
 		if (ret < 0) {
 			pr_err("%s: port_id: 0x%x for[0x%x] failed %d\n",
 			__func__, tmp_port, port_id, ret);
@@ -2481,7 +2592,6 @@
 	return copp_idx;
 }
 
-
 void adm_copp_mfc_cfg(int port_id, int copp_idx, int dst_sample_rate)
 {
 	struct audproc_mfc_output_media_fmt mfc_cfg;
@@ -2584,8 +2694,43 @@
 	return;
 }
 
+static void route_set_opcode_matrix_id(
+			struct adm_cmd_matrix_map_routings_v5 **route_addr,
+			int path, uint32_t passthr_mode)
+{
+	struct adm_cmd_matrix_map_routings_v5 *route = *route_addr;
 
-int adm_matrix_map(int path, struct route_payload payload_map, int perf_mode)
+	switch (path) {
+	case ADM_PATH_PLAYBACK:
+		route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
+		route->matrix_id = ADM_MATRIX_ID_AUDIO_RX;
+		break;
+	case ADM_PATH_LIVE_REC:
+		if (passthr_mode == LISTEN) {
+			route->hdr.opcode =
+				ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
+			route->matrix_id = ADM_MATRIX_ID_LISTEN_TX;
+			break;
+		}
+		/* fall through to set matrix id for non-listen case */
+	case ADM_PATH_NONLIVE_REC:
+		route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
+		route->matrix_id = ADM_MATRIX_ID_AUDIO_TX;
+		break;
+	case ADM_PATH_COMPRESSED_RX:
+		route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
+		route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_RX;
+		break;
+	default:
+		pr_err("%s: Wrong path set[%d]\n", __func__, path);
+		break;
+	}
+	pr_debug("%s: opcode 0x%x, matrix id %d\n",
+		 __func__, route->hdr.opcode, route->matrix_id);
+}
+
+int adm_matrix_map(int path, struct route_payload payload_map, int perf_mode,
+			uint32_t passthr_mode)
 {
 	struct adm_cmd_matrix_map_routings_v5	*route;
 	struct adm_session_map_node_v5 *node;
@@ -2618,32 +2763,9 @@
 	route->hdr.dest_domain = APR_DOMAIN_ADSP;
 	route->hdr.dest_port = 0; /* Ignored */;
 	route->hdr.token = 0;
-	if (path == ADM_PATH_COMPRESSED_RX) {
-		pr_debug("%s: ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5 0x%x\n",
-			 __func__, ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5);
-		route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
-	} else {
-		pr_debug("%s: DM_CMD_MATRIX_MAP_ROUTINGS_V5 0x%x\n",
-			 __func__, ADM_CMD_MATRIX_MAP_ROUTINGS_V5);
-		route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
-	}
 	route->num_sessions = 1;
+	route_set_opcode_matrix_id(&route, path, passthr_mode);
 
-	switch (path) {
-	case ADM_PATH_PLAYBACK:
-		route->matrix_id = ADM_MATRIX_ID_AUDIO_RX;
-		break;
-	case ADM_PATH_LIVE_REC:
-	case ADM_PATH_NONLIVE_REC:
-		route->matrix_id = ADM_MATRIX_ID_AUDIO_TX;
-		break;
-	case ADM_PATH_COMPRESSED_RX:
-		route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_RX;
-		break;
-	default:
-		pr_err("%s: Wrong path set[%d]\n", __func__, path);
-		break;
-	}
 	payload = ((u8 *)matrix_map +
 			sizeof(struct adm_cmd_matrix_map_routings_v5));
 	node = (struct adm_session_map_node_v5 *)payload;
@@ -2711,8 +2833,8 @@
 							[port_idx][copp_idx]),
 					    get_cal_path(path),
 					    payload_map.session_id,
-					    payload_map.app_type,
-					    payload_map.acdb_dev_id);
+					    payload_map.app_type[i],
+					    payload_map.acdb_dev_id[i]);
 
 			if (!test_bit(ADM_STATUS_CALIBRATION_REQUIRED,
 				(void *)&this_adm.copp.adm_status[port_idx]
@@ -2723,9 +2845,9 @@
 			}
 			send_adm_cal(payload_map.port_id[i], copp_idx,
 				     get_cal_path(path), perf_mode,
-				     payload_map.app_type,
-				     payload_map.acdb_dev_id,
-				     payload_map.sample_rate);
+				     payload_map.app_type[i],
+				     payload_map.acdb_dev_id[i],
+				     payload_map.sample_rate[i]);
 			/* ADM COPP calibration is already sent */
 			clear_bit(ADM_STATUS_CALIBRATION_REQUIRED,
 				(void *)&this_adm.copp.
@@ -2744,7 +2866,28 @@
 void adm_ec_ref_rx_id(int port_id)
 {
 	this_adm.ec_ref_rx = port_id;
-	pr_debug("%s: ec_ref_rx:%d", __func__, this_adm.ec_ref_rx);
+	pr_debug("%s: ec_ref_rx:%d\n", __func__, this_adm.ec_ref_rx);
+}
+
+void adm_num_ec_ref_rx_chans(int num_chans)
+{
+	this_adm.num_ec_ref_rx_chans = num_chans;
+	pr_debug("%s: num_ec_ref_rx_chans:%d\n",
+		__func__, this_adm.num_ec_ref_rx_chans);
+}
+
+void adm_ec_ref_rx_bit_width(int bit_width)
+{
+	this_adm.ec_ref_rx_bit_width = bit_width;
+	pr_debug("%s: ec_ref_rx_bit_width:%d\n",
+		__func__, this_adm.ec_ref_rx_bit_width);
+}
+
+void adm_ec_ref_rx_sampling_rate(int sampling_rate)
+{
+	this_adm.ec_ref_rx_sampling_rate = sampling_rate;
+	pr_debug("%s: ec_ref_rx_sampling_rate:%d\n",
+		__func__, this_adm.ec_ref_rx_sampling_rate);
 }
 
 int adm_close(int port_id, int perf_mode, int copp_idx)
@@ -3491,6 +3634,172 @@
 	return rc;
 }
 
+int adm_set_mic_gain(int port_id, int copp_idx, int volume)
+{
+	struct adm_set_mic_gain_params	mic_gain_params;
+	int rc = 0;
+	int sz, port_idx;
+
+	pr_debug("%s:\n", __func__);
+	port_id = afe_convert_virtual_to_portid(port_id);
+	port_idx = adm_validate_and_get_port_index(port_id);
+	if (port_idx < 0) {
+		pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+		return -EINVAL;
+	}
+
+	sz = sizeof(struct adm_set_mic_gain_params);
+
+	mic_gain_params.params.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mic_gain_params.params.hdr.pkt_size = sz;
+	mic_gain_params.params.hdr.src_svc = APR_SVC_ADM;
+	mic_gain_params.params.hdr.src_domain = APR_DOMAIN_APPS;
+	mic_gain_params.params.hdr.src_port = port_id;
+	mic_gain_params.params.hdr.dest_svc = APR_SVC_ADM;
+	mic_gain_params.params.hdr.dest_domain = APR_DOMAIN_ADSP;
+	mic_gain_params.params.hdr.dest_port =
+			atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+	mic_gain_params.params.hdr.token = port_idx << 16 | copp_idx;
+	mic_gain_params.params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+	mic_gain_params.params.payload_addr_lsw = 0;
+	mic_gain_params.params.payload_addr_msw = 0;
+	mic_gain_params.params.mem_map_handle = 0;
+	mic_gain_params.params.payload_size =
+		sizeof(struct adm_param_data_v5) +
+		sizeof(struct admx_mic_gain);
+	mic_gain_params.data.module_id = ADM_MODULE_IDX_MIC_GAIN_CTRL;
+	mic_gain_params.data.param_id = ADM_PARAM_IDX_MIC_GAIN;
+	mic_gain_params.data.param_size =
+		sizeof(struct admx_mic_gain);
+	mic_gain_params.data.reserved = 0;
+	mic_gain_params.mic_gain_data.tx_mic_gain = volume;
+	mic_gain_params.mic_gain_data.reserved = 0;
+	pr_debug("%s: Mic Gain set to %d at port_id 0x%x\n",
+		__func__, volume, port_id);
+
+	atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+	rc = apr_send_pkt(this_adm.apr, (uint32_t *)&mic_gain_params);
+	if (rc < 0) {
+		pr_err("%s: Set params failed port = %#x\n",
+			__func__, port_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	/* Wait for the callback */
+	rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+		atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+		msecs_to_jiffies(TIMEOUT_MS));
+	if (!rc) {
+		pr_err("%s: Mic Gain Set params timed out port = %#x\n",
+			 __func__, port_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	} else if (atomic_read(&this_adm.copp.stat
+				[port_idx][copp_idx]) > 0) {
+		pr_err("%s: DSP returned error[%s]\n",
+				__func__, adsp_err_get_err_str(
+				atomic_read(&this_adm.copp.stat
+				[port_idx][copp_idx])));
+		rc = adsp_err_get_lnx_err_code(
+				atomic_read(&this_adm.copp.stat
+					[port_idx][copp_idx]));
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	return rc;
+}
+
+int adm_send_set_multichannel_ec_primary_mic_ch(int port_id, int copp_idx,
+			int primary_mic_ch)
+{
+	struct adm_set_sec_primary_ch_params sec_primary_ch_params;
+	int rc = 0;
+	int sz, port_idx;
+
+	pr_debug("%s port_id 0x%x, copp_idx 0x%x, primary_mic_ch %d\n",
+			__func__, port_id,  copp_idx,  primary_mic_ch);
+	port_id = afe_convert_virtual_to_portid(port_id);
+	port_idx = adm_validate_and_get_port_index(port_id);
+	if (port_idx < 0) {
+		pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+		return -EINVAL;
+	}
+
+	if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+		pr_err("%s: Invalid copp_idx 0x%x\n", __func__, copp_idx);
+		return -EINVAL;
+	}
+
+	sz = sizeof(struct adm_set_sec_primary_ch_params);
+
+	sec_primary_ch_params.params.hdr.hdr_field =
+			APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	sec_primary_ch_params.params.hdr.pkt_size = sz;
+	sec_primary_ch_params.params.hdr.src_svc = APR_SVC_ADM;
+	sec_primary_ch_params.params.hdr.src_domain = APR_DOMAIN_APPS;
+	sec_primary_ch_params.params.hdr.src_port = port_id;
+	sec_primary_ch_params.params.hdr.dest_svc = APR_SVC_ADM;
+	sec_primary_ch_params.params.hdr.dest_domain = APR_DOMAIN_ADSP;
+	sec_primary_ch_params.params.hdr.dest_port =
+			atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+	sec_primary_ch_params.params.hdr.token = port_idx << 16 | copp_idx;
+	sec_primary_ch_params.params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+	sec_primary_ch_params.params.payload_addr_lsw = 0;
+	sec_primary_ch_params.params.payload_addr_msw = 0;
+	sec_primary_ch_params.params.mem_map_handle = 0;
+	sec_primary_ch_params.params.payload_size =
+			sizeof(struct adm_param_data_v5) +
+			sizeof(struct admx_sec_primary_mic_ch);
+	sec_primary_ch_params.data.module_id =
+			AUDPROC_MODULE_ID_VOICE_TX_SECNS;
+	sec_primary_ch_params.data.param_id =
+			AUDPROC_PARAM_IDX_SEC_PRIMARY_MIC_CH;
+	sec_primary_ch_params.data.param_size =
+			sizeof(struct admx_sec_primary_mic_ch);
+	sec_primary_ch_params.data.reserved = 0;
+	sec_primary_ch_params.sec_primary_mic_ch_data.version = 0;
+	sec_primary_ch_params.sec_primary_mic_ch_data.reserved = 0;
+	sec_primary_ch_params.sec_primary_mic_ch_data.sec_primary_mic_ch =
+			primary_mic_ch;
+	sec_primary_ch_params.sec_primary_mic_ch_data.reserved1 = 0;
+
+	atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+	rc = apr_send_pkt(this_adm.apr, (uint32_t *)&sec_primary_ch_params);
+	if (rc < 0) {
+		pr_err("%s: Set params failed port = %#x\n",
+				__func__, port_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	/* Wait for the callback */
+	rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+		atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+		msecs_to_jiffies(TIMEOUT_MS));
+	if (!rc) {
+		pr_err("%s: Mic Set params timed out port = %#x\n",
+				__func__, port_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	} else if (atomic_read(&this_adm.copp.stat
+				[port_idx][copp_idx]) > 0) {
+		pr_err("%s: DSP returned error[%s]\n",
+				__func__, adsp_err_get_err_str(
+				atomic_read(&this_adm.copp.stat
+				[port_idx][copp_idx])));
+		rc = adsp_err_get_lnx_err_code(
+				atomic_read(&this_adm.copp.stat
+					[port_idx][copp_idx]));
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	return rc;
+}
+
 int adm_param_enable(int port_id, int copp_idx, int module_id,  int enable)
 {
 	struct audproc_enable_param_t adm_mod_enable;
@@ -4365,6 +4674,9 @@
 
 	this_adm.apr = NULL;
 	this_adm.ec_ref_rx = -1;
+	this_adm.num_ec_ref_rx_chans = 0;
+	this_adm.ec_ref_rx_bit_width = 0;
+	this_adm.ec_ref_rx_sampling_rate = 0;
 	atomic_set(&this_adm.matrix_map_stat, 0);
 	init_waitqueue_head(&this_adm.matrix_map_wait);
 	atomic_set(&this_adm.adm_stat, 0);
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index b0249f4..176b8aa 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -36,6 +36,7 @@
 	AFE_FB_SPKR_PROT_CAL,
 	AFE_HW_DELAY_CAL,
 	AFE_SIDETONE_CAL,
+	AFE_SIDETONE_IIR_CAL,
 	AFE_TOPOLOGY_CAL,
 	AFE_CUST_TOPOLOGY_CAL,
 	AFE_FB_SPKR_PROT_TH_VI_CAL,
@@ -112,12 +113,15 @@
 	struct audio_cal_info_sp_ex_vi_ftm_cfg	ex_ftm_cfg;
 	struct afe_sp_th_vi_get_param_resp	th_vi_resp;
 	struct afe_sp_ex_vi_get_param_resp	ex_vi_resp;
+	struct afe_av_dev_drift_get_param_resp	av_dev_drift_resp;
 	int vi_tx_port;
 	int vi_rx_port;
 	uint32_t afe_sample_rates[AFE_MAX_PORTS];
 	struct aanc_data aanc_info;
 	struct mutex afe_cmd_lock;
 	int set_custom_topology;
+	int dev_acdb_id[AFE_MAX_PORTS];
+	routing_cb rt_cb;
 };
 
 static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
@@ -144,7 +148,7 @@
 	int topology;
 	int port_index = afe_get_port_index(port_id);
 
-	if ((port_index < 0) || (port_index > AFE_MAX_PORTS)) {
+	if ((port_index < 0) || (port_index >= AFE_MAX_PORTS)) {
 		pr_err("%s: Invalid port index %d\n", __func__, port_index);
 		topology = -EINVAL;
 		goto done;
@@ -187,6 +191,38 @@
 			__func__, data->opcode, data->payload_size);
 }
 
+static void av_dev_drift_afe_cb_handler(uint32_t *payload,
+					uint32_t payload_size)
+{
+	u32 param_id;
+	struct afe_av_dev_drift_get_param_resp *resp =
+		(struct afe_av_dev_drift_get_param_resp *) payload;
+
+	if (!(&(resp->pdata))) {
+		pr_err("%s: Error: resp pdata is NULL\n", __func__);
+		return;
+	}
+
+	param_id = resp->pdata.param_id;
+	if (param_id == AFE_PARAM_ID_DEV_TIMING_STATS) {
+		if (payload_size < sizeof(this_afe.av_dev_drift_resp)) {
+			pr_err("%s: Error: received size %d, resp size %zu\n",
+				__func__, payload_size,
+				sizeof(this_afe.av_dev_drift_resp));
+			return;
+		}
+		memcpy(&this_afe.av_dev_drift_resp, payload,
+				sizeof(this_afe.av_dev_drift_resp));
+		if (!this_afe.av_dev_drift_resp.status) {
+			atomic_set(&this_afe.state, 0);
+		} else {
+			pr_debug("%s: av_dev_drift_resp status: %d", __func__,
+				  this_afe.av_dev_drift_resp.status);
+			atomic_set(&this_afe.state, -1);
+		}
+	}
+}
+
 static int32_t sp_make_afe_callback(uint32_t *payload, uint32_t payload_size)
 {
 	u32 param_id;
@@ -272,6 +308,7 @@
 		mutex_lock(&this_afe.cal_data[AFE_CUST_TOPOLOGY_CAL]->lock);
 		this_afe.set_custom_topology = 1;
 		mutex_unlock(&this_afe.cal_data[AFE_CUST_TOPOLOGY_CAL]->lock);
+		rtac_clear_mapping(AFE_RTAC_CAL);
 
 		if (this_afe.apr) {
 			apr_reset(this_afe.apr);
@@ -306,10 +343,7 @@
 	}
 	afe_callback_debug_print(data);
 	if (data->opcode == AFE_PORT_CMDRSP_GET_PARAM_V2) {
-		u8 *payload = data->payload;
-
-		if (rtac_make_afe_callback(data->payload, data->payload_size))
-			return 0;
+		uint32_t *payload = data->payload;
 
 		if (!payload || (data->token >= AFE_MAX_PORTS)) {
 			pr_err("%s: Error: size %d payload %pK token %d\n",
@@ -317,9 +351,19 @@
 				payload, data->token);
 			return -EINVAL;
 		}
-		if (sp_make_afe_callback(data->payload, data->payload_size))
-			return -EINVAL;
 
+		if (payload[2] == AFE_PARAM_ID_DEV_TIMING_STATS) {
+			av_dev_drift_afe_cb_handler(data->payload,
+						    data->payload_size);
+		} else {
+			if (rtac_make_afe_callback(data->payload,
+						   data->payload_size))
+				return 0;
+
+			if (sp_make_afe_callback(data->payload,
+						 data->payload_size))
+				return -EINVAL;
+		}
 		wake_up(&this_afe.wait[data->token]);
 	} else if (data->payload_size) {
 		uint32_t *payload;
@@ -726,7 +770,7 @@
 	}
 
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		result = -EINVAL;
@@ -870,7 +914,7 @@
 		goto fail_cmd;
 	}
 	index = q6audio_get_port_index(port);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		ret = -EINVAL;
@@ -951,7 +995,7 @@
 		goto fail_cmd;
 	}
 	index = q6audio_get_port_index(src_port);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		ret = -EINVAL;
@@ -1179,6 +1223,7 @@
 
 	pr_debug("%s:\n", __func__);
 
+	memset(&delay_entry, 0, sizeof(delay_entry));
 	delay_entry.sample_rate = rate;
 	if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
 		ret = afe_get_cal_hw_delay(TX_DEVICE, &delay_entry);
@@ -1197,7 +1242,7 @@
 	}
 
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		ret = -EINVAL;
@@ -1246,6 +1291,10 @@
 	struct cal_block_data	*cal_block = NULL;
 	int32_t path;
 	struct audio_cal_info_afe_top *afe_top;
+	int afe_port_index = q6audio_get_port_index(port_id);
+
+	if (afe_port_index < 0)
+		goto err_exit;
 
 	list_for_each_safe(ptr, next,
 		&cal_type->cal_blocks) {
@@ -1257,12 +1306,25 @@
 		afe_top =
 		(struct audio_cal_info_afe_top *)cal_block->cal_info;
 		if (afe_top->path == path) {
-			pr_debug("%s: top_id:%x acdb_id:%d afe_port:%d\n",
-			__func__, afe_top->topology, afe_top->acdb_id,
-			q6audio_get_port_id(port_id));
-			return cal_block;
+			if (this_afe.dev_acdb_id[afe_port_index] > 0) {
+				if (afe_top->acdb_id ==
+				    this_afe.dev_acdb_id[afe_port_index]) {
+					pr_debug("%s: top_id:%x acdb_id:%d afe_port_id:%d\n",
+						 __func__, afe_top->topology,
+						 afe_top->acdb_id,
+						 q6audio_get_port_id(port_id));
+					return cal_block;
+				}
+			} else {
+				pr_debug("%s: top_id:%x acdb_id:%d afe_port:%d\n",
+				 __func__, afe_top->topology, afe_top->acdb_id,
+				 q6audio_get_port_id(port_id));
+				return cal_block;
+			}
 		}
 	}
+
+err_exit:
 	return NULL;
 }
 
@@ -1319,7 +1381,7 @@
 	u32 topology_id = 0;
 
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS - 1) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -1365,6 +1427,7 @@
 	}
 
 	this_afe.topology[index] = topology_id;
+	rtac_update_afe_topology(port_id);
 done:
 	pr_debug("%s: AFE set topology id 0x%x  enable for port 0x%x ret %d\n",
 			__func__, topology_id, port_id, ret);
@@ -1406,10 +1469,46 @@
 	return ret;
 }
 
+static struct cal_block_data *afe_find_cal(int cal_index, int port_id)
+{
+	struct list_head *ptr, *next;
+	struct cal_block_data *cal_block = NULL;
+	struct audio_cal_info_afe *afe_cal_info = NULL;
+	int afe_port_index = q6audio_get_port_index(port_id);
+
+	pr_debug("%s: cal_index %d port_id %d port_index %d\n", __func__,
+		  cal_index, port_id, afe_port_index);
+	if (afe_port_index < 0) {
+		pr_err("%s: Error getting AFE port index %d\n",
+			__func__, afe_port_index);
+		goto exit;
+	}
+
+	list_for_each_safe(ptr, next,
+			   &this_afe.cal_data[cal_index]->cal_blocks) {
+		cal_block = list_entry(ptr, struct cal_block_data, list);
+		afe_cal_info = cal_block->cal_info;
+		if ((afe_cal_info->acdb_id ==
+		     this_afe.dev_acdb_id[afe_port_index]) &&
+		    (afe_cal_info->sample_rate ==
+		     this_afe.afe_sample_rates[afe_port_index])) {
+			pr_debug("%s: cal block is a match, size is %zd\n",
+				 __func__, cal_block->cal_data.size);
+			goto exit;
+		}
+	}
+	pr_err("%s: no matching cal_block found\n", __func__);
+	cal_block = NULL;
+
+exit:
+	return cal_block;
+}
+
 static void send_afe_cal_type(int cal_index, int port_id)
 {
 	struct cal_block_data		*cal_block = NULL;
 	int ret;
+	int afe_port_index = q6audio_get_port_index(port_id);
 
 	pr_debug("%s:\n", __func__);
 
@@ -1419,8 +1518,22 @@
 		goto done;
 	}
 
+	if (afe_port_index < 0) {
+		pr_err("%s: Error getting AFE port index %d\n",
+			__func__, afe_port_index);
+		goto done;
+	}
+
 	mutex_lock(&this_afe.cal_data[cal_index]->lock);
-	cal_block = cal_utils_get_only_cal_block(this_afe.cal_data[cal_index]);
+
+	if (((cal_index == AFE_COMMON_RX_CAL) ||
+	     (cal_index == AFE_COMMON_TX_CAL)) &&
+	    (this_afe.dev_acdb_id[afe_port_index] > 0))
+		cal_block = afe_find_cal(cal_index, port_id);
+	else
+		cal_block = cal_utils_get_only_cal_block(
+				this_afe.cal_data[cal_index]);
+
 	if (cal_block == NULL) {
 		pr_err("%s cal_block not found!!\n", __func__);
 		goto unlock;
@@ -1677,7 +1790,7 @@
 
 	pr_debug("%s: enter, port_id =  0x%x\n", __func__, port_id);
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -1731,7 +1844,7 @@
 	}
 
 	index = q6audio_get_port_index(tx_port);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -1816,7 +1929,7 @@
 	}
 
 	index = q6audio_get_port_index(tx_port);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -1932,7 +2045,8 @@
 {
 	int i;
 
-	if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX) {
+	if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX ||
+		port_id == AFE_PORT_ID_INT3_MI2S_TX) {
 		mad_type = MAD_SW_AUDIO;
 		return 0;
 	}
@@ -1950,7 +2064,8 @@
 {
 	int i;
 
-	if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX)
+	if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX ||
+		port_id == AFE_PORT_ID_INT3_MI2S_TX)
 		return MAD_SW_AUDIO;
 
 	i = port_id - SLIMBUS_0_RX;
@@ -2039,7 +2154,7 @@
 		return ret;
 	}
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -2125,7 +2240,7 @@
 		return ret;
 	}
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -2199,7 +2314,7 @@
 
 	pr_debug("%s: enter\n", __func__);
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -2270,7 +2385,7 @@
 	pr_debug("%s: port id: 0x%x\n", __func__, port_id);
 
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -2345,7 +2460,7 @@
 	pr_debug("%s: port id: 0x%x\n", __func__, port_id);
 
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -2424,7 +2539,7 @@
 	pr_debug("%s: port id: 0x%x\n", __func__, port_id);
 
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -2488,7 +2603,7 @@
 }
 
 int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port,
-		u32 rate)
+		       u32 rate, u16 num_groups)
 {
 	struct afe_audioif_config_command config;
 	int ret = 0;
@@ -2504,7 +2619,7 @@
 	pr_debug("%s: port id: 0x%x\n", __func__, port_id);
 
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -2521,9 +2636,17 @@
 		return ret;
 	}
 
-	/* Also send the topology id here: */
+	if ((index >= 0) && (index < AFE_MAX_PORTS)) {
+		this_afe.afe_sample_rates[index] = rate;
+
+		if (this_afe.rt_cb)
+			this_afe.dev_acdb_id[index] = this_afe.rt_cb(port_id);
+	}
+
+	/* Also send the topology id here if multiple ports: */
 	port_index = afe_get_port_index(port_id);
-	if (!(this_afe.afe_cal_mode[port_index] == AFE_CAL_MODE_NONE)) {
+	if (!(this_afe.afe_cal_mode[port_index] == AFE_CAL_MODE_NONE) &&
+	    num_groups > 1) {
 		/* One time call: only for first time */
 		afe_send_custom_topology();
 		afe_send_port_topology_id(port_id);
@@ -2585,11 +2708,14 @@
 		ret = -EINVAL;
 		goto fail_cmd;
 	}
-
-	ret = afe_send_slot_mapping_cfg(&tdm_port->slot_mapping, port_id);
-	if (ret < 0) {
-		pr_err("%s: afe send failed %d\n", __func__, ret);
-		goto fail_cmd;
+	/* slot mapping is not need if there is only one group */
+	if (num_groups > 1) {
+		ret = afe_send_slot_mapping_cfg(&tdm_port->slot_mapping,
+						port_id);
+		if (ret < 0) {
+			pr_err("%s: afe send failed %d\n", __func__, ret);
+			goto fail_cmd;
+		}
 	}
 
 	if (tdm_port->custom_tdm_header.header_type) {
@@ -2615,6 +2741,11 @@
 	this_afe.afe_cal_mode[port_index] = afe_cal_mode;
 }
 
+void afe_set_routing_callback(routing_cb cb)
+{
+	this_afe.rt_cb = cb;
+}
+
 int afe_port_send_usb_dev_param(u16 port_id, union afe_port_config *afe_config)
 {
 	struct afe_usb_audio_dev_param_command config;
@@ -2626,7 +2757,7 @@
 		goto exit;
 	}
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid! for port ID 0x%x\n",
 				__func__, index, port_id);
 		ret = -EINVAL;
@@ -2660,6 +2791,21 @@
 		ret = -EINVAL;
 		goto exit;
 	}
+
+	config.pdata.param_id = AFE_PARAM_ID_USB_AUDIO_DEV_LPCM_FMT;
+	config.pdata.param_size = sizeof(config.lpcm_fmt);
+	config.lpcm_fmt.cfg_minor_version =
+		AFE_API_MINIOR_VERSION_USB_AUDIO_CONFIG;
+	config.lpcm_fmt.endian = afe_config->usb_audio.endian;
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+	if (ret) {
+		pr_err("%s: AFE device param cmd LPCM_FMT failed %d\n",
+			__func__, ret);
+		ret = -EINVAL;
+		goto exit;
+	}
+
 exit:
 	return ret;
 }
@@ -2683,6 +2829,11 @@
 	}
 	memset(&config, 0, sizeof(config));
 	index = q6audio_get_port_index(port_id);
+	if (index < 0) {
+		pr_err("%s: Invalid index number: %d\n", __func__, index);
+		return -EINVAL;
+	}
+
 	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
 	config.hdr.pkt_size = sizeof(config);
@@ -2820,7 +2971,7 @@
 	pr_debug("%s: port id: 0x%x\n", __func__, port_id);
 
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -2837,6 +2988,13 @@
 		return ret;
 	}
 
+	if ((index >= 0) && (index < AFE_MAX_PORTS)) {
+		this_afe.afe_sample_rates[index] = rate;
+
+		if (this_afe.rt_cb)
+			this_afe.dev_acdb_id[index] = this_afe.rt_cb(port_id);
+	}
+
 	mutex_lock(&this_afe.afe_cmd_lock);
 	/* Also send the topology id here: */
 	port_index = afe_get_port_index(port_id);
@@ -2934,6 +3092,20 @@
 	case AFE_PORT_ID_QUINARY_MI2S_RX:
 	case AFE_PORT_ID_QUINARY_MI2S_TX:
 	case AFE_PORT_ID_SENARY_MI2S_TX:
+	case AFE_PORT_ID_INT0_MI2S_RX:
+	case AFE_PORT_ID_INT0_MI2S_TX:
+	case AFE_PORT_ID_INT1_MI2S_RX:
+	case AFE_PORT_ID_INT1_MI2S_TX:
+	case AFE_PORT_ID_INT2_MI2S_RX:
+	case AFE_PORT_ID_INT2_MI2S_TX:
+	case AFE_PORT_ID_INT3_MI2S_RX:
+	case AFE_PORT_ID_INT3_MI2S_TX:
+	case AFE_PORT_ID_INT4_MI2S_RX:
+	case AFE_PORT_ID_INT4_MI2S_TX:
+	case AFE_PORT_ID_INT5_MI2S_RX:
+	case AFE_PORT_ID_INT5_MI2S_TX:
+	case AFE_PORT_ID_INT6_MI2S_RX:
+	case AFE_PORT_ID_INT6_MI2S_TX:
 		cfg_type = AFE_PARAM_ID_I2S_CONFIG;
 		break;
 	case HDMI_RX:
@@ -3026,7 +3198,6 @@
 
 	port_index = afe_get_port_index(port_id);
 	if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
-		this_afe.afe_sample_rates[port_index] = rate;
 		/*
 		 * If afe_port_start() for tx port called before
 		 * rx port, then aanc rx sample rate is zero. So,
@@ -3311,6 +3482,34 @@
 		return IDX_AFE_PORT_ID_QUATERNARY_TDM_RX_7;
 	case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
 		return IDX_AFE_PORT_ID_QUATERNARY_TDM_TX_7;
+	case AFE_PORT_ID_INT0_MI2S_RX:
+		return IDX_AFE_PORT_ID_INT0_MI2S_RX;
+	case AFE_PORT_ID_INT0_MI2S_TX:
+		return IDX_AFE_PORT_ID_INT0_MI2S_TX;
+	case AFE_PORT_ID_INT1_MI2S_RX:
+		return IDX_AFE_PORT_ID_INT1_MI2S_RX;
+	case AFE_PORT_ID_INT1_MI2S_TX:
+		return IDX_AFE_PORT_ID_INT1_MI2S_TX;
+	case AFE_PORT_ID_INT2_MI2S_RX:
+		return IDX_AFE_PORT_ID_INT2_MI2S_RX;
+	case AFE_PORT_ID_INT2_MI2S_TX:
+		return IDX_AFE_PORT_ID_INT2_MI2S_TX;
+	case AFE_PORT_ID_INT3_MI2S_RX:
+		return IDX_AFE_PORT_ID_INT3_MI2S_RX;
+	case AFE_PORT_ID_INT3_MI2S_TX:
+		return IDX_AFE_PORT_ID_INT3_MI2S_TX;
+	case AFE_PORT_ID_INT4_MI2S_RX:
+		return IDX_AFE_PORT_ID_INT4_MI2S_RX;
+	case AFE_PORT_ID_INT4_MI2S_TX:
+		return IDX_AFE_PORT_ID_INT4_MI2S_TX;
+	case AFE_PORT_ID_INT5_MI2S_RX:
+		return IDX_AFE_PORT_ID_INT5_MI2S_RX;
+	case AFE_PORT_ID_INT5_MI2S_TX:
+		return IDX_AFE_PORT_ID_INT5_MI2S_TX;
+	case AFE_PORT_ID_INT6_MI2S_RX:
+		return IDX_AFE_PORT_ID_INT6_MI2S_RX;
+	case AFE_PORT_ID_INT6_MI2S_TX:
+		return IDX_AFE_PORT_ID_INT6_MI2S_TX;
 	default:
 		pr_err("%s: port 0x%x\n", __func__, port_id);
 		return -EINVAL;
@@ -3335,7 +3534,7 @@
 	pr_err("%s: port_id 0x%x rate %d\n", __func__, port_id, rate);
 
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -3360,6 +3559,14 @@
 		pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
 		return -EINVAL;
 	}
+
+	if ((index >= 0) && (index < AFE_MAX_PORTS)) {
+		this_afe.afe_sample_rates[index] = rate;
+
+		if (this_afe.rt_cb)
+			this_afe.dev_acdb_id[index] = this_afe.rt_cb(port_id);
+	}
+
 	/* Also send the topology id here: */
 	afe_send_custom_topology(); /* One time call: only for first time  */
 	afe_send_port_topology_id(port_id);
@@ -3503,7 +3710,7 @@
 	}
 
 	index = q6audio_get_port_index(rx_port);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -3569,7 +3776,7 @@
 		goto fail_cmd;
 	}
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -3672,7 +3879,7 @@
 	}
 
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -3715,7 +3922,7 @@
 		return -EINVAL;
 	}
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -3876,7 +4083,7 @@
 	}
 
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -4162,7 +4369,7 @@
 		rtac_set_afe_handle(this_afe.apr);
 	}
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -4426,7 +4633,7 @@
 	}
 
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -4766,7 +4973,7 @@
 		goto fail_cmd;
 	}
 	index = q6audio_get_port_index(this_afe.dtmf_gen_rx_portid);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		ret = -EINVAL;
@@ -4795,58 +5002,249 @@
 	return ret;
 }
 
-int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain)
+static int afe_sidetone_iir(u16 tx_port_id)
 {
-	struct afe_loopback_cfg_v1 cmd_sidetone;
-	int ret = 0;
+	struct afe_loopback_iir_cfg_v2 iir_sidetone;
+	int ret;
 	int index = 0;
+	uint16_t size = 0;
+	int cal_index = AFE_SIDETONE_IIR_CAL;
+	int iir_pregain = 0;
+	int iir_num_biquad_stages = 0;
+	int iir_enable;
+	struct cal_block_data *cal_block;
+	int mid;
 
-	pr_info("%s: tx_port_id: 0x%x rx_port_id: 0x%x enable:%d gain:%d\n",
-			__func__, tx_port_id, rx_port_id, enable, gain);
-	index = q6audio_get_port_index(rx_port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
-		pr_err("%s: AFE port index[%d] invalid!\n",
-				__func__, index);
-		return -EINVAL;
+	memset(&iir_sidetone, 0, sizeof(iir_sidetone));
+	index = q6audio_get_port_index(tx_port_id);
+	iir_sidetone.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				     APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	iir_sidetone.hdr.pkt_size = sizeof(iir_sidetone);
+	iir_sidetone.hdr.src_port = 0;
+	iir_sidetone.hdr.dest_port = 0;
+	iir_sidetone.hdr.token = index;
+	iir_sidetone.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	iir_sidetone.param.port_id = tx_port_id;
+	iir_sidetone.param.payload_address_lsw = 0x00;
+	iir_sidetone.param.payload_address_msw = 0x00;
+	iir_sidetone.param.mem_map_handle = 0x00;
+
+	if (this_afe.cal_data[cal_index] == NULL) {
+		pr_err("%s: cal data is NULL\n", __func__);
+		ret = -EINVAL;
+		goto done;
 	}
-	ret = q6audio_validate_port(rx_port_id);
-	if (ret < 0) {
-		pr_err("%s: Invalid port 0x%x %d", __func__, rx_port_id, ret);
-		return -EINVAL;
+	mutex_lock(&this_afe.cal_data[cal_index]->lock);
+	cal_block = cal_utils_get_only_cal_block(this_afe.cal_data[cal_index]);
+	if (cal_block == NULL) {
+		pr_err("%s: cal_block not found\n ", __func__);
+		mutex_unlock(&this_afe.cal_data[cal_index]->lock);
+		ret = -EINVAL;
+		goto done;
 	}
 
+	iir_pregain = ((struct audio_cal_info_sidetone_iir *)
+			cal_block->cal_info)->pregain;
+	iir_enable = ((struct audio_cal_info_sidetone_iir *)
+			cal_block->cal_info)->iir_enable;
+	iir_num_biquad_stages = ((struct audio_cal_info_sidetone_iir *)
+			cal_block->cal_info)->num_biquad_stages;
+	mid = ((struct audio_cal_info_sidetone_iir *)
+			cal_block->cal_info)->mid;
+
+	/*
+	 * calculate the actual size of payload based on no of stages
+	 * enabled in calibration
+	 */
+	size = (MAX_SIDETONE_IIR_DATA_SIZE / MAX_NO_IIR_FILTER_STAGE) *
+		iir_num_biquad_stages;
+	/*
+	 * For an odd number of stages, 2 bytes of padding are
+	 * required at the end of the payload.
+	 */
+	if (iir_num_biquad_stages % 2) {
+		pr_debug("%s: adding 2 to size:%d\n", __func__, size);
+		size = size + 2;
+	}
+	memcpy(&iir_sidetone.st_iir_filter_config_data.iir_config,
+		&((struct audio_cal_info_sidetone_iir *)
+		cal_block->cal_info)->iir_config,
+		sizeof(iir_sidetone.st_iir_filter_config_data.iir_config));
+	mutex_unlock(&this_afe.cal_data[cal_index]->lock);
+
+	/*
+	 * Calculate the payload size for setparams command
+	 */
+	iir_sidetone.param.payload_size = (sizeof(iir_sidetone) -
+				sizeof(struct apr_hdr) -
+				sizeof(struct afe_port_cmd_set_param_v2) -
+				(MAX_SIDETONE_IIR_DATA_SIZE - size));
+
+	pr_debug("%s: payload size :%d\n", __func__,
+		 iir_sidetone.param.payload_size);
+
+	/*
+	 * Set IIR enable params
+	 */
+	iir_sidetone.st_iir_enable_pdata.module_id = mid;
+	iir_sidetone.st_iir_enable_pdata.param_id =
+			AFE_PARAM_ID_ENABLE;
+	iir_sidetone.st_iir_enable_pdata.param_size =
+			sizeof(iir_sidetone.st_iir_mode_enable_data);
+	iir_sidetone.st_iir_mode_enable_data.enable = iir_enable;
+
+	/*
+	 * Set IIR filter config params
+	 */
+	iir_sidetone.st_iir_filter_config_pdata.module_id = mid;
+	iir_sidetone.st_iir_filter_config_pdata.param_id =
+			AFE_PARAM_ID_SIDETONE_IIR_FILTER_CONFIG;
+	iir_sidetone.st_iir_filter_config_pdata.param_size =
+		sizeof(iir_sidetone.st_iir_filter_config_data.num_biquad_stages)
+		+
+		sizeof(iir_sidetone.st_iir_filter_config_data.pregain) + size;
+	iir_sidetone.st_iir_filter_config_pdata.reserved = 0;
+	iir_sidetone.st_iir_filter_config_data.num_biquad_stages =
+			iir_num_biquad_stages;
+	iir_sidetone.st_iir_filter_config_data.pregain = iir_pregain;
+	pr_debug("%s: tx(0x%x)mid(0x%x)iir_en(%d)stg(%d)gain(0x%x)size(%d)\n",
+		  __func__, tx_port_id, mid,
+		  iir_sidetone.st_iir_mode_enable_data.enable,
+		  iir_sidetone.st_iir_filter_config_data.num_biquad_stages,
+		  iir_sidetone.st_iir_filter_config_data.pregain,
+		  iir_sidetone.st_iir_filter_config_pdata.param_size);
+	ret = afe_apr_send_pkt(&iir_sidetone, &this_afe.wait[index]);
+	if (ret)
+		pr_err("%s: AFE sidetone failed for tx_port(0x%x)\n",
+			 __func__, tx_port_id);
+
+done:
+	return ret;
+
+}
+
+static int afe_sidetone(u16 tx_port_id, u16 rx_port_id, bool enable)
+{
+	struct afe_st_loopback_cfg_v1 cmd_sidetone;
+	int ret;
+	int index;
+	int cal_index = AFE_SIDETONE_CAL;
+	int sidetone_gain;
+	int sidetone_enable;
+	struct cal_block_data *cal_block;
+	int mid = 0;
+
+	memset(&cmd_sidetone, 0, sizeof(cmd_sidetone));
+	if (this_afe.cal_data[cal_index] == NULL) {
+		pr_err("%s: cal data is NULL\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+	mutex_lock(&this_afe.cal_data[cal_index]->lock);
+	cal_block = cal_utils_get_only_cal_block(this_afe.cal_data[cal_index]);
+	if (cal_block == NULL) {
+		pr_err("%s: cal_block not found\n", __func__);
+		mutex_unlock(&this_afe.cal_data[cal_index]->lock);
+		ret = -EINVAL;
+		goto done;
+	}
+	sidetone_gain = ((struct audio_cal_info_sidetone *)
+			 cal_block->cal_info)->gain;
+	sidetone_enable = ((struct audio_cal_info_sidetone *)
+			 cal_block->cal_info)->enable;
+	mid = ((struct audio_cal_info_sidetone *)
+			 cal_block->cal_info)->mid;
+	mutex_unlock(&this_afe.cal_data[cal_index]->lock);
+
+	index = q6audio_get_port_index(tx_port_id);
 	cmd_sidetone.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
 	cmd_sidetone.hdr.pkt_size = sizeof(cmd_sidetone);
 	cmd_sidetone.hdr.src_port = 0;
 	cmd_sidetone.hdr.dest_port = 0;
-	cmd_sidetone.hdr.token = 0;
+	cmd_sidetone.hdr.token = index;
 	cmd_sidetone.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
-	/* should it be rx or tx port id ?? , bharath*/
 	cmd_sidetone.param.port_id = tx_port_id;
-	/* size of data param & payload */
 	cmd_sidetone.param.payload_size = (sizeof(cmd_sidetone) -
 			sizeof(struct apr_hdr) -
 			sizeof(struct afe_port_cmd_set_param_v2));
 	cmd_sidetone.param.payload_address_lsw = 0x00;
 	cmd_sidetone.param.payload_address_msw = 0x00;
 	cmd_sidetone.param.mem_map_handle = 0x00;
-	cmd_sidetone.pdata.module_id = AFE_MODULE_LOOPBACK;
-	cmd_sidetone.pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
-	/* size of actual payload only */
-	cmd_sidetone.pdata.param_size =  cmd_sidetone.param.payload_size -
-				sizeof(struct afe_port_param_data_v2);
+	cmd_sidetone.gain_pdata.module_id = AFE_MODULE_LOOPBACK;
+	cmd_sidetone.gain_pdata.param_id = AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH;
+	/*
+	 * size of actual payload only
+	 */
+	cmd_sidetone.gain_pdata.param_size = sizeof(
+					     struct afe_loopback_sidetone_gain);
+	cmd_sidetone.gain_data.rx_port_id = rx_port_id;
+	cmd_sidetone.gain_data.gain = sidetone_gain;
 
-	cmd_sidetone.loopback_cfg_minor_version =
+	cmd_sidetone.cfg_pdata.module_id = AFE_MODULE_LOOPBACK;
+	cmd_sidetone.cfg_pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
+	/*
+	 * size of actual payload only
+	 */
+	cmd_sidetone.cfg_pdata.param_size = sizeof(struct loopback_cfg_data);
+	cmd_sidetone.cfg_data.loopback_cfg_minor_version =
 					AFE_API_VERSION_LOOPBACK_CONFIG;
-	cmd_sidetone.dst_port_id = rx_port_id;
-	cmd_sidetone.routing_mode = LB_MODE_SIDETONE;
-	cmd_sidetone.enable = enable;
+	cmd_sidetone.cfg_data.dst_port_id = rx_port_id;
+	cmd_sidetone.cfg_data.routing_mode = LB_MODE_SIDETONE;
+	cmd_sidetone.cfg_data.enable = ((enable == 1) ? sidetone_enable : 0);
+
+	pr_debug("%s rx(0x%x) tx(0x%x) enable(%d) mid(0x%x) gain(%d) sidetone_enable(%d)\n",
+		  __func__, rx_port_id, tx_port_id,
+		  enable, mid, sidetone_gain, sidetone_enable);
 
 	ret = afe_apr_send_pkt(&cmd_sidetone, &this_afe.wait[index]);
 	if (ret)
-		pr_err("%s: sidetone failed tx_port:0x%x rx_port:0x%x ret%d\n",
-		__func__, tx_port_id, rx_port_id, ret);
+		pr_err("%s: AFE sidetone send failed for tx_port:%d rx_port:%d ret:%d\n",
+			__func__, tx_port_id, rx_port_id, ret);
+done:
+	return ret;
+}
+
+int afe_sidetone_enable(u16 tx_port_id, u16 rx_port_id, bool enable)
+{
+	int ret;
+	int index;
+
+	index = q6audio_get_port_index(rx_port_id);
+	if (index < 0 || index >= AFE_MAX_PORTS) {
+		pr_err("%s: AFE port index[%d] invalid!\n",
+				__func__, index);
+		ret = -EINVAL;
+		goto done;
+	}
+	if (q6audio_validate_port(rx_port_id) < 0) {
+		pr_err("%s: Invalid port 0x%x\n",
+				__func__, rx_port_id);
+		ret = -EINVAL;
+		goto done;
+	}
+	index = q6audio_get_port_index(tx_port_id);
+	if (index < 0 || index >= AFE_MAX_PORTS) {
+		pr_err("%s: AFE port index[%d] invalid!\n",
+				__func__, index);
+		ret = -EINVAL;
+		goto done;
+	}
+	if (q6audio_validate_port(tx_port_id) < 0) {
+		pr_err("%s: Invalid port 0x%x\n",
+				__func__, tx_port_id);
+		ret = -EINVAL;
+		goto done;
+	}
+	if (enable) {
+		ret = afe_sidetone_iir(tx_port_id);
+		if (ret)
+			goto done;
+	}
+
+	ret = afe_sidetone(tx_port_id, rx_port_id, enable);
+
+done:
 	return ret;
 }
 
@@ -4979,6 +5377,20 @@
 	case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
 	case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
 	case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+	case AFE_PORT_ID_INT0_MI2S_RX:
+	case AFE_PORT_ID_INT1_MI2S_RX:
+	case AFE_PORT_ID_INT2_MI2S_RX:
+	case AFE_PORT_ID_INT3_MI2S_RX:
+	case AFE_PORT_ID_INT4_MI2S_RX:
+	case AFE_PORT_ID_INT5_MI2S_RX:
+	case AFE_PORT_ID_INT6_MI2S_RX:
+	case AFE_PORT_ID_INT0_MI2S_TX:
+	case AFE_PORT_ID_INT1_MI2S_TX:
+	case AFE_PORT_ID_INT2_MI2S_TX:
+	case AFE_PORT_ID_INT3_MI2S_TX:
+	case AFE_PORT_ID_INT4_MI2S_TX:
+	case AFE_PORT_ID_INT5_MI2S_TX:
+	case AFE_PORT_ID_INT6_MI2S_TX:
 	{
 		ret = 0;
 		break;
@@ -5099,7 +5511,7 @@
 
 	port_id = q6audio_convert_virtual_to_portid(port_id);
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -5130,6 +5542,7 @@
 	if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
 		this_afe.afe_sample_rates[port_index] = 0;
 		this_afe.topology[port_index] = 0;
+		this_afe.dev_acdb_id[port_index] = 0;
 	} else {
 		pr_err("%s: port %d\n", __func__, port_index);
 		ret = -EINVAL;
@@ -5257,7 +5670,7 @@
 		return ret;
 	}
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -5423,7 +5836,7 @@
 	int ret = 0;
 
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -5456,7 +5869,7 @@
 		return ret;
 	}
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -5537,7 +5950,7 @@
 	int ret = 0;
 
 	index = q6audio_get_port_index(port_id);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		return -EINVAL;
@@ -5798,6 +6211,88 @@
 	return ret;
 }
 
+int afe_get_av_dev_drift(struct afe_param_id_dev_timing_stats *timing_stats,
+			 u16 port)
+{
+	int ret = -EINVAL;
+	int index = 0;
+	struct afe_av_dev_drift_get_param av_dev_drift;
+
+	if (!timing_stats) {
+		pr_err("%s: Invalid params\n", __func__);
+		goto exit;
+	}
+
+	ret = q6audio_validate_port(port);
+	if (ret < 0) {
+		pr_err("%s: invalid port 0x%x ret %d\n", __func__, port, ret);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	index = q6audio_get_port_index(port);
+	if (index < 0 || index >= AFE_MAX_PORTS) {
+		pr_err("%s: Invalid AFE port index[%d]\n",
+				__func__, index);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	memset(&av_dev_drift, 0, sizeof(struct afe_av_dev_drift_get_param));
+
+	av_dev_drift.hdr.hdr_field =
+		APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	av_dev_drift.hdr.pkt_size = sizeof(av_dev_drift);
+	av_dev_drift.hdr.src_port = 0;
+	av_dev_drift.hdr.dest_port = 0;
+	av_dev_drift.hdr.token = index;
+	av_dev_drift.hdr.opcode =  AFE_PORT_CMD_GET_PARAM_V2;
+	av_dev_drift.get_param.mem_map_handle = 0;
+	av_dev_drift.get_param.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+	av_dev_drift.get_param.param_id = AFE_PARAM_ID_DEV_TIMING_STATS;
+	av_dev_drift.get_param.payload_address_lsw = 0;
+	av_dev_drift.get_param.payload_address_msw = 0;
+	av_dev_drift.get_param.payload_size = sizeof(av_dev_drift)
+		- sizeof(av_dev_drift.get_param) - sizeof(av_dev_drift.hdr);
+	av_dev_drift.get_param.port_id = q6audio_get_port_id(port);
+	av_dev_drift.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+	av_dev_drift.pdata.param_id = AFE_PARAM_ID_DEV_TIMING_STATS;
+	av_dev_drift.pdata.param_size = sizeof(av_dev_drift.timing_stats);
+	atomic_set(&this_afe.status, 0);
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *)&av_dev_drift);
+	if (ret < 0) {
+		pr_err("%s: get param port 0x%x param id[0x%x] failed %d\n",
+			__func__, port, av_dev_drift.get_param.param_id, ret);
+		goto exit;
+	}
+
+	ret = wait_event_timeout(this_afe.wait[index],
+			(atomic_read(&this_afe.state) == 0),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	if (atomic_read(&this_afe.status) > 0) {
+		pr_err("%s: config cmd failed [%s]\n",
+				__func__, adsp_err_get_err_str(
+					atomic_read(&this_afe.status)));
+		ret = adsp_err_get_lnx_err_code(
+				atomic_read(&this_afe.status));
+		goto exit;
+	}
+
+	memcpy(timing_stats, &this_afe.av_dev_drift_resp.timing_stats,
+	       sizeof(this_afe.av_dev_drift_resp.timing_stats));
+	ret = 0;
+exit:
+	return ret;
+}
+
 int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib_resp)
 {
 	int ret = -EINVAL;
@@ -5817,7 +6312,7 @@
 		goto fail_cmd;
 	}
 	index = q6audio_get_port_index(port);
-	if (index < 0 || index > AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: AFE port index[%d] invalid!\n",
 				__func__, index);
 		ret = -EINVAL;
@@ -5946,6 +6441,9 @@
 	case AFE_SIDETONE_CAL_TYPE:
 		ret = AFE_SIDETONE_CAL;
 		break;
+	case AFE_SIDETONE_IIR_CAL_TYPE:
+		ret = AFE_SIDETONE_IIR_CAL;
+		break;
 	case AFE_TOPOLOGY_CAL_TYPE:
 		ret = AFE_TOPOLOGY_CAL;
 		break;
@@ -6476,6 +6974,11 @@
 		afe_set_cal, NULL, NULL} },
 		{NULL, NULL, cal_utils_match_buf_num} },
 
+		{{AFE_SIDETONE_IIR_CAL_TYPE,
+		{NULL, NULL, NULL,
+		afe_set_cal, NULL, NULL} },
+		{NULL, NULL, cal_utils_match_buf_num} },
+
 		{{AFE_TOPOLOGY_CAL_TYPE,
 		{NULL, NULL, NULL,
 		afe_set_cal, NULL, NULL} },
@@ -6605,6 +7108,8 @@
 	mutex_init(&this_afe.afe_cmd_lock);
 	for (i = 0; i < AFE_MAX_PORTS; i++) {
 		this_afe.afe_cal_mode[i] = AFE_CAL_MODE_DEFAULT;
+		this_afe.afe_sample_rates[i] = 0;
+		this_afe.dev_acdb_id[i] = 0;
 		init_waitqueue_head(&this_afe.wait[i]);
 	}
 	wakeup_source_init(&wl.ws, "spkr-prot");
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 78f70be..b52c83b 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1703,6 +1703,7 @@
 		case ASM_STREAM_CMD_OPEN_PUSH_MODE_READ:
 		case ASM_STREAM_CMD_OPEN_READWRITE_V2:
 		case ASM_STREAM_CMD_OPEN_LOOPBACK_V2:
+		case ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK:
 		case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
 		case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
@@ -2431,13 +2432,14 @@
  * @ac: Client session handle
  * @format: encoder format
  * @bits_per_sample: bit width of capture session
+ * @ts_mode: timestamp mode
  */
 int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
-			uint16_t bits_per_sample)
+			uint16_t bits_per_sample, bool ts_mode)
 {
 	return __q6asm_open_read(ac, format, bits_per_sample,
 				 PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/,
-				 true/*ts_mode*/);
+				 ts_mode);
 }
 EXPORT_SYMBOL(q6asm_open_read_v4);
 
@@ -2478,6 +2480,10 @@
 	case FORMAT_DSD:
 		open.fmt_id = ASM_MEDIA_FMT_DSD;
 		break;
+	case FORMAT_GEN_COMPR:
+		open.fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
+		break;
+
 	default:
 		pr_err("%s: Invalid format[%d]\n", __func__, format);
 		rc = -EINVAL;
@@ -2487,7 +2493,8 @@
 	 * stream is not IEC 61937 or IEC 60958 packetizied
 	 */
 	if (passthrough_flag == COMPRESSED_PASSTHROUGH ||
-		passthrough_flag == COMPRESSED_PASSTHROUGH_DSD) {
+		passthrough_flag == COMPRESSED_PASSTHROUGH_DSD ||
+		passthrough_flag == COMPRESSED_PASSTHROUGH_GEN) {
 		open.flags = 0x0;
 		pr_debug("%s: Flag 0 COMPRESSED_PASSTHROUGH\n", __func__);
 	} else if (passthrough_flag == COMPRESSED_PASSTHROUGH_CONVERT) {
@@ -2651,6 +2658,12 @@
 	case FORMAT_DSD:
 		open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
 		break;
+	case FORMAT_APTX:
+		open.dec_fmt_id = ASM_MEDIA_FMT_APTX;
+		break;
+	case FORMAT_GEN_COMPR:
+		open.dec_fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
+		break;
 	default:
 		pr_err("%s: Invalid format 0x%x\n", __func__, format);
 		rc = -EINVAL;
@@ -2868,6 +2881,7 @@
 		break;
 	case FORMAT_DSD:
 		open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
+		break;
 	case FORMAT_G711_ALAW_FS:
 		open.dec_fmt_id = ASM_MEDIA_FMT_G711_ALAW_FS;
 		break;
@@ -2973,7 +2987,6 @@
 int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample)
 {
 	int rc = 0x00;
-	struct asm_stream_cmd_open_loopback_v2 open;
 
 	if (ac == NULL) {
 		pr_err("%s: APR handle NULL\n", __func__);
@@ -2985,29 +2998,67 @@
 	}
 	pr_debug("%s: session[%d]\n", __func__, ac->session);
 
-	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
-	atomic_set(&ac->cmd_state, -1);
-	open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2;
+	if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
+		struct asm_stream_cmd_open_transcode_loopback_t open;
 
-	open.mode_flags = 0;
-	open.src_endpointype = 0;
-	open.sink_endpointype = 0;
-	/* source endpoint : matrix */
-	open.postprocopo_id = q6asm_get_asm_topology_cal();
+		q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+		atomic_set(&ac->cmd_state, -1);
+		open.hdr.opcode = ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK;
 
-	ac->app_type = q6asm_get_asm_app_type_cal();
-	ac->topology = open.postprocopo_id;
-	open.bits_per_sample = bits_per_sample;
-	open.reserved = 0;
+		open.mode_flags = 0;
+		open.src_endpoint_type = 0;
+		open.sink_endpoint_type = 0;
+		open.src_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
+		open.sink_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
+		/* source endpoint : matrix */
+		open.audproc_topo_id = q6asm_get_asm_topology_cal();
 
-	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
-	if (rc < 0) {
-		pr_err("%s: open failed op[0x%x]rc[%d]\n", __func__,
-				open.hdr.opcode, rc);
-		rc = -EINVAL;
-		goto fail_cmd;
+		ac->app_type = q6asm_get_asm_app_type_cal();
+		if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
+			open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
+		else
+			open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
+		ac->topology = open.audproc_topo_id;
+		open.bits_per_sample = bits_per_sample;
+		open.reserved = 0;
+		pr_debug("%s: opening a transcode_loopback with mode_flags =[%d] session[%d]\n",
+				__func__, open.mode_flags, ac->session);
+
+		rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+		if (rc < 0) {
+			pr_err("%s: open failed op[0x%x]rc[%d]\n",
+					__func__, open.hdr.opcode, rc);
+			rc = -EINVAL;
+			goto fail_cmd;
+		}
+	} else {/*if(ac->perf_mode == LEGACY_PCM_MODE)*/
+		struct asm_stream_cmd_open_loopback_v2 open;
+
+		q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+		atomic_set(&ac->cmd_state, -1);
+		open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2;
+
+		open.mode_flags = 0;
+		open.src_endpointype = 0;
+		open.sink_endpointype = 0;
+		/* source endpoint : matrix */
+		open.postprocopo_id = q6asm_get_asm_topology_cal();
+
+		ac->app_type = q6asm_get_asm_app_type_cal();
+		ac->topology = open.postprocopo_id;
+		open.bits_per_sample = bits_per_sample;
+		open.reserved = 0;
+		pr_debug("%s: opening a loopback_v2 with mode_flags =[%d] session[%d]\n",
+				__func__, open.mode_flags, ac->session);
+
+		rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+		if (rc < 0) {
+			pr_err("%s: open failed op[0x%x]rc[%d]\n",
+					__func__, open.hdr.opcode, rc);
+			rc = -EINVAL;
+			goto fail_cmd;
+		}
 	}
-
 	rc = wait_event_timeout(ac->cmd_wait,
 			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
 	if (!rc) {
@@ -5141,6 +5192,82 @@
 }
 EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v4);
 
+/*
+ * q6asm_media_format_block_gen_compr - set up generic compress format params
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @use_default_chmap: true if default channel map to be used
+ * @channel_map: input channel map
+ * @bits_per_sample: bit width of gen compress stream
+ */
+int q6asm_media_format_block_gen_compr(struct audio_client *ac,
+				uint32_t rate, uint32_t channels,
+				bool use_default_chmap, char *channel_map,
+				uint16_t bits_per_sample)
+{
+	struct asm_generic_compressed_fmt_blk_t fmt;
+	u8 *channel_mapping;
+	int rc = 0;
+
+	pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]\n",
+		 __func__, ac->session, rate,
+		 channels, bits_per_sample);
+
+	memset(&fmt, 0, sizeof(fmt));
+	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+	fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+					sizeof(fmt.fmt_blk);
+	fmt.num_channels = channels;
+	fmt.bits_per_sample = bits_per_sample;
+	fmt.sampling_rate = rate;
+
+	channel_mapping = fmt.channel_mapping;
+
+	memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+	if (use_default_chmap) {
+		if (q6asm_map_channels(channel_mapping, channels, false)) {
+			pr_err("%s: map channels failed %d\n",
+				__func__, channels);
+			return -EINVAL;
+		}
+	} else {
+		memcpy(channel_mapping, channel_map,
+		       PCM_FORMAT_MAX_NUM_CHANNEL);
+	}
+
+	atomic_set(&ac->cmd_state, -1);
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+	if (rc < 0) {
+		pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout. waited for format update\n", __func__);
+		rc = -ETIMEDOUT;
+		goto fail_cmd;
+	}
+
+	if (atomic_read(&ac->cmd_state) > 0) {
+		pr_err("%s: DSP returned error[%s]\n",
+			__func__, adsp_err_get_err_str(
+			atomic_read(&ac->cmd_state)));
+		rc = adsp_err_get_lnx_err_code(
+				atomic_read(&ac->cmd_state));
+	}
+	return 0;
+fail_cmd:
+	return rc;
+}
+EXPORT_SYMBOL(q6asm_media_format_block_gen_compr);
+
 static int __q6asm_media_format_block_multi_aac(struct audio_client *ac,
 				struct asm_aac_cfg *cfg, int stream_id)
 {
@@ -5727,6 +5854,57 @@
 }
 EXPORT_SYMBOL(q6asm_media_format_block_dsd);
 
+int q6asm_stream_media_format_block_aptx_dec(struct audio_client *ac,
+						uint32_t srate, int stream_id)
+{
+	struct asm_aptx_dec_fmt_blk_v2 aptx_fmt;
+	int rc = 0;
+
+	if (!ac->session) {
+		pr_err("%s: ac session invalid\n", __func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	pr_debug("%s :session[%d] rate[%d] stream_id[%d]\n",
+		__func__, ac->session, srate, stream_id);
+
+	q6asm_stream_add_hdr(ac, &aptx_fmt.hdr, sizeof(aptx_fmt), TRUE,
+				stream_id);
+	atomic_set(&ac->cmd_state, -1);
+
+	aptx_fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+	aptx_fmt.fmtblk.fmt_blk_size = sizeof(aptx_fmt) - sizeof(aptx_fmt.hdr) -
+						sizeof(aptx_fmt.fmtblk);
+
+	aptx_fmt.sample_rate = srate;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &aptx_fmt);
+	if (rc < 0) {
+		pr_err("%s :Comamnd media format update failed %d\n",
+				__func__, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+				(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
+		rc = -ETIMEDOUT;
+		goto fail_cmd;
+	}
+
+	if (atomic_read(&ac->cmd_state) > 0) {
+		pr_err("%s: DSP returned error[%s]\n",
+				__func__, adsp_err_get_err_str(
+				atomic_read(&ac->cmd_state)));
+		rc = adsp_err_get_lnx_err_code(
+				atomic_read(&ac->cmd_state));
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	return rc;
+}
+
 static int __q6asm_ds1_set_endp_params(struct audio_client *ac, int param_id,
 				int param_value, int stream_id)
 {
@@ -6746,6 +6924,69 @@
 	return __q6asm_set_volume(ac, volume, instance);
 }
 
+int q6asm_set_aptx_dec_bt_addr(struct audio_client *ac,
+				struct aptx_dec_bt_addr_cfg *cfg)
+{
+	struct aptx_dec_bt_dev_addr paylod;
+	int sz = 0;
+	int rc = 0;
+
+	pr_debug("%s: BT addr nap %d, uap %d, lap %d\n", __func__, cfg->nap,
+			cfg->uap, cfg->lap);
+
+	if (ac == NULL) {
+		pr_err("%s: AC handle NULL\n", __func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	if (ac->apr == NULL) {
+		pr_err("%s: AC APR handle NULL\n", __func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	sz = sizeof(struct aptx_dec_bt_dev_addr);
+	q6asm_add_hdr_async(ac, &paylod.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, -1);
+	paylod.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	paylod.encdec.param_id = APTX_DECODER_BT_ADDRESS;
+	paylod.encdec.param_size = sz - sizeof(paylod.hdr)
+					- sizeof(paylod.encdec);
+	paylod.bt_addr_cfg.lap = cfg->lap;
+	paylod.bt_addr_cfg.uap = cfg->uap;
+	paylod.bt_addr_cfg.nap = cfg->nap;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &paylod);
+	if (rc < 0) {
+		pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
+				__func__, paylod.encdec.param_id, rc);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
+			paylod.encdec.param_id);
+		rc = -ETIMEDOUT;
+		goto fail_cmd;
+	}
+	if (atomic_read(&ac->cmd_state) > 0) {
+		pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
+				__func__, adsp_err_get_err_str(
+				atomic_read(&ac->cmd_state)),
+				paylod.encdec.param_id);
+		rc = adsp_err_get_lnx_err_code(
+			atomic_read(&ac->cmd_state));
+		goto fail_cmd;
+	}
+	pr_debug("%s: set BT addr is success\n", __func__);
+	rc = 0;
+fail_cmd:
+	return rc;
+}
+
 int q6asm_set_softpause(struct audio_client *ac,
 			struct asm_softpause_params *pause_param)
 {
@@ -7187,7 +7428,7 @@
 	}
 
 	q6asm_stream_add_hdr_async(
-			ac, &write.hdr, sizeof(write), FALSE, ac->stream_id);
+			ac, &write.hdr, sizeof(write), TRUE, ac->stream_id);
 	port = &ac->port[IN];
 	ab = &port->buf[port->dsp_buf];
 
@@ -7208,9 +7449,13 @@
 	else if (ac->io_mode == io_compressed ||
 			ac->io_mode == io_compressed_stream)
 		lbuf_phys_addr = (param->paddr - param->metadata_len);
-	else
-		lbuf_phys_addr = param->paddr;
-
+	else {
+		if (param->flags & SET_TIMESTAMP)
+			lbuf_phys_addr = param->paddr -
+				sizeof(struct snd_codec_metadata);
+		else
+			lbuf_phys_addr = param->paddr;
+	}
 	dev_vdbg(ac->dev, "%s: token[0x%x], buf_addr[%pK], buf_size[0x%x], ts_msw[0x%x], ts_lsw[0x%x], lbuf_phys_addr: 0x[%pK]\n",
 			__func__,
 			write.hdr.token, &param->paddr,
@@ -7348,7 +7593,7 @@
 				   0, /* Stream ID is NA */
 				   port->dsp_buf,
 				   0, /* Direction flag is NA */
-				   WAIT_CMD);
+				   NO_WAIT_CMD);
 		write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
 		write.buf_addr_lsw = lower_32_bits(ab->phys);
 		write.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
@@ -7427,7 +7672,7 @@
 				   0, /* Stream ID is NA */
 				   port->dsp_buf,
 				   0, /* Direction flag is NA */
-				   WAIT_CMD);
+				   NO_WAIT_CMD);
 
 		write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
 		write.buf_addr_lsw = lower_32_bits(ab->phys);
@@ -7676,16 +7921,18 @@
 	matrix.param.data_payload_addr_lsw = 0;
 	matrix.param.data_payload_addr_msw = 0;
 	matrix.param.mem_map_handle = 0;
-	matrix.param.data_payload_size = sizeof(matrix) -
-			sizeof(matrix.hdr) - sizeof(matrix.param);
+	matrix.param.data_payload_size =
+		sizeof(struct asm_stream_param_data_v2) +
+		sizeof(struct asm_session_mtmx_strtr_param_window_v2_t);
 	matrix.param.direction = 0; /* RX */
 	matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
 	matrix.data.param_id = param_id;
-	matrix.data.param_size = matrix.param.data_payload_size -
-			sizeof(matrix.data);
+	matrix.data.param_size =
+		sizeof(struct asm_session_mtmx_strtr_param_window_v2_t);
 	matrix.data.reserved = 0;
-	matrix.window_lsw = window_param->window_lsw;
-	matrix.window_msw = window_param->window_msw;
+	memcpy(&(matrix.config.window_param),
+	       window_param,
+	       sizeof(struct asm_session_mtmx_strtr_param_window_v2_t));
 
 	rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
 	if (rc < 0) {
@@ -7715,7 +7962,177 @@
 	rc = 0;
 fail_cmd:
 	return rc;
-};
+}
+
+int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac,
+		uint32_t render_mode)
+{
+	struct asm_mtmx_strtr_params matrix;
+	struct asm_session_mtmx_strtr_param_render_mode_t render_param;
+	int sz = 0;
+	int rc  = 0;
+
+	pr_debug("%s: render mode is %d\n", __func__, render_mode);
+
+	if (!ac) {
+		pr_err("%s: audio client handle is NULL\n", __func__);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if (ac->apr == NULL) {
+		pr_err("%s: ac->apr is NULL\n", __func__);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if ((render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT) &&
+	    (render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC)) {
+		pr_err("%s: Invalid render mode %d\n", __func__, render_mode);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	memset(&render_param, 0,
+	       sizeof(struct asm_session_mtmx_strtr_param_render_mode_t));
+	render_param.flags = render_mode;
+
+	memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
+	sz = sizeof(struct asm_mtmx_strtr_params);
+	q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, -1);
+	matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
+
+	matrix.param.data_payload_addr_lsw = 0;
+	matrix.param.data_payload_addr_msw = 0;
+	matrix.param.mem_map_handle = 0;
+	matrix.param.data_payload_size =
+		sizeof(struct asm_stream_param_data_v2) +
+		sizeof(struct asm_session_mtmx_strtr_param_render_mode_t);
+	matrix.param.direction = 0; /* RX */
+	matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
+	matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_MODE_CMD;
+	matrix.data.param_size =
+		sizeof(struct asm_session_mtmx_strtr_param_render_mode_t);
+	matrix.data.reserved = 0;
+	memcpy(&(matrix.config.render_param),
+	       &render_param,
+	       sizeof(struct asm_session_mtmx_strtr_param_render_mode_t));
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
+	if (rc < 0) {
+		pr_err("%s: Render mode send failed paramid [0x%x]\n",
+			__func__, matrix.data.param_id);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout, Render mode send paramid [0x%x]\n",
+			__func__, matrix.data.param_id);
+		rc = -ETIMEDOUT;
+		goto exit;
+	}
+
+	if (atomic_read(&ac->cmd_state) > 0) {
+		pr_err("%s: DSP returned error[%s]\n",
+				__func__, adsp_err_get_err_str(
+				atomic_read(&ac->cmd_state)));
+		rc = adsp_err_get_lnx_err_code(
+				atomic_read(&ac->cmd_state));
+		goto exit;
+	}
+	rc = 0;
+exit:
+	return rc;
+}
+
+int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac,
+		uint32_t clk_rec_mode)
+{
+	struct asm_mtmx_strtr_params matrix;
+	struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param;
+	int sz = 0;
+	int rc  = 0;
+
+	pr_debug("%s: clk rec mode is %d\n", __func__, clk_rec_mode);
+
+	if (!ac) {
+		pr_err("%s: audio client handle is NULL\n", __func__);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if (ac->apr == NULL) {
+		pr_err("%s: ac->apr is NULL\n", __func__);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if ((clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE) &&
+	    (clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO)) {
+		pr_err("%s: Invalid clk rec mode %d\n", __func__, clk_rec_mode);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	memset(&clk_rec_param, 0,
+	       sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t));
+	clk_rec_param.flags = clk_rec_mode;
+
+	memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
+	sz = sizeof(struct asm_mtmx_strtr_params);
+	q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, -1);
+	matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
+
+	matrix.param.data_payload_addr_lsw = 0;
+	matrix.param.data_payload_addr_msw = 0;
+	matrix.param.mem_map_handle = 0;
+	matrix.param.data_payload_size =
+		sizeof(struct asm_stream_param_data_v2) +
+		sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t);
+	matrix.param.direction = 0; /* RX */
+	matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
+	matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_CMD;
+	matrix.data.param_size =
+		sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t);
+	matrix.data.reserved = 0;
+	memcpy(&(matrix.config.clk_rec_param),
+	       &clk_rec_param,
+	       sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t));
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
+	if (rc < 0) {
+		pr_err("%s: clk rec mode send failed paramid [0x%x]\n",
+			__func__, matrix.data.param_id);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout, clk rec mode send paramid [0x%x]\n",
+			__func__, matrix.data.param_id);
+		rc = -ETIMEDOUT;
+		goto exit;
+	}
+
+	if (atomic_read(&ac->cmd_state) > 0) {
+		pr_err("%s: DSP returned error[%s]\n",
+				__func__, adsp_err_get_err_str(
+				atomic_read(&ac->cmd_state)));
+		rc = adsp_err_get_lnx_err_code(
+				atomic_read(&ac->cmd_state));
+		goto exit;
+	}
+	rc = 0;
+exit:
+	return rc;
+}
 
 static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
 {
@@ -7875,7 +8292,7 @@
 				   stream_id,
 				   0, /* Buffer index is NA */
 				   0, /* Direction flag is NA */
-				   WAIT_CMD);
+				   NO_WAIT_CMD);
 
 	pr_debug("%s: token = 0x%x, stream_id  %d, session 0x%x\n",
 			__func__, hdr.token, stream_id, ac->session);
@@ -7939,7 +8356,7 @@
 		return -EINVAL;
 	}
 	pr_debug("%s: session[%d]\n", __func__, ac->session);
-	q6asm_stream_add_hdr_async(ac, &silence.hdr, sizeof(silence), FALSE,
+	q6asm_stream_add_hdr_async(ac, &silence.hdr, sizeof(silence), TRUE,
 			stream_id);
 
 	/*
@@ -7953,7 +8370,7 @@
 				   stream_id,
 				   0, /* Buffer index is NA */
 				   0, /* Direction flag is NA */
-				   WAIT_CMD);
+				   NO_WAIT_CMD);
 	pr_debug("%s: token = 0x%x, stream_id  %d, session 0x%x\n",
 			__func__, silence.hdr.token, stream_id, ac->session);
 
@@ -8169,14 +8586,17 @@
 
 int q6asm_get_asm_topology(int session_id)
 {
-	int topology;
+	int topology = -EINVAL;
 
 	if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
 		pr_err("%s: invalid session_id = %d\n", __func__, session_id);
-		topology = -EINVAL;
 		goto done;
 	}
-
+	if (session[session_id] == NULL) {
+		pr_err("%s: session not created for session id = %d\n",
+		       __func__, session_id);
+		goto done;
+	}
 	topology = session[session_id]->topology;
 done:
 	return topology;
@@ -8184,14 +8604,17 @@
 
 int q6asm_get_asm_app_type(int session_id)
 {
-	int app_type;
+	int app_type = -EINVAL;
 
 	if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
 		pr_err("%s: invalid session_id = %d\n", __func__, session_id);
-		app_type = -EINVAL;
 		goto done;
 	}
-
+	if (session[session_id] == NULL) {
+		pr_err("%s: session not created for session id = %d\n",
+		       __func__, session_id);
+		goto done;
+	}
 	app_type = session[session_id]->app_type;
 done:
 	return app_type;
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index 847a815..d6ad97d 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -220,7 +220,6 @@
 int32_t core_set_license(uint32_t key, uint32_t module_id)
 {
 	struct avcs_cmd_set_license *cmd_setl = NULL;
-	struct audio_cal_info_metainfo *metainfo = NULL;
 	struct cal_block_data *cal_block = NULL;
 	int rc = 0, packet_size = 0;
 
@@ -275,9 +274,9 @@
 	memcpy((uint8_t *)cmd_setl + sizeof(struct avcs_cmd_set_license),
 		cal_block->cal_data.kvaddr,
 		cal_block->cal_data.size);
-	pr_info("%s: Set license opcode=0x%x ,key=0x%x, id =0x%x, size = %d\n",
+	pr_info("%s: Set license opcode=0x%x, id =0x%x, size = %d\n",
 			__func__, cmd_setl->hdr.opcode,
-			metainfo->nKey, cmd_setl->id, cmd_setl->size);
+			cmd_setl->id, cmd_setl->size);
 	rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)cmd_setl);
 	if (rc < 0)
 		pr_err("%s: SET_LICENSE failed op[0x%x]rc[%d]\n",
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
index d761cf5..08ddde4 100644
--- a/sound/soc/msm/qdsp6v2/q6lsm.c
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -38,6 +38,8 @@
 #define LSM_ALIGN_BOUNDARY 512
 #define LSM_SAMPLE_RATE 16000
 #define QLSM_PARAM_ID_MINOR_VERSION 1
+#define QLSM_PARAM_ID_MINOR_VERSION_2 2
+
 static int lsm_afe_port;
 
 enum {
@@ -706,29 +708,28 @@
 	return rc;
 }
 
-static int q6lsm_send_params(struct lsm_client *client,
+static int q6lsm_send_param_opmode(struct lsm_client *client,
 		struct lsm_module_param_ids *opmode_ids,
-		struct lsm_module_param_ids *connectport_ids,
 		u32 set_param_opcode)
 {
 	int rc;
-	struct lsm_cmd_set_opmode_connectport opmode_connectport;
+	struct lsm_cmd_set_params_opmode opmode_params;
 	struct apr_hdr  *msg_hdr;
-	struct lsm_param_connect_to_port *connect_to_port;
+
 	struct lsm_param_op_mode *op_mode;
 	u32 data_payload_size, param_size;
 
-	msg_hdr = &opmode_connectport.msg_hdr;
+	msg_hdr = &opmode_params.msg_hdr;
 	q6lsm_add_hdr(client, msg_hdr,
-		      sizeof(opmode_connectport), true);
+		      sizeof(opmode_params), true);
 	msg_hdr->opcode = set_param_opcode;
-	data_payload_size = sizeof(opmode_connectport) -
+	data_payload_size = sizeof(opmode_params) -
 			    sizeof(*msg_hdr) -
-			    sizeof(opmode_connectport.params_hdr);
-	q6lsm_set_param_hdr_info(&opmode_connectport.params_hdr,
+			    sizeof(opmode_params.params_hdr);
+	q6lsm_set_param_hdr_info(&opmode_params.params_hdr,
 				 data_payload_size, 0, 0, 0);
-	connect_to_port = &opmode_connectport.connect_to_port;
-	op_mode = &opmode_connectport.op_mode;
+	op_mode = &opmode_params.op_mode;
+
 
 	param_size = sizeof(struct lsm_param_op_mode) -
 		     sizeof(op_mode->common);
@@ -740,18 +741,8 @@
 	op_mode->reserved = 0;
 	pr_debug("%s: mode = 0x%x", __func__, op_mode->mode);
 
-	param_size = (sizeof(struct lsm_param_connect_to_port) -
-		      sizeof(connect_to_port->common));
-	q6lsm_set_param_common(&connect_to_port->common,
-			       connectport_ids, param_size,
-			       set_param_opcode);
-	connect_to_port->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
-	connect_to_port->port_id = client->connect_to_port;
-	connect_to_port->reserved = 0;
-	pr_debug("%s: port= %d", __func__, connect_to_port->port_id);
-
 	rc = q6lsm_apr_send_pkt(client, client->apr,
-				&opmode_connectport, true, NULL);
+				&opmode_params, true, NULL);
 	if (rc)
 		pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
 		       __func__, msg_hdr->opcode, rc);
@@ -770,12 +761,241 @@
 	return lsm_afe_port;
 }
 
+int q6lsm_set_port_connected(struct lsm_client *client)
+{
+	int rc;
+	struct lsm_cmd_set_connectport connectport;
+	struct lsm_module_param_ids connectport_ids;
+	struct apr_hdr *msg_hdr;
+	struct lsm_param_connect_to_port *connect_to_port;
+	u32 data_payload_size, param_size, set_param_opcode;
+
+	if (client->use_topology) {
+		set_param_opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
+		connectport_ids.module_id = LSM_MODULE_ID_FRAMEWORK;
+		connectport_ids.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
+	} else {
+		set_param_opcode = LSM_SESSION_CMD_SET_PARAMS;
+		connectport_ids.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+		connectport_ids.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
+	}
+	client->connect_to_port = get_lsm_port();
+
+	msg_hdr = &connectport.msg_hdr;
+	q6lsm_add_hdr(client, msg_hdr,
+		      sizeof(connectport), true);
+	msg_hdr->opcode = set_param_opcode;
+	data_payload_size = sizeof(connectport) -
+			    sizeof(*msg_hdr) -
+			    sizeof(connectport.params_hdr);
+	q6lsm_set_param_hdr_info(&connectport.params_hdr,
+				 data_payload_size, 0, 0, 0);
+	connect_to_port = &connectport.connect_to_port;
+
+	param_size = (sizeof(struct lsm_param_connect_to_port) -
+		      sizeof(connect_to_port->common));
+	q6lsm_set_param_common(&connect_to_port->common,
+			       &connectport_ids, param_size,
+			       set_param_opcode);
+	connect_to_port->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
+	connect_to_port->port_id = client->connect_to_port;
+	connect_to_port->reserved = 0;
+	pr_debug("%s: port= %d", __func__, connect_to_port->port_id);
+
+	rc = q6lsm_apr_send_pkt(client, client->apr,
+				&connectport, true, NULL);
+	if (rc)
+		pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+			__func__, msg_hdr->opcode, rc);
+
+	return rc;
+}
+static int q6lsm_send_param_polling_enable(struct lsm_client *client,
+		bool poll_en,
+		struct lsm_module_param_ids *poll_enable_ids,
+		u32 set_param_opcode)
+{
+	int rc = 0;
+	struct lsm_cmd_poll_enable cmd;
+	struct apr_hdr  *msg_hdr;
+	struct lsm_param_poll_enable *poll_enable;
+	u32 data_payload_size, param_size;
+
+	msg_hdr = &cmd.msg_hdr;
+	q6lsm_add_hdr(client, msg_hdr,
+		      sizeof(struct lsm_cmd_poll_enable), true);
+	msg_hdr->opcode = set_param_opcode;
+	data_payload_size = sizeof(struct lsm_cmd_poll_enable) -
+			    sizeof(struct apr_hdr) -
+			    sizeof(struct lsm_set_params_hdr);
+	q6lsm_set_param_hdr_info(&cmd.params_hdr,
+				 data_payload_size, 0, 0, 0);
+	poll_enable = &cmd.poll_enable;
+
+	param_size = (sizeof(struct lsm_param_poll_enable) -
+		      sizeof(poll_enable->common));
+	q6lsm_set_param_common(&poll_enable->common,
+			       poll_enable_ids, param_size,
+			       set_param_opcode);
+	poll_enable->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
+	poll_enable->polling_enable = (poll_en) ? 1 : 0;
+	pr_debug("%s: poll enable= %d", __func__, poll_enable->polling_enable);
+
+	rc = q6lsm_apr_send_pkt(client, client->apr,
+				&cmd, true, NULL);
+	if (rc)
+		pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+		       __func__, msg_hdr->opcode, rc);
+
+	return rc;
+}
+
+int q6lsm_set_fwk_mode_cfg(struct lsm_client *client,
+			   uint32_t event_mode)
+{
+	int rc = 0;
+	struct lsm_cmd_set_fwk_mode_cfg cmd;
+	struct lsm_module_param_ids fwk_mode_cfg_ids;
+	struct apr_hdr  *msg_hdr;
+	struct lsm_param_fwk_mode_cfg *fwk_mode_cfg;
+	u32 data_payload_size, param_size, set_param_opcode;
+
+	if (client->use_topology) {
+		set_param_opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
+		fwk_mode_cfg_ids.module_id = LSM_MODULE_ID_FRAMEWORK;
+		fwk_mode_cfg_ids.param_id = LSM_PARAM_ID_FWK_MODE_CONFIG;
+	} else {
+		pr_debug("%s: Ignore sending event mode\n", __func__);
+		return rc;
+	}
+
+	msg_hdr = &cmd.msg_hdr;
+	q6lsm_add_hdr(client, msg_hdr,
+		      sizeof(struct lsm_cmd_set_fwk_mode_cfg), true);
+	msg_hdr->opcode = set_param_opcode;
+	data_payload_size = sizeof(struct lsm_cmd_set_fwk_mode_cfg) -
+			    sizeof(struct apr_hdr) -
+			    sizeof(struct lsm_set_params_hdr);
+	q6lsm_set_param_hdr_info(&cmd.params_hdr,
+				 data_payload_size, 0, 0, 0);
+	fwk_mode_cfg = &cmd.fwk_mode_cfg;
+
+	param_size = (sizeof(struct lsm_param_fwk_mode_cfg) -
+		      sizeof(fwk_mode_cfg->common));
+	q6lsm_set_param_common(&fwk_mode_cfg->common,
+			       &fwk_mode_cfg_ids, param_size,
+			       set_param_opcode);
+
+	fwk_mode_cfg->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
+	fwk_mode_cfg->mode = event_mode;
+	pr_debug("%s: mode = %d\n", __func__, fwk_mode_cfg->mode);
+
+	rc = q6lsm_apr_send_pkt(client, client->apr,
+				&cmd, true, NULL);
+	if (rc)
+		pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+		       __func__, msg_hdr->opcode, rc);
+	return rc;
+}
+
+static int q6lsm_arrange_mch_map(struct lsm_param_media_fmt *media_fmt,
+			 int channel_count)
+{
+	int rc = 0;
+
+	memset(media_fmt->channel_mapping, 0, LSM_MAX_NUM_CHANNELS);
+
+	switch (channel_count) {
+	case 1:
+		media_fmt->channel_mapping[0] = PCM_CHANNEL_FC;
+		break;
+	case 2:
+		media_fmt->channel_mapping[0] = PCM_CHANNEL_FL;
+		media_fmt->channel_mapping[1] = PCM_CHANNEL_FR;
+		break;
+	case 3:
+		media_fmt->channel_mapping[0] = PCM_CHANNEL_FL;
+		media_fmt->channel_mapping[1] = PCM_CHANNEL_FR;
+		media_fmt->channel_mapping[2] = PCM_CHANNEL_FC;
+		break;
+	case 4:
+		media_fmt->channel_mapping[0] = PCM_CHANNEL_FL;
+		media_fmt->channel_mapping[1] = PCM_CHANNEL_FR;
+		media_fmt->channel_mapping[2] = PCM_CHANNEL_LS;
+		media_fmt->channel_mapping[3] = PCM_CHANNEL_RS;
+		break;
+	default:
+		pr_err("%s: invalid num_chan %d\n", __func__, channel_count);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+int q6lsm_set_media_fmt_params(struct lsm_client *client)
+{
+	int rc = 0;
+	struct lsm_cmd_set_media_fmt cmd;
+	struct lsm_module_param_ids media_fmt_ids;
+	struct apr_hdr  *msg_hdr;
+	struct lsm_param_media_fmt *media_fmt;
+	u32 data_payload_size, param_size, set_param_opcode;
+	struct lsm_hw_params param = client->hw_params;
+
+	if (client->use_topology) {
+		set_param_opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
+		media_fmt_ids.module_id = LSM_MODULE_ID_FRAMEWORK;
+		media_fmt_ids.param_id = LSM_PARAM_ID_MEDIA_FMT;
+	} else {
+		pr_debug("%s: Ignore sending media format\n", __func__);
+		goto err_ret;
+	}
+
+	msg_hdr = &cmd.msg_hdr;
+	q6lsm_add_hdr(client, msg_hdr,
+		      sizeof(struct lsm_cmd_set_media_fmt), true);
+	msg_hdr->opcode = set_param_opcode;
+	data_payload_size = sizeof(struct lsm_cmd_set_media_fmt) -
+			    sizeof(struct apr_hdr) -
+			    sizeof(struct lsm_set_params_hdr);
+	q6lsm_set_param_hdr_info(&cmd.params_hdr,
+				 data_payload_size, 0, 0, 0);
+	media_fmt = &cmd.media_fmt;
+
+	param_size = (sizeof(struct lsm_param_media_fmt) -
+		      sizeof(media_fmt->common));
+	q6lsm_set_param_common(&media_fmt->common,
+			       &media_fmt_ids, param_size,
+			       set_param_opcode);
+
+	media_fmt->minor_version = QLSM_PARAM_ID_MINOR_VERSION_2;
+	media_fmt->sample_rate = param.sample_rate;
+	media_fmt->num_channels = param.num_chs;
+	media_fmt->bit_width = param.sample_size;
+
+	rc = q6lsm_arrange_mch_map(media_fmt, media_fmt->num_channels);
+	if (rc)
+		goto err_ret;
+
+	pr_debug("%s: sample rate= %d, channels %d bit width %d\n",
+		 __func__, media_fmt->sample_rate, media_fmt->num_channels,
+		 media_fmt->bit_width);
+
+	rc = q6lsm_apr_send_pkt(client, client->apr,
+				&cmd, true, NULL);
+	if (rc)
+		pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+		       __func__, msg_hdr->opcode, rc);
+err_ret:
+	return rc;
+}
+
 int q6lsm_set_data(struct lsm_client *client,
 			   enum lsm_detection_mode mode,
 			   bool detectfailure)
 {
 	int rc = 0;
-	struct lsm_module_param_ids opmode_ids, connectport_ids;
+	struct lsm_module_param_ids opmode_ids;
 	struct lsm_module_param_ids conf_levels_ids;
 
 	if (!client->confidence_levels) {
@@ -799,16 +1019,12 @@
 		goto err_ret;
 	}
 	client->mode |= detectfailure << 2;
-	client->connect_to_port = get_lsm_port();
 
 	opmode_ids.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
 	opmode_ids.param_id = LSM_PARAM_ID_OPERATION_MODE;
 
-	connectport_ids.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
-	connectport_ids.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
-
-	rc = q6lsm_send_params(client, &opmode_ids, &connectport_ids,
-			      LSM_SESSION_CMD_SET_PARAMS);
+	rc = q6lsm_send_param_opmode(client, &opmode_ids,
+					LSM_SESSION_CMD_SET_PARAMS);
 	if (rc) {
 		pr_err("%s: Failed to set lsm config params %d\n",
 			__func__, rc);
@@ -1388,7 +1604,7 @@
 
 int q6lsm_set_one_param(struct lsm_client *client,
 	struct lsm_params_info *p_info, void *data,
-	enum LSM_PARAM_TYPE param_type)
+	uint32_t param_type)
 {
 	int rc = 0, pkt_sz;
 	struct lsm_module_param_ids ids;
@@ -1407,7 +1623,6 @@
 	case LSM_OPERATION_MODE: {
 		struct snd_lsm_detect_mode *det_mode = data;
 		struct lsm_module_param_ids opmode_ids;
-		struct lsm_module_param_ids connectport_ids;
 
 		if (det_mode->mode == LSM_MODE_KEYWORD_ONLY_DETECTION) {
 			client->mode = 0x01;
@@ -1420,16 +1635,12 @@
 		}
 
 		client->mode |= det_mode->detect_failure << 2;
-		client->connect_to_port = get_lsm_port();
 
 		opmode_ids.module_id = p_info->module_id;
 		opmode_ids.param_id = p_info->param_id;
 
-		connectport_ids.module_id = LSM_MODULE_ID_FRAMEWORK;
-		connectport_ids.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
-
-		rc = q6lsm_send_params(client, &opmode_ids, &connectport_ids,
-				       LSM_SESSION_CMD_SET_PARAMS_V2);
+		rc = q6lsm_send_param_opmode(client, &opmode_ids,
+					LSM_SESSION_CMD_SET_PARAMS_V2);
 		if (rc)
 			pr_err("%s: OPERATION_MODE failed, rc %d\n",
 				__func__, rc);
@@ -1457,6 +1668,20 @@
 			pr_err("%s: CONFIDENCE_LEVELS cmd failed, rc %d\n",
 				 __func__, rc);
 		break;
+	case LSM_POLLING_ENABLE: {
+		struct snd_lsm_poll_enable *lsm_poll_enable =
+				(struct snd_lsm_poll_enable *) data;
+		ids.module_id = p_info->module_id;
+		ids.param_id = p_info->param_id;
+		rc = q6lsm_send_param_polling_enable(client,
+				lsm_poll_enable->poll_en, &ids,
+				LSM_SESSION_CMD_SET_PARAMS_V2);
+		if (rc)
+			pr_err("%s: POLLING ENABLE cmd failed, rc %d\n",
+				 __func__, rc);
+		break;
+	}
+
 	case LSM_REG_SND_MODEL: {
 		struct lsm_cmd_set_params model_param;
 		u32 payload_size;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 33d2225..b829c65 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -3962,6 +3962,10 @@
 {
 	int ret;
 
+	ret = voice_send_cvp_device_channels_cmd(v);
+	if (ret < 0)
+		goto done;
+
 	if (voice_get_cvd_int_version(common.cvd_version) >=
 	    CVD_INT_VERSION_2_3) {
 		ret = voice_send_cvp_media_format_cmd(v, RX_PATH);
@@ -3974,8 +3978,6 @@
 
 		if (common.ec_ref_ext)
 			ret = voice_send_cvp_media_format_cmd(v, EC_REF_PATH);
-	} else {
-		ret = voice_send_cvp_device_channels_cmd(v);
 	}
 
 done:
@@ -5820,6 +5822,48 @@
 	return ret;
 }
 
+int voc_set_afe_sidetone(uint32_t session_id, bool sidetone_enable)
+{
+	struct voice_data *v = NULL;
+	int ret = -EINVAL;
+	struct voice_session_itr itr;
+	u16 rx_port, tx_port;
+
+	common.sidetone_enable = sidetone_enable;
+	voice_itr_init(&itr, session_id);
+	while (voice_itr_get_next_session(&itr, &v)) {
+		if (v == NULL) {
+			pr_err("%s: invalid session_id 0x%x\n", __func__,
+				  session_id);
+			ret = -EINVAL;
+			break;
+		}
+		mutex_lock(&v->lock);
+		if (v->voc_state != VOC_RUN) {
+			mutex_unlock(&v->lock);
+			continue;
+		}
+		rx_port = v->dev_rx.port_id;
+		tx_port = v->dev_tx.port_id;
+		ret = afe_sidetone_enable(tx_port, rx_port,
+					  sidetone_enable);
+		if (!ret) {
+			mutex_unlock(&v->lock);
+			break;
+		}
+		mutex_unlock(&v->lock);
+	}
+	return ret;
+}
+
+bool voc_get_afe_sidetone(void)
+{
+	bool ret;
+
+	ret = common.sidetone_enable;
+	return ret;
+}
+
 int voc_get_pp_enable(uint32_t session_id, uint32_t module_id)
 {
 	struct voice_data *v = voice_get_session(session_id);
@@ -8530,6 +8574,9 @@
 	memset(&common.ec_media_fmt_info.channel_mapping, 0,
 	       VSS_CHANNEL_MAPPING_SIZE);
 
+	/* Initialize AFE Sidetone Enable */
+	common.sidetone_enable = false;
+
 	/* Initialize MVS info. */
 	common.mvs_info.network_type = VSS_NETWORK_ID_DEFAULT;
 
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 73a78a5..74d80be 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -1762,6 +1762,7 @@
 	struct vss_isoundfocus_rsp_get_sectors_t soundFocusResponse;
 	struct shared_mem_info source_tracking_sh_mem;
 	struct vss_isourcetrack_activity_data_t sourceTrackingResponse;
+	bool sidetone_enable;
 };
 
 struct voice_session_itr {
@@ -1894,4 +1895,6 @@
 int voc_set_sound_focus(struct sound_focus_param sound_focus_param);
 int voc_get_sound_focus(struct sound_focus_param *soundFocusData);
 int voc_get_source_tracking(struct source_tracking_param *sourceTrackingData);
+int voc_set_afe_sidetone(uint32_t session_id, bool sidetone_enable);
+bool voc_get_afe_sidetone(void);
 #endif
diff --git a/sound/soc/msm/qdsp6v2/rtac.c b/sound/soc/msm/qdsp6v2/rtac.c
index 7a7db18..cd02501 100644
--- a/sound/soc/msm/qdsp6v2/rtac.c
+++ b/sound/soc/msm/qdsp6v2/rtac.c
@@ -400,6 +400,24 @@
 	return;
 }
 
+void rtac_update_afe_topology(u32 port_id)
+{
+	u32 i = 0;
+
+	mutex_lock(&rtac_adm_mutex);
+	for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
+		if (rtac_adm_data.device[i].afe_port == port_id) {
+			rtac_adm_data.device[i].afe_topology =
+						afe_get_topology(port_id);
+			pr_debug("%s: port_id = 0x%x topology_id = 0x%x copp_id = %d\n",
+				 __func__, port_id,
+				 rtac_adm_data.device[i].afe_topology,
+				 rtac_adm_data.device[i].copp);
+		}
+	}
+	mutex_unlock(&rtac_adm_mutex);
+}
+
 void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id,
 			 u32 app_type, u32 acdb_id)
 {
diff --git a/sound/soc/msm/msmfalcon-common.c b/sound/soc/msm/sdm660-common.c
similarity index 83%
rename from sound/soc/msm/msmfalcon-common.c
rename to sound/soc/msm/sdm660-common.c
index baf6a4f..f1fbce3 100644
--- a/sound/soc/msm/msmfalcon-common.c
+++ b/sound/soc/msm/sdm660-common.c
@@ -16,14 +16,16 @@
 #include <sound/pcm_params.h>
 #include <sound/q6afe-v2.h>
 #include "qdsp6v2/msm-pcm-routing-v2.h"
-#include "msm-audio-pinctrl.h"
-#include "msmfalcon-common.h"
-#include "msmfalcon-internal.h"
-#include "msmfalcon-external.h"
-#include "../codecs/msm8x16/msm8x16-wcd.h"
+#include "sdm660-common.h"
+#include "sdm660-internal.h"
+#include "sdm660-external.h"
+#include "../codecs/sdm660_cdc/msm-analog-cdc.h"
 #include "../codecs/wsa881x.h"
 
-#define DRV_NAME "msmfalcon-asoc-snd"
+#define DRV_NAME "sdm660-asoc-snd"
+
+#define MSM_INT_DIGITAL_CODEC "msm-dig-codec"
+#define PMIC_INT_ANALOG_CODEC "analog-codec"
 
 #define DEV_NAME_STR_LEN  32
 #define DEFAULT_MCLK_RATE 9600000
@@ -34,6 +36,11 @@
 	u32 channels;
 };
 
+enum {
+	DP_RX_IDX,
+	EXT_DISP_RX_IDX_MAX,
+};
+
 /* TDM default config */
 static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
 	{ /* PRI TDM */
@@ -122,6 +129,10 @@
 	}
 };
 
+/* Default configuration of external display BE */
+static struct dev_config ext_disp_rx_cfg[] = {
+	[DP_RX_IDX] =   {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
 static struct dev_config usb_rx_cfg = {
 	.sample_rate = SAMPLING_RATE_48KHZ,
 	.bit_format = SNDRV_PCM_FORMAT_S16_LE,
@@ -158,20 +169,18 @@
 	PCM_I2S_SEL_MAX,
 };
 
-struct mi2s_aux_pcm_common_conf {
-	struct mutex lock;
-	void *pcm_i2s_sel_vt_addr;
-};
-
 struct mi2s_conf {
 	struct mutex lock;
 	u32 ref_cnt;
 	u32 msm_is_mi2s_master;
+	u32 msm_is_ext_mclk;
 };
 
-struct auxpcm_conf {
-	struct mutex lock;
-	u32 ref_cnt;
+static u32 mi2s_ebit_clk[MI2S_MAX] = {
+	Q6AFE_LPASS_CLK_ID_PRI_MI2S_EBIT,
+	Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT,
+	Q6AFE_LPASS_CLK_ID_TER_MI2S_EBIT,
+	Q6AFE_LPASS_CLK_ID_QUAD_MI2S_EBIT
 };
 
 struct msm_wsa881x_dev_info {
@@ -189,7 +198,7 @@
 	.detect_extn_cable = true,
 	.mono_stero_detection = false,
 	.swap_gnd_mic = NULL,
-	.hs_ext_micbias = false,
+	.hs_ext_micbias = true,
 	.key_code[0] = KEY_MEDIA,
 	.key_code[1] = KEY_VOICECOMMAND,
 	.key_code[2] = KEY_VOLUMEUP,
@@ -251,6 +260,8 @@
 					   "Eight"};
 static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
 					  "S32_LE"};
+static char const *mi2s_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
+					  "S32_LE"};
 static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four",
 				    "Five", "Six", "Seven", "Eight"};
 static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
@@ -264,7 +275,11 @@
 					"KHZ_16", "KHZ_22P05",
 					"KHZ_32", "KHZ_44P1", "KHZ_48",
 					"KHZ_96", "KHZ_192", "KHZ_384"};
+static char const *ext_disp_bit_format_text[] = {"S16_LE", "S24_LE"};
+static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+						  "KHZ_192"};
 
+static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_chs, ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_rx_sample_rate, auxpcm_rate_text);
 static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_rx_sample_rate, auxpcm_rate_text);
@@ -282,6 +297,14 @@
 static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_sample_rate, mi2s_rate_text);
 static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_sample_rate, mi2s_rate_text);
 static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_format, mi2s_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_format, mi2s_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_format, mi2s_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_format, mi2s_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_format, mi2s_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_format, mi2s_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_format, mi2s_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_format, mi2s_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_chs, mi2s_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_chs, mi2s_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_chs, mi2s_ch_text);
@@ -294,8 +317,11 @@
 static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_format, ext_disp_bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text);
 static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_sample_rate,
+				ext_disp_sample_rate_text);
 static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_chs, tdm_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_format, tdm_bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_sample_rate, tdm_sample_rate_text);
@@ -338,9 +364,42 @@
 	}
 };
 
-static struct mi2s_aux_pcm_common_conf mi2s_auxpcm_conf[PCM_I2S_SEL_MAX];
+static struct afe_clk_set mi2s_mclk[MI2S_MAX] = {
+	{
+		AFE_API_VERSION_I2S_CONFIG,
+		Q6AFE_LPASS_CLK_ID_MCLK_3,
+		Q6AFE_LPASS_OSR_CLK_9_P600_MHZ,
+		Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+		Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+		0,
+	},
+	{
+		AFE_API_VERSION_I2S_CONFIG,
+		Q6AFE_LPASS_CLK_ID_MCLK_4,
+		Q6AFE_LPASS_OSR_CLK_9_P600_MHZ,
+		Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+		Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+		0,
+	},
+	{
+		AFE_API_VERSION_I2S_CONFIG,
+		Q6AFE_LPASS_CLK_ID_MCLK_1,
+		Q6AFE_LPASS_OSR_CLK_9_P600_MHZ,
+		Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+		Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+		0,
+	},
+	{
+		AFE_API_VERSION_I2S_CONFIG,
+		Q6AFE_LPASS_CLK_ID_MCLK_2,
+		Q6AFE_LPASS_OSR_CLK_9_P600_MHZ,
+		Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+		Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+		0,
+	}
+};
+
 static struct mi2s_conf mi2s_intf_conf[MI2S_MAX];
-static struct auxpcm_conf auxpcm_intf_conf[AUX_PCM_MAX];
 
 static int proxy_rx_ch_get(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
@@ -634,6 +693,54 @@
 	return value;
 }
 
+static int mi2s_get_format(int value)
+{
+	int format = 0;
+
+	switch (value) {
+	case 0:
+		format = SNDRV_PCM_FORMAT_S16_LE;
+		break;
+	case 1:
+		format = SNDRV_PCM_FORMAT_S24_LE;
+		break;
+	case 2:
+		format = SNDRV_PCM_FORMAT_S24_3LE;
+		break;
+	case 3:
+		format = SNDRV_PCM_FORMAT_S32_LE;
+		break;
+	default:
+		format = SNDRV_PCM_FORMAT_S16_LE;
+		break;
+	}
+	return format;
+}
+
+static int mi2s_get_format_value(int format)
+{
+	int value = 0;
+
+	switch (format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		value = 0;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		value = 1;
+		break;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		value = 2;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		value = 3;
+		break;
+	default:
+		value = 0;
+		break;
+	}
+	return value;
+}
+
 static int tdm_rx_format_get(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
@@ -1099,6 +1206,78 @@
 	return 0;
 }
 
+static int mi2s_tx_format_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	mi2s_tx_cfg[idx].bit_format =
+		mi2s_get_format(ucontrol->value.enumerated.item[0]);
+
+	pr_debug("%s: idx[%d] _tx_format = %d, item = %d\n", __func__,
+		  idx, mi2s_tx_cfg[idx].bit_format,
+		  ucontrol->value.enumerated.item[0]);
+
+	return 0;
+}
+
+static int mi2s_tx_format_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	ucontrol->value.enumerated.item[0] =
+		mi2s_get_format_value(mi2s_tx_cfg[idx].bit_format);
+
+	pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__,
+		idx, mi2s_tx_cfg[idx].bit_format,
+		ucontrol->value.enumerated.item[0]);
+
+	return 0;
+}
+
+static int mi2s_rx_format_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	mi2s_rx_cfg[idx].bit_format =
+		mi2s_get_format(ucontrol->value.enumerated.item[0]);
+
+	pr_debug("%s: idx[%d] _rx_format = %d, item = %d\n", __func__,
+		  idx, mi2s_rx_cfg[idx].bit_format,
+		  ucontrol->value.enumerated.item[0]);
+
+	return 0;
+}
+
+static int mi2s_rx_format_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	ucontrol->value.enumerated.item[0] =
+		mi2s_get_format_value(mi2s_rx_cfg[idx].bit_format);
+
+	pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
+		idx, mi2s_rx_cfg[idx].bit_format,
+		ucontrol->value.enumerated.item[0]);
+
+	return 0;
+}
+
 static int msm_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
@@ -1481,6 +1660,162 @@
 	return rc;
 }
 
+static int ext_disp_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+	int idx;
+
+	if (strnstr(kcontrol->id.name, "Display Port RX",
+			 sizeof("Display Port RX")))
+		idx = DP_RX_IDX;
+	else {
+		pr_err("%s: unsupported BE: %s",
+			__func__, kcontrol->id.name);
+		idx = -EINVAL;
+	}
+
+	return idx;
+}
+
+static int ext_disp_rx_format_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = ext_disp_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	switch (ext_disp_rx_cfg[idx].bit_format) {
+	case SNDRV_PCM_FORMAT_S24_LE:
+		ucontrol->value.integer.value[0] = 1;
+		break;
+
+	case SNDRV_PCM_FORMAT_S16_LE:
+	default:
+		ucontrol->value.integer.value[0] = 0;
+		break;
+	}
+
+	pr_debug("%s: ext_disp_rx[%d].format = %d, ucontrol value = %ld\n",
+		 __func__, idx, ext_disp_rx_cfg[idx].bit_format,
+		 ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int ext_disp_rx_format_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = ext_disp_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 1:
+		ext_disp_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S24_LE;
+		break;
+	case 0:
+	default:
+		ext_disp_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S16_LE;
+		break;
+	}
+	pr_debug("%s: ext_disp_rx[%d].format = %d, ucontrol value = %ld\n",
+		 __func__, idx, ext_disp_rx_cfg[idx].bit_format,
+		 ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int ext_disp_rx_ch_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = ext_disp_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	ucontrol->value.integer.value[0] =
+			ext_disp_rx_cfg[idx].channels - 2;
+
+	pr_debug("%s: ext_disp_rx[%d].ch = %d\n", __func__,
+		 idx, ext_disp_rx_cfg[idx].channels);
+
+	return 0;
+}
+
+static int ext_disp_rx_ch_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = ext_disp_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	ext_disp_rx_cfg[idx].channels =
+			ucontrol->value.integer.value[0] + 2;
+
+	pr_debug("%s: ext_disp_rx[%d].ch = %d\n", __func__,
+		 idx, ext_disp_rx_cfg[idx].channels);
+	return 1;
+}
+
+static int ext_disp_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	int sample_rate_val;
+	int idx = ext_disp_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	switch (ext_disp_rx_cfg[idx].sample_rate) {
+	case SAMPLING_RATE_192KHZ:
+		sample_rate_val = 2;
+		break;
+
+	case SAMPLING_RATE_96KHZ:
+		sample_rate_val = 1;
+		break;
+
+	case SAMPLING_RATE_48KHZ:
+	default:
+		sample_rate_val = 0;
+		break;
+	}
+
+	ucontrol->value.integer.value[0] = sample_rate_val;
+	pr_debug("%s: ext_disp_rx[%d].sample_rate = %d\n", __func__,
+		 idx, ext_disp_rx_cfg[idx].sample_rate);
+
+	return 0;
+}
+
+static int ext_disp_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = ext_disp_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 2:
+		ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_192KHZ;
+		break;
+	case 1:
+		ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_96KHZ;
+		break;
+	case 0:
+	default:
+		ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_48KHZ;
+		break;
+	}
+
+	pr_debug("%s: control value = %ld, ext_disp_rx[%d].sample_rate = %d\n",
+		 __func__, ucontrol->value.integer.value[0], idx,
+		 ext_disp_rx_cfg[idx].sample_rate);
+	return 0;
+}
+
 const struct snd_kcontrol_new msm_common_snd_controls[] = {
 	SOC_ENUM_EXT("PROXY_RX Channels", proxy_rx_chs,
 			proxy_rx_ch_get, proxy_rx_ch_put),
@@ -1532,6 +1867,30 @@
 	SOC_ENUM_EXT("QUAT_MI2S_TX SampleRate", quat_mi2s_tx_sample_rate,
 			mi2s_tx_sample_rate_get,
 			mi2s_tx_sample_rate_put),
+	SOC_ENUM_EXT("PRIM_MI2S_RX Format", prim_mi2s_rx_format,
+			mi2s_rx_format_get,
+			mi2s_rx_format_put),
+	SOC_ENUM_EXT("SEC_MI2S_RX Format", sec_mi2s_rx_format,
+			mi2s_rx_format_get,
+			mi2s_rx_format_put),
+	SOC_ENUM_EXT("TERT_MI2S_RX Format", tert_mi2s_rx_format,
+			mi2s_rx_format_get,
+			mi2s_rx_format_put),
+	SOC_ENUM_EXT("QUAT_MI2S_RX Format", quat_mi2s_rx_format,
+			mi2s_rx_format_get,
+			mi2s_rx_format_put),
+	SOC_ENUM_EXT("PRIM_MI2S_TX Format", prim_mi2s_tx_format,
+			mi2s_tx_format_get,
+			mi2s_tx_format_put),
+	SOC_ENUM_EXT("SEC_MI2S_TX Format", sec_mi2s_tx_format,
+			mi2s_tx_format_get,
+			mi2s_tx_format_put),
+	SOC_ENUM_EXT("TERT_MI2S_TX Format", tert_mi2s_tx_format,
+			mi2s_tx_format_get,
+			mi2s_tx_format_put),
+	SOC_ENUM_EXT("QUAT_MI2S_TX Format", quat_mi2s_tx_format,
+			mi2s_tx_format_get,
+			mi2s_tx_format_put),
 	SOC_ENUM_EXT("PRIM_MI2S_RX Channels", prim_mi2s_rx_chs,
 			msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
 	SOC_ENUM_EXT("PRIM_MI2S_TX Channels", prim_mi2s_tx_chs,
@@ -1552,16 +1911,23 @@
 			usb_audio_rx_ch_get, usb_audio_rx_ch_put),
 	SOC_ENUM_EXT("USB_AUDIO_TX Channels", usb_tx_chs,
 			usb_audio_tx_ch_get, usb_audio_tx_ch_put),
+	SOC_ENUM_EXT("Display Port RX Channels", ext_disp_rx_chs,
+			ext_disp_rx_ch_get, ext_disp_rx_ch_put),
 	SOC_ENUM_EXT("USB_AUDIO_RX Format", usb_rx_format,
 			usb_audio_rx_format_get, usb_audio_rx_format_put),
 	SOC_ENUM_EXT("USB_AUDIO_TX Format", usb_tx_format,
 			usb_audio_tx_format_get, usb_audio_tx_format_put),
+	SOC_ENUM_EXT("Display Port RX Bit Format", ext_disp_rx_format,
+			ext_disp_rx_format_get, ext_disp_rx_format_put),
 	SOC_ENUM_EXT("USB_AUDIO_RX SampleRate", usb_rx_sample_rate,
 			usb_audio_rx_sample_rate_get,
 			usb_audio_rx_sample_rate_put),
 	SOC_ENUM_EXT("USB_AUDIO_TX SampleRate", usb_tx_sample_rate,
 			usb_audio_tx_sample_rate_get,
 			usb_audio_tx_sample_rate_put),
+	SOC_ENUM_EXT("Display Port RX SampleRate", ext_disp_rx_sample_rate,
+			ext_disp_rx_sample_rate_get,
+			ext_disp_rx_sample_rate_put),
 	SOC_ENUM_EXT("PRI_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
 			tdm_rx_sample_rate_get,
 			tdm_rx_sample_rate_put),
@@ -1636,6 +2002,17 @@
 			tdm_tx_ch_put),
 };
 
+/**
+ * msm_common_snd_controls_size - to return controls size
+ *
+ * Return: returns size of common controls array
+ */
+int msm_common_snd_controls_size(void)
+{
+	return ARRAY_SIZE(msm_common_snd_controls);
+}
+EXPORT_SYMBOL(msm_common_snd_controls_size);
+
 static inline int param_is_mask(int p)
 {
 	return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
@@ -1661,6 +2038,23 @@
 	}
 }
 
+static int msm_ext_disp_get_idx_from_beid(int32_t be_id)
+{
+	int idx;
+
+	switch (be_id) {
+	case MSM_BACKEND_DAI_DISPLAY_PORT_RX:
+		idx = DP_RX_IDX;
+		break;
+	default:
+		pr_err("%s: Incorrect ext_disp be_id %d\n", __func__, be_id);
+		idx = -EINVAL;
+		break;
+	}
+
+	return idx;
+}
+
 /**
  * msm_common_be_hw_params_fixup - updates settings of ALSA BE hw params.
  *
@@ -1678,6 +2072,7 @@
 	struct snd_interval *channels = hw_param_interval(params,
 					SNDRV_PCM_HW_PARAM_CHANNELS);
 	int rc = 0;
+	int idx;
 
 	pr_debug("%s: format = %d, rate = %d\n",
 		  __func__, params_format(params), params_rate(params));
@@ -1697,6 +2092,21 @@
 		channels->min = channels->max = usb_tx_cfg.channels;
 		break;
 
+	case MSM_BACKEND_DAI_DISPLAY_PORT_RX:
+		idx = msm_ext_disp_get_idx_from_beid(dai_link->be_id);
+		if (IS_ERR_VALUE(idx)) {
+			pr_err("%s: Incorrect ext disp idx %d\n",
+			       __func__, idx);
+			rc = idx;
+			break;
+		}
+
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+				ext_disp_rx_cfg[idx].bit_format);
+		rate->min = rate->max = ext_disp_rx_cfg[idx].sample_rate;
+		channels->min = channels->max = ext_disp_rx_cfg[idx].channels;
+		break;
+
 	case MSM_BACKEND_DAI_AFE_PCM_RX:
 		channels->min = channels->max = proxy_rx_cfg.channels;
 		rate->min = rate->max = SAMPLING_RATE_48KHZ;
@@ -1826,48 +2236,64 @@
 		rate->min = rate->max = mi2s_rx_cfg[PRIM_MI2S].sample_rate;
 		channels->min = channels->max =
 			mi2s_rx_cfg[PRIM_MI2S].channels;
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			       mi2s_rx_cfg[PRIM_MI2S].bit_format);
 		break;
 
 	case MSM_BACKEND_DAI_PRI_MI2S_TX:
 		rate->min = rate->max = mi2s_tx_cfg[PRIM_MI2S].sample_rate;
 		channels->min = channels->max =
 			mi2s_tx_cfg[PRIM_MI2S].channels;
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			       mi2s_tx_cfg[PRIM_MI2S].bit_format);
 		break;
 
 	case MSM_BACKEND_DAI_SECONDARY_MI2S_RX:
 		rate->min = rate->max = mi2s_rx_cfg[SEC_MI2S].sample_rate;
 		channels->min = channels->max =
 			mi2s_rx_cfg[SEC_MI2S].channels;
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			       mi2s_rx_cfg[SEC_MI2S].bit_format);
 		break;
 
 	case MSM_BACKEND_DAI_SECONDARY_MI2S_TX:
 		rate->min = rate->max = mi2s_tx_cfg[SEC_MI2S].sample_rate;
 		channels->min = channels->max =
 			mi2s_tx_cfg[SEC_MI2S].channels;
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			       mi2s_tx_cfg[SEC_MI2S].bit_format);
 		break;
 
 	case MSM_BACKEND_DAI_TERTIARY_MI2S_RX:
 		rate->min = rate->max = mi2s_rx_cfg[TERT_MI2S].sample_rate;
 		channels->min = channels->max =
 			mi2s_rx_cfg[TERT_MI2S].channels;
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			       mi2s_rx_cfg[TERT_MI2S].bit_format);
 		break;
 
 	case MSM_BACKEND_DAI_TERTIARY_MI2S_TX:
 		rate->min = rate->max = mi2s_tx_cfg[TERT_MI2S].sample_rate;
 		channels->min = channels->max =
 			mi2s_tx_cfg[TERT_MI2S].channels;
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			       mi2s_tx_cfg[TERT_MI2S].bit_format);
 		break;
 
 	case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX:
 		rate->min = rate->max = mi2s_rx_cfg[QUAT_MI2S].sample_rate;
 		channels->min = channels->max =
 			mi2s_rx_cfg[QUAT_MI2S].channels;
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			       mi2s_rx_cfg[QUAT_MI2S].bit_format);
 		break;
 
 	case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX:
 		rate->min = rate->max = mi2s_tx_cfg[QUAT_MI2S].sample_rate;
 		channels->min = channels->max =
 			mi2s_tx_cfg[QUAT_MI2S].channels;
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			       mi2s_tx_cfg[QUAT_MI2S].bit_format);
 		break;
 
 	default:
@@ -1887,46 +2313,14 @@
  */
 int msm_aux_pcm_snd_startup(struct snd_pcm_substream *substream)
 {
-	int ret = 0;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	int index = cpu_dai->id - 1;
-	return ret = 0;
 
 	dev_dbg(rtd->card->dev,
 		"%s: substream = %s  stream = %d, dai name %s, dai ID %d\n",
 		__func__, substream->name, substream->stream,
-		cpu_dai->name, cpu_dai->id);
+		rtd->cpu_dai->name, rtd->cpu_dai->id);
 
-	if (index < PRIM_AUX_PCM || index > QUAT_AUX_PCM) {
-		ret = -EINVAL;
-		dev_err(rtd->card->dev,
-			"%s: CPU DAI id (%d) out of range\n",
-			__func__, cpu_dai->id);
-		goto done;
-	}
-
-	mutex_lock(&auxpcm_intf_conf[index].lock);
-	if (++auxpcm_intf_conf[index].ref_cnt == 1) {
-		if (mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr != NULL) {
-			mutex_lock(&mi2s_auxpcm_conf[index].lock);
-			iowrite32(1,
-				mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr);
-			mutex_unlock(&mi2s_auxpcm_conf[index].lock);
-		} else {
-			dev_err(rtd->card->dev,
-				"%s lpaif_tert_muxsel_virt_addr is NULL\n",
-				__func__);
-			ret = -EINVAL;
-		}
-	}
-	if (ret < 0)
-		auxpcm_intf_conf[index].ref_cnt--;
-
-	mutex_unlock(&auxpcm_intf_conf[index].lock);
-
-done:
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL(msm_aux_pcm_snd_startup);
 
@@ -1938,36 +2332,12 @@
 void msm_aux_pcm_snd_shutdown(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	int index = rtd->cpu_dai->id - 1;
 
 	dev_dbg(rtd->card->dev,
 		"%s: substream = %s  stream = %d, dai name %s, dai ID %d\n",
 		__func__,
 		substream->name, substream->stream,
 		rtd->cpu_dai->name, rtd->cpu_dai->id);
-
-	if (index < PRIM_AUX_PCM || index > QUAT_AUX_PCM) {
-		dev_err(rtd->card->dev,
-			"%s: CPU DAI id (%d) out of range\n",
-			__func__, rtd->cpu_dai->id);
-		return;
-	}
-
-	mutex_lock(&auxpcm_intf_conf[index].lock);
-	if (--auxpcm_intf_conf[index].ref_cnt == 0) {
-		if (mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr != NULL) {
-			mutex_lock(&mi2s_auxpcm_conf[index].lock);
-			iowrite32(0,
-				mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr);
-			mutex_unlock(&mi2s_auxpcm_conf[index].lock);
-		} else {
-			dev_err(rtd->card->dev,
-				"%s lpaif_tert_muxsel_virt_addr is NULL\n",
-				__func__);
-			auxpcm_intf_conf[index].ref_cnt++;
-		}
-	}
-	mutex_unlock(&auxpcm_intf_conf[index].lock);
 }
 EXPORT_SYMBOL(msm_aux_pcm_snd_shutdown);
 
@@ -2013,6 +2383,7 @@
 	u32 bit_per_sample;
 
 	switch (bit_format) {
+	case SNDRV_PCM_FORMAT_S32_LE:
 	case SNDRV_PCM_FORMAT_S24_3LE:
 	case SNDRV_PCM_FORMAT_S24_LE:
 		bit_per_sample = 32;
@@ -2093,6 +2464,7 @@
 	int ret = 0;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int port_id = msm_get_port_id(rtd->dai_link->be_id);
 	int index = cpu_dai->id;
 	unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
 
@@ -2115,6 +2487,11 @@
 	 */
 	mutex_lock(&mi2s_intf_conf[index].lock);
 	if (++mi2s_intf_conf[index].ref_cnt == 1) {
+		/* Check if msm needs to provide the clock to the interface */
+		if (!mi2s_intf_conf[index].msm_is_mi2s_master) {
+			mi2s_clk[index].clk_id = mi2s_ebit_clk[index];
+			fmt = SND_SOC_DAIFMT_CBM_CFM;
+		}
 		ret = msm_mi2s_set_sclk(substream, true);
 		if (ret < 0) {
 			dev_err(rtd->card->dev,
@@ -2122,21 +2499,6 @@
 				__func__, ret);
 			goto clean_up;
 		}
-		if (mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr != NULL) {
-			mutex_lock(&mi2s_auxpcm_conf[index].lock);
-			iowrite32(0,
-				mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr);
-			mutex_unlock(&mi2s_auxpcm_conf[index].lock);
-		} else {
-			dev_err(rtd->card->dev,
-				"%s lpaif_muxsel_virt_addr is NULL for dai %d\n",
-				__func__, index);
-			ret = -EINVAL;
-			goto clk_off;
-		}
-		/* Check if msm needs to provide the clock to the interface */
-		if (!mi2s_intf_conf[index].msm_is_mi2s_master)
-			fmt = SND_SOC_DAIFMT_CBM_CFM;
 		ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
 		if (ret < 0) {
 			dev_err(rtd->card->dev,
@@ -2144,7 +2506,21 @@
 				__func__, index, ret);
 			goto clk_off;
 		}
+		if (mi2s_intf_conf[index].msm_is_ext_mclk) {
+			mi2s_mclk[index].enable = 1;
+			pr_debug("%s: Enabling mclk, clk_freq_in_hz = %u\n",
+				__func__, mi2s_mclk[index].clk_freq_in_hz);
+			ret = afe_set_lpass_clock_v2(port_id,
+						     &mi2s_mclk[index]);
+			if (ret < 0) {
+				pr_err("%s: afe lpass mclk failed, err:%d\n",
+					__func__, ret);
+				goto clk_off;
+			}
+		}
 	}
+	mutex_unlock(&mi2s_intf_conf[index].lock);
+	return 0;
 clk_off:
 	if (ret < 0)
 		msm_mi2s_set_sclk(substream, false);
@@ -2166,6 +2542,7 @@
 {
 	int ret;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	int port_id = msm_get_port_id(rtd->dai_link->be_id);
 	int index = rtd->cpu_dai->id;
 
 	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
@@ -2183,6 +2560,17 @@
 				__func__, index, ret);
 			mi2s_intf_conf[index].ref_cnt++;
 		}
+		if (mi2s_intf_conf[index].msm_is_ext_mclk) {
+			mi2s_mclk[index].enable = 0;
+			pr_debug("%s: Disabling mclk, clk_freq_in_hz = %u\n",
+				 __func__, mi2s_mclk[index].clk_freq_in_hz);
+			ret = afe_set_lpass_clock_v2(port_id,
+						     &mi2s_mclk[index]);
+			if (ret < 0) {
+				pr_err("%s: mclk disable failed for MCLK (%d); ret=%d\n",
+					__func__, index, ret);
+			}
+		}
 	}
 	mutex_unlock(&mi2s_intf_conf[index].lock);
 }
@@ -2233,6 +2621,7 @@
 }
 
 static int msm_populate_dai_link_component_of_node(
+		struct msm_asoc_mach_data *pdata,
 		struct snd_soc_card *card)
 {
 	int i, index, ret = 0;
@@ -2312,6 +2701,31 @@
 			dai_link[i].codec_of_node = phandle;
 			dai_link[i].codec_name = NULL;
 		}
+		if (pdata->snd_card_val == INT_SND_CARD) {
+			if ((dai_link[i].be_id ==
+					MSM_BACKEND_DAI_INT0_MI2S_RX) ||
+			    (dai_link[i].be_id ==
+					MSM_BACKEND_DAI_INT1_MI2S_RX) ||
+			    (dai_link[i].be_id ==
+					MSM_BACKEND_DAI_INT2_MI2S_TX) ||
+			    (dai_link[i].be_id ==
+					MSM_BACKEND_DAI_INT3_MI2S_TX)) {
+				index = of_property_match_string(cdev->of_node,
+							"asoc-codec-names",
+							MSM_INT_DIGITAL_CODEC);
+				phandle = of_parse_phandle(cdev->of_node,
+							   "asoc-codec",
+							   index);
+				dai_link[i].codecs[DIG_CDC].of_node = phandle;
+				index = of_property_match_string(cdev->of_node,
+							"asoc-codec-names",
+							PMIC_INT_ANALOG_CODEC);
+				phandle = of_parse_phandle(cdev->of_node,
+							   "asoc-codec",
+							   index);
+				dai_link[i].codecs[ANA_CDC].of_node = phandle;
+			}
+		}
 	}
 err:
 	return ret;
@@ -2570,44 +2984,19 @@
 
 static void i2s_auxpcm_init(struct platform_device *pdev)
 {
-	struct resource *muxsel;
 	int count;
 	u32 mi2s_master_slave[MI2S_MAX];
+	u32 mi2s_ext_mclk[MI2S_MAX];
 	int ret;
-	char *str[PCM_I2S_SEL_MAX] = {
-		"lpaif_pri_mode_muxsel",
-		"lpaif_sec_mode_muxsel",
-		"lpaif_tert_mode_muxsel",
-		"lpaif_quat_mode_muxsel"
-	};
 
 	for (count = 0; count < MI2S_MAX; count++) {
 		mutex_init(&mi2s_intf_conf[count].lock);
 		mi2s_intf_conf[count].ref_cnt = 0;
 	}
 
-	for (count = 0; count < AUX_PCM_MAX; count++) {
-		mutex_init(&auxpcm_intf_conf[count].lock);
-		auxpcm_intf_conf[count].ref_cnt = 0;
-	}
-
-	for (count = 0; count < PCM_I2S_SEL_MAX; count++) {
-		mutex_init(&mi2s_auxpcm_conf[count].lock);
-		mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr = NULL;
-	}
-
-	for (count = 0; count < PCM_I2S_SEL_MAX; count++) {
-		muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-						      str[count]);
-		if (muxsel) {
-			mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr
-				= ioremap(muxsel->start, resource_size(muxsel));
-		}
-	}
-
 	ret = of_property_read_u32_array(pdev->dev.of_node,
-			"qcom,msm-mi2s-master",
-			mi2s_master_slave, MI2S_MAX);
+					 "qcom,msm-mi2s-master",
+					 mi2s_master_slave, MI2S_MAX);
 	if (ret) {
 		dev_dbg(&pdev->dev, "%s: no qcom,msm-mi2s-master in DT node\n",
 			__func__);
@@ -2617,25 +3006,26 @@
 				mi2s_master_slave[count];
 		}
 	}
+
+	ret = of_property_read_u32_array(pdev->dev.of_node,
+					 "qcom,msm-mi2s-ext-mclk",
+					 mi2s_ext_mclk, MI2S_MAX);
+	if (ret) {
+		dev_dbg(&pdev->dev, "%s: no qcom,msm-mi2s-ext-mclk in DT node\n",
+			__func__);
+	} else {
+		for (count = 0; count < MI2S_MAX; count++)
+			mi2s_intf_conf[count].msm_is_ext_mclk =
+				mi2s_ext_mclk[count];
+	}
 }
 
-static void i2s_auxpcm_deinit(void)
-{
-	int count;
-
-	for (count = 0; count < PCM_I2S_SEL_MAX; count++)
-		if (mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr !=
-			NULL)
-			iounmap(
-			mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr);
-}
-
-static const struct of_device_id msmfalcon_asoc_machine_of_match[]  = {
-	{ .compatible = "qcom,msmfalcon-asoc-snd",
+static const struct of_device_id sdm660_asoc_machine_of_match[]  = {
+	{ .compatible = "qcom,sdm660-asoc-snd",
 	  .data = "internal_codec"},
-	{ .compatible = "qcom,msmfalcon-asoc-snd-tasha",
+	{ .compatible = "qcom,sdm660-asoc-snd-tasha",
 	  .data = "tasha_codec"},
-	{ .compatible = "qcom,msmfalcon-asoc-snd-tavil",
+	{ .compatible = "qcom,sdm660-asoc-snd-tavil",
 	  .data = "tavil_codec"},
 	{},
 };
@@ -2654,7 +3044,7 @@
 	if (!pdata)
 		return -ENOMEM;
 
-	match = of_match_node(msmfalcon_asoc_machine_of_match,
+	match = of_match_node(sdm660_asoc_machine_of_match,
 			      pdev->dev.of_node);
 	if (!match)
 		goto err;
@@ -2691,13 +3081,14 @@
 
 	if (pdata->snd_card_val == INT_SND_CARD) {
 		/*reading the gpio configurations from dtsi file*/
-		ret = msm_gpioset_initialize(CLIENT_WCD, &pdev->dev);
-		if (ret < 0) {
-			dev_err(&pdev->dev,
-				"%s: error reading dtsi files%d\n",
-				__func__, ret);
-			goto err;
-		}
+		pdata->pdm_gpio_p = of_parse_phandle(pdev->dev.of_node,
+					"qcom,cdc-pdm-gpios", 0);
+		pdata->comp_gpio_p = of_parse_phandle(pdev->dev.of_node,
+					"qcom,cdc-comp-gpios", 0);
+		pdata->dmic_gpio_p = of_parse_phandle(pdev->dev.of_node,
+					"qcom,cdc-dmic-gpios", 0);
+		pdata->ext_spk_gpio_p = of_parse_phandle(pdev->dev.of_node,
+					"qcom,cdc-ext-spk-gpios", 0);
 	}
 
 	/*
@@ -2730,22 +3121,37 @@
 	if (ret)
 		goto err;
 
-	ret = msm_populate_dai_link_component_of_node(card);
+	ret = msm_populate_dai_link_component_of_node(pdata, card);
 	if (ret) {
 		ret = -EPROBE_DEFER;
 		goto err;
 	}
-	ret = msm_init_wsa_dev(pdev, card);
-	if (ret)
-		goto err;
 
+	if (!of_property_read_bool(pdev->dev.of_node, "qcom,wsa-disable")) {
+		ret = msm_init_wsa_dev(pdev, card);
+		if (ret)
+			goto err;
+	}
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
-	if (ret) {
+	if (ret == -EPROBE_DEFER) {
+		if (codec_reg_done) {
+			/*
+			 * return failure as EINVAL since other codec
+			 * registered sound card successfully.
+			 * This avoids any further probe calls.
+			 */
+			ret = -EINVAL;
+		}
+		goto err;
+	} else if (ret) {
 		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
 			ret);
 		goto err;
 	}
+	if (pdata->snd_card_val != INT_SND_CARD)
+		msm_ext_register_audio_notifier(pdev);
+
 	return 0;
 err:
 	if (pdata->us_euro_gpio > 0) {
@@ -2765,6 +3171,8 @@
 		gpio_free(pdata->hph_en0_gpio);
 		pdata->hph_en0_gpio = 0;
 	}
+	if (pdata->snd_card_val != INT_SND_CARD)
+		msm_ext_cdc_deinit(pdata);
 	devm_kfree(&pdev->dev, pdata);
 	return ret;
 }
@@ -2776,29 +3184,30 @@
 
 	if (pdata->snd_card_val == INT_SND_CARD)
 		mutex_destroy(&pdata->cdc_int_mclk0_mutex);
+	else
+		msm_ext_cdc_deinit(pdata);
 	msm_free_auxdev_mem(pdev);
 
 	gpio_free(pdata->us_euro_gpio);
 	gpio_free(pdata->hph_en1_gpio);
 	gpio_free(pdata->hph_en0_gpio);
-	i2s_auxpcm_deinit();
 	snd_soc_unregister_card(card);
 	return 0;
 }
 
-static struct platform_driver msmfalcon_asoc_machine_driver = {
+static struct platform_driver sdm660_asoc_machine_driver = {
 	.driver = {
 		.name = DRV_NAME,
 		.owner = THIS_MODULE,
 		.pm = &snd_soc_pm_ops,
-		.of_match_table = msmfalcon_asoc_machine_of_match,
+		.of_match_table = sdm660_asoc_machine_of_match,
 	},
 	.probe = msm_asoc_machine_probe,
 	.remove = msm_asoc_machine_remove,
 };
-module_platform_driver(msmfalcon_asoc_machine_driver);
+module_platform_driver(sdm660_asoc_machine_driver);
 
 MODULE_DESCRIPTION("ALSA SoC msm");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_DEVICE_TABLE(of, msmfalcon_asoc_machine_of_match);
+MODULE_DEVICE_TABLE(of, sdm660_asoc_machine_of_match);
diff --git a/sound/soc/msm/msmfalcon-common.h b/sound/soc/msm/sdm660-common.h
similarity index 78%
rename from sound/soc/msm/msmfalcon-common.h
rename to sound/soc/msm/sdm660-common.h
index 5f6b859..bca8cd7 100644
--- a/sound/soc/msm/msmfalcon-common.h
+++ b/sound/soc/msm/sdm660-common.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
@@ -59,8 +59,15 @@
 	u32 channel;
 };
 
+enum {
+	DIG_CDC,
+	ANA_CDC,
+	CODECS_MAX,
+};
+
 extern const struct snd_kcontrol_new msm_common_snd_controls[];
-struct msmfalcon_codec {
+extern bool codec_reg_done;
+struct sdm660_codec {
 	void* (*get_afe_config_fn)(struct snd_soc_codec *codec,
 				   enum afe_config_type config_type);
 };
@@ -71,6 +78,14 @@
 	EXT_SND_CARD_TAVIL,
 };
 
+struct msm_snd_interrupt {
+	void __iomem *mpm_wakeup;
+	void __iomem *intr1_cfg_apps;
+	void __iomem *lpi_gpio_intr_cfg;
+	void __iomem *lpi_gpio_cfg;
+	void __iomem *lpi_gpio_inout;
+};
+
 struct msm_asoc_mach_data {
 	int us_euro_gpio; /* used by gpio driver API */
 	int hph_en1_gpio;
@@ -78,11 +93,16 @@
 	struct device_node *us_euro_gpio_p; /* used by pinctrl API */
 	struct device_node *hph_en1_gpio_p; /* used by pinctrl API */
 	struct device_node *hph_en0_gpio_p; /* used by pinctrl API */
+	struct device_node *pdm_gpio_p; /* used by pinctrl API */
+	struct device_node *comp_gpio_p; /* used by pinctrl API */
+	struct device_node *dmic_gpio_p; /* used by pinctrl API */
+	struct device_node *ext_spk_gpio_p; /* used by pinctrl API */
 	struct snd_soc_codec *codec;
-	struct msmfalcon_codec msmfalcon_codec_fn;
+	struct sdm660_codec sdm660_codec_fn;
 	struct snd_info_entry *codec_root;
 	int spk_ext_pa_gpio;
 	int mclk_freq;
+	bool native_clk_set;
 	int lb_mode;
 	int snd_card_val;
 	u8 micbias1_cap_mode;
@@ -92,6 +112,7 @@
 	struct mutex cdc_int_mclk0_mutex;
 	struct delayed_work disable_int_mclk0_work;
 	struct afe_clk_set digital_cdc_core_clk;
+	struct msm_snd_interrupt msm_snd_intr_lpi;
 };
 
 int msm_common_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -100,4 +121,5 @@
 void msm_aux_pcm_snd_shutdown(struct snd_pcm_substream *substream);
 int msm_mi2s_snd_startup(struct snd_pcm_substream *substream);
 void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream);
+int msm_common_snd_controls_size(void);
 #endif
diff --git a/sound/soc/msm/msmfalcon-ext-dai-links.c b/sound/soc/msm/sdm660-ext-dai-links.c
similarity index 95%
rename from sound/soc/msm/msmfalcon-ext-dai-links.c
rename to sound/soc/msm/sdm660-ext-dai-links.c
index 6f066c5..f64074d 100644
--- a/sound/soc/msm/msmfalcon-ext-dai-links.c
+++ b/sound/soc/msm/sdm660-ext-dai-links.c
@@ -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
@@ -19,11 +19,11 @@
 #include <sound/pcm_params.h>
 #include "qdsp6v2/msm-pcm-routing-v2.h"
 #include "../codecs/wcd9335.h"
-#include "msmfalcon-common.h"
-#include "msmfalcon-external.h"
+#include "sdm660-common.h"
+#include "sdm660-external.h"
 
 #define DEV_NAME_STR_LEN            32
-#define __CHIPSET__ "MSMFALCON "
+#define __CHIPSET__ "SDM660 "
 #define MSM_DAILINK_NAME(name) (__CHIPSET__#name)
 
 #define WCN_CDC_SLIM_RX_CH_MAX 2
@@ -861,6 +861,7 @@
 		.stream_name = "Compress1",
 		.cpu_dai_name	= "MultiMedia4",
 		.platform_name  = "msm-compress-dsp",
+		.async_ops = ASYNC_DPCM_SND_SOC_HW_PARAMS,
 		.dynamic = 1,
 		.dpcm_capture = 1,
 		.dpcm_playback = 1,
@@ -1301,6 +1302,39 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
+	{/* hw:x,35 */
+		.name = "SLIMBUS7 Hostless",
+		.stream_name = "SLIMBUS7 Hostless",
+		.cpu_dai_name = "SLIMBUS7_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",
+	},
+	{/* hw:x,36 */
+		.name = "SDM660 HFP TX",
+		.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,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+	},
 };
 
 static struct snd_soc_dai_link msm_ext_common_be_dai[] = {
@@ -1827,6 +1861,24 @@
 	},
 };
 
+static struct snd_soc_dai_link ext_disp_be_dai_link[] = {
+	/* DISP PORT BACK END DAI Link */
+	{
+		.name = LPASS_BE_DISPLAY_PORT,
+		.stream_name = "Display Port Playback",
+		.cpu_dai_name = "msm-dai-q6-dp.24608",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-ext-disp-audio-codec-rx",
+		.codec_dai_name = "msm_dp_audio_codec_rx_dai",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.be_id = MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+		.be_hw_params_fixup = msm_common_be_hw_params_fixup,
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+};
+
 static struct snd_soc_dai_link msm_ext_tasha_dai_links[
 ARRAY_SIZE(msm_ext_common_fe_dai) +
 ARRAY_SIZE(msm_ext_tasha_fe_dai) +
@@ -1834,7 +1886,8 @@
 ARRAY_SIZE(msm_ext_tasha_be_dai) +
 ARRAY_SIZE(msm_mi2s_be_dai_links) +
 ARRAY_SIZE(msm_auxpcm_be_dai_links) +
-ARRAY_SIZE(msm_wcn_be_dai_links)];
+ARRAY_SIZE(msm_wcn_be_dai_links) +
+ARRAY_SIZE(ext_disp_be_dai_link)];
 
 static struct snd_soc_dai_link msm_ext_tavil_dai_links[
 ARRAY_SIZE(msm_ext_common_fe_dai) +
@@ -1843,7 +1896,8 @@
 ARRAY_SIZE(msm_ext_tavil_be_dai) +
 ARRAY_SIZE(msm_mi2s_be_dai_links) +
 ARRAY_SIZE(msm_auxpcm_be_dai_links) +
-ARRAY_SIZE(msm_wcn_be_dai_links)];
+ARRAY_SIZE(msm_wcn_be_dai_links) +
+ARRAY_SIZE(ext_disp_be_dai_link)];
 
 /**
  * populate_snd_card_dailinks - prepares dailink array and initializes card.
@@ -1881,7 +1935,7 @@
 	if (strnstr(card->name, "tasha", strlen(card->name))) {
 		codec_ver = tasha_codec_ver();
 		if (codec_ver == WCD9326)
-			card->name = "msmfalcon-tashalite-snd-card";
+			card->name = "sdm660-tashalite-snd-card";
 
 		len1 = ARRAY_SIZE(msm_ext_common_fe_dai);
 		len2 = len1 + ARRAY_SIZE(msm_ext_tasha_fe_dai);
@@ -1917,6 +1971,15 @@
 				   sizeof(msm_wcn_be_dai_links));
 			len4 += ARRAY_SIZE(msm_wcn_be_dai_links);
 		}
+		if (of_property_read_bool(dev->of_node,
+					  "qcom,ext-disp-audio-rx")) {
+			dev_dbg(dev, "%s(): ext disp audio support present\n",
+					__func__);
+			memcpy(msm_ext_tasha_dai_links + len4,
+				ext_disp_be_dai_link,
+				sizeof(ext_disp_be_dai_link));
+			len4 += ARRAY_SIZE(ext_disp_be_dai_link);
+		}
 		msm_ext_dai_links = msm_ext_tasha_dai_links;
 	} else if (strnstr(card->name, "tavil", strlen(card->name))) {
 		len1 = ARRAY_SIZE(msm_ext_common_fe_dai);
@@ -1953,6 +2016,15 @@
 				   sizeof(msm_wcn_be_dai_links));
 			len4 += ARRAY_SIZE(msm_wcn_be_dai_links);
 		}
+		if (of_property_read_bool(dev->of_node,
+					  "qcom,ext-disp-audio-rx")) {
+			dev_dbg(dev, "%s(): ext disp audio support present\n",
+					__func__);
+			memcpy(msm_ext_tavil_dai_links + len4,
+				ext_disp_be_dai_link,
+				sizeof(ext_disp_be_dai_link));
+			len4 += ARRAY_SIZE(ext_disp_be_dai_link);
+		}
 		msm_ext_dai_links = msm_ext_tavil_dai_links;
 	} else {
 		dev_err(dev, "%s: failing as no matching card name\n",
diff --git a/sound/soc/msm/msmfalcon-external.c b/sound/soc/msm/sdm660-external.c
similarity index 91%
rename from sound/soc/msm/msmfalcon-external.c
rename to sound/soc/msm/sdm660-external.c
index d7b002e..b603b8a 100644
--- a/sound/soc/msm/msmfalcon-external.c
+++ b/sound/soc/msm/sdm660-external.c
@@ -21,25 +21,42 @@
 #include <linux/qdsp6v2/audio_notifier.h>
 #include "qdsp6v2/msm-pcm-routing-v2.h"
 #include "msm-audio-pinctrl.h"
-#include "msmfalcon-common.h"
-#include "msmfalcon-external.h"
+#include "sdm660-common.h"
+#include "sdm660-external.h"
 #include "../codecs/wcd9335.h"
 #include "../codecs/wcd934x/wcd934x.h"
 #include "../codecs/wcd934x/wcd934x-mbhc.h"
 
-#define MSMFALCON_SPK_ON     1
-#define MSMFALCON_SPK_OFF    0
+#define SDM660_SPK_ON     1
+#define SDM660_SPK_OFF    0
 
 #define WCD9XXX_MBHC_DEF_BUTTONS    8
 #define WCD9XXX_MBHC_DEF_RLOADS     5
 #define CODEC_EXT_CLK_RATE          9600000
 #define ADSP_STATE_READY_TIMEOUT_MS 3000
 
+#define TLMM_CENTER_MPM_WAKEUP_INT_EN_0 0x03596000
+#define LPI_GPIO_22_WAKEUP_VAL 0x00000002
+
+#define TLMM_LPI_DIR_CONN_INTR1_CFG_APPS 0x0359D004
+#define LPI_GPIO_22_INTR1_CFG_VAL 0x01
+#define LPI_GPIO_22_INTR1_CFG_MASK 0x03
+
+#define TLMM_LPI_GPIO_INTR_CFG1  0x0359B004
+#define LPI_GPIO_INTR_CFG1_VAL 0x00000113
+
+#define TLMM_LPI_GPIO22_CFG  0x15078040
+#define LPI_GPIO22_CFG_VAL 0x0000009
+
+#define TLMM_LPI_GPIO22_INOUT  0x179D1318
+#define LPI_GPIO22_INOUT_VAL 0x0020000
+
 #define WSA8810_NAME_1 "wsa881x.20170211"
 #define WSA8810_NAME_2 "wsa881x.20170212"
 
 static int msm_ext_spk_control = 1;
 static struct wcd_mbhc_config *wcd_mbhc_cfg_ptr;
+bool codec_reg_done;
 
 struct msm_asoc_wcd93xx_codec {
 	void* (*get_afe_config_fn)(struct snd_soc_codec *codec,
@@ -637,7 +654,7 @@
 			snd_soc_codec_get_dapm(codec);
 
 	pr_debug("%s: msm_ext_spk_control = %d", __func__, msm_ext_spk_control);
-	if (msm_ext_spk_control == MSMFALCON_SPK_ON) {
+	if (msm_ext_spk_control == SDM660_SPK_ON) {
 		snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
 		snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
 	} else {
@@ -659,7 +676,7 @@
 static int msm_ext_set_spk(struct snd_kcontrol *kcontrol,
 			   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 
 	pr_debug("%s()\n", __func__);
 	if (msm_ext_spk_control == ucontrol->value.integer.value[0])
@@ -1193,12 +1210,37 @@
 	afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
 }
 
+static void msm_snd_interrupt_config(struct msm_asoc_mach_data *pdata)
+{
+	int val;
+
+	val = ioread32(pdata->msm_snd_intr_lpi.mpm_wakeup);
+	val |= LPI_GPIO_22_WAKEUP_VAL;
+	iowrite32(val, pdata->msm_snd_intr_lpi.mpm_wakeup);
+
+	val = ioread32(pdata->msm_snd_intr_lpi.intr1_cfg_apps);
+	val &= ~(LPI_GPIO_22_INTR1_CFG_MASK);
+	val |= LPI_GPIO_22_INTR1_CFG_VAL;
+	iowrite32(val, pdata->msm_snd_intr_lpi.intr1_cfg_apps);
+
+	iowrite32(LPI_GPIO_INTR_CFG1_VAL,
+			pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg);
+	iowrite32(LPI_GPIO22_CFG_VAL,
+			pdata->msm_snd_intr_lpi.lpi_gpio_cfg);
+	val = ioread32(pdata->msm_snd_intr_lpi.lpi_gpio_inout);
+	val |= LPI_GPIO22_INOUT_VAL;
+	iowrite32(val, pdata->msm_snd_intr_lpi.lpi_gpio_inout);
+}
+
 static int msm_adsp_power_up_config(struct snd_soc_codec *codec)
 {
 	int ret = 0;
 	unsigned long timeout;
 	int adsp_ready = 0;
+	struct snd_soc_card *card = codec->component.card;
+	struct msm_asoc_mach_data *pdata;
 
+	pdata = snd_soc_card_get_drvdata(card);
 	timeout = jiffies +
 		msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
 
@@ -1221,6 +1263,7 @@
 		ret = -ETIMEDOUT;
 		goto err_fail;
 	}
+	msm_snd_interrupt_config(pdata);
 
 	ret = msm_afe_set_config(codec);
 	if (ret)
@@ -1233,7 +1276,7 @@
 	return ret;
 }
 
-static int msmfalcon_notifier_service_cb(struct notifier_block *this,
+static int sdm660_notifier_service_cb(struct notifier_block *this,
 					 unsigned long opcode, void *ptr)
 {
 	int ret;
@@ -1291,7 +1334,7 @@
 }
 
 static struct notifier_block service_nb = {
-	.notifier_call  = msmfalcon_notifier_service_cb,
+	.notifier_call  = sdm660_notifier_service_cb,
 	.priority = -INT_MAX,
 };
 
@@ -1469,6 +1512,17 @@
 					     134, 135, 136, 137, 138, 139,
 					     140, 141, 142, 143};
 
+	/* Tavil Codec SLIMBUS configuration
+	 * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8
+	 * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+	 * TX14, TX15, TX16
+	 */
+	unsigned int rx_ch_tavil[WCD934X_RX_MAX] = {144, 145, 146, 147, 148,
+					    149, 150, 151};
+	unsigned int tx_ch_tavil[WCD934X_TX_MAX] = {128, 129, 130, 131, 132,
+					    133, 134, 135, 136, 137, 138,
+					    139, 140, 141, 142, 143};
+
 	pr_debug("%s: dev_name%s\n", __func__, dev_name(cpu_dai->dev));
 
 	rtd->pmdown_time = 0;
@@ -1481,6 +1535,14 @@
 		return ret;
 	}
 
+	ret = snd_soc_add_codec_controls(codec, msm_common_snd_controls,
+					 msm_common_snd_controls_size());
+	if (ret < 0) {
+		pr_err("%s: add_common_snd_controls failed: %d\n",
+			__func__, ret);
+		return ret;
+	}
+
 	snd_soc_dapm_new_controls(dapm, msm_dapm_widgets,
 			ARRAY_SIZE(msm_dapm_widgets));
 
@@ -1521,14 +1583,11 @@
 	snd_soc_dapm_ignore_suspend(dapm, "EAR");
 	snd_soc_dapm_ignore_suspend(dapm, "LINEOUT1");
 	snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2");
-	snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3");
-	snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4");
 	snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
 	snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
 	snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
 	snd_soc_dapm_ignore_suspend(dapm, "AMIC4");
 	snd_soc_dapm_ignore_suspend(dapm, "AMIC5");
-	snd_soc_dapm_ignore_suspend(dapm, "AMIC6");
 	snd_soc_dapm_ignore_suspend(dapm, "DMIC0");
 	snd_soc_dapm_ignore_suspend(dapm, "DMIC1");
 	snd_soc_dapm_ignore_suspend(dapm, "DMIC2");
@@ -1536,21 +1595,33 @@
 	snd_soc_dapm_ignore_suspend(dapm, "DMIC4");
 	snd_soc_dapm_ignore_suspend(dapm, "DMIC5");
 	snd_soc_dapm_ignore_suspend(dapm, "ANC EAR");
-	snd_soc_dapm_ignore_suspend(dapm, "ANC HEADPHONE");
 	snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT");
 	snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT");
 	snd_soc_dapm_ignore_suspend(dapm, "HPHL");
 	snd_soc_dapm_ignore_suspend(dapm, "HPHR");
-	snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL");
-	snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
-	snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1");
-	snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2");
 	snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI");
 	snd_soc_dapm_ignore_suspend(dapm, "VIINPUT");
 
+	if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) {
+		snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3");
+		snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4");
+		snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL");
+		snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
+		snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1");
+		snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2");
+	}
+
 	snd_soc_dapm_sync(dapm);
-	snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
-				    tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
+	if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
+		snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch_tavil),
+					tx_ch_tavil, ARRAY_SIZE(rx_ch_tavil),
+					rx_ch_tavil);
+	} else {
+		snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+					tx_ch, ARRAY_SIZE(rx_ch),
+					rx_ch);
+	}
 
 	if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
 		msm_codec_fn.get_afe_config_fn = tavil_get_afe_config;
@@ -1674,6 +1745,7 @@
 		}
 
 	}
+	codec_reg_done = true;
 done:
 	return 0;
 
@@ -1687,11 +1759,13 @@
 /**
  * msm_ext_register_audio_notifier - register SSR notifier.
  */
-void msm_ext_register_audio_notifier(void)
+void msm_ext_register_audio_notifier(struct platform_device *pdev)
 {
 	int ret;
 
-	ret = audio_notifier_register("msmfalcon", AUDIO_NOTIFIER_ADSP_DOMAIN,
+	is_initial_boot = true;
+	spdev = pdev;
+	ret = audio_notifier_register("sdm660", AUDIO_NOTIFIER_ADSP_DOMAIN,
 				      &service_nb);
 	if (ret < 0)
 		pr_err("%s: Audio notifier register failed ret = %d\n",
@@ -1729,10 +1803,8 @@
 		ret = -EPROBE_DEFER;
 		goto err;
 	}
-	spdev = pdev;
 	platform_set_drvdata(pdev, *card);
 	snd_soc_card_set_drvdata(*card, pdata);
-	is_initial_boot = true;
 	pdata->hph_en1_gpio = of_get_named_gpio(pdev->dev.of_node,
 						"qcom,hph-en1-gpio", 0);
 	if (!gpio_is_valid(pdata->hph_en1_gpio))
@@ -1759,7 +1831,36 @@
 			ret);
 		ret = 0;
 	}
+	pdata->msm_snd_intr_lpi.mpm_wakeup =
+			ioremap(TLMM_CENTER_MPM_WAKEUP_INT_EN_0, 4);
+	pdata->msm_snd_intr_lpi.intr1_cfg_apps =
+			ioremap(TLMM_LPI_DIR_CONN_INTR1_CFG_APPS, 4);
+	pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg =
+			ioremap(TLMM_LPI_GPIO_INTR_CFG1, 4);
+	pdata->msm_snd_intr_lpi.lpi_gpio_cfg =
+			ioremap(TLMM_LPI_GPIO22_CFG, 4);
+	pdata->msm_snd_intr_lpi.lpi_gpio_inout =
+			ioremap(TLMM_LPI_GPIO22_INOUT, 4);
 err:
 	return ret;
 }
 EXPORT_SYMBOL(msm_ext_cdc_init);
+
+/**
+ * msm_ext_cdc_deinit - external codec machine specific deinit.
+ */
+void msm_ext_cdc_deinit(struct msm_asoc_mach_data *pdata)
+{
+	if (pdata->msm_snd_intr_lpi.mpm_wakeup)
+		iounmap(pdata->msm_snd_intr_lpi.mpm_wakeup);
+	if (pdata->msm_snd_intr_lpi.intr1_cfg_apps)
+		iounmap(pdata->msm_snd_intr_lpi.intr1_cfg_apps);
+	if (pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg)
+		iounmap(pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg);
+	if (pdata->msm_snd_intr_lpi.lpi_gpio_cfg)
+		iounmap(pdata->msm_snd_intr_lpi.lpi_gpio_cfg);
+	if (pdata->msm_snd_intr_lpi.lpi_gpio_inout)
+		iounmap(pdata->msm_snd_intr_lpi.lpi_gpio_inout);
+
+}
+EXPORT_SYMBOL(msm_ext_cdc_deinit);
diff --git a/sound/soc/msm/msmfalcon-external.h b/sound/soc/msm/sdm660-external.h
similarity index 83%
rename from sound/soc/msm/msmfalcon-external.h
rename to sound/soc/msm/sdm660-external.h
index 654cb70..acf5735 100644
--- a/sound/soc/msm/msmfalcon-external.h
+++ b/sound/soc/msm/sdm660-external.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
@@ -10,8 +10,8 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __MSMFALCON_EXTERNAL
-#define __MSMFALCON_EXTERNAL
+#ifndef __SDM660_EXTERNAL
+#define __SDM660_EXTERNAL
 
 int msm_snd_hw_params(struct snd_pcm_substream *substream,
 		      struct snd_pcm_hw_params *params);
@@ -33,7 +33,8 @@
 #ifdef CONFIG_SND_SOC_EXT_CODEC
 int msm_ext_cdc_init(struct platform_device *, struct msm_asoc_mach_data *,
 		     struct snd_soc_card **, struct wcd_mbhc_config *);
-void msm_ext_register_audio_notifier(void);
+void msm_ext_register_audio_notifier(struct platform_device *pdev);
+void msm_ext_cdc_deinit(struct msm_asoc_mach_data *pdata);
 #else
 inline int msm_ext_cdc_init(struct platform_device *pdev,
 			    struct msm_asoc_mach_data *pdata,
@@ -43,7 +44,10 @@
 	return 0;
 }
 
-inline void msm_ext_register_audio_notifier(void)
+inline void msm_ext_register_audio_notifier(struct platform_device *pdev)
+{
+}
+inline void msm_ext_cdc_deinit(void)
 {
 }
 #endif
diff --git a/sound/soc/msm/msmfalcon-internal.c b/sound/soc/msm/sdm660-internal.c
similarity index 90%
rename from sound/soc/msm/msmfalcon-internal.c
rename to sound/soc/msm/sdm660-internal.c
index 50efd69..b924cad 100644
--- a/sound/soc/msm/msmfalcon-internal.c
+++ b/sound/soc/msm/sdm660-internal.c
@@ -13,13 +13,15 @@
 #include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
+#include <linux/mfd/msm-cdc-pinctrl.h>
 #include <sound/pcm_params.h>
 #include "qdsp6v2/msm-pcm-routing-v2.h"
-#include "msm-audio-pinctrl.h"
-#include "msmfalcon-common.h"
-#include "../codecs/msm8x16/msm8x16-wcd.h"
+#include "sdm660-common.h"
+#include "../codecs/sdm660_cdc/msm-digital-cdc.h"
+#include "../codecs/sdm660_cdc/msm-analog-cdc.h"
+#include "../codecs/msm_sdw/msm_sdw.h"
 
-#define __CHIPSET__ "MSMFALCON "
+#define __CHIPSET__ "SDM660 "
 #define MSM_DAILINK_NAME(name) (__CHIPSET__#name)
 
 #define DEFAULT_MCLK_RATE 9600000
@@ -30,6 +32,9 @@
 #define WCN_CDC_SLIM_RX_CH_MAX 2
 #define WCN_CDC_SLIM_TX_CH_MAX 3
 
+#define WSA8810_NAME_1 "wsa881x.20170211"
+#define WSA8810_NAME_2 "wsa881x.20170212"
+
 enum {
 	INT0_MI2S = 0,
 	INT1_MI2S,
@@ -131,7 +136,7 @@
 	[INT2_MI2S]  = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
 	[INT3_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
 	[INT4_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
-	[INT5_MI2S] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+	[INT5_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
 	[INT6_MI2S] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
 };
 
@@ -176,6 +181,7 @@
 static void msm_int_mi2s_snd_shutdown(struct snd_pcm_substream *substream);
 
 static struct wcd_mbhc_config *mbhc_cfg_ptr;
+static struct snd_info_entry *codec_root;
 
 static int int_mi2s_get_bit_format_val(int bit_format)
 {
@@ -443,22 +449,25 @@
 	SND_SOC_DAPM_MIC("Digital Mic4", msm_dmic_event),
 };
 
-static int msm_config_hph_compander_gpio(bool enable)
+static int msm_config_hph_compander_gpio(bool enable,
+					 struct snd_soc_codec *codec)
 {
+	struct snd_soc_card *card = codec->component.card;
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
 	int ret = 0;
 
 	pr_debug("%s: %s HPH Compander\n", __func__,
 		enable ? "Enable" : "Disable");
 
 	if (enable) {
-		ret = msm_gpioset_activate(CLIENT_WCD, "comp_gpio");
+		ret = msm_cdc_pinctrl_select_active_state(pdata->comp_gpio_p);
 		if (ret) {
 			pr_err("%s: gpio set cannot be activated %s\n",
 				__func__, "comp_gpio");
 			goto done;
 		}
 	} else {
-		ret = msm_gpioset_suspend(CLIENT_WCD, "comp_gpio");
+		ret = msm_cdc_pinctrl_select_sleep_state(pdata->comp_gpio_p);
 		if (ret) {
 			pr_err("%s: gpio set cannot be de-activated %s\n",
 				__func__, "comp_gpio");
@@ -509,7 +518,8 @@
 		enable ? "Enable" : "Disable");
 
 	if (enable) {
-		ret = msm_gpioset_activate(CLIENT_WCD, "ext_spk_gpio");
+		ret = msm_cdc_pinctrl_select_active_state(
+						pdata->ext_spk_gpio_p);
 		if (ret) {
 			pr_err("%s: gpio set cannot be de-activated %s\n",
 					__func__, "ext_spk_gpio");
@@ -518,7 +528,8 @@
 		gpio_set_value_cansleep(pdata->spk_ext_pa_gpio, enable);
 	} else {
 		gpio_set_value_cansleep(pdata->spk_ext_pa_gpio, enable);
-		ret = msm_gpioset_suspend(CLIENT_WCD, "ext_spk_gpio");
+		ret = msm_cdc_pinctrl_select_sleep_state(
+						pdata->ext_spk_gpio_p);
 		if (ret) {
 			pr_err("%s: gpio set cannot be de-activated %s\n",
 					__func__, "ext_spk_gpio");
@@ -672,10 +683,13 @@
 		   atomic_read(&pdata->int_mclk0_rsc_ref));
 	if (enable) {
 		if (int_mi2s_cfg[INT0_MI2S].sample_rate ==
-				SAMPLING_RATE_44P1KHZ)
+				SAMPLING_RATE_44P1KHZ) {
 			clk_freq_in_hz = NATIVE_MCLK_RATE;
-		else
+			pdata->native_clk_set = true;
+		} else {
 			clk_freq_in_hz = pdata->mclk_freq;
+			pdata->native_clk_set = false;
+		}
 
 		if (pdata->digital_cdc_core_clk.clk_freq_in_hz
 				!= clk_freq_in_hz)
@@ -687,6 +701,12 @@
 			mutex_lock(&pdata->cdc_int_mclk0_mutex);
 			if (atomic_read(&pdata->int_mclk0_enabled) == false ||
 				int_mclk0_freq_chg) {
+				if (atomic_read(&pdata->int_mclk0_enabled)) {
+					pdata->digital_cdc_core_clk.enable = 0;
+					afe_set_lpass_clock_v2(
+						AFE_PORT_ID_INT0_MI2S_RX,
+						&pdata->digital_cdc_core_clk);
+				}
 				pdata->digital_cdc_core_clk.clk_freq_in_hz =
 							clk_freq_in_hz;
 				pdata->digital_cdc_core_clk.enable = 1;
@@ -744,7 +764,7 @@
 			ucontrol->value.integer.value[0]);
 	switch (ucontrol->value.integer.value[0]) {
 	case 1:
-		ret = msm_gpioset_activate(CLIENT_WCD, "int_pdm");
+		ret = msm_cdc_pinctrl_select_active_state(pdata->pdm_gpio_p);
 		if (ret) {
 			pr_err("%s: failed to enable the pri gpios: %d\n",
 					__func__, ret);
@@ -761,8 +781,8 @@
 				pr_err("%s: failed to enable the MCLK: %d\n",
 						__func__, ret);
 				mutex_unlock(&pdata->cdc_int_mclk0_mutex);
-				ret = msm_gpioset_suspend(CLIENT_WCD,
-								"int_pdm");
+				ret = msm_cdc_pinctrl_select_sleep_state(
+							pdata->pdm_gpio_p);
 				if (ret)
 					pr_err("%s: failed to disable the pri gpios: %d\n",
 							__func__, ret);
@@ -772,12 +792,12 @@
 		}
 		mutex_unlock(&pdata->cdc_int_mclk0_mutex);
 		atomic_inc(&pdata->int_mclk0_rsc_ref);
-		msm8x16_wcd_mclk_enable(codec, 1, true);
+		msm_anlg_cdc_mclk_enable(codec, 1, true);
 		break;
 	case 0:
 		if (atomic_read(&pdata->int_mclk0_rsc_ref) <= 0)
 			break;
-		msm8x16_wcd_mclk_enable(codec, 0, true);
+		msm_anlg_cdc_mclk_enable(codec, 0, true);
 		mutex_lock(&pdata->cdc_int_mclk0_mutex);
 		if ((!atomic_dec_return(&pdata->int_mclk0_rsc_ref)) &&
 				(atomic_read(&pdata->int_mclk0_enabled))) {
@@ -794,7 +814,7 @@
 			atomic_set(&pdata->int_mclk0_enabled, false);
 		}
 		mutex_unlock(&pdata->cdc_int_mclk0_mutex);
-		ret = msm_gpioset_suspend(CLIENT_WCD, "int_pdm");
+		ret = msm_cdc_pinctrl_select_sleep_state(pdata->pdm_gpio_p);
 		if (ret)
 			pr_err("%s: failed to disable the pri gpios: %d\n",
 					__func__, ret);
@@ -871,15 +891,6 @@
 	SOC_ENUM_EXT("INT3_MI2S_TX SampleRate", int3_mi2s_tx_sample_rate,
 			int_mi2s_sample_rate_get,
 			int_mi2s_sample_rate_put),
-	SOC_ENUM_EXT("INT0_MI2S_RX SampleRate", int0_mi2s_rx_sample_rate,
-			int_mi2s_sample_rate_get,
-			int_mi2s_sample_rate_put),
-	SOC_ENUM_EXT("INT2_MI2S_TX SampleRate", int2_mi2s_tx_sample_rate,
-			int_mi2s_sample_rate_get,
-			int_mi2s_sample_rate_put),
-	SOC_ENUM_EXT("INT3_MI2S_TX SampleRate", int3_mi2s_tx_sample_rate,
-			int_mi2s_sample_rate_get,
-			int_mi2s_sample_rate_put),
 	SOC_ENUM_EXT("INT0_MI2S_RX Channels", int0_mi2s_rx_chs,
 			int_mi2s_ch_get, int_mi2s_ch_put),
 	SOC_ENUM_EXT("INT2_MI2S_TX Channels", int2_mi2s_tx_chs,
@@ -893,15 +904,12 @@
 			msm_bt_sample_rate_put),
 };
 
-static const struct snd_kcontrol_new msm_swr_controls[] = {
+static const struct snd_kcontrol_new msm_sdw_controls[] = {
 	SOC_ENUM_EXT("INT4_MI2S_RX Format", int4_mi2s_rx_format,
 		     int_mi2s_bit_format_get, int_mi2s_bit_format_put),
 	SOC_ENUM_EXT("INT4_MI2S_RX SampleRate", int4_mi2s_rx_sample_rate,
 			int_mi2s_sample_rate_get,
 			int_mi2s_sample_rate_put),
-	SOC_ENUM_EXT("INT4_MI2S_RX SampleRate", int4_mi2s_rx_sample_rate,
-			int_mi2s_sample_rate_get,
-			int_mi2s_sample_rate_put),
 	SOC_ENUM_EXT("INT4_MI2S_RX Channels", int4_mi2s_rx_chs,
 			int_mi2s_ch_get, int_mi2s_ch_put),
 	SOC_ENUM_EXT("VI_FEED_TX Channels", int5_mi2s_tx_chs,
@@ -919,7 +927,7 @@
 	pr_debug("%s: event = %d\n", __func__, event);
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		ret = msm_gpioset_activate(CLIENT_WCD, "dmic_gpio");
+		ret = msm_cdc_pinctrl_select_active_state(pdata->dmic_gpio_p);
 		if (ret < 0) {
 			pr_err("%s: gpio set cannot be activated %sd",
 					__func__, "dmic_gpio");
@@ -927,7 +935,7 @@
 		}
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		ret = msm_gpioset_suspend(CLIENT_WCD, "dmic_gpio");
+		ret = msm_cdc_pinctrl_select_sleep_state(pdata->dmic_gpio_p);
 		if (ret < 0) {
 			pr_err("%s: gpio set cannot be de-activated %sd",
 					__func__, "dmic_gpio");
@@ -954,7 +962,7 @@
 	case SND_SOC_DAPM_POST_PMD:
 		pr_debug("%s: mclk_res_ref = %d\n",
 			__func__, atomic_read(&pdata->int_mclk0_rsc_ref));
-		ret = msm_gpioset_suspend(CLIENT_WCD, "int_pdm");
+		ret = msm_cdc_pinctrl_select_sleep_state(pdata->pdm_gpio_p);
 		if (ret < 0) {
 			pr_err("%s: gpio set cannot be de-activated %sd",
 					__func__, "int_pdm");
@@ -963,7 +971,7 @@
 		if (atomic_read(&pdata->int_mclk0_rsc_ref) == 0) {
 			pr_debug("%s: disabling MCLK\n", __func__);
 			/* disable the codec mclk config*/
-			msm8x16_wcd_mclk_enable(codec, 0, true);
+			msm_anlg_cdc_mclk_enable(codec, 0, true);
 			msm_int_enable_dig_cdc_clk(codec, 0, true);
 		}
 		break;
@@ -1055,8 +1063,7 @@
 	bit_per_sample =
 	    get_int_mi2s_bits_per_sample(int_mi2s_cfg[idx].bit_format);
 	int_mi2s_clk[idx].clk_freq_in_hz =
-	    (int_mi2s_cfg[idx].sample_rate * int_mi2s_cfg[idx].channels
-					* bit_per_sample);
+	    (int_mi2s_cfg[idx].sample_rate * 2 * bit_per_sample);
 }
 
 static int int_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
@@ -1098,7 +1105,7 @@
 	return ret;
 }
 
-static int msm_swr_mi2s_snd_startup(struct snd_pcm_substream *substream)
+static int msm_sdw_mi2s_snd_startup(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -1113,13 +1120,6 @@
 				__func__, ret);
 		return ret;
 	}
-	/* Enable the codec mclk config */
-	ret = msm_gpioset_activate(CLIENT_WCD, "swr_pin");
-	if (ret < 0) {
-		pr_err("%s: gpio set cannot be activated %sd",
-				__func__, "swr_pin");
-		return ret;
-	}
 	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
 	if (ret < 0)
 		pr_err("%s: set fmt cpu dai failed; ret=%d\n", __func__, ret);
@@ -1127,7 +1127,7 @@
 	return ret;
 }
 
-static void msm_swr_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+static void msm_sdw_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
 {
 	int ret;
 
@@ -1144,9 +1144,11 @@
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = rtd->codec_dais[ANA_CDC]->codec;
 	int ret = 0;
+	struct msm_asoc_mach_data *pdata = NULL;
 
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
 	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
 		 substream->name, substream->stream);
 
@@ -1162,13 +1164,13 @@
 		return ret;
 	}
 	/* Enable the codec mclk config */
-	ret = msm_gpioset_activate(CLIENT_WCD, "int_pdm");
+	ret = msm_cdc_pinctrl_select_active_state(pdata->pdm_gpio_p);
 	if (ret < 0) {
 		pr_err("%s: gpio set cannot be activated %s\n",
 				__func__, "int_pdm");
 		return ret;
 	}
-	msm8x16_wcd_mclk_enable(codec, 1, true);
+	msm_anlg_cdc_mclk_enable(codec, 1, true);
 	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
 	if (ret < 0)
 		pr_err("%s: set fmt cpu dai failed; ret=%d\n", __func__, ret);
@@ -1249,22 +1251,33 @@
 
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_codec *codec = rtd->codec;
-	struct snd_soc_dapm_context *dapm =
-			snd_soc_codec_get_dapm(codec);
+	struct snd_soc_codec *dig_cdc = rtd->codec_dais[DIG_CDC]->codec;
+	struct snd_soc_codec *ana_cdc = rtd->codec_dais[ANA_CDC]->codec;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(ana_cdc);
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_card *card;
 	int ret = -ENOMEM;
 
 	pr_debug("%s(),dev_name%s\n", __func__, dev_name(cpu_dai->dev));
 
-	snd_soc_add_codec_controls(codec, msm_snd_controls,
-			ARRAY_SIZE(msm_snd_controls));
-
-	snd_soc_add_codec_controls(codec, msm_common_snd_controls,
-			ARRAY_SIZE(msm_snd_controls));
+	ret = snd_soc_add_codec_controls(ana_cdc, msm_snd_controls,
+				   ARRAY_SIZE(msm_snd_controls));
+	if (ret < 0) {
+		pr_err("%s: add_codec_controls failed: %d\n",
+			__func__, ret);
+		return ret;
+	}
+	ret = snd_soc_add_codec_controls(ana_cdc, msm_common_snd_controls,
+				   msm_common_snd_controls_size());
+	if (ret < 0) {
+		pr_err("%s: add common snd controls failed: %d\n",
+			__func__, ret);
+		return ret;
+	}
 
 	snd_soc_dapm_new_controls(dapm, msm_int_dapm_widgets,
-			ARRAY_SIZE(msm_int_dapm_widgets));
+				  ARRAY_SIZE(msm_int_dapm_widgets));
 
 	snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
 	snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
@@ -1285,39 +1298,78 @@
 
 	snd_soc_dapm_sync(dapm);
 
-	msm8x16_wcd_spk_ext_pa_cb(enable_spk_ext_pa, codec);
-	msm8x16_wcd_hph_comp_cb(msm_config_hph_compander_gpio, codec);
+	msm_anlg_cdc_spk_ext_pa_cb(enable_spk_ext_pa, ana_cdc);
+	msm_dig_cdc_hph_comp_cb(msm_config_hph_compander_gpio, dig_cdc);
 
 	mbhc_cfg_ptr->calibration = def_msm_int_wcd_mbhc_cal();
 	if (mbhc_cfg_ptr->calibration) {
-		ret = msm8x16_wcd_hs_detect(codec, mbhc_cfg_ptr);
+		ret = msm_anlg_cdc_hs_detect(ana_cdc, mbhc_cfg_ptr);
 		if (ret) {
-			pr_err("%s: msm8x16_wcd_hs_detect failed\n", __func__);
+			pr_err("%s: msm_anlg_cdc_hs_detect failed\n", __func__);
 			kfree(mbhc_cfg_ptr->calibration);
 			return ret;
 		}
 	}
+	card = rtd->card->snd_card;
+	if (!codec_root)
+		codec_root = snd_register_module_info(card->module, "codecs",
+						      card->proc_root);
+	if (!codec_root) {
+		pr_debug("%s: Cannot create codecs module entry\n",
+			 __func__);
+		goto done;
+	}
+	pdata->codec_root = codec_root;
+	msm_dig_codec_info_create_codec_entry(codec_root, dig_cdc);
+	msm_anlg_codec_info_create_codec_entry(codec_root, ana_cdc);
+done:
 	return 0;
 }
 
-static int msm_swr_audrx_init(struct snd_soc_pcm_runtime *rtd)
+static int msm_sdw_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_dapm_context *dapm =
 			snd_soc_codec_get_dapm(codec);
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_pcm_runtime *rtd_aux = rtd->card->rtd_aux;
+	struct snd_card *card;
 
-	snd_soc_add_codec_controls(codec, msm_swr_controls,
-			ARRAY_SIZE(msm_swr_controls));
+	snd_soc_add_codec_controls(codec, msm_sdw_controls,
+			ARRAY_SIZE(msm_sdw_controls));
 
-	snd_soc_dapm_ignore_suspend(dapm, "AIF1_SWR Playback");
-	snd_soc_dapm_ignore_suspend(dapm, "VIfeed_SWR");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF1_SDW Playback");
+	snd_soc_dapm_ignore_suspend(dapm, "VIfeed_SDW");
 	snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT");
 	snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT");
-	snd_soc_dapm_ignore_suspend(dapm, "AIF1_SWR VI");
-	snd_soc_dapm_ignore_suspend(dapm, "VIINPUT_SWR");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF1_SDW VI");
+	snd_soc_dapm_ignore_suspend(dapm, "VIINPUT_SDW");
 
 	snd_soc_dapm_sync(dapm);
 
+	/*
+	 * Send speaker configuration only for WSA8810.
+	 * Default configuration is for WSA8815.
+	 */
+	if (rtd_aux && rtd_aux->component)
+		if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) ||
+		    !strcmp(rtd_aux->component->name, WSA8810_NAME_2)) {
+			msm_sdw_set_spkr_mode(rtd->codec, SPKR_MODE_1);
+			msm_sdw_set_spkr_gain_offset(rtd->codec,
+						   RX_GAIN_OFFSET_M1P5_DB);
+	}
+	card = rtd->card->snd_card;
+	if (!codec_root)
+		codec_root = snd_register_module_info(card->module, "codecs",
+						      card->proc_root);
+	if (!codec_root) {
+		pr_debug("%s: Cannot create codecs module entry\n",
+			 __func__);
+		goto done;
+	}
+	pdata->codec_root = codec_root;
+	msm_sdw_codec_info_create_codec_entry(codec_root, codec);
+done:
 	return 0;
 }
 
@@ -1540,9 +1592,42 @@
 	.shutdown = msm_int_mi2s_snd_shutdown,
 };
 
-static struct snd_soc_ops msm_swr_mi2s_be_ops = {
-	.startup = msm_swr_mi2s_snd_startup,
-	.shutdown = msm_swr_mi2s_snd_shutdown,
+static struct snd_soc_ops msm_sdw_mi2s_be_ops = {
+	.startup = msm_sdw_mi2s_snd_startup,
+	.shutdown = msm_sdw_mi2s_snd_shutdown,
+};
+
+struct snd_soc_dai_link_component dlc_rx1[] = {
+	{
+		.of_node = NULL,
+		.dai_name = "msm_dig_cdc_dai_rx1",
+	},
+	{
+		.of_node = NULL,
+		.dai_name  = "msm_anlg_cdc_i2s_rx1",
+	},
+};
+
+struct snd_soc_dai_link_component dlc_tx1[] = {
+	{
+		.of_node = NULL,
+		.dai_name = "msm_dig_cdc_dai_tx1",
+	},
+	{
+		.of_node = NULL,
+		.dai_name  = "msm_anlg_cdc_i2s_tx1",
+	},
+};
+
+struct snd_soc_dai_link_component dlc_tx2[] = {
+	{
+		.of_node = NULL,
+		.dai_name = "msm_dig_cdc_dai_tx2",
+	},
+	{
+		.of_node = NULL,
+		.dai_name  = "msm_anlg_cdc_i2s_tx2",
+	},
 };
 
 /* Digital audio interface glue - connects codec <---> CPU */
@@ -1675,6 +1760,7 @@
 		.stream_name = "Compress1",
 		.cpu_dai_name	= "MultiMedia4",
 		.platform_name  = "msm-compress-dsp",
+		.async_ops = ASYNC_DPCM_SND_SOC_HW_PARAMS,
 		.dynamic = 1,
 		.dpcm_capture = 1,
 		.dpcm_playback = 1,
@@ -1721,25 +1807,24 @@
 		.codec_name = "snd-soc-dummy",
 	},
 	{/* hw:x,11 */
-		.name = "SLIMBUS_3 Hostless",
-		.stream_name = "SLIMBUS_3 Hostless",
-		.cpu_dai_name = "SLIMBUS3_HOSTLESS",
+		.name = "INT3 MI2S_TX Hostless",
+		.stream_name = "INT3 MI2S_TX Hostless",
+		.cpu_dai_name = "INT3_MI2S_TX_HOSTLESS",
 		.platform_name = "msm-pcm-hostless",
 		.dynamic = 1,
 		.dpcm_capture = 1,
-		.dpcm_playback = 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, /* dai link has playback support */
+		.ignore_pmdown_time = 1,
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
 	{/* hw:x,12 */
-		.name = "SLIMBUS_4 Hostless",
-		.stream_name = "SLIMBUS_4 Hostless",
-		.cpu_dai_name = "SLIMBUS4_HOSTLESS",
+		.name = "SLIMBUS_7 Hostless",
+		.stream_name = "SLIMBUS_7 Hostless",
+		.cpu_dai_name = "SLIMBUS7_HOSTLESS",
 		.platform_name = "msm-pcm-hostless",
 		.dynamic = 1,
 		.dpcm_capture = 1,
@@ -2114,21 +2199,6 @@
 		.codec_name = "snd-soc-dummy",
 	},
 	{/* hw:x,35 */
-		.name = LPASS_BE_INT5_MI2S_TX,
-		.stream_name = "INT5_mi2s Capture",
-		.cpu_dai_name = "msm-dai-q6-mi2s.12",
-		.platform_name = "msm-pcm-hostless",
-		.codec_name = "msm_swr_codec",
-		.codec_dai_name = "msm_swr_vifeedback",
-		.be_id = MSM_BACKEND_DAI_INT5_MI2S_TX,
-		.be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
-		.ops = &msm_swr_mi2s_be_ops,
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.dpcm_capture = 1,
-		.ignore_pmdown_time = 1,
-	},
-	{/* hw:x,36 */
 		.name = "Primary MI2S_RX Hostless",
 		.stream_name = "Primary MI2S_RX Hostless",
 		.cpu_dai_name = "PRI_MI2S_RX_HOSTLESS",
@@ -2145,7 +2215,7 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
-	{/* hw:x,37 */
+	{/* hw:x,36 */
 		.name = "Secondary MI2S_RX Hostless",
 		.stream_name = "Secondary MI2S_RX Hostless",
 		.cpu_dai_name = "SEC_MI2S_RX_HOSTLESS",
@@ -2162,7 +2232,7 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
-	{/* hw:x,38 */
+	{/* hw:x,37 */
 		.name = "Tertiary MI2S_RX Hostless",
 		.stream_name = "Tertiary MI2S_RX Hostless",
 		.cpu_dai_name = "TERT_MI2S_RX_HOSTLESS",
@@ -2179,7 +2249,7 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
-	{/* hw:x,39 */
+	{/* hw:x,38 */
 		.name = "INT0 MI2S_RX Hostless",
 		.stream_name = "INT0 MI2S_RX Hostless",
 		.cpu_dai_name = "INT0_MI2S_RX_HOSTLESS",
@@ -2196,14 +2266,53 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
+	{/* hw:x,39 */
+		.name = "SDM660 HFP TX",
+		.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,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+	},
+};
+
+
+static struct snd_soc_dai_link msm_int_wsa_dai[] = {
+	{/* hw:x,40 */
+		.name = LPASS_BE_INT5_MI2S_TX,
+		.stream_name = "INT5_mi2s Capture",
+		.cpu_dai_name = "msm-dai-q6-mi2s.12",
+		.platform_name = "msm-pcm-hostless",
+		.codec_name = "msm_sdw_codec",
+		.codec_dai_name = "msm_sdw_vifeedback",
+		.be_id = MSM_BACKEND_DAI_INT5_MI2S_TX,
+		.be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
+		.ops = &msm_sdw_mi2s_be_ops,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.dpcm_capture = 1,
+		.ignore_pmdown_time = 1,
+	},
+};
+
+static struct snd_soc_dai_link msm_int_be_dai[] = {
 	/* Backend I2S DAI Links */
 	{
 		.name = LPASS_BE_INT0_MI2S_RX,
 		.stream_name = "INT0 MI2S Playback",
 		.cpu_dai_name = "msm-dai-q6-mi2s.7",
 		.platform_name = "msm-pcm-routing",
-		.codec_name     = "cajon_codec",
-		.codec_dai_name = "msm8x16_wcd_i2s_rx1",
+		.codecs = dlc_rx1,
+		.num_codecs = CODECS_MAX,
 		.no_pcm = 1,
 		.dpcm_playback = 1,
 		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE |
@@ -2215,18 +2324,19 @@
 		.ignore_suspend = 1,
 	},
 	{
-		.name = LPASS_BE_INT4_MI2S_RX,
-		.stream_name = "INT4 MI2S Playback",
-		.cpu_dai_name = "msm-dai-q6-mi2s.11",
+		.name = LPASS_BE_INT3_MI2S_TX,
+		.stream_name = "INT3 MI2S Capture",
+		.cpu_dai_name = "msm-dai-q6-mi2s.10",
 		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm_swr_codec",
-		.codec_dai_name = "msm_swr_i2s_rx1",
+		.codecs = dlc_tx1,
+		.num_codecs = CODECS_MAX,
 		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.be_id = MSM_BACKEND_DAI_INT4_MI2S_RX,
-		.init = &msm_swr_audrx_init,
+		.dpcm_capture = 1,
+		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE |
+			ASYNC_DPCM_SND_SOC_HW_PARAMS,
+		.be_id = MSM_BACKEND_DAI_INT3_MI2S_TX,
 		.be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
-		.ops = &msm_swr_mi2s_be_ops,
+		.ops = &msm_int_mi2s_be_ops,
 		.ignore_suspend = 1,
 	},
 	{
@@ -2234,8 +2344,8 @@
 		.stream_name = "INT2 MI2S Capture",
 		.cpu_dai_name = "msm-dai-q6-mi2s.9",
 		.platform_name = "msm-pcm-routing",
-		.codec_name     = "cajon_codec",
-		.codec_dai_name = "msm8x16_wcd_i2s_tx2",
+		.codecs = dlc_tx2,
+		.num_codecs = CODECS_MAX,
 		.no_pcm = 1,
 		.dpcm_capture = 1,
 		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE |
@@ -2246,22 +2356,6 @@
 		.ignore_suspend = 1,
 	},
 	{
-		.name = LPASS_BE_INT3_MI2S_TX,
-		.stream_name = "INT3 MI2S Capture",
-		.cpu_dai_name = "msm-dai-q6-mi2s.10",
-		.platform_name = "msm-pcm-routing",
-		.codec_name     = "cajon_codec",
-		.codec_dai_name = "msm8x16_wcd_i2s_tx1",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE |
-			ASYNC_DPCM_SND_SOC_HW_PARAMS,
-		.be_id = MSM_BACKEND_DAI_INT3_MI2S_TX,
-		.be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
-		.ops = &msm_int_mi2s_be_ops,
-		.ignore_suspend = 1,
-	},
-	{
 		.name = LPASS_BE_AFE_PCM_RX,
 		.stream_name = "AFE Playback",
 		.cpu_dai_name = "msm-dai-q6-dev.224",
@@ -2785,15 +2879,55 @@
 	},
 };
 
+static struct snd_soc_dai_link msm_wsa_be_dai_links[] = {
+	{
+		.name = LPASS_BE_INT4_MI2S_RX,
+		.stream_name = "INT4 MI2S Playback",
+		.cpu_dai_name = "msm-dai-q6-mi2s.11",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm_sdw_codec",
+		.codec_dai_name = "msm_sdw_i2s_rx1",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.be_id = MSM_BACKEND_DAI_INT4_MI2S_RX,
+		.init = &msm_sdw_audrx_init,
+		.be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
+		.ops = &msm_sdw_mi2s_be_ops,
+		.ignore_suspend = 1,
+	},
+};
+
+static struct snd_soc_dai_link ext_disp_be_dai_link[] = {
+	/* DISP PORT BACK END DAI Link */
+	{
+		.name = LPASS_BE_DISPLAY_PORT,
+		.stream_name = "Display Port Playback",
+		.cpu_dai_name = "msm-dai-q6-dp.24608",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-ext-disp-audio-codec-rx",
+		.codec_dai_name = "msm_dp_audio_codec_rx_dai",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.be_id = MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+		.be_hw_params_fixup = msm_common_be_hw_params_fixup,
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+};
+
 static struct snd_soc_dai_link msm_int_dai_links[
 ARRAY_SIZE(msm_int_dai) +
+ARRAY_SIZE(msm_int_wsa_dai) +
+ARRAY_SIZE(msm_int_be_dai) +
 ARRAY_SIZE(msm_mi2s_be_dai_links) +
 ARRAY_SIZE(msm_auxpcm_be_dai_links)+
-ARRAY_SIZE(msm_wcn_be_dai_links)];
+ARRAY_SIZE(msm_wcn_be_dai_links) +
+ARRAY_SIZE(msm_wsa_be_dai_links) +
+ARRAY_SIZE(ext_disp_be_dai_link)];
 
-static struct snd_soc_card msmfalcon_card = {
-	/* snd_soc_card_msmfalcon */
-	.name		= "msmfalcon-snd-card",
+static struct snd_soc_card sdm660_card = {
+	/* snd_soc_card_sdm660 */
+	.name		= "sdm660-snd-card",
 	.dai_link	= msm_int_dai,
 	.num_links	= ARRAY_SIZE(msm_int_dai),
 };
@@ -2844,7 +2978,7 @@
 static struct snd_soc_card *msm_int_populate_sndcard_dailinks(
 						struct device *dev)
 {
-	struct snd_soc_card *card = &msmfalcon_card;
+	struct snd_soc_card *card = &sdm660_card;
 	struct snd_soc_dai_link *dailink;
 	int len1;
 
@@ -2852,6 +2986,16 @@
 	len1 = ARRAY_SIZE(msm_int_dai);
 	memcpy(msm_int_dai_links, msm_int_dai, sizeof(msm_int_dai));
 	dailink = msm_int_dai_links;
+	if (!of_property_read_bool(dev->of_node,
+				  "qcom,wsa-disable")) {
+		memcpy(dailink + len1,
+		       msm_int_wsa_dai,
+		       sizeof(msm_int_wsa_dai));
+		len1 += ARRAY_SIZE(msm_int_wsa_dai);
+	}
+	memcpy(dailink + len1, msm_int_be_dai, sizeof(msm_int_be_dai));
+	len1 += ARRAY_SIZE(msm_int_be_dai);
+
 	if (of_property_read_bool(dev->of_node,
 				  "qcom,mi2s-audio-intf")) {
 		memcpy(dailink + len1,
@@ -2874,6 +3018,20 @@
 		       sizeof(msm_wcn_be_dai_links));
 		len1 += ARRAY_SIZE(msm_wcn_be_dai_links);
 	}
+	if (!of_property_read_bool(dev->of_node, "qcom,wsa-disable")) {
+		memcpy(dailink + len1,
+		       msm_wsa_be_dai_links,
+		       sizeof(msm_wsa_be_dai_links));
+		len1 += ARRAY_SIZE(msm_wsa_be_dai_links);
+	}
+	if (of_property_read_bool(dev->of_node, "qcom,ext-disp-audio-rx")) {
+		dev_dbg(dev, "%s(): ext disp audio support present\n",
+				__func__);
+		memcpy(dailink + len1,
+			ext_disp_be_dai_link,
+			sizeof(ext_disp_be_dai_link));
+		len1 += ARRAY_SIZE(ext_disp_be_dai_link);
+	}
 	card->dai_link = dailink;
 	card->num_links = len1;
 	return card;
@@ -2913,8 +3071,7 @@
 			AFE_API_VERSION_I2S_CONFIG;
 	pdata->digital_cdc_core_clk.clk_id =
 			Q6AFE_LPASS_CLK_ID_INT_MCLK_0;
-	pdata->digital_cdc_core_clk.clk_freq_in_hz =
-			pdata->mclk_freq;
+	pdata->digital_cdc_core_clk.clk_freq_in_hz = pdata->mclk_freq;
 	pdata->digital_cdc_core_clk.clk_attri =
 			Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO;
 	pdata->digital_cdc_core_clk.clk_root =
diff --git a/sound/soc/msm/msmfalcon-internal.h b/sound/soc/msm/sdm660-internal.h
similarity index 94%
rename from sound/soc/msm/msmfalcon-internal.h
rename to sound/soc/msm/sdm660-internal.h
index e5e3e7c..ccc62b8 100644
--- a/sound/soc/msm/msmfalcon-internal.h
+++ b/sound/soc/msm/sdm660-internal.h
@@ -10,8 +10,8 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __MSMFALCON_INTERNAL
-#define __MSMFALCON_INTERNAL
+#ifndef __SDM660_INTERNAL
+#define __SDM660_INTERNAL
 
 #include <sound/soc.h>
 
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index e80017f..ad3cc68 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -528,6 +528,11 @@
 				cstream, &async_domain);
 			} else {
 				be_list[j++] = be;
+				if (j == DPCM_MAX_BE_USERS) {
+					dev_dbg(fe->dev,
+						"ASoC: MAX backend users!\n");
+					break;
+				}
 			}
 		}
 		for (i = 0; i < j; i++) {
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 7d505e2..94ea909 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -78,8 +78,7 @@
 	[snd_soc_dapm_dai_link] = 2,
 	[snd_soc_dapm_dai_in] = 4,
 	[snd_soc_dapm_dai_out] = 4,
-	[snd_soc_dapm_aif_in] = 4,
-	[snd_soc_dapm_aif_out] = 4,
+	[snd_soc_dapm_adc] = 4,
 	[snd_soc_dapm_mic] = 5,
 	[snd_soc_dapm_mux] = 6,
 	[snd_soc_dapm_demux] = 6,
@@ -88,7 +87,8 @@
 	[snd_soc_dapm_mixer] = 8,
 	[snd_soc_dapm_mixer_named_ctl] = 8,
 	[snd_soc_dapm_pga] = 9,
-	[snd_soc_dapm_adc] = 10,
+	[snd_soc_dapm_aif_in] = 9,
+	[snd_soc_dapm_aif_out] = 9,
 	[snd_soc_dapm_out_drv] = 11,
 	[snd_soc_dapm_hp] = 11,
 	[snd_soc_dapm_spk] = 11,
@@ -100,7 +100,9 @@
 static int dapm_down_seq[] = {
 	[snd_soc_dapm_pre] = 0,
 	[snd_soc_dapm_kcontrol] = 1,
-	[snd_soc_dapm_adc] = 2,
+	[snd_soc_dapm_aif_in] = 2,
+	[snd_soc_dapm_aif_out] = 2,
+	[snd_soc_dapm_adc] = 5,
 	[snd_soc_dapm_hp] = 3,
 	[snd_soc_dapm_spk] = 3,
 	[snd_soc_dapm_line] = 3,
@@ -114,8 +116,6 @@
 	[snd_soc_dapm_micbias] = 8,
 	[snd_soc_dapm_mux] = 9,
 	[snd_soc_dapm_demux] = 9,
-	[snd_soc_dapm_aif_in] = 10,
-	[snd_soc_dapm_aif_out] = 10,
 	[snd_soc_dapm_dai_in] = 10,
 	[snd_soc_dapm_dai_out] = 10,
 	[snd_soc_dapm_dai_link] = 11,
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 4f4d230..be6290d 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1931,14 +1931,14 @@
 
 	dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
 
-	/* shutdown the BEs */
-	dpcm_be_dai_shutdown(fe, substream->stream);
-
 	dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
 
 	/* now shutdown the frontend */
 	soc_pcm_close(substream);
 
+	/* shutdown the BEs */
+	dpcm_be_dai_shutdown(fe, substream->stream);
+
 	/* run the stream event for each BE */
 	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
 
@@ -2521,6 +2521,10 @@
 							    dpcm, domain);
 		} else {
 			dpcm_async[i++] = dpcm;
+			if (i == DPCM_MAX_BE_USERS) {
+				dev_dbg(fe->dev, "ASoC: MAX backend users!\n");
+				break;
+			}
 		}
 	}