Merge "dt-bindings: clock: add bindings for kona video cc driver"
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
new file mode 100644
index 0000000..a547067d
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -0,0 +1,280 @@
+* Low Power Management Levels
+
+The application processor in MSM can do a variety of C-States for low power
+management. The LPM module performs the System low power modes based on
+the latency/residency information of the individual CPUs and clusters.
+
+LPM-levels defines a hierarchy of low power modes that a cluster and
+clusters/cpus within that cluster can enter. The bottom hierarchy level
+represents the low power modes that a CPU can enter. The CPU low power nodes
+are associated with a cluster that defines the low power modes that a cluster
+can enter. For system involving a hierarchy of clusters, the cluster low power
+modes can be contained within another cluster.
+
+[Top Level Node]
+Required properties:
+
+- compatible: "qcom,lpm-levels"
+
+[Node bindings for qcom,pm-cluster]
+ Required properties:
+	- reg - The numeric cluster id
+	- label: Identifies the cluster name. The name is used when reporting
+	the stats for each low power mode.
+	- qcom,psci-mode-shift: The property is used to determine with bit
+	location of the cluster mode in the composite state ID used to define
+	cluster low power modes in PSCI.
+	- qcom,psci-mode-mask: The property is used to determine with bit
+	mask of the cluster mode in the composite state ID used to define
+	cluster low power modes in PSCI.
+
+Optional properties:
+	- qcom,disable-prediction: This property is used to indicate the LPM
+	governor will not use LPM prediction for this cluster.
+	- qcom,clstr-tmr-add: This property is used as correction timer for
+	wrong prediction by lpm prediction algorithm for cluster predictions.
+	This value should be between 100 to 1500. Higher values would mean
+	longer time staying in shallower state before waking up to select a
+	deeper state in case of wrong prediction.
+	qcom,pm-cluster contains qcom,pm-cluster-level nodes which identify
+	the various low power modes that the cluster can enter. The
+	qcom,pm-cluster node should also include another cluster node or a cpu
+	node that defines their respective low power modes.
+
+[Node bindings for qcom,pm-cluster-level]
+ Required properties:
+	- reg: The numeric cluster level id
+	- label: Name to identify the low power mode in stats
+	module.
+	- qcom,psci-mode: ID to be passed into the PSCI firmware.
+	- qcom,min-child-idx: The minimum level that a child CPU should be in
+	before this level can be chosen. This property is required for all
+        non-default level.
+	- qcom,entry-latency-us: The latency to enter LPM level, in uSec
+	- qcom,exit-latency-us: The latency to exit LPM level, in uSec
+	- qcom,min-residency-us: The minimum residency value from which entering
+	to low power mode is beneficial, in uSec
+
+ Optional properties:
+	- qcom,notify-rpm: When set, the driver configures the sleep and wake
+	sets. It also configures the next wakeup time for APPS.
+	- qcom,is-reset: This boolean property tells whether cluster level need
+	power management notifications to be sent out or not for the drivers to
+	prepare for cluster collapse.
+	- qcom,reset-level: This property is used to determine in this
+	low power mode only control logic power collapse happens or memory
+	logic power collapse aswell happens or retention state.
+	The accepted values for this property are:
+		"LPM_RESET_LVL_NONE" - No power collapse
+		"LPM_RESET_LVL_RET"  - Retention state
+		"LPM_RESET_LVL_GDHS" - Only control logic power collapse (GDHS)
+		"LPM_RESET_LVL_PC" - Control logic and memory logic
+					power collapse (PC)
+
+[Node bindings for qcom,pm-cpu]
+qcom,pm-cpu contains the low power modes that a cpu could enter and the CPUs
+that share the parameters.It contains the following properties.
+	- qcom,cpu: List of CPU phandles to identify the CPUs associated with
+	this cluster.
+	- qcom,psci-mode-shift: Same as cluster level fields.
+	- qcom,psci-mode-mask: Same as cluster level fields.
+	- qcom,pm-cpu-levels: The different low power modes that a CPU could
+	enter. The following section explains the required properties of this
+	node.
+
+Optional properties:
+	- qcom,disable-prediction: This property is used to indicate the
+	LPM governor is to disable sleep prediction to this cpu.
+	- qcom,ref-stddev: This property is used as reference standard deviation
+	in lpm prediction algorithm. This value should be between 100 to 1000.
+	Higher value would result in more predictions and thereby resulting in
+	shallower low power modes.
+	- qcom,tmr-add: This property is used as correction timer for wrong
+	prediction by lpm prediction algorithm. This value should be between
+	100 to 1500. Higher values would mean longer time staying in shallower
+	state before waking up to select a deeper state in case of wrong prediction.
+	- qcom,ref-premature-cnt: This property is used as reference premature
+	count to predict next sleep state by the prediction algorithm. This value
+	should be between 1 to 5. Higher value for this parameter would result in
+	less predictions to disallow deeper low power modes.
+
+[Node bindings for qcom,pm-cpu-levels]
+ Required properties:
+	- reg: The numeric cpu level id
+	- label: Name to identify the low power mode in stats
+	- qcom,psci-cpu-mode: ID to be passed into PSCI firmware.
+	- qcom,entry-latency-us: The latency to enter LPM level, in uSec
+	- qcom,exit-latency-us: The latency to exit LPM level, in uSec
+	- qcom,min-residency-us: The minimum residency value from which entering
+	to low power mode is beneficial, in uSec
+
+ Optional properties:
+	- qcom,is-reset: This boolean property maps to "power state" bit in PSCI
+	state_id configuration. This property will tell whether CPU get reset for
+	a particular LPM or not. This property is also used to notify the drivers
+	in case of cpu reset.
+	- qcom,use-broadcast-timer: Indicates that the timer gets reset during
+	power collapse and the cpu relies on Broadcast timer for scheduled wakeups.
+	Required only for states where the CPUs internal timer state is lost.
+
+[Example dts]
+
+	qcom,lpm-levels {
+		compatible = "qcom,lpm-levels";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,pm-cluster@0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			label = "L3";
+			qcom,psci-mode-shift = <4>;
+			qcom,psci-mode-mask = <0xfff>;
+
+			qcom,pm-cluster-level@0 { /* D1 */
+				reg = <0>;
+				label = "l3-wfi";
+				qcom,psci-mode = <0x1>;
+				qcom,entry-latency-us = <48>;
+				qcom,exit-latency-us = <51>;
+				qcom,min-residency-us = <99>;
+			};
+
+			qcom,pm-cluster-level@1 { /* D2 */
+				reg = <1>;
+				label = "l3-dyn-ret";
+				qcom,psci-mode = <0x2>;
+				qcom,entry-latency-us = <317>;
+				qcom,exit-latency-us = <659>;
+				qcom,min-residency-us = <4065>;
+			};
+
+			qcom,pm-cluster-level@2 { /* D4, D3 is not supported */
+				reg = <2>;
+				label = "l3-pc";
+				qcom,psci-mode = <0x4>;
+				qcom,entry-latency-us = <814>;
+				qcom,exit-latency-us = <4562>;
+				qcom,min-residency-us = <7085>;
+				qcom,min-child-idx = <2>;
+				qcom,is-reset;
+			};
+
+			qcom,pm-cluster-level@3 { /* Cx off */
+				reg = <3>;
+				label = "cx-off";
+				qcom,psci-mode = <0x224>;
+				qcom,entry-latency-us = <814>;
+				qcom,exit-latency-us = <5562>;
+				qcom,min-residency-us = <9987>;
+				qcom,min-child-idx = <3>;
+				qcom,is-reset;
+				qcom,notify-rpm;
+			};
+
+			qcom,pm-cluster-level@4 { /* LLCC off, AOSS sleep */
+				reg = <4>;
+				label = "llcc-off";
+				qcom,psci-mode = <0xC24>;
+				qcom,entry-latency-us = <814>;
+				qcom,exit-latency-us = <6562>;
+				qcom,min-residency-us = <10100>;
+				qcom,min-child-idx = <3>;
+				qcom,is-reset;
+				qcom,notify-rpm;
+			};
+
+			qcom,pm-cpu@0 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				qcom,psci-mode-shift = <0>;
+				qcom,psci-mode-mask = <0xf>;
+				qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>;
+
+				qcom,pm-cpu-level@0 { /* C1 */
+					reg = <0>;
+					label = "wfi";
+					qcom,psci-cpu-mode = <0x1>;
+					qcom,entry-latency-us = <40>;
+					qcom,exit-latency-us = <43>;
+					qcom,min-residency-us = <100>;
+				};
+
+				qcom,pm-cpu-level@1 { /* C2D */
+					reg = <1>;
+					label = "ret";
+					qcom,psci-cpu-mode = <0x2>;
+					qcom,entry-latency-us = <81>;
+					qcom,exit-latency-us = <86>;
+					qcom,min-residency-us = <965>;
+				};
+
+				qcom,pm-cpu-level@2 {  /* C3 */
+					reg = <2>;
+					label = "pc";
+					qcom,psci-cpu-mode = <0x3>;
+					qcom,entry-latency-us = <273>;
+					qcom,exit-latency-us = <612>;
+					qcom,min-residency-us = <1890>;
+					qcom,is-reset;
+				};
+
+				qcom,pm-cpu-level@3 {  /* C4 */
+					reg = <3>;
+					label = "rail-pc";
+					qcom,psci-cpu-mode = <0x4>;
+					qcom,entry-latency-us = <300>;
+					qcom,exit-latency-us = <700>;
+					qcom,min-residency-us = <3934>;
+					qcom,is-reset;
+				};
+			};
+
+			qcom,pm-cpu@1 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				qcom,psci-mode-shift = <0>;
+				qcom,psci-mode-mask = <0xf>;
+				qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>;
+
+				qcom,pm-cpu-level@0 { /* C1 */
+					reg = <0>;
+					label = "wfi";
+					qcom,psci-cpu-mode = <0x1>;
+					qcom,entry-latency-us = <40>;
+					qcom,exit-latency-us = <43>;
+					qcom,min-residency-us = <83>;
+				};
+
+				qcom,pm-cpu-level@1 { /* C2D */
+					reg = <1>;
+					label = "ret";
+					qcom,psci-cpu-mode = <0x2>;
+					qcom,entry-latency-us = <81>;
+					qcom,exit-latency-us = <86>;
+					qcom,min-residency-us = <637>;
+				};
+
+				qcom,pm-cpu-level@2 {  /* C3 */
+					reg = <2>;
+					label = "pc";
+					qcom,psci-cpu-mode = <0x3>;
+					qcom,entry-latency-us = <273>;
+					qcom,exit-latency-us = <612>;
+					qcom,min-residency-us = <952>;
+					qcom,is-reset;
+				};
+
+				qcom,pm-cpu-level@3 {  /* C4 */
+					reg = <3>;
+					label = "rail-pc";
+					qcom,psci-cpu-mode = <0x4>;
+					qcom,entry-latency-us = <300>;
+					qcom,exit-latency-us = <700>;
+					qcom,min-residency-us = <4488>;
+					qcom,is-reset;
+				};
+			};
+		};
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/rpm_stats.txt b/Documentation/devicetree/bindings/arm/msm/rpm_stats.txt
new file mode 100644
index 0000000..8b4bc6a
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/rpm_stats.txt
@@ -0,0 +1,40 @@
+* RPM Stats
+
+RPM maintains a counter of the number of times the SoC entered a deeper sleep
+mode involving lowering or powering down the backbone rails - Cx and Mx and
+the oscillator clock, XO.
+
+PROPERTIES
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: Should be "qcom,rpm-stats".
+
+- reg:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: The address on the RPM RAM from where the stats are read
+	            should be provided as "phys_addr_base". The offset from
+	            which the stats are available should be provided as
+	            "offset_addr".
+
+- reg-names:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: Provides labels for the reg property.
+
+- qcom,num-records:
+	Usage: optional
+	Value type: <u32>
+	Definition: Specifies number of records to read from RPM RAM.
+
+EXAMPLE:
+
+	qcom,rpm-stats@c000000 {
+		compatible = "qcom,rpm-stats";
+		reg = <0xC000000 0x1000>, <0x3F0000 0x4>;
+		reg-names = "phys_addr_base", "offset_addr";
+		qcom,num-records = <3>;
+	};
+
diff --git a/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
new file mode 100644
index 0000000..a53eba5
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
@@ -0,0 +1,31 @@
+* RPMH Master Stats
+
+Differet Subsystems maintains master data in SMEM.
+It tells about the individual masters information at any given
+time like "system sleep counts", "system sleep last entered at"
+and "system sleep accumulated duration" etc. These stats can be
+displayed using the sysfs interface.
+To achieve this, device tree node has been added.
+
+Additionally, RPMH master stats also maintains application processor's
+master stats. It uses profiling units to calculate power down and power
+up stats.
+
+The required properties for rpmh-master-stats are:
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: Should be "qcom,rpmh-master-stats-v1".
+
+- reg:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: Specifies physical address of start of profiling unit.
+
+Example:
+
+qcom,rpmh-master-stats {
+	compatible = "qcom,rpmh-master-stats";
+	reg = <0xb221200 0x60>;
+};
diff --git a/Documentation/devicetree/bindings/arm/msm/system_pm.txt b/Documentation/devicetree/bindings/arm/msm/system_pm.txt
new file mode 100644
index 0000000..9628d9e
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/system_pm.txt
@@ -0,0 +1,29 @@
+SYSTEM PM
+
+System PM device is a virtual device that handles all CPU subsystem low power
+mode activties. When entering core shutdown, resource state that were requested
+from the processor may be relinquished and set to idle and restored when the
+cores are brought out of sleep.
+
+PROPERTIES
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: must be "qcom,system-pm".
+
+-mboxes:
+	Usage: optional
+	Value type: <phandle>
+	Definition: phandle the TCS mailbox controller for the CPU subsystem.
+	This property is generally set only for SoCs that use RPMH communication
+	through a mailbox controller.
+
+EXAMPLE
+
+	system_pm {
+		compatible = "qcom,system-pm";
+		mboxes = <&apps_rsc 0>;
+	};
+
+
diff --git a/Documentation/devicetree/bindings/gpu/adreno-busmon.txt b/Documentation/devicetree/bindings/gpu/adreno-busmon.txt
new file mode 100644
index 0000000..f9a99bb
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/adreno-busmon.txt
@@ -0,0 +1,16 @@
+Adreno bus monitor device
+
+kgsl-busmon is a psedo device that represents a devfreq bus bandwidth
+governor. If this device is present then two different governors are used
+for GPU DCVS and bus DCVS.
+
+Required properties:
+- compatible:	Must be "qcom,kgsl-busmon"
+- label:	Device name used for sysfs entry.
+
+Example:
+
+qcom,kgsl-busmon {
+	compatible = "qcom,kgsl-busmon";
+	label = "kgsl-busmon";
+};
diff --git a/Documentation/devicetree/bindings/gpu/adreno-gmu.txt b/Documentation/devicetree/bindings/gpu/adreno-gmu.txt
new file mode 100644
index 0000000..062551e
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/adreno-gmu.txt
@@ -0,0 +1,129 @@
+Qualcomm Technologies, Inc. GPU Graphics Management Unit (GMU)
+
+Required properties:
+- compatible :
+	- "qcom,gpu-gmu"
+	- "qcom,gpu-rgmu"
+- reg:		Specifies the GMU register base address and size.
+- reg-names:		Resource names used for the physical address
+		and length of GMU registers.
+- interrupts:	Interrupt mapping for GMU and HFI IRQs.
+- interrupt-names:	String property to describe the name of each interrupt.
+
+Bus Scaling Data:
+qcom,msm-bus,name: String property to describe the name of bus client.
+qcom,msm-bus,num-cases: This is the the number of Bus Scaling use cases defined in the vectors property.
+qcom,msm-bus,num-paths: This represents the number of paths in each Bus Scaling Usecase.
+qcom,msm-bus,vectors-KBps: A series of 4 cell properties, format of which is:
+		<src dst ab ib>, <src dst ab ib>, // For Bus Scaling Usecase 1
+		<src dst ab ib>, <src dst ab ib>, // For Bus Scaling Usecase 2
+		<..  ..  .. ..>, <..  ..  .. ..>; // For Bus Scaling Usecase n
+		This property is a series of all vectors for all Bus Scaling Usecases.
+		Each set of vectors for each usecase describes bandwidth votes for a combination
+		of src/dst ports.  The driver will set the desired use case based on the selected
+		power level and the desired bandwidth vote will be registered for the port pairs.
+
+GMU GDSC/regulators:
+- regulator-names:	List of regulator name strings
+- vddcx-supply:		Phandle for vddcx regulator device node.
+- vdd-supply:		Phandle for vdd regulator device node.
+
+- clock:	List of clocks to be used for GMU register access and DCVS. See
+		  Documentation/devicetree/bindings/clock/clock-bindings.txt
+		  for information about the format. For each clock specified
+		  here, there must be a corresponding entry in clock-names
+		  (see below).
+
+- clock-names:	List of clock names corresponding to the clocks specified in
+		  the "clocks" property (above). See
+		  Documentation/devicetree/bindings/clock/clock-bindings.txt
+		  for more info. Currently GMU required these clock names:
+			"gmu_clk", "ahb_clk", "cxo_clk", "axi_clk", "memnoc_clk",
+			"rbcpr_clk"
+
+- qcom,gmu-pwrlevels: device node defines a set of GMU power levels. It has
+		following required properties:
+
+		- compatible : "qcom,gmu-pwrlevels"
+		- qcom,gmu-pwrlevel: a single power level. Each power level has
+		  below properties:
+			- reg: index of the powerlevel (0 = highest perf)
+			- qcom, gmu-freq: GMU frequency for the power level in Hz.
+
+- List of sub nodes, one for each of the translation context banks needed
+		for GMU to access system memory in different operating mode. Currently
+		supported names are:
+		- gmu_user: used for GMU 'user' mode address space.
+		- gmu_kernel: used for GMU 'kernel' mode address space.
+		Each sub node has the following required properties:
+
+		- compatible : "qcom,smmu-gmu-user-cb" or "qcom,smmu-gmu-kernel-cb"
+		- iommus : Specifies the SID's used by this context bank, this
+			needs to be <kgsl_smmu SID> pair, kgsl_smmu is the string
+			parsed by iommu driver to match this context bank with the
+			kgsl_smmu device defined in iommu device tree. On targets
+			where the msm iommu driver is used rather than the arm smmu
+			driver, this property may be absent.
+
+Example:
+
+gmu: qcom,gmu@2c6a000 {
+	label = "kgsl-gmu";
+	compatible = "qcom,gpu-gmu";
+
+	reg = <0x2c6a000 0x30000>;
+	reg-names = "kgsl_gmu_reg";
+
+	interrupts = <0 304 0>, <0 305 0>;
+	interrupt-names = "kgsl_gmu_irq", "kgsl_hfi_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-name = "vddcx", "vdd";
+	vddcx-supply = <&gpu_cx_gdsc>;
+	vdd-supply = <&gpu_gx_gdsc>;
+
+	clocks = <&clock_gpugcc clk_gcc_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_gpucc GPU_CC_RBCPR_CLK>;
+
+	clock-names = "gmu_clk", "ahb_clk", "cxo_clk",
+				"axi_clk", "memnoc_clk", "rbcpr_clk";
+
+	qcom,gmu-pwrlevels {
+
+	      compatible = "qcom,gmu-pwrlevels";
+	      qcom,gpu-pwrlevel@0 {
+	          reg = <0>;
+	          qcom,gmu-freq = <500000000>;
+	      };
+
+	      qcom,gpu-pwrlevel@1 {
+	          reg = <1>;
+	          qcom,gmu-freq = <200000000>;
+	      };
+
+	      qcom,gpu-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/Documentation/devicetree/bindings/gpu/adreno-iommu.txt b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
new file mode 100644
index 0000000..175c51a
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
@@ -0,0 +1,93 @@
+Qualcomm Technologies, Inc. GPU IOMMU
+
+Required properties:
+
+Required properties:
+- compatible : one of:
+	- "qcom,kgsl-smmu-v1"
+	- "qcom,kgsl-smmu-v2"
+
+- reg		: Base address and size of the SMMU.
+
+- clocks	: List of clocks to be used during SMMU register access. See
+		  Documentation/devicetree/bindings/clock/clock-bindings.txt
+		  for information about the format. For each clock specified
+		  here, there must be a corresponding entry in clock-names
+		  (see below).
+
+- clock-names	: List of clock names corresponding to the clocks specified in
+		  the "clocks" property (above). See
+		  Documentation/devicetree/bindings/clock/clock-bindings.txt
+		  for more info.
+- qcom,protect  : The GPU register region which must be protected by a CP
+		  protected mode. On some targets this region must cover
+		  the entire SMMU register space, on others there
+		  is a separate aperture for CP to program context banks.
+
+Optional properties:
+- qcom,micro-mmu-control : Some targets provide an implementation defined
+		  register for blocking translation requests during GPU side
+		  programming.  This property specifies the offset of this
+		  register within the iommu register space.
+- qcom,retention :  A boolean specifying if retention is supported on this target
+- qcom,global_pt :  A boolean specifying if global pagetable should be used.
+		  When not set we use per process pagetables
+- qcom,hyp_secure_alloc : A bool specifying if the hypervisor is used on this target
+		  for secure buffer allocation
+- qcom,secure_align_mask: A mask for determining how secure buffers need to
+		  be aligned
+
+- List of sub nodes, one for each of the translation context banks supported.
+  The driver uses the names of these nodes to determine how they are used,
+  currently supported names are:
+  - gfx3d_user : Used for the 'normal' GPU address space.
+  - gfx3d_secure : Used for the content protection address space.
+  - gfx3d_secure_alt : Used for the content protection address space for alternative SID.
+
+  Each sub node has the following required properties:
+
+	- compatible : "qcom,smmu-kgsl-cb"
+	- iommus : Specifies the SID's used by this context bank, this needs to be
+		   <kgsl_smmu SID> pair, kgsl_smmu is the string parsed by iommu
+		   driver to match this context bank with the kgsl_smmu device
+		   defined in iommu device tree. On targets where the msm iommu
+		   driver is used rather than the arm smmu driver, this property
+		   may be absent.
+	- qcom,gpu-offset :  Offset into the GPU register space for accessing
+		   this context bank. On some targets the iommu registers are not
+		   part of the GPU's register space, and a separate register aperture
+		   is used. Otherwise the same register offsets may be used for CPU
+		   or GPU side programming.
+
+Example:
+
+msm_iommu: qcom,kgsl-iommu@2ca0000 {
+	compatible = "qcom,kgsl-smmu-v2";
+	reg = <0x2ca0000 0x10000>;
+	qcom,protect = <0xa0000 0xc000>;
+	clocks = <&clock_mmss clk_gpu_ahb_clk>,
+		<&clock_gcc clk_gcc_mmss_bimc_gfx_clk>,
+		<&clock_mmss clk_mmss_mmagic_ahb_clk>,
+		<&clock_mmss clk_mmss_mmagic_cfg_ahb_clk>;
+	clock-names = "gpu_ahb_clk", "bimc_gfx_clk", "mmagic_ahb_clk", "mmagic_cfg_ahb_clk";
+	qcom,secure_align_mask = <0xfff>;
+	qcom,retention;
+	qcom,global_pt;
+
+	gfx3d_user: gfx3d_user {
+		compatible = "qcom,smmu-kgsl-cb";
+		iommus = <&kgsl_smmu 0>,
+			 <&kgsl_smmu 1>;
+		qcom,gpu-offset = <0xa8000>;
+	};
+
+	gfx3d_secure: gfx3d_secure {
+		compatible = "qcom,smmu-kgsl-cb";
+		iommus = <&kgsl_smmu 2>;
+	};
+
+	gfx3d_secure_alt: gfx3d_secure_alt {
+		compatible = "qcom,smmu-kgsl-cb";
+		iommus = <&kgsl_smmu 2>, <&kgsl_smmu 1>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt
new file mode 100644
index 0000000..0b4510a
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt
@@ -0,0 +1,45 @@
+Qualcomm Technologies, Inc. GPU powerlevels
+
+Powerlevels are defined in sets by qcom,gpu-pwrlevels. Multiple sets (bins)
+can be defined within qcom,gpu-pwrelvel-bins. Each powerlevel defines a
+voltage, bus, bandwidth level, and a DVM value.
+
+- qcom,gpu-pwrlevel-bins:	Contains one or more qcom,gpu-pwrlevels sets
+
+Properties:
+- compatible:			Must be qcom,gpu-pwrlevel-bins
+- qcom,gpu-pwrlevels:		Defines a set of powerlevels
+
+Properties:
+- qcom,speed-bin:		Speed bin identifier for the set - must match
+				the value read from the hardware
+- qcom,initial-pwrlevel:	GPU wakeup powerlevel
+
+- qcom,gpu-pwrlevel:		A single powerlevel
+
+- qcom,ca-target-pwrlevel:
+				This value indicates which qcom,gpu-pwrlevel
+				to jump on in case of context aware power level
+				jump.
+Properties:
+- reg:				Index of the powerlevel (0 = highest perf)
+- qcom,gpu-freq			GPU frequency for the powerlevel (in Hz)
+- qcom,bus-freq			Index to a bus level (defined by the bus
+				settings)
+- qcom,bus-min			Minimum bus level to set for the power level
+- qcom,bus-max			maximum bus level to set for the power level
+- qcom,dvm-val:			Value that is used as a register setting for
+				the ACD power feature. It helps determine the
+				threshold for when ACD activates. 0xFFFFFFFF
+				is the default value, and the setting where
+				ACD will never activate.
+Example:
+
+qcom,gpu-pwrlevel@6 {
+	reg = <6>;
+	qcom,gpu-freq = <0>;
+	qcom,bus-freq = <0>;
+	qcom,bus-min = <0>;
+	qcom,bus-max = <0>;
+	qcom,dvm-val = <0xffffffff>;
+};
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
new file mode 100644
index 0000000..bbb1f54
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -0,0 +1,471 @@
+Qualcomm Technologies, Inc. GPU
+
+Qualcomm Technologies, Inc. Adreno GPU
+
+Required properties:
+- label:		A string used as a descriptive name for the device.
+- compatible:		Must be "qcom,kgsl-3d0" and "qcom,kgsl-3d"
+- reg:			Specifies the register base address and size, the shader memory
+			base address and size (if it exists), and the base address and size
+			of the CX_DBGC block (if it exists).
+- reg-names:		Resource names used for the physical address of device registers
+			and shader memory. "kgsl_3d0_reg_memory" gives the physical address
+			and length of device registers while "kgsl_3d0_shader_memory" gives
+			physical address and length of device shader memory.  If
+			specified, "qfprom_memory" gives the range for the efuse
+			registers used for various configuration options. If specified,
+			"kgsl_3d0_cx_dbgc_memory" gives the physical address and length
+			of the CX DBGC block.
+- interrupts:		Interrupt mapping for GPU IRQ.
+- interrupt-names:	String property to describe the name of the interrupt.
+- qcom,id:		An integer used as an identification number for the device.
+- qcom,gpu-bimc-interface-clk-freq:
+			GPU-BIMC interface clock needs to be set to this value for
+			targets where B/W requirements does not meet GPU Turbo use cases.
+- clocks:		List of phandle and clock specifier pairs, one pair
+			for each clock input to the device.
+- clock-names:		List of clock input name strings sorted in the same
+			order as the clocks property.
+				Current values of clock-names are:
+				"src_clk", "core_clk", "iface_clk", "mem_clk", "mem_iface_clk",
+				"alt_mem_iface_clk", "rbbmtimer_clk",  "alwayson_clk",
+				"iref_clk", "l3_vote"
+				"core_clk" and "iface_clk" are required and others are optional
+
+- qcom,base-leakage-coefficient: Dynamic leakage coefficient.
+- qcom,lm-limit:	Current limit for GPU limit management.
+- qcom,isense-clk-on-level: below or equal this power level isense clock is at XO rate,
+				above this powerlevel isense clock is at working frequency.
+
+Bus Scaling Data:
+- qcom,msm-bus,name: String property to describe the name of the 3D graphics processor.
+- qcom,msm-bus,num-cases: This is the the number of Bus Scaling use cases defined in the vectors property.
+- qcom,msm-bus,active-only: A boolean flag indicating if it is active only.
+- qcom,msm-bus,num-paths: This represents the number of paths in each Bus Scaling Usecase.
+- qcom,msm-bus,vectors-KBps: A series of 4 cell properties, format of which is:
+					<src dst ab ib>, <src dst ab ib>, // For Bus Scaling Usecase 1
+					<src dst ab ib>, <src dst ab ib>, // For Bus Scaling Usecase 2
+					<..  ..  .. ..>, <..  ..  .. ..>; // For Bus Scaling Usecase n
+					This property is a series of all vectors for all Bus Scaling Usecases.
+					Each set of vectors for each usecase describes bandwidth votes for a combination
+					of src/dst ports.  The driver will set the desired use case based on the selected
+					power level and the desired bandwidth vote will be registered for the port pairs.
+				Current values of src are:
+					0 = MSM_BUS_MASTER_GRAPHICS_3D
+					1 = MSM_BUS_MASTER_GRAPHICS_3D_PORT1
+					2 = MSM_BUS_MASTER_V_OCMEM_GFX3D
+				Current values of dst are:
+					0 = MSM_BUS_SLAVE_EBI_CH0
+					1 = MSM_BUS_SLAVE_OCMEM
+				ab: Represents aggregated bandwidth. This value is 0 for Graphics.
+				ib: Represents instantaneous bandwidth. This value has a range <0 8000 MB/s>
+
+- qcom,ocmem-bus-client: Container for another set of bus scaling properties
+						qcom,msm-bus,name
+						qcom,msm-bus,num-cases
+						qcom,msm-bus,num-paths
+						qcom,msm-bus,vectors-KBps
+			to be used by ocmem msm bus scaling client.
+
+GDSC Oxili Regulators:
+- regulator-names:		List of regulator name strings sorted in power-on order
+- vddcx-supply:			Phandle for vddcx regulator device node.
+- vdd-supply:			Phandle for vdd regulator device node.
+
+IOMMU Data:
+- iommu:			Phandle for the KGSL IOMMU device node
+
+GPU Power levels:
+- qcom,gpu-pwrlevel-bins:	Container for sets of GPU power levels (see
+				adreno-pwrlevels.txt)
+DCVS Core info
+- qcom,dcvs-core-info		Container for the DCVS core info (see
+				dcvs-core-info.txt)
+
+Optional Properties:
+- qcom,initial-powerlevel: This value indicates which qcom,gpu-pwrlevel should be used at start time
+			   and when coming back out of resume
+- qcom,bus-control:	   Boolean. Enables an independent bus vote from the gpu frequency
+- qcom,bus-width:	   Bus width in number of bytes. This enables dynamic AB bus voting based on
+			   bus width and actual bus transactions.
+- qcom,gpubw-dev:	   a phandle to a device representing bus bandwidth requirements
+			   (see devdw.txt)
+- qcom,idle-timeout:	   This property represents the time in milliseconds for idle timeout.
+- qcom,no-nap:		   If it exists software clockgating will be disabled at boot time.
+- qcom,chipid:		   If it exists this property is used to replace
+			   the chip identification read from the GPU hardware.
+			   This is used to override faulty hardware readings.
+- qcom,disable-wake-on-touch:   Boolean. Disables the GPU power up on a touch input event.
+- qcom,disable-busy-time-burst:
+				Boolean. Disables the busy time burst to avoid switching
+				of power level for large frames based on the busy time limit.
+
+- qcom,pm-qos-active-latency:
+				Right after GPU wakes up from sleep, driver votes for
+				acceptable maximum latency to the pm-qos driver. This
+				voting demands that the system can not go into any
+				power save state *if* the latency to bring system back
+				into active state is more than this value.
+				Value is in microseconds.
+- qcom,pm-qos-wakeup-latency:
+				Similar to the above. Driver votes against deep low
+				power modes right before GPU wakes up from sleep.
+- qcom,l2pc-cpu-mask-latency:
+				The CPU mask latency in microseconds to avoid L2PC
+				on masked CPUs.
+
+- qcom,gpu-cx-ipeak:
+				CX Ipeak is a mitigation scheme which throttles cDSP frequency
+				if all the clients are running at their respective threshold
+				frequencies to limit CX peak current.
+				<phandle bit>
+				phandle - phandle of CX Ipeak device node
+				bit     - Every bit corresponds to a client of CX Ipeak
+				driver in the relevant register.
+- qcom, gpu-cx-ipeak-freq:
+				GPU frequency threshold for CX Ipeak voting. GPU votes
+				to CX Ipeak driver when GPU clock crosses this threshold.
+				CX Ipeak can limit peak current based on voting from other clients.
+
+- qcom,force-32bit:
+				Force the GPU to use 32 bit data sizes even if
+				it is capable of doing 64 bit.
+
+- qcom,gpu-speed-bin:      GPU speed bin information in the format
+			   <offset mask shift>
+				offset - offset of the efuse register from the base.
+				mask   - mask for the relevant bits in the efuse register.
+				shift  - number of bits to right shift to get the speed bin
+				value.
+- qcom,gpu-disable-fuse:	GPU disable fuse
+				<offset mask shift>
+				offset - offset of the efuse register from the base.
+				mask   - mask for the relevant bits in the efuse register.
+				shift  - number of bits to right shift to get the disable_gpu
+				fuse bit value.
+
+- qcom,soc-hw-rev-efuse:	SOC hardware revision fuse information in the format
+				<offset bit_position mask>
+				offset - offset of the efuse register from the base.
+				bit_position - hardware revision starting bit in the efuse register.
+				mask - mask for the relevant bits in the efuse register.
+
+- qcom,highest-bank-bit:
+				Specify the bit of the highest DDR bank. This
+				is programmed into protected registers and also
+				passed to the user as a property.
+- qcom,min-access-length:
+				Specify the minimum access length for the chip.
+				Either 32 or 64 bytes.
+				Based on the above options, program the appropriate bit into
+				certain protected registers and also pass to the user as
+				a property.
+- qcom,ubwc-mode:
+				Specify the ubwc mode for this chip.
+				1: UBWC 1.0
+				2: UBWC 2.0
+				3: UBWC 3.0
+				Based on the ubwc mode, program the appropriate bit into
+				certain protected registers and also pass to the user as
+				a property.
+- qcom,l2pc-cpu-mask:
+				Disables L2PC on masked CPUs when any of Graphics
+				rendering thread is running on masked CPUs.
+				Bit 0 is for CPU-0, bit 1 is for CPU-1...
+
+- qcom,l2pc-update-queue:
+				Disables L2PC on masked CPUs at queue time when it's true.
+
+- qcom,snapshot-size:
+				Specify the size of snapshot in bytes. This will override
+				snapshot size defined in the driver code.
+
+- qcom,enable-ca-jump:
+                                Boolean. Enables use of context aware DCVS
+- qcom,ca-busy-penalty:
+                                This property represents the time in microseconds required to
+                                initiate context aware power level jump.
+- qcom,ca-target-pwrlevel:
+                                This value indicates which qcom,gpu-pwrlevel to jump on in case
+                                of context aware power level jump.
+
+- qcom,gpu-qdss-stm:
+				<baseAddr size>
+				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.
+
+- qcom,enable-midframe-timer:
+				Boolean. Enables the use of midframe sampling timer. This timer
+				samples the GPU powerstats if the cmdbatch expiry takes longer than
+				the threshold set by KGSL_GOVERNOR_CALL_INTERVAL. Enable only if
+				target has NAP state enabled.
+
+GPU Quirks:
+- qcom,gpu-quirk-two-pass-use-wfi:
+				Signal the GPU to set Set TWOPASSUSEWFI bit in
+				PC_DBG_ECO_CNTL (5XX and 6XX only)
+- qcom,gpu-quirk-critical-packets:
+				Submit a set of critical PM4 packets when the GPU wakes up
+- qcom,gpu-quirk-fault-detect-mask:
+				Mask out RB1-3 activity signals from HW hang
+				detection logic
+- qcom,gpu-quirk-dp2clockgating-disable:
+				Disable RB sampler data path clock gating optimization
+- qcom,gpu-quirk-lmloadkill-disable:
+				Use register setting to disable local memory(LM) feature
+				to avoid corner case error
+- qcom,gpu-quirk-hfi-use-reg:
+				Use registers to replace DCVS HFI message to avoid GMU failure
+				to access system memory during IFPC
+- qcom,gpu-quirk-limit-uche-gbif-rw:
+				Limit number of read and write transactions from UCHE block to
+				GBIF to avoid possible deadlock between GBIF, SMMU and MEMNOC.
+- qcom,gpu-quirk-mmu-secure-cb-alt:
+				Select alternate secure context bank to generate SID1 for
+				secure playback.
+
+KGSL Memory Pools:
+- qcom,gpu-mempools:		Container for sets of GPU mempools.Multiple sets
+				(pools) can be defined within qcom,gpu-mempools.
+				Each mempool defines a pool order, reserved pages,
+				allocation allowed.
+Properties:
+- compatible:			Must be qcom,gpu-mempools.
+- qcom,mempool-max-pages:	Max pages for all mempools, If not defined there is no limit.
+- qcom,gpu-mempool:		Defines a set of mempools.
+
+Properties:
+- reg:				Index of the pool (0 = lowest pool order).
+- qcom,mempool-page-size:	Size of page.
+- qcom,mempool-reserved:	Number of pages reserved at init time for a pool.
+- qcom,mempool-allocate:	Allocate memory from the system memory when the
+				reserved pool exhausted.
+
+SOC Hardware revisions:
+- qcom,soc-hw-revisions:
+		Container of sets of SOC hardware revisions specified by
+		qcom,soc-hw-revision.
+Properties:
+- compatible:
+		Must be qcom,soc-hw-revisions.
+
+- qcom,soc-hw-revision:
+		Defines a SOC hardware revision.
+
+Properties:
+-  qcom,soc-hw-revision:
+		Identifier for the hardware revision - must match the value read
+		from the hardware.
+- qcom,chipid:
+		GPU Chip ID to be used for this hardware revision.
+- qcom,gpu-quirk-*:
+		GPU quirks applicable for this hardware revision.
+
+GPU LLC slice info:
+- cache-slice-names:		List of LLC cache slices for GPU transactions
+				and pagetable walk.
+- cache-slices:			phandle to the system LLC driver, cache slice index.
+
+L3 Power levels:
+- qcom,l3-pwrlevels:		Container for sets of L3 power levels, the
+				L3 frequency is adjusted according to the
+				performance hint received from userspace.
+
+Properties:
+- compatible:			Must be qcom,l3-pwrlevels
+- qcom,l3-pwrlevel:		A single L3 powerlevel
+
+Properties:
+- reg:				Index of the L3 powerlevel
+				0 = powerlevel for no L3 vote
+				1 = powerlevel for medium L3 vote
+				2 = powerlevel for maximum L3 vote
+- qcom,l3-freq:			The L3 frequency for the powerlevel (in Hz)
+
+GPU coresight info:
+The following properties are optional as collecting data via coresight might
+not be supported for every chipset. The documentation for coresight
+properties can be found in:
+Documentation/devicetree/bindings/coresight/coresight.txt
+
+- qcom,gpu-coresights:	 Container for sets of GPU coresight sources.
+- coresight-id:          Unique integer identifier for the bus.
+- coresight-name:        Unique descriptive name of the bus.
+- coresight-nr-inports:  Number of input ports on the bus.
+- coresight-outports:    List of output port numbers on the bus.
+- coresight-child-list:  List of phandles pointing to the children of this
+                         component.
+- coresight-child-ports: List of input port numbers of the children.
+- coresight-atid:        The unique ATID value of the coresight device
+
+Example of A330 GPU in MSM8916:
+
+&soc {
+	msm_gpu: qcom,kgsl-3d0@1c00000 {
+		label = "kgsl-3d0";
+		compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+		reg = <0x1c00000 0x10000
+		       0x1c20000 0x20000>;
+		reg-names = "kgsl_3d0_reg_memory" , "kgsl_3d0_shader_memory";
+		interrupts = <0 33 0>;
+		interrupt-names = "kgsl_3d0_irq";
+		qcom,id = <0>;
+
+		qcom,chipid = <0x03000600>;
+
+		qcom,initial-pwrlevel = <1>;
+
+		/* Idle Timeout = HZ/12 */
+		qcom,idle-timeout = <8>;
+		qcom,strtstp-sleepwake;
+
+		clocks = <&clock_gcc clk_gcc_oxili_gfx3d_clk>,
+			<&clock_gcc clk_gcc_oxili_ahb_clk>,
+			<&clock_gcc clk_gcc_oxili_gmem_clk>,
+			<&clock_gcc clk_gcc_bimc_gfx_clk>,
+			<&clock_gcc clk_gcc_bimc_gpu_clk>;
+		clock-names = "core_clk", "iface_clk", "mem_clk",
+				"mem_iface_clk", "alt_mem_iface_clk";
+
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "grp3d";
+		qcom,msm-bus,num-cases = <4>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<26 512 0 0>,
+			<26 512 0 1600000>,
+			<26 512 0 3200000>,
+			<26 512 0 4264000>;
+
+		/* GDSC oxili regulators */
+		vdd-supply = <&gdsc_oxili_gx>;
+
+		/* IOMMU Data */
+		iommu = <&gfx_iommu>;
+
+		/* Trace bus */
+		coresight-id = <67>;
+		coresight-name = "coresight-gfx";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <5>;
+
+		/* Enable context aware freq. scaling */
+		qcom,enable-ca-jump;
+
+		/* Context aware jump busy penalty in us */
+		qcom,ca-busy-penalty = <12000>;
+
+		/* Context aware jump target power level */
+		qcom,ca-target-pwrlevel = <1>;
+
+		qcom,soc-hw-revisions {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			compatible="qcom,soc-hw-revisions";
+
+			qcom,soc-hw-revision@0 {
+				reg = <0>;
+
+				qcom,chipid = <0x06010500>;
+				qcom,gpu-quirk-hfi-use-reg;
+				qcom,gpu-quirk-limit-uche-gbif-rw;
+			};
+
+			qcom,soc-hw-revision@1 {
+				reg = <1>;
+
+				qcom,chipid = <0x06010501>;
+				qcom,gpu-quirk-hfi-use-reg;
+			};
+		};
+
+		/* 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-bins {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,gpu-pwrlevels-0 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				qcom,speed-bin = <0>;
+				qcom,ca-target-pwrlevel = <1>;
+
+				qcom,gpu-pwrlevel@0 {
+					reg = <0>;
+					qcom,gpu-freq = <400000000>;
+					qcom,bus-freq = <3>;
+					qcom,io-fraction = <33>;
+				};
+
+				qcom,gpu-pwrlevel@1 {
+					reg = <1>;
+					qcom,gpu-freq = <310000000>;
+					qcom,bus-freq = <2>;
+					qcom,io-fraction = <66>;
+				};
+
+				qcom,gpu-pwrlevel@2 {
+					reg = <2>;
+					qcom,gpu-freq = <200000000>;
+					qcom,bus-freq = <1>;
+					qcom,io-fraction = <100>;
+				};
+
+				qcom,gpu-pwrlevel@3 {
+					reg = <3>;
+					qcom,gpu-freq = <27000000>;
+					qcom,bus-freq = <0>;
+					qcom,io-fraction = <0>;
+				};
+			};
+		};
+
+	};
+};
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index 1113039..f720ef4 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -180,6 +180,63 @@
                   property, indicating the number of Stream ID
                   arguments associated with its phandle.
 
+** Additional properties for Iommu Clients:
+- qcom,iommu-dma:
+		Optional, String.
+		Can be one of "bypass", "fastmap", "atomic", "disabled".
+--- "default":
+		Standard iommu translation behavior.
+		The iommu framework will automatically create a domain for the client.
+		iommu and DMA apis may not be called in atomic context.
+--- "bypass":
+		DMA APIs will use 1-to-1 translation between dma_addr and phys_addr.
+		Allows using iommu and DMA apis in atomic context.
+--- "fastmap":
+		DMA APIs will run faster, but use several orders of magnitude more memory.
+		Also allows using iommu and DMA apis in atomic context.
+--- "atomic":
+		Allows using iommu and DMA apis in atomic context.
+--- "disabled":
+		The iommu client is responsible for allocating an iommu domain, as
+		well as calling iommu_map to create the desired mappings.
+
+- qcom,iommu-faults:
+		Optional, List of Strings.
+		The SCTLR register setting which affect iommu faults handling.
+		Any combination of the below strings may be used. Mutliple
+		values are accepted.
+--- "default":
+		Any faults are treated as fatal errors.
+--- "no-CFRE":
+		Iommu faults do not return an abort to the client hardware.
+--- "non-fatal":
+		Iommu faults do not trigger a kernel panic.
+--- "stall-disable":
+		Iommu faults do not stall the client while the fault
+		interrupt is being handled.
+
+- qcom,iommu-vmid:
+		Optional, Int.
+		An identifier indicating the security state of the client.
+
+- qcom,iommu-pagetable:
+		Optional, String.
+		Enables coherency for the IOMMU device, but not for the Client.
+--- "default":
+		Pagetables are not coherent nor cached in the system cache..
+--- "coherent"
+		Pagetables are io-coherent.
+--- "LLC"
+		Pagetables may be saved in the system cache.
+--- "LLC_NWA"
+		Pagetables may be saved in the system cache is used, and
+		 write-allocate hint is disabled.
+
+- qcom,iommu-earlymap:
+		Optional, Bool.
+		Support creating mappings in the page-table before Stage 1 translation is
+		enabled.
+
 ** Examples:
 
         /* SMMU with stream matching or stream indexing */
diff --git a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt
new file mode 100644
index 0000000..cace019
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt
@@ -0,0 +1,290 @@
+Bindings for Qualcomm Technologies, Inc. WLED driver
+
+WLED (White Light Emitting Diode) driver is used for controlling display
+backlight that is part of PMIC on Qualcomm Technologies, Inc. reference
+platforms. The PMIC is connected to the host processor via SPMI bus.
+
+- compatible
+	Usage:      required
+	Value type: <string>
+	Definition: should be one of the below.
+			"qcom,pmi8998-spmi-wled",
+			"qcom,pm8150l-spmi-wled",
+			"qcom,pm6150l-spmi-wled"
+
+- reg
+	Usage:      required
+	Value type: <prop-encoded-array>
+	Definition:  Base address and size of the WLED modules.
+
+- reg-names
+	Usage:      required
+	Value type: <string>
+	Definition:  Names associated with base addresses. should be
+		     "wled-ctrl-base", "wled-sink-base".
+
+- interrupts
+	Usage:      optional
+	Value type: <prop encoded array>
+	Definition: Interrupts associated with WLED. Interrupts can be
+		    specified as per the encoding listed under
+		    Documentation/devicetree/bindings/spmi/
+		    qcom,spmi-pmic-arb.txt.
+
+- interrupt-names
+	Usage:      optional
+	Value type: <string>
+	Definition: Interrupt names associated with the interrupts.
+		    Currently supported interrupts are "sc-irq", "ovp-irq",
+		    "pre-flash-irq" and "flash-irq". Pre_flash and flash
+		    interrupts can be specified only for PMICs that has WLED5.
+
+- label
+	Usage:      required
+	Value type: <string>
+	Definition: The name of the backlight device.
+
+- default-brightness
+	Usage:      optional
+	Value type: <u32>
+	Definition: Brightness value on boot. Default is 2048.
+		    Range of values are:
+		    For pmi8998, it is 0-4095.
+		    For pm8150l, this can vary from 0-4095 or 0-32767 depending
+		    on the brightness control mode. If CABC is enabled, 0-4095
+		    range is used.
+
+- max-brightness
+	Usage:      optional
+	Value type: <u32>
+	Definition: Maximum brightness level. Allowed values are:
+		    For pmi8998, it is 4095.
+		    For pm8150l, this can be either 4095 or 32767.
+		    If CABC is enabled, this is capped to 4095.
+
+- qcom,fs-current-limit
+	Usage:      optional
+	Value type: <u32>
+	Definition: per-string full scale current limit in uA. value from
+		    0 to 30000 with 5000 uA resolution. Default: 25000 uA
+
+- qcom,boost-current-limit
+	Usage:      optional
+	Value type: <u32>
+	Definition: ILIM threshold in mA. values are 105, 280, 450, 620, 970,
+		    1150, 1300, 1500. Default: 970 mA
+
+- qcom,switching-freq
+	Usage:      optional
+	Value type: <u32>
+	Definition: Switching frequency in KHz. values are
+		    600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371,
+		    1600, 1920, 2400, 3200, 4800, 9600.
+		    Default: 800 KHz
+
+- qcom,ovp
+	Usage:      optional
+	Value type: <u32>
+	Definition: Over-voltage protection limit in mV. values are 31100,
+		    29600, 19600, 18100.
+	            Default: 29600 mV
+
+- qcom,string-cfg
+	Usage:      optional
+	Value type: <u32>
+	Definition: Bit mask of the WLED strings. Bit 0 to 3 indicates strings
+		    0 to 3 respectively. WLED module has four strings of leds
+		    numbered from 0 to 3. Each string of leds are operated
+		    individually. Specify the strings using the bit mask. Any
+		    combination of led strings can be used.
+		    Default value is 15 (b1111).
+
+- qcom,en-cabc
+	Usage:      optional
+	Value type: <bool>
+	Definition: Specify if cabc (content adaptive backlight control) is
+		    needed.
+
+- qcom,ext-pfet-sc-pro-en
+	Usage:      optional
+	Value type: <bool>
+	Definition: Specify if external PFET control for short circuit
+		    protection is needed. This is not applicable for PM8150L.
+
+- qcom,auto-calibration
+	Usage:      optional
+	Value type: <bool>
+	Definition: Enables auto-calibration of the WLED sink configuration.
+
+- qcom,modulator-sel
+	Usage:      optional
+	Value type: <u32>
+	Definition: Selects the modulator used for brightness modulation.
+		    Allowed values are:
+		    0 - Modulator A
+		    1 - Modulator B
+		    If not specified, then modulator A will be used by default.
+		    This property is applicable only to WLED5 peripheral.
+
+- qcom,cabc-sel
+	Usage:      optional
+	Value type: <u32>
+	Definition: Selects the CABC pin signal used for brightness modulation.
+		    Allowed values are:
+		    0 - CABC disabled
+		    1 - CABC 1
+		    2 - CABC 2
+		    3 - External signal (e.g. LPG) is used for dimming
+		    This property is applicable only to WLED5 peripheral.
+
+- qcom,pmic-revid
+	Usage:      optional
+	Value type: <phandle>
+	Definition: If specified, can be used to get PMIC revision information.
+
+- qcom,leds-per-string
+	Usage:      optional
+	Value type: <u32>
+	Definition: If specified, can be used to calculate available current
+		    during selfie flash operation. If not specified, available
+		    current calculated is simply the configured threshold.
+
+Following properties are for child subnodes that are needed for WLED preflash
+(or torch), flash and switch. These child subnodes can be specified only for
+PMICs that has WLED5 (e.g. PM8150L).
+
+For wled_torch child subnode,
+
+- label
+	Usage:      required
+	Value type: <string>
+	Definition: Should be "torch".
+
+- qcom,default-led-trigger
+	Usage:      optional
+	Value type: <string>
+	Definition: Name for LED trigger. If unspecified, "wled_torch" is used.
+
+- qcom,wled-torch-fsc
+	Usage:      optional
+	Value type: <u32>
+	Definition: WLED torch full scale current in mA. This configures the
+		    maximum current allowed for torch device. Allowed values
+		    are from 5 to 60 mA with a step of 5 mA. If not specified,
+		    default value is set to 30 mA.
+
+- qcom,wled-torch-step
+	Usage:      optional
+	Value type: <u32>
+	Definition: WLED torch step delay in us. This configures the step delay
+		    when the output is ramped up to the desired target current.
+		    Allowed values are from 50 to 400 us with a step of 50 us.
+		    If not specified, default value is set to 200 us.
+
+- qcom,wled-torch-timer
+	Usage:      optional
+	Value type: <u32>
+	Definition: WLED torch safety timer in ms. This configures the safety
+		    timer to turn off torch automatically after timer expiry.
+		    Allowed values are: 50, 100, 200, 400, 600, 800, 1000 and
+		    1200. If not specified, default value is set to 1200 ms.
+
+For wled_flash child subnode,
+
+- label
+	Usage:      required
+	Value type: <string>
+	Definition: Should be "flash".
+
+- qcom,default-led-trigger
+	Usage:      optional
+	Value type: <string>
+	Definition: Name for LED trigger. If unspecified, "wled_flash" is used.
+
+- qcom,wled-flash-fsc
+	Usage:      optional
+	Value type: <u32>
+	Definition: WLED flash full scale current in mA. This configures the
+		    maximum current allowed for flash device. Allowed values
+		    are from 5 to 60 mA with a step of 5 mA. If not specified,
+		    default value is set to 40 mA.
+
+- qcom,wled-flash-step
+	Usage:      optional
+	Value type: <u32>
+	Definition: WLED flash step delay in us. This configures the step delay
+		    when the output is ramped up to the desired target current.
+		    Allowed values are from 50 to 400 us with a step of 50 us.
+		    If not specified, default value is set to 200 us.
+
+- qcom,wled-flash-timer
+	Usage:      optional
+	Value type: <u32>
+	Definition: WLED flash safety timer in ms. This configures the safety
+		    timer to turn off flash automatically after timer expiry.
+		    Allowed values are: 50, 100, 200, 400, 600, 800, 1000 and
+		    1200. If not specified, default value is set to 100 ms.
+
+For wled_switch child subnode,
+
+- label
+	Usage:      required
+	Value type: <string>
+	Definition: Should be "switch".
+
+- qcom,default-led-trigger
+	Usage:      optional
+	Value type: <string>
+	Definition: Name for LED trigger. If unspecified, "wled_switch" is
+		    used.
+
+Example:
+
+qcom-wled@d800 {
+	compatible = "qcom,pmi8998-spmi-wled";
+	#address-cells = <1>;
+	#size-cells = <0>;
+	reg = <0xd800 0xd900>;
+	reg-names = "wled-ctrl-base", "wled-sink-base";
+	label = "backlight";
+
+	interrupts = <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>,
+			<0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>;
+	interrupt-names = "sc-irq", "ovp-irq";
+	qcom,fs-current-limit = <25000>;
+	qcom,boost-current-limit = <970>;
+	qcom,switching-freq = <800>;
+	qcom,ovp = <29600>;
+	qcom,string-cfg = <15>;
+};
+
+qcom-wled@d800 {
+	compatible = "qcom,pm8150l-spmi-wled";
+	#address-cells = <2>;
+	#size-cells = <0>;
+	reg = <0xd800 0x100>, <0xd900 0x100>;
+	reg-names = "wled-ctrl-base", "wled-sink-base";
+	label = "backlight";
+
+	interrupts = <0x5 0xd8 0x1 IRQ_TYPE_EDGE_RISING>;
+	interrupt-names = "ovp-irq";
+	qcom,string-cfg = <7>;
+
+	wled_torch: qcom,wled-torch {
+		label = "torch";
+		qcom,wled-torch-fsc = <40>;
+		qcom,wled-torch-step = <300>;
+		qcom,wled-torch-timer = <600>;
+	};
+
+	wled_flash: qcom,wled-flash {
+		label = "flash";
+		qcom,wled-flash-fsc = <60>;
+		qcom,wled-flash-step = <100>;
+		qcom,wled-flash-timer = <200>;
+	};
+
+	wled_switch: qcom,wled-switch {
+		label = "switch";
+	};
+};
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
new file mode 100644
index 0000000..8728a1b
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
@@ -0,0 +1,320 @@
+Qualcomm Technologies Inc. PNP v2 Flash LED
+
+QPNP (Qualcomm Technologies Inc. Plug N Play) Flash LED (Light
+Emitting Diode) driver v2 is used to provide illumination to
+camera sensor when background light is dim to capture good
+picture. It can also be used for flashlight/torch application.
+It is part of PMIC on Qualcomm Technologies Inc. reference platforms.
+
+Main node:
+
+Required properties:
+- compatible		: Should be "qcom,qpnp-flash-led-v2"
+- reg			: Base address and size for flash LED modules
+- qcom,pmic-revid	: phandle of PMIC revid module. This is used to
+			  identify the PMIC subtype.
+
+Optional properties:
+- interrupts		: Specifies the interrupts associated with flash-led.
+- interrupt-names	: Specify the interrupt names associated with interrupts.
+- qcom,hdrm-auto-mode	: Boolean type to select headroom auto mode enabled or not
+- qcom,isc-delay-us	: Integer type to specify short circuit delay. Valid values are 32, 64,
+			  128, 192. Unit is uS.
+- qcom,warmup-delay-us	: Integer type to specify warm up delay. Valid values are 32, 64,
+			  128, 192. Unit is uS.
+- qcom,short-circuit-det	: Boolean property which enables short circuit fault detection.
+- qcom,open-circuit-det		: Boolean property which enables open circuit fault detection.
+- qcom,vph-droop-det		: Boolean property which enables VPH droop detection.
+- qcom,vph-droop-hysteresis-mv	: Integer property to specify VPH droop hysteresis. It is only used if
+				  qcom,vph-droop-det is specified. Valid values are 0, 25, 50 and 75.
+				  Unit is mV.
+- qcom,vph-droop-threshold-mv	: Integer property to specify VPH droop threshold. It is only used if
+				  qcom,vph-droop-det is specified. Valid values are
+				  2500 to 3200 with step size of 100. Unit is mV.
+- qcom,vph-droop-debounce-us	: Integer property to specify VPH droop debounce time. It is only used
+				  if qcom,vph-droop-det is specified. Valid values are 0, 8, 16 and 26.
+				  Unit is uS.
+- qcom,led1n2-iclamp-low-ma	: Integer property to specify current clamp low
+				  level for mitigation. Unit is mA. Allowed
+				  values are same as under qcom,max-current.
+- qcom,led1n2-iclamp-mid-ma	: Integer property to specify current clamp mid
+				  level for mitigation. Unit is mA. Allowed
+				  values are same as under qcom,max-current.
+- qcom,led3-iclamp-low-ma	: Integer property to specify current clamp low
+				  level for mitigation. Unit is mA. Allowed
+				  values are same as under qcom,max-current.
+- qcom,led3-iclamp-mid-ma	: Integer property to specify current clamp mid
+				  level for mitigation. Unit is mA. Allowed
+				  values are same as under qcom,max-current.
+- qcom,vled-max-uv		: Integer property for flash current predictive mitigation.
+				  Default value is 3500000 uV.
+- qcom,ibatt-ocp-threshold-ua	: Integer property for flash current predictive mitigation.
+				  Default value is 4500000 uA.
+- qcom,rparasitic-uohm		: Integer property for flash current predictive mitigation indicating
+				  parasitic component of battery resistance. Default value is 0 uOhm.
+- qcom,lmh-ocv-threshold-uv	: Required property for flash current preemptive LMH mitigation.
+				  Default value is 3700000 uV.
+- qcom,lmh-rbatt-threshold-uohm	: Required property for flash current preemptive LMH mitigation.
+				  Default value is 400000 uOhm.
+- qcom,lmh-mitigation-sel	: Optional property to configure flash current preemptive LMH mitigation.
+				  Accepted values are:
+				  0: MITIGATION_DISABLED
+				  1: MITIGATION_BY_ILED_THRESHOLD
+				  2: MITIGATION_BY_SW
+				  Default value is 2.
+- qcom,chgr-mitigation-sel	: Optional property to configure flash current preemptive charger mitigation.
+				  Accepted values are:
+				  0: MITIGATION_DISABLED
+				  1: MITIGATION_BY_ILED_THRESHOLD
+				  2: MITIGATION_BY_SW
+				  Default value is 2.
+- qcom,lmh-level		: Optional property to configure flash current preemptive LMH mitigation.
+				  Accepted values are 0, 1, and 3. Default value is 0.
+- qcom,iled-thrsh-ma		: Optional property to configure the led current threshold at which HW
+				  preemptive mitigation is triggered. Unit is mA. Default value is 1000.
+				  Accepted values are in the range 0 - 3100, with steps of 100.
+				  0 disables autonomous HW mitigation.
+- qcom,thermal-derate-en	: Boolean property to enable flash current thermal mitigation.
+- qcom,thermal-derate-current	: Array of currrent limits for thermal mitigation. Required if
+				  qcom,thermal-derate-en is specified. Unit is mA. Format is
+				  qcom,thermal-derate-current = <OTST1_LIMIT, OTST2_LIMIT, OTST3_LIMIT>.
+- qcom,otst-ramp-back-up-dis	: Boolean property to disable current ramp
+				  backup after thermal derate trigger is
+				  deasserted.
+- qcom,thermal-derate-slow	: Integer property to specify slow ramping
+				  down thermal rate. Unit is in uS. Allowed
+				  values are: 128, 256, 512, 1024, 2048, 4096,
+				  8192 and 314592.
+- qcom,thermal-derate-fast	: Integer property to specify fast ramping
+				  down thermal rate. Unit is in uS. Allowed
+				  values are: 32, 64, 96, 128, 256, 384 and
+				  512.
+- qcom,thermal-debounce		: Integer property to specify thermal debounce
+				  time. It is only used if qcom,thermal-derate-en
+				  is specified. Unit is in uS. Allowed values
+				  are: 0, 16, 32, 64.
+- qcom,thermal-hysteresis	: Integer property to specify thermal derating
+				  hysteresis. Unit is in deciDegC. It is only
+				  used if qcom,thermal-derate-en is specified.
+				  Allowed values are:
+				  0, 15, 30, 45 for pmi8998.
+				  0, 20, 40, 60 for pm660l.
+- qcom,thermal-thrsh1		: Integer property to specify OTST1 threshold
+				  for thermal mitigation. Unit is in Celsius.
+				  Accepted values are:
+				  85, 79, 73, 67, 109, 103, 97, 91.
+- qcom,thermal-thrsh2		: Integer property to specify OTST2 threshold
+				  for thermal mitigation. Unit is in Celsius.
+				  Accepted values are:
+				  110, 104, 98, 92, 134, 128, 122, 116.
+- qcom,thermal-thrsh3		: Integer property to specify OTST3 threshold
+				  for thermal mitigation. Unit is in Celsius.
+				  Accepted values are:
+				  125, 119, 113, 107, 149, 143, 137, 131.
+- qcom,hw-strobe-option	: Integer type to specify hardware strobe option. Based on the specified
+			  value, additional GPIO configuration may be required to provide strobing
+			  support. Supported values are:
+			  0: Flash strobe is used for LED1, LED2, LED3
+			  1: Flash strobe is used for LED1, LED2 and GPIO10 is used for LED3
+			  2: Flash strobe is used for LED1; GPIO9 is used for LED2; GPIO10 is used for LED3
+- switchX-supply		: phandle of the regulator that needs to be used
+				  as a supply for flash switch_X device.
+
+Child node: Contains settings for each individual LED. Each LED channel needs a flash node and
+torch node for itself, and an individual switch node to serve as an overall switch.
+
+Required Properties:
+- label			: Type of led that will be used, either "flash", "torch", or "switch.
+- qcom,led-name		: Name of the LED.
+- qcom,default-led-trigger	: Trigger for the camera flash and torch. Accepted values are
+			  "flash0_trigger", "flash1_trigger", "flash2_trigger, "torch0_trigger",
+			  "torch1_trigger", "torch2_trigger", and "switch_trigger".
+- qcom,id		: ID for each physical LED equipped. In order to handle situation when
+			  only 1 or 2 LEDs are installed, flash and torch nodes on LED channel 0
+			  should be specified with ID 0; nodes on channel 1 be ID 1, etc. This is
+			  not required for switch node.
+- qcom,max-current	: Maximum current allowed on this LED. Valid values should be
+			  integer from 0 to 1500 inclusive. Flash 2 should have maximum current of
+			  750 per hardware requirement. Unit is mA. For torch, the maximum current
+			  is clamped at 500 mA. This is not required for the switch node.
+- qcom,duration-ms	: Required property for flash nodes but not needed for torch. Integer
+			  type specifying flash duration. Values are from 10ms to 1280ms with
+			  10ms resolution. This is not required for switch node.
+- qcom,led-mask		: Required property for switch nodes. Bitmask to indicate which leds are
+			  controlled by this switch node. Accepted values are in the range 1 to 7,
+			  inclusive. Example:
+			  qcom,led-mask = <4>; /* This switch node controls the flash2/torch2 led. */
+
+Optional properties:
+- qcom,current-ma	: operational current intensity for LED in mA. Accepted values are a
+			  positive integer in the range of 0 to qcom,max-current inclusive.
+- qcom,ires-ua		: Integer type to specify current resolution. Accepted values should be
+			  12500, 10000, 7500, and 5000. Unit is uA.
+- qcom,hdrm-voltage-mv	: Integer type specifying headroom voltage. Values are from 125mV to 500mV
+			  with 25mV resolution. Default setting is 325mV
+- qcom,hdrm-vol-hi-lo-win-mv	: Integer type to specify headroom voltage swing range. Values are
+				  from 0mV to 375mV with 25mV resolution. Default setting is 100mV.
+- pinctrl-names		: Name of the pinctrl configuration that will be used when external GPIOs
+			  are used for enabling/disabling, HW strobing of flash LEDs. For more
+			  information on using pinctrl, please refer
+			  Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt
+                          Following are the pinctrl configs that can be specified:
+                          "led_enable" : pinctrl config to enable led. This should specify the active
+                          configuration defined for each pin or pin group.
+                          "led_disable" : pinctrl config to disable led. This should specify the sleep
+                          configuration defined for each pin or pin group.
+                          "strobe_enable" : pinctrl config to enable hw-strobe. This should specify the
+                          active configuration defined for each pin or pin group.
+                          "strobe_disable" : pinctrl config to disable hw-strobe. This should specify the
+                          sleep configuration defined for each pin or pin group.
+- qcom,hw-strobe-gpio	: phandle to specify GPIO for hardware strobing. This is used when there is no
+			  pinctrl support or PMIC GPIOs are used.
+- qcom,strobe-sel	: Property to select strobe type. If not defined,
+			  software strobe will be used. Allowed options are:
+			  0 - SW strobe
+			  1 - HW strobe
+			  2 - LPG strobe
+			  LPG strobe is supported only for LED3.
+			  If LPG strobe is specified, then strobe control is
+			  configured for active high and level triggered. Also
+			  qcom,hw-strobe-option should be set to 1 or 2.
+- qcom,hw-strobe-edge-trigger	: Boolean property to select trigger type. If defined, hw-strobe is set to
+				  be edge triggered. Otherwise, it is level triggered.
+- qcom,hw-strobe-active-low	: Boolean property to select strobe signal polarity. If defined, hw-strobe
+				  signal polarity is set to active-low, else it is active-high.
+- qcom,symmetry-en	: Boolean property to specify if the flash LEDs under a
+			  switch node are controlled symmetrically. This needs
+			  to be specified if a group of flash LED channels are
+			  connected to a single LED.
+Example:
+	qcom,leds@d300 {
+		compatible = "qcom,qpnp-flash-led-v2";
+		status = "okay";
+		reg = <0xd300 0x100>;
+		label = "flash";
+		interrupts = <0x3 0xd3 0x0 IRQ_TYPE_EDGE_BOTH>,
+			     <0x3 0xd3 0x1 IRQ_TYPE_EDGE_BOTH>,
+			     <0x3 0xd3 0x2 IRQ_TYPE_EDGE_BOTH>,
+			     <0x3 0xd3 0x3 IRQ_TYPE_EDGE_BOTH>,
+			     <0x3 0xd3 0x4 IRQ_TYPE_EDGE_BOTH>,
+			     <0x3 0xd3 0x5 IRQ_TYPE_EDGE_BOTH>,
+			     <0x3 0xd3 0x6 IRQ_TYPE_EDGE_BOTH>,
+			     <0x3 0xd3 0x7 IRQ_TYPE_EDGE_BOTH>;
+		interrupt-names = "led-fault-irq",
+				"mitigation-irq",
+				"flash-timer-exp-irq",
+				"all-ramp-down-done-irq",
+				"all-ramp-up-done-irq",
+				"led3-ramp-up-done-irq",
+				"led2-ramp-up-done-irq",
+				"led1-ramp-up-done-irq";
+
+		qcom,hdrm-auto-mode;
+		qcom,isc-delay = <192>;
+		switch0-supply = <&pmi8998_bob>;
+
+		pmi8998_flash0: qcom,flash_0 {
+			label = "flash";
+			qcom,led-name = "led:flash_0";
+			qcom,max-current = <1500>;
+			qcom,default-led-trigger =
+						"flash0_trigger";
+			qcom,id = <0>;
+			qcom,current-ma = <1000>;
+			qcom,duration-ms = <1280>;
+			qcom,ires-ua = <12500>;
+			qcom,hdrm-voltage-mv = <325>;
+			qcom,hdrm-vol-hi-lo-win-mv = <100>;
+		};
+
+		pmi8998_flash1: qcom,flash_1 {
+			label = "flash";
+			qcom,led-name = "led:flash_1";
+			qcom,max-current = <1500>;
+			qcom,default-led-trigger =
+						"flash1_trigger";
+			qcom,id = <1>;
+			qcom,current-ma = <1000>;
+			qcom,duration-ms = <1280>;
+			qcom,ires-ua = <12500>;
+			qcom,hdrm-voltage-mv = <325>;
+			qcom,hdrm-vol-hi-lo-win-mv = <100>;
+		};
+
+		pmi8998_flash2: qcom,flash_2 {
+			label = "flash";
+			qcom,led-name = "led:flash_2";
+			qcom,max-current = <750>;
+			qcom,default-led-trigger =
+						"flash2_trigger";
+			qcom,id = <2>;
+			qcom,current-ma = <500>;
+			qcom,duration-ms = <1280>;
+			qcom,ires-ua = <12500>;
+			qcom,hdrm-voltage-mv = <325>;
+			qcom,hdrm-vol-hi-lo-win-mv = <100>;
+			pinctrl-names = "led_enable","led_disable";
+			pinctrl-0 = <&led_enable>;
+			pinctrl-1 = <&led_disable>;
+		};
+
+		pmi8998_torch0: qcom,torch_0 {
+			label = "torch";
+			qcom,led-name = "led:torch_0";
+			qcom,max-current = <500>;
+			qcom,default-led-trigger =
+						"torch0_trigger";
+			qcom,id = <0>;
+			qcom,current-ma = <300>;
+			qcom,ires-ua = <12500>;
+			qcom,hdrm-voltage-mv = <325>;
+			qcom,hdrm-vol-hi-lo-win-mv = <100>;
+		};
+
+		pmi8998_torch1: qcom,torch_1 {
+			label = "torch";
+			qcom,led-name = "led:torch_1";
+			qcom,max-current = <500>;
+			qcom,default-led-trigger =
+						"torch1_trigger";
+			qcom,id = <1>;
+			qcom,current-ma = <300>;
+			qcom,ires-ua = <12500>;
+			qcom,hdrm-voltage-mv = <325>;
+			qcom,hdrm-vol-hi-lo-win-mv = <100>;
+		};
+
+		pmi8998_torch2: qcom,torch_2 {
+			label = "torch";
+			qcom,led-name = "led:torch_2";
+			qcom,max-current = <500>;
+			qcom,default-led-trigger =
+						"torch2_trigger";
+			qcom,id = <2>;
+			qcom,current-ma = <300>;
+			qcom,ires-ua = <12500>;
+			qcom,hdrm-voltage-mv = <325>;
+			qcom,hdrm-vol-hi-lo-win-mv = <100>;
+			pinctrl-names = "led_enable","led_disable";
+			pinctrl-0 = <&led_enable>;
+			pinctrl-1 = <&led_disable>;
+		};
+
+		pmi8998_switch0: qcom,led_switch_0 {
+			label = "switch";
+			qcom,led-name = "led:switch_0";
+			qcom,led-mask = <3>;
+			qcom,default-led-trigger =
+						"switch0_trigger";
+			qcom,symmetry-en;
+		};
+
+		pmi8998_switch1: qcom,led_switch_1 {
+			label = "switch";
+			qcom,led-name = "led:switch_1";
+			qcom,led-mask = <4>;
+			qcom,default-led-trigger =
+						"switch1_trigger";
+		};
+	};
+
diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt
index 1437062..272e9c0 100644
--- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt
+++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt
@@ -45,6 +45,8 @@
                    see:
                    Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
 - interrupt-names: Corresponding interrupt name to the interrupts property
+- qcom,can-sleep:  Boolean flag indicating that processes waiting on SPMI
+		   transactions may sleep
 
 Each child node of SPMI slave id represents a function of the PMIC. In the
 example below the rtc device node represents a peripheral of pm8941
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt
new file mode 100644
index 0000000..dd14890
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt
@@ -0,0 +1,19 @@
+QPNP-REVID
+
+QPNP-REVID provides a way to read the PMIC part number and revision.
+
+Required properties:
+- compatible : should be "qcom,qpnp-revid"
+- reg : offset and length of the PMIC peripheral register map.
+
+Optional property:
+- qcom,fab-id-valid: Use this property when support to read Fab
+	identification from REV ID peripheral is available.
+- qcom,tp-rev-valid: Use this property when support to read TP
+	revision identification from REV ID peripheral.
+
+Example:
+	qcom,revid@100 {
+		compatible = "qcom,qpnp-revid";
+		reg = <0x100 0x100>;
+	};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
new file mode 100644
index 0000000..4e420fd
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -0,0 +1,1783 @@
+Qualcomm Technologies, Inc. Audio devices for ALSA sound SoC
+
+* msm-pcm
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-dsp"
+
+ - qcom,msm-pcm-dsp-id : device node id
+
+* msm-pcm-low-latency
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-dsp"
+
+ - qcom,msm-pcm-dsp-id : device node id
+
+Optional properties:
+
+ - qcom,msm-pcm-low-latency : Flag indicating whether
+   the device node is of type low latency.
+
+ - qcom,latency-level : Flag indicating whether the device node
+                        is of type regular low latency or ultra
+                        low latency.
+                        regular : regular low latency stream
+                        ultra : ultra low latency stream
+                        ull-pp : ultra low latency stream with post-processing capability
+
+* msm-pcm-dsp-noirq
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-dsp-noirq";
+
+Optional properties:
+
+ - qcom,msm-pcm-low-latency : Flag indicating whether
+                              the device node is of type low latency.
+
+ - qcom,latency-level : Flag indicating whether the device node
+                        is of type low latency or ultra low latency
+                        ultra : ultra low latency stream
+                        ull-pp : ultra low latency stream with post-processing capability
+* msm-pcm-routing
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-routing"
+
+* msm-pcm-lpa
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-lpa"
+
+* msm-compr-dsp
+
+Required properties:
+
+ - compatible : "qcom,msm-compr-dsp"
+
+* msm-compress-dsp
+
+Required properties:
+
+ - compatible : "qcom,msm-compress-dsp"
+
+Optional properties:
+ - qcom,adsp-version:
+        This property can be used to specify the ADSP version/name.
+        Based on ADSP version, we decide if we have to use older
+        ADSP APIs or newer. Right now we are adding "MDSP 1.2" for
+        8909 purpose. If the ADSP version is anything other than this
+        we use new ADSP APIs.
+
+* msm-voip-dsp
+
+Required properties:
+
+ - compatible : "qcom,msm-voip-dsp"
+
+* msm-pcm-voice
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-voice"
+ - qcom,destroy-cvd : Flag indicating whether to destroy cvd at
+                      the end of call for low memory targets
+
+* msm-voice-host-pcm
+
+Required properties:
+
+ - compatible : "qcom,msm-voice-host-pcm"
+
+* msm-voice-svc
+
+Required properties:
+
+ - compatible : "qcom,msm-voice-svc"
+
+* msm-stub-codec
+
+Required properties:
+
+ - compatible : "qcom,msm-stub-codec"
+
+* msm-hdmi-dba-codec-rx
+
+Required properties:
+
+ - compatible : "qcom,msm-hdmi-dba-codec-rx"
+ - qcom,dba-bridge-chip: String info to indicate which bridge-chip
+                         is used for HDMI using DBA.
+
+* msm-dai-fe
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-fe"
+
+* msm-pcm-afe
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-afe"
+
+* msm-pcm-dtmf
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-dtmf"
+ - qcom,msm-pcm-dtmf : Enable DTMF driver in Audio. DTMF driver is
+   used for generation and detection of DTMF tones, when user is in
+   active voice call. APR commands are sent from DTMF driver to ADSP.
+
+* msm-dai-stub
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "msm-dai-stub"
+
+[Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-stub-dev"
+ - qcom,msm-dai-stub-dev-id : Stub dai port ID value is from 0 to 3.
+   This enables stub CPU dai in Audio. The stub dai is used when
+   there is no real backend in Audio.
+
+* msm-dai-q6-spdif
+
+Optional properties:
+
+ - compatible : "msm-dai-q6-spdif"
+
+* msm-dai-q6-hdmi
+
+Required properties:
+ - compatible : "msm-dai-q6-hdmi"
+ - qcom,msm-dai-q6-dev-id : The hdmi multi channel port ID.
+   It is passed onto the dsp from the apps to form an audio
+   path to the HDMI device. Currently the only supported value
+   is 8, which indicates the rx path used for audio playback
+   on HDMI device.
+
+* msm-lsm-client
+
+Required properties:
+
+ - compatible : "qcom,msm-lsm-client"
+
+* msm-pcm-loopback
+
+Required properties:
+
+ - 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-transcode-loopback
+
+Required properties:
+
+ - compatible : "qcom,msm-transcode-loopback"
+
+* msm-dai-q6
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "msm-dai-q6"
+
+Optional properties:
+
+ - qcom,ext-spk-amp-supply : External speaker amplifier power supply.
+ - qcom,ext-spk-amp-gpio : External speaker amplifier enable signal.
+
+[Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-q6-dev"
+ - qcom,msm-dai-q6-dev-id : The slimbus multi channel port ID
+                            Value is from 16384 to 16397.
+                            BT SCO port ID value from 12288 to 12289.
+                            RT Proxy port ID values from 224 to 225 and 240 to
+                            241.
+                            FM Rx and TX port ID values from 12292 to 12293.
+                            incall record Rx and TX port ID values from 32771 to 32772.
+                            inCall Music Delivery port ID is 32773.
+                            incall Music 2 Delivery port ID is 32770.
+
+* msm_dai_cdc_dma
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-cdc-dma"
+
+[Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-cdc-dma-dev"
+ - qcom,msm-dai-cdc-dma-dev-id : WSA codec dma port ID
+                            Value is from 45056 to 45061.
+                            VA codec dma port ID Value is from 45089 to 45091.
+                            RX and TX codec dma port ID values from 45120
+                            to 45135.
+
+Optional properties:
+
+- qcom,msm-dai-is-island-supported:       Defines whether this dai supported in
+                                          island mode or not.
+                                          0 - Unsupported
+                                          1 - Supported
+
+* msm-auxpcm
+
+Required properties:
+
+ - compatible :                           "qcom,msm-auxpcm-dev"
+
+ - qcom,msm-cpudai-auxpcm-mode:           mode information. The first value is
+                                          for 8khz mode, the second is for
+                                          16khz
+                                          0 - for PCM
+
+ - qcom,msm-cpudai-auxpcm-sync:           sync information. The first value is
+                                          for 8khz mode, the second is for
+                                          16khz
+
+ - qcom,msm-cpudai-auxpcm-frame:          No.of bytes per frame. The first
+                                          value is for 8khz mode, the second
+                                          is for 16khz
+                                          5 - 256BPF
+                                          4 - 128BPF
+
+ - qcom,msm-cpudai-auxpcm-quant:          Type of quantization. The first
+                                          value is for 8khz mode, the second
+                                          is for 16khz
+                                          2 - Linear quantization
+
+ - qcom,msm-cpudai-auxpcm-num-slots:      Number of slots per mode in the
+                                          msm-cpudai-auxpcm-slot-mapping
+                                          array.
+                                          The first value is for 8khz mode, the
+                                          second is for 16khz. Max number of
+                                          slots supported by DSP is 4, anything
+                                          above 4 will be truncated to 4 when
+                                          sent to DSP.
+
+ - qcom,msm-cpudai-auxpcm-slot-mapping:   Array of slot numbers for multi
+                                          slot scenario. The first array
+                                          is for 8khz mode, the second is
+                                          for 16khz. The size of the array
+                                          is determined by the value in
+                                          qcom,msm-cpudai-auxpcm-num-slots
+
+ - qcom,msm-cpudai-auxpcm-data:           Data field - 0. The first value is
+                                          for 8khz mode, the second is for
+                                          16khz
+
+ - qcom,msm-cpudai-auxpcm-pcm-clk-rate:   Clock rate for pcm - 2048000. The
+                                          first value is for 8khz mode, the
+                                          second is for 16KHz mode. When clock
+                                          rate is set to zero, then external
+                                          clock is assumed.
+
+ - qcom,msm-auxpcm-interface:             name of AUXPCM interface "primary"
+                                          indicates primary AUXPCM interface
+                                          "secondary" indicates secondary
+                                          AUXPCM interface
+Optional properties:
+
+- pinctrl-names:                          Pinctrl state names for each pin
+                                          group configuration.
+- pinctrl-x:                              Defines pinctrl state for each pin
+                                          group
+- qcom,msm-cpudai-afe-clk-ver:            Indicates version of AFE clock
+                                          interface to be used for enabling
+                                          PCM clock. If not defined, selects
+                                          default AFE clock interface.
+- qcom,msm-dai-is-island-supported:       Defines whether this dai supported in
+                                          island mode or not.
+                                          0 - Unsupported
+                                          1 - Supported
+
+* msm-pcm-hostless
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-hostless"
+
+* msm-audio-apr
+
+Required properties:
+
+ - compatible : "qcom,msm-audio-apr"
+		This device is added to represent APR module.
+
+ - qcom,subsys-name: This value provides the subsystem name where codec
+		is present. It can be "apr_modem" or "apr_adsp". This
+		property enable apr driver to receive subsystem up/down
+		notification from modem/adsp.
+
+* msm-ocmem-audio
+
+Required properties:
+
+ - compatible :                            "qcom,msm-ocmem-audio"
+
+ - qcom,msm_bus,name:                      Client name
+
+ - qcom,msm_bus,num_cases:                 Total number of use cases
+
+ - qcom,msm_bus,active_only:               Context flag for requests in active
+                                           or dual (active & sleep) contex
+
+ - qcom,msm_bus,num_paths:                 Total number of master-slave pairs
+
+ - qcom,msm_bus,vectors:                   Arrays of unsigned integers
+                                           representing:
+                                               master-id, slave-id, arbitrated
+                                               bandwidth,
+                                               instantaneous bandwidth
+* wcd9xxx_intc
+
+Required properties:
+
+ - compatible :                            "qcom,wcd9xxx-irq"
+
+ - interrupt-controller :                  Mark this device node as an
+                                           interrupt controller
+
+ - #interrupt-cells :                      Should be 1
+
+ - interrupt-parent :                      Parent interrupt controller
+
+ - qcom,gpio-connect                       Gpio that connects to parent
+                                           interrupt controller
+
+* audio-ext-clk-up
+
+Required properties:
+
+ - compatible :                            "qcom,audio-ref-clk"
+
+ - qcom,codec-ext-clk-src:                  Clock source type like PMIC, LPASS
+                                            requested to enable reference
+                                            or external clock.
+
+Optional properties:
+
+ - qcom,codec-lpass-ext-clk-freq:           Property used to specify frequency.
+
+ - qcom,codec-lpass-clk-id:                 Property used to specify LPASS clock
+                                            ID value.
+
+ - clock-names:                             Name of the PMIC clock that needs
+                                            to be enabled for audio ref clock.
+                                            This clock is set as parent.
+
+ - clocks:                                  phandle reference to the parent
+                                            clock.
+
+ - qcom,mclk-clk-reg:                       Indicate the register address for mclk.
+
+ - qcom,use-pinctrl:                        Indicates pinctrl required or not for this
+                                            clock node.
+
+* audio_slimslave
+
+Required properties:
+
+ - compatible :                            "qcom,audio-slimslave"
+
+ - elemental-addr:                         slimbus slave enumeration address.
+
+* msm-cpe-lsm
+
+Required properties:
+
+ - compatible : "qcom,msm-cpe-lsm"
+ - qcom,msm-cpe-lsm-id : lsm afe port ID. CPE lsm driver uses
+   this property to find out the input afe port ID. Currently
+   only supported values are 1 and 3.
+
+* wcd_us_euro_gpio
+
+Required properties:
+
+ - 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:
+
+ - compatible :                            "qcom,msm-dai-slim"
+
+ - elemental-addr:                         slimbus slave enumeration address.
+
+* wcd_gpio_ctrl
+
+Required properties:
+
+ - compatible :                            "qcom,msm-cdc-pinctrl"
+
+ - qcom,cdc-rst-n-gpio :                   TLMM GPIO number
+
+ - pinctrl-names:                          Pinctrl state names for each pin
+                                           group configuration.
+ - pinctrl-x:                              Defines pinctrl state for each pin
+                                           group.
+* msm_cdc_pinctrl
+
+Required properties:
+
+ - compatible :                            "qcom,msm-cdc-pinctrl"
+
+ - pinctrl-names:                          Pinctrl state names for each pin
+                                           group configuration.
+ - pinctrl-x:                              Defines pinctrl state for each pin
+                                           group.
+
+* wcd_dsp_glink
+
+Required properties:
+
+ - compatible :                            "qcom,wcd-dsp-glink"
+ - qcom,wdsp-channels:                      List of wdsp supported channel names.
+
+* msm_ext_disp_audio_codec_rx
+
+Required properties:
+
+ - compatible :                            "qcom,msm-ext-disp-audio-codec-rx"
+
+Example:
+
+	qcom,msm-pcm {
+		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <0>;
+	};
+
+	qcom,msm-pcm-low-latency {
+		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <1>;
+		qcom,msm-pcm-low-latency;
+	};
+
+	qcom,msm-pcm-loopback-low-latency {
+		compatible = "qcom,msm-pcm-loopback";
+		qcom,msm-pcm-loopback-low-latency;
+	};
+
+	qcom,msm-pcm-routing {
+		compatible = "qcom,msm-pcm-routing";
+	};
+
+	qcom,msm-pcm-lpa {
+		compatible = "qcom,msm-pcm-lpa";
+	};
+
+	qcom,msm-compr-dsp {
+		compatible = "qcom,msm-compr-dsp";
+	};
+
+	qcom,msm-compress-dsp {
+		compatible = "qcom,msm-compress-dsp";
+	};
+
+	qcom,msm-voip-dsp {
+		compatible = "qcom,msm-voip-dsp";
+	};
+
+	qcom,msm-pcm-voice {
+		compatible = "qcom,msm-pcm-voice";
+		qcom,destroy-cvd;
+	};
+
+	qcom,msm-voice-host-pcm {
+		compatible = "qcom,msm-voice-host-pcm";
+	};
+
+	qcom,msm-stub-codec {
+		compatible = "qcom,msm-stub-codec";
+	};
+
+	qcom,msm-dai-fe {
+		compatible = "qcom,msm-dai-fe";
+	};
+
+	qcom,msm-pcm-dtmf {
+		compatible = "qcom,msm-pcm-dtmf";
+	};
+
+	qcom,msm-dai-stub {
+		compatible = "qcom,msm-dai-stub";
+	};
+
+	qcom,msm-dai-q6-spdif {
+		compatible = "qcom,msm-dai-q6-spdif";
+	};
+
+	qcom,msm-dai-q6-hdmi {
+		compatible = "qcom,msm-dai-q6-hdmi";
+		qcom,msm-dai-q6-dev-id = <8>;
+	};
+
+	dai_dp: qcom,msm-dai-q6-dp {
+		compatible = "qcom,msm-dai-q6-hdmi";
+		qcom,msm-dai-q6-dev-id = <24608>;
+	};
+
+	qcom,msm-dai-q6 {
+		compatible = "qcom,msm-dai-q6";
+		qcom,msm-dai-q6-sb-0-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16384>;
+		};
+
+		qcom,msm-dai-q6-sb-0-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16385>;
+		};
+
+		qcom,msm-dai-q6-sb-1-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16386>;
+		};
+
+		qcom,msm-dai-q6-sb-1-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16387>;
+		};
+
+		qcom,msm-dai-q6-sb-3-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16390>;
+		};
+
+		qcom,msm-dai-q6-sb-3-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16391>;
+		};
+
+		qcom,msm-dai-q6-sb-4-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16392>;
+		};
+
+		qcom,msm-dai-q6-sb-4-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16393>;
+		};
+
+		qcom,msm-dai-q6-sb-5-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16395>;
+		};
+
+		qcom,msm-dai-q6-sb-6-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16396>;
+		};
+
+		qcom,msm-dai-q6-sb-6-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16397>;
+		};
+
+		qcom,msm-dai-q6-bt-sco-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12288>;
+		};
+
+		qcom,msm-dai-q6-bt-sco-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12289>;
+		};
+
+		qcom,msm-dai-q6-int-fm-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12292>;
+		};
+
+		qcom,msm-dai-q6-int-fm-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12293>;
+		};
+
+		qcom,msm-dai-q6-be-afe-pcm-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <224>;
+		};
+
+		qcom,msm-dai-q6-be-afe-pcm-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <225>;
+		};
+
+		qcom,msm-dai-q6-afe-proxy-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <241>;
+		};
+
+		qcom,msm-dai-q6-afe-proxy-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <240>;
+		};
+
+		qcom,msm-dai-q6-incall-record-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32771>;
+		};
+
+		qcom,msm-dai-q6-incall-record-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32772>;
+		};
+
+		qcom,msm-dai-q6-incall-music-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32773>;
+		};
+
+		qcom,msm-dai-q6-incall-music-2-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32770>;
+		};
+	};
+
+	qcom,msm-pri-auxpcm {
+		qcom,msm-cpudai-auxpcm-mode = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+		qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+		qcom,msm-cpudai-auxpcm-num-slots = <4>, <4>;
+		qcom,msm-cpudai-auxpcm-slot-mapping = <1 0 0 0>, <1 3 0 0>;
+		qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+		qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+		qcom,msm-auxpcm-interface = "primary";
+		compatible = "qcom,msm-auxpcm-dev";
+		pinctrl-names = "default", "idle";
+		pinctrl-0 = <&pri_aux_pcm_active &pri_aux_pcm_din_active>;
+		pinctrl-1 = <&pri_aux_pcm_sleep &pri_aux_pcm_din_sleep>;
+	};
+
+	qcom,msm-pcm-hostless {
+		compatible = "qcom,msm-pcm-hostless";
+	};
+
+	audio_apr: qcom,msm-audio-apr {
+		compatible = "qcom,msm-audio-apr";
+		qcom,subsys-name = "apr_adsp";
+                q6core {
+                        compatible = "qcom,q6core-audio";
+                        bolero: bolero-cdc {
+                                compatible = "qcom,bolero-codec";
+                        };
+                };
+	};
+
+	qcom,msm-ocmem-audio {
+		compatible = "qcom,msm-ocmem-audio";
+		qcom,msm_bus,name = "audio-ocmem";
+		qcom,msm_bus,num_cases = <2>;
+		qcom,msm_bus,active_only = <0>;
+		qcom,msm_bus,num_paths = <1>;
+		qcom,msm_bus,vectors =
+			<11 604 0 0>,
+			<11 604 32505856 325058560>;
+	};
+
+	wcd9xxx_intc: wcd9xxx-irq {
+		compatible = "qcom,wcd9xxx-irq";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupt-parent = <&msmgpio>;
+		interrupts = <72 0>;
+		interrupt-names = "cdc-int";
+	};
+
+	clock_audio: audio_ext_clk {
+		compatible = "qcom,audio-ref-clk";
+		qcom,codec-ext-clk-src = <2>;
+		qcom,codec-lpass-ext-clk-freq = <19200000>;
+		qcom,codec-lpass-clk-id = <1>;
+		clock-names = "osr_clk";
+		clocks = <&clock_rpm clk_div_clk1>;
+		#clock-cells = <1>;
+		pinctrl-names = "sleep", "active";
+		pinctrl-0 = <&spkr_i2s_clk_sleep>;
+		pinctrl-1 = <&spkr_i2s_clk_active>;
+	};
+
+	audio_slimslave {
+		compatible = "qcom,audio-slimslave";
+		elemental-addr = [ff ff ff ff 17 02];
+	};
+
+	msm_dai_slim {
+		compatible = "qcom,msm_dai_slim";
+		elemental-addr = [ff ff ff fe 17 02];
+	};
+
+	wcd_gpio_ctrl {
+		compatible = "qcom,msm-cdc-pinctrl";
+		qcom,cdc-rst-n-gpio = <&tlmm 64 0>;
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&cdc_reset_active>;
+		pinctrl-1 = <&cdc_reset_sleep>;
+	};
+
+	msm_cdc_pinctrl {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&cdc_reset_active>;
+		pinctrl-1 = <&cdc_reset_sleep>;
+	};
+
+	wcd_dsp_glink {
+		compatible = "qcom,wcd-dsp-glink";
+	};
+
+	msm_ext_disp_audio_codec_rx {
+		compatible = "qcom,msm-ext-disp-audio-codec-rx";
+	};
+
+* msm-dai-mi2s
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "msm-dai-mi2s"
+
+ [Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-q6-mi2s"
+ - qcom,msm-dai-q6-mi2s-dev-id: MSM or MDM can use Slimbus or I2S interface to
+				transfer data to (WCD9XXX) codec.
+				If slimbus interface is used then "msm-dai-q6"
+				needs to be filled with correct data for
+				slimbus interface.
+				The sections "msm-dai-mi2s" is used by MDM or
+				MSM to use I2S interface with codec.
+				This section is used by CPU driver in ASOC MSM
+				to configure MI2S interface. MSM internally
+				has multiple MI2S namely Primary, Secondary,
+				Tertiary and Quaternary MI2S.
+				They are represented with id 0, 1, 2, 3
+				respectively.
+				The field "qcom,msm-dai-q6-mi2s-dev-id"
+				represents which of the MI2S block is used.
+				These MI2S are connected to I2S interface.
+
+ - qcom,msm-mi2s-rx-lines:	Each MI2S interface in MSM has one or more SD
+				lines. These lines are used for data transfer
+				between codec and MSM.
+				This element in indicates which output RX lines
+				are used in the MI2S interface.
+
+ - qcom,msm-mi2s-tx-lines:  	Each MI2S interface in MSM has one or more SD
+				lines. These lines are used for data transfer
+				between codec and MSM.
+				This element in indicates which input TX lines
+				are used in the MI2S interface.
+
+Optional properties:
+
+- pinctrl-names:		          Pinctrl state names for each pin group
+				          configuration.
+- pinctrl-x: 			          Defines pinctrl state for each pin group
+- qcom,msm-dai-is-island-supported:       Defines whether this dai supported in
+                                          island mode or not.
+                                          0 - Unsupported
+                                          1 - Supported
+
+Example:
+
+qcom,msm-dai-mi2s {
+		compatible = "qcom,msm-dai-mi2s";
+		qcom,msm-dai-q6-mi2s-prim {
+			compatible = "qcom,msm-dai-q6-mi2s";
+			qcom,msm-dai-q6-mi2s-dev-id = <0>;
+			qcom,msm-mi2s-rx-lines = <2>;
+			qcom,msm-mi2s-tx-lines = <1>;
+			pinctrl-names = "default", "idle";
+			pinctrl-0 = <&tert_mi2s_active &tert_mi2s_sd0_active>;
+			pinctrl-1 = <&tert_mi2s_sleep &tert_mi2s_sd0_sleep>;
+		};
+};
+
+* msm-dai-spdif
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "msm-dai-spdif"
+
+ [Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-q6-spdif"
+ - qcom,msm-dai-q6-dev-id: The SPDIF port ID
+                            Value is from 20480 to 20483.
+
+Example:
+
+qcom,msm-dai-spdif {
+	compatible = "qcom,msm-dai-spdif";
+	qcom,msm-dai-q6-spdif-pri-rx {
+		compatible = "qcom,msm-dai-q6-spdif";
+		qcom,msm-dai-q6-dev-id = <20480>;
+	};
+};
+
+* msm-adsp-loader
+
+Required properties:
+ - compatible : "qcom,adsp-loader"
+ - qcom,adsp-state:
+	It is possible that some MSM use PIL to load the ADSP image. While
+	other MSM may use SBL to load the ADSP image at boot. Audio APR needs
+	state of ADSP to register and enable APR to be used for sending commands
+	to ADSP. so adsp-state represents the state of ADSP to ADSP loader.
+	Value of 0 indicates ADSP loader needs to use PIL and value of 2 means
+	ADSP image is already loaded by SBL.
+
+Optional properties:
+ - qcom,proc-img-to-load:
+	This property can be used to override default ADSP
+	loading by PIL. Based on string input, different proc is
+	loaded. Right now we are adding option "modem"
+	for 8916 purpose. Default image will be "adsp" which
+	will load LPASS Q6 for other targets as expected.
+	"adsp" option need not be explicitly mentioned in
+	DTSI file, as it is default option.
+
+Example:
+
+qcom,msm-adsp-loader {
+	compatible = "qcom,adsp-loader";
+	qcom,adsp-state = <2>;
+	qcom,proc-img-to-load = "modem";
+};
+
+* msm-audio-ion
+
+Required properties:
+ - compatible : "qcom,msm-audio-ion"
+
+Optional properties:
+ - qcom,smmu-version:
+	version ID to provide info regarding smmu version
+	used in chipset. If ARM SMMU HW - use id value as 1,
+	If QSMMU HW - use id value as 2.
+
+ - qcom,smmu-sid-mask:
+	Mask for the Stream ID part of SMMU SID.
+
+ - qcom,smmu-enabled:
+        It is possible that some MSM have SMMU in ADSP.  While other MSM use
+	no SMMU. Audio lib introduce wrapper for ION APIs. The wrapper needs
+        presence of SMMU in ADSP to handle ION APIs differently.
+        Presence of this property means ADSP has SMMU in it.
+ - iommus:
+	A phandle parsed by smmu driver. Number of entries will vary across
+	targets.
+
+Example:
+
+	qcom,msm-audio-ion {
+		compatible = "qcom,msm-audio-ion;
+		qcom,smmu-enabled;
+	};
+
+* msm-dai-tdm
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-tdm"
+ - qcom,msm-cpudai-tdm-group-id: ID of the group device. TDM interface
+				supports up to 8 groups:
+				Primary RX: 	37120
+				Primary TX: 	37121
+				Secondary RX: 	37136
+				Secondary TX: 	37137
+				Tertiary RX: 	37152
+				Tertiary TX: 	37153
+				Quaternary RX: 	37168
+				Quaternary TX: 	37169
+
+ - qcom,msm-cpudai-tdm-group-num-ports:	Number of ports in
+				msm-cpudai-tdm-group-port-id array.
+				Max number of ports supported by DSP is 8.
+
+ - qcom,msm-cpudai-tdm-group-port-id: Array of TDM port IDs of the group.
+				The size of the array is determined by
+				the value in msm-cpudai-tdm-group-num-ports.
+				Each group supports up to 8 ports:
+				Primary RX: 	36864, 36866, 36868, 36870,
+								36872, 36874, 36876, 36878
+				Primary TX: 	36865, 36867, 36869, 36871,
+								36873, 36875, 36877, 36879
+				Secondary RX: 	36880, 36882, 36884, 36886,
+								36888, 36890, 36892, 36894
+				Secondary TX:	36881, 36883, 36885, 36887,
+								36889, 36891, 36893, 36895
+				Tertiary RX: 	36896, 36898, 36900, 36902,
+								36904, 36906, 36908, 36910
+				Tertiary TX: 	36897, 36899, 36901, 36903,
+								36905, 36907, 36909, 36911
+				Quaternary RX:	36912, 36914, 36916, 36918,
+								36920, 36922, 36924, 36926
+				Quaternary TX:	36913, 36915, 36917, 36919,
+								36921, 36923, 36925, 36927
+
+ - qcom,msm-cpudai-tdm-clk-rate: Clock rate for tdm - 12288000.
+				When clock rate is set to zero,
+				then external clock is assumed.
+
+ - qcom,msm-cpudai-tdm-clk-internal: Clock Source.
+				0 - EBIT clock from clk tree
+				1 - IBIT clock from clk tree
+
+ - qcom,msm-cpudai-tdm-sync-mode: Synchronization setting.
+				0 - Short sync bit mode
+				1 - Long sync mode
+				2 - Short sync slot mode
+
+ - qcom,msm-cpudai-tdm-sync-src: Synchronization source.
+				0 - External source
+				1 - Internal source
+
+ - qcom,msm-cpudai-tdm-data-out: Data out signal to drive with other masters.
+				0 - Disable
+				1 - Enable
+
+ - qcom,msm-cpudai-tdm-invert-sync: Invert the sync.
+				0 - Normal
+				1 - Invert
+
+ - qcom,msm-cpudai-tdm-data-delay: Number of bit clock to delay data
+				with respect to sync edge.
+				0 - 0 bit clock cycle
+				1 - 1 bit clock cycle
+				2 - 2 bit clock cycle
+
+ [Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-q6-tdm"
+ - qcom,msm-dai-q6-mi2s-dev-id: TDM port ID.
+
+ - qcom,msm-cpudai-tdm-data-align: Indicate how data is packed
+				within the slot. For example, 32 slot width in case of
+				sample bit width is 24.
+				0 - MSB
+				1 - LSB
+
+Optional properties:
+
+ - qcom,msm-cpudai-tdm-header-start-offset: TDM Custom header start offset
+				in bytes from this sub-frame. The bytes is counted from 0.
+				0 is mapped to the 1st byte in or out of
+				the digital serial data line this sub-frame belong to.
+				Supported value: 0, 4, 8.
+
+ - qcom,msm-cpudai-tdm-header-width: Header width per frame followed.
+				2 bytes for MOST/TDM case.
+				Supported value: 2.
+
+ - qcom,msm-cpudai-tdm-header-num-frame-repeat: Number of header followed.
+				Supported value: 8.
+
+ - pinctrl-names: Pinctrl state names for each pin group
+				configuration.
+
+ - pinctrl-x: Defines pinctrl state for each pin group.
+
+ - qcom,msm-dai-is-island-supported:      Defines whether this dai supported in
+                                          island mode or not.
+                                          0 - Unsupported
+                                          1 - Supported
+
+Example:
+
+	qcom,msm-dai-tdm-quat-rx {
+		compatible = "qcom,msm-dai-tdm";
+		qcom,msm-cpudai-tdm-group-id = <37168>;
+		qcom,msm-cpudai-tdm-group-num-ports = <1>;
+		qcom,msm-cpudai-tdm-group-port-id = <36912>;
+		qcom,msm-cpudai-tdm-clk-rate = <12288000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <0>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <0>;
+		qcom,msm-cpudai-tdm-data-delay = <0>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&quat_tdm_active &quat_tdm_dout_active>;
+		pinctrl-1 = <&quat_tdm_sleep &quat_tdm_dout_sleep>;
+		dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36912>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+			qcom,msm-cpudai-tdm-header-start-offset = <0>;
+			qcom,msm-cpudai-tdm-header-width = <2>;
+			qcom,msm-cpudai-tdm-header-num-frame-repeat = <8>;
+		};
+	};
+
+* MSMSTUB ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,sm8150-asoc-snd-stub" for SM8150 target.
+- qcom,model : The user-visible name of this sound card.
+- qcom,tasha-mclk-clk-freq : MCLK frequency value for tasha codec
+- asoc-platform: This is phandle list containing the references to platform device
+		 nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+		       the platform names should match to that of the phandle order
+		       given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+	    that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+		  cpu dai names should match to that of the phandle order given
+		  in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+		  where the id (%d) field represents the back-end AFE port id that
+		  this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+	      nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+		    codec dai names should match to that of the phandle order given
+		    in "asoc-codec".
+Optional properties:
+- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
+
+Example:
+
+	sound_stub {
+		compatible = "qcom,sm8150-asoc-snd-stub";
+		qcom,model = "sm8150-stub-snd-card";
+
+		qcom,tasha-mclk-clk-freq = <9600000>;
+		asoc-platform = <&pcm0>;
+		asoc-platform-names = "msm-pcm-dsp.0";
+		asoc-cpu = <&sb_0_rx>, <&sb_0_tx>;
+		asoc-cpu-names = "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385";
+		asoc-codec = <&stub_codec>;
+		asoc-codec-names = "msm-stub-codec.1";
+		qcom,wsa-max-devs = <0>;
+	};
+
+* WCD DSP manager driver
+
+Required properties:
+- compatible : "qcom,wcd-dsp-mgr"
+- qcom,wdsp-components : This is phandle list containing the references to the
+			 components of the manager driver. Manager driver will
+			 register to component framework with these phandles.
+- qcom,img-filename : String property to provide the dsp image file name that is
+		     to be read from file system and downloaded to dsp memory
+Optional properties:
+- qcom,wdsp-cmpnt-dev-name : Property that manager driver will parse, but defined
+			     in the child's DT entry that is given to manager driver
+			     with phandle. This property will be used by the manager
+			     driver in case the manager driver cannot match child's
+			     of_node pointer to registered phandle.
+
+Example:
+
+	qcom,wcd-dsp-mgr {
+		compatible = "qcom,wcd-dsp-mgr";
+		qcom,wdsp-components = <&wcd934x_cdc 0>,
+				       <&wcd_spi_0 1>,
+				       <&glink_spi 2>;
+		qcom,img-filename = "cpe_9340";
+	};
+
+Example of child node that would have qcom,wdsp-cmpnt-dev-name property
+
+	wcd934x_cdc: tavil_codec {
+		qcom,wdsp-cmpnt-dev-name = "tavil_codec";
+	};
+
+* msm-mdf
+
+Required properties:
+ - compatible : "qcom,msm-mdf"
+
+Optional subnodes:
+ - qcom,msm_mdf_cb : Child nodes representing the compute context banks.
+
+Subnode Required properties:
+ - compatible : "qcom,msm-mdf-cb"
+ - label: Label describing the subsystem this context bank belongs to.
+
+Subnode Optional properties:
+ - qcom,smmu-enabled:
+		It is possible that some MSM subsystems have SMMU, while other MSM
+		subsystems do not. MDF platform driver needs to handle SMMU APIs
+		differently according to the availability of SMMU.
+		Presence of this property means the subsystem has SMMU in it.
+ - iommus : A list of phandle and IOMMU specifier pairs that describe the
+		IOMMU master interfaces of the device.
+
+Example:
+	qcom,msm-mdf {
+		compatible = "qcom,msm-mdf";
+
+		qcom,msm_mdf_cb1 {
+			compatible = "qcom,msm-mdf-cb";
+			label = "adsp";
+			qcom,smmu-enabled;
+		};
+		qcom,msm_mdf_cb2 {
+			compatible = "qcom,msm-mdf-cb";
+			label = "dsps";
+		};
+		qcom,msm_mdf_cb3 {
+			compatible = "qcom,msm-mdf-cb";
+			label = "modem";
+		};
+	};
+
+* msm-mdf-mem
+
+Required properties:
+ - compatible : "qcom,msm-mdf-mem-region"
+ - qcom,msm-mdf-mem-data-size: indicates the size of memory
+				for MDF purpose
+ - memory-region : CMA region which is owned by this device.
+
+Example:
+	qcom,msm-mdf-mem {
+		compatible = "qcom,msm-mdf-mem-region";
+		memory-region = <&mdf_mem>;
+	};
+
+* SM8150 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,sm8150-asoc-snd-pahu-aqt" for pahu codec and
+               "qcom,sm8150-asoc-snd-tavil" for tavil codec.
+- qcom,model : The user-visible name of this sound card.
+- qcom,pahu-ext-clk-freq : External CLK frequency value for pahu codec
+- qcom,audio-routing : A list of the connections between audio components.
+- asoc-platform: This is phandle list containing the references to platform device
+		 nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+		       the platform names should match to that of the phandle order
+		       given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+	    that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+		  cpu dai names should match to that of the phandle order given
+		  in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+		  where the id (%d) field represents the back-end AFE port id that
+		  this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+	      nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+		    codec dai names should match to that of the phandle order given
+		    in "asoc-codec".
+Optional properties:
+- clock-names : clock name defined for external clock.
+- clocks : external clock defined for codec clock.
+- 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,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target
+
+Example:
+
+	sound-pahu {
+		compatible = "qcom,sm8150-asoc-snd-pahu-aqt";
+		qcom,model = "sm8150-pahu-aqt-snd-card";
+		qcom,ext-disp-audio-rx;
+		qcom,wcn-btfm;
+		qcom,mi2s-audio-intf;
+		qcom,auxpcm-audio-intf;
+		qcom,msm-mi2s-master = <1>, <1>, <1>, <1>;
+
+		reg = <0x1711a000 0x4>,
+		      <0x1711b000 0x4>,
+		      <0x1711c000 0x4>,
+		      <0x1711d000 0x4>;
+		reg-names = "lpaif_pri_mode_muxsel",
+			    "lpaif_sec_mode_muxsel",
+			    "lpaif_tert_mode_muxsel",
+			    "lpaif_quat_mode_muxsel";
+
+		qcom,audio-routing =
+			"MADINPUT", "MCLK",
+			"AMIC2", "MIC BIAS2",
+			"AMIC3", "MIC BIAS2",
+			"AMIC4", "MIC BIAS2",
+			"AMIC5", "MIC BIAS3",
+			"MIC BIAS3", "Handset Mic",
+			"DMIC0", "MIC BIAS1",
+			"MIC BIAS1", "Digital Mic0",
+			"DMIC1", "MIC BIAS1",
+			"MIC BIAS1", "Digital Mic1",
+			"DMIC2", "MIC BIAS3",
+			"MIC BIAS3", "Digital Mic2",
+			"DMIC3", "MIC BIAS3",
+			"MIC BIAS3", "Digital Mic3",
+			"DMIC4", "MIC BIAS4",
+			"MIC BIAS4", "Digital Mic4",
+			"DMIC5", "MIC BIAS4",
+			"MIC BIAS4", "Digital Mic5",
+			"SpkrLeft IN", "SPK1 OUT",
+			"SpkrRight IN", "SPK2 OUT";
+
+		qcom,pahu-ext-clk-freq = <19200000>;
+		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+				<&loopback>, <&compress>, <&hostless>,
+				<&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
+				<&pcm_noirq>;
+		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-cpe-lsm",
+				"msm-compr-dsp", "msm-pcm-dsp-noirq";
+		asoc-cpu = <&dai_hdmi>, <&dai_dp>,
+				<&dai_mi2s0>, <&dai_mi2s1>,
+				<&dai_mi2s2>, <&dai_mi2s3>,
+				<&dai_pri_auxpcm>, <&dai_sec_auxpcm>,
+				<&dai_tert_auxpcm>, <&dai_quat_auxpcm>,
+				<&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+				<&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+				<&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>,
+				<&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+				<&afe_proxy_tx>, <&incall_record_rx>,
+				<&incall_record_tx>, <&incall_music_rx>,
+				<&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>,
+				<&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>,
+				<&usb_audio_rx>, <&usb_audio_tx>,
+				<&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+				<&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+				<&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+				<&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>;
+		asoc-cpu-names = "msm-dai-q6-hdmi.8",  "msm-dai-q6-dp.24608",
+				"msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+				"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+				"msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
+				"msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4",
+				"msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+				"msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+				"msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+				"msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+				"msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+				"msm-dai-q6-dev.16395", "msm-dai-q6-dev.224",
+				"msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+				"msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+				"msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+				"msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394",
+				"msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398",
+				"msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401",
+				"msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673",
+				"msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865",
+				"msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
+				"msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
+				"msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913";
+		asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>;
+		asoc-codec-names = "msm-stub-codec.1",
+				   "msm-ext-disp-audio-codec-rx";
+		qcom,wsa-max-devs = <2>;
+		qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
+				<&wsa881x_0213>, <&wsa881x_0214>;
+		qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+					  "SpkrLeft", "SpkrRight";
+	};
+
+
+* QCS405 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,qcs405-asoc-snd".
+- qcom,model : The user-visible name of this sound card.
+- qcom,audio-routing : A list of the connections between audio components.
+- asoc-platform: This is phandle list containing the references to platform device
+		 nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+		       the platform names should match to that of the phandle order
+		       given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+	    that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+		  cpu dai names should match to that of the phandle order given
+		  in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+		  where the id (%d) field represents the back-end AFE port id that
+		  this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+	      nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+		    codec dai names should match to that of the phandle order given
+		    in "asoc-codec".
+Optional properties:
+- clock-names : clock name defined for external clock.
+- clocks : external clock defined for codec clock.
+- 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,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target
+- qcom,wsa_bolero_codec : Property to specify if WSA macro in Bolero codec is used for this target
+- qcom,va_bolero_codec : Property to specify if VA macro in Bolero codec is used for this target
+- qcom,tasha_codec : Property to specify if Tasha codec is used for this target
+- qcom,cdc-dmic-gpios : phandle for Digital mic clk and data gpios.
+- qcom,csra-codec : Property to specify if CSRA66x0 is used for this target
+- qcom,csra-max-devs : Maximum number of CSRA66x0 devices present in the target
+- qcom,csra-devs : List of phandles of all possible CSRA66x0 devices supported for the target
+- qcom,csra-aux-dev-prefix : Name prefix in multi-channel configuration for CSRA66x0 device
+Example:
+
+	qcs405_snd {
+		compatible = "qcom,qcs405-asoc-snd";
+		qcom,wsa_bolero_codec =  <1>;
+		qcom,va_bolero_codec = <1>;
+		qcom,tasha_codec = <1>;
+		qcom,ext-disp-audio-rx = <1>;
+		qcom,wcn-btfm = <1>;
+		qcom,mi2s-audio-intf = <1>;
+		qcom,auxpcm-audio-intf = <1>;
+		qcom,msm-mi2s-master = <1>, <1>, <1>, <1>;
+
+		qcom,audio-routing =
+			"MADINPUT", "MCLK",
+			"AMIC2", "MIC BIAS2",
+			"AMIC3", "MIC BIAS2",
+			"AMIC4", "MIC BIAS2",
+			"AMIC5", "MIC BIAS3",
+			"MIC BIAS3", "Handset Mic",
+			"DMIC0", "MIC BIAS1",
+			"MIC BIAS1", "Digital Mic0",
+			"DMIC1", "MIC BIAS1",
+			"MIC BIAS1", "Digital Mic1",
+			"DMIC2", "MIC BIAS3",
+			"MIC BIAS3", "Digital Mic2",
+			"DMIC3", "MIC BIAS3",
+			"MIC BIAS3", "Digital Mic3",
+			"DMIC4", "MIC BIAS4",
+			"MIC BIAS4", "Digital Mic4",
+			"DMIC5", "MIC BIAS4",
+			"MIC BIAS4", "Digital Mic5",
+			"SpkrLeft IN", "SPK1 OUT",
+			"SpkrRight IN", "SPK2 OUT";
+
+		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+				<&loopback>, <&compress>, <&hostless>,
+				<&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
+				<&pcm_noirq>;
+		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-cpe-lsm",
+				"msm-compr-dsp", "msm-pcm-dsp-noirq";
+		asoc-cpu = <&dai_hdmi>, <&dai_dp>,
+				<&dai_mi2s0>, <&dai_mi2s1>,
+				<&dai_mi2s2>, <&dai_mi2s3>,
+				<&dai_pri_auxpcm>, <&dai_sec_auxpcm>,
+				<&dai_tert_auxpcm>, <&dai_quat_auxpcm>,
+				<&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+				<&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+				<&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>,
+				<&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+				<&afe_proxy_tx>, <&incall_record_rx>,
+				<&incall_record_tx>, <&incall_music_rx>,
+				<&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>,
+				<&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>,
+				<&usb_audio_rx>, <&usb_audio_tx>,
+				<&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+				<&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+				<&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+				<&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>,
+				<&wsa_cdc_dma_0_rx>, <&wsa_cdc_dma_0_tx>,
+				<&wsa_cdc_dma_1_rx>, <&wsa_cdc_dma_1_tx>,
+				<&wsa_cdc_dma_2_tx>, <&va_cdc_dma_0_tx>,
+				<&va_cdc_dma_1_tx>;
+		asoc-cpu-names = "msm-dai-q6-hdmi.8",  "msm-dai-q6-dp.24608",
+				"msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+				"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+				"msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
+				"msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4",
+				"msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+				"msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+				"msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+				"msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+				"msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+				"msm-dai-q6-dev.16395", "msm-dai-q6-dev.224",
+				"msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+				"msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+				"msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+				"msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394",
+				"msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398",
+				"msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401",
+				"msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673",
+				"msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865",
+				"msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
+				"msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
+				"msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913",
+				"msm-dai-q6-cdc-dma-dev.45056",
+				"msm-dai-q6-cdc-dma-dev.45057",
+				"msm-dai-q6-cdc-dma-dev.45058",
+				"msm-dai-q6-cdc-dma-dev.45059",
+				"msm-dai-q6-cdc-dma-dev.45061",
+				"msm-dai-q6-cdc-dma-dev.45089",
+				"msm-dai-q6-cdc-dma-dev.45091";
+		asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>,
+				<&bolero>;;
+		asoc-codec-names = "msm-stub-codec.1",
+				   "msm-ext-disp-audio-codec-rx",
+				   "bolero_codec";
+		qcom,wsa-max-devs = <2>;
+		qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
+				<&wsa881x_0213>, <&wsa881x_0214>;
+		qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+					  "SpkrLeft", "SpkrRight";
+		qcom,cdc-dmic-gpios = <&cdc_dmic12_gpios>, <&cdc_dmic34_gpios>,
+					<&cdc_dmic56_gpios>, <&cdc_dmic78_gpios>;
+	};
+
+* SM6150 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,sm6150-asoc-snd".
+- qcom,model : The user-visible name of this sound card.
+- qcom,audio-routing : A list of the connections between audio components.
+- asoc-platform: This is phandle list containing the references to platform device
+		 nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+		       the platform names should match to that of the phandle order
+		       given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+	    that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+		  cpu dai names should match to that of the phandle order given
+		  in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+		  where the id (%d) field represents the back-end AFE port id that
+		  this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+	      nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+		    codec dai names should match to that of the phandle order given
+		    in "asoc-codec".
+- qcom,codec-aux-devs: This is phandle list containing the references to Auxilary
+		       codec devices.
+
+Optional properties:
+- 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-mbhc-hphl-swh: This property is used to distinguish headset HPHL
+  switch type on target typically the switch type will be normally open or
+  normally close, value for this property 0 for normally close and 1 for
+  normally open.
+- qcom,msm-mbhc-gnd-swh: This property is used to distinguish headset GND
+  switch type on target typically the switch type will be normally open or
+  normally close, value for this property 0 for normally close and 1 for
+  normally open.
+- 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,ext-disp-audio-rx: Property to specify if Audio over Display port is supported for the target
+- qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target
+- qcom,mi2s-audio-intf: Property to specify if MI2S interface is used for the target
+- qcom,auxpcm-audio-intf: Property to specify if Aux PCM interface is used for the target
+- qcom,tavil_codec : Property to specify if Tavil codec is used for this target
+- qcom,cdc-dmic-gpios : phandle for Digital mic clk and data gpios.
+- qcom,msm_audio_ssr_devs: List the snd event framework clients
+
+Example:
+	sm6150_snd: sound {
+		status = "okay";
+		compatible = "qcom,sm6150-asoc-snd";
+		qcom,ext-disp-audio-rx = <1>;
+		qcom,wcn-btfm = <1>;
+		qcom,mi2s-audio-intf = <1>;
+		qcom,auxpcm-audio-intf = <1>;
+
+		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+				<&loopback>, <&compress>, <&hostless>,
+				<&afe>, <&lsm>, <&routing>, <&compr>,
+				<&pcm_noirq>;
+		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-dsp-noirq";
+		asoc-cpu = <&dai_dp>,
+				<&dai_mi2s0>, <&dai_mi2s1>,
+				<&dai_mi2s2>, <&dai_mi2s3>,
+				<&dai_mi2s4>, <&dai_pri_auxpcm>,
+				<&dai_sec_auxpcm>, <&dai_tert_auxpcm>,
+				<&dai_quat_auxpcm>, <&dai_quin_auxpcm>,
+				<&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+				<&afe_proxy_tx>, <&incall_record_rx>,
+				<&incall_record_tx>, <&incall_music_rx>,
+				<&incall_music_2_rx>,
+				<&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, <&sb_8_rx>,
+				<&usb_audio_rx>, <&usb_audio_tx>,
+				<&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+				<&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+				<&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+				<&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>,
+				<&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>,
+				<&wsa_cdc_dma_0_rx>, <&wsa_cdc_dma_0_tx>,
+				<&wsa_cdc_dma_1_rx>, <&wsa_cdc_dma_1_tx>,
+				<&wsa_cdc_dma_2_tx>,
+				<&va_cdc_dma_0_tx>, <&va_cdc_dma_1_tx>,
+				<&rx_cdc_dma_0_rx>, <&tx_cdc_dma_0_tx>,
+				<&rx_cdc_dma_1_rx>, <&tx_cdc_dma_1_tx>,
+				<&rx_cdc_dma_2_rx>, <&tx_cdc_dma_2_tx>,
+				<&rx_cdc_dma_3_rx>, <&tx_cdc_dma_3_tx>,
+				<&rx_cdc_dma_4_rx>, <&tx_cdc_dma_4_tx>,
+				<&rx_cdc_dma_5_rx>, <&tx_cdc_dma_5_tx>,
+				<&tx_cdc_dma_6_tx>, <&tx_cdc_dma_7_tx>;
+		asoc-cpu-names = "msm-dai-q6-dp.24608",
+				"msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+				"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+				"msm-dai-q6-mi2s.4", "msm-dai-q6-auxpcm.1",
+				"msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3",
+				"msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5",
+				"msm-dai-q6-dev.224",
+				"msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+				"msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+				"msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+				"msm-dai-q6-dev.32770", "msm-dai-q6-dev.16398",
+				"msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401",
+				"msm-dai-q6-dev.16400",
+				"msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673",
+				"msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865",
+				"msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
+				"msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
+				"msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913",
+				"msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929",
+				"msm-dai-cdc-dma-dev.45056",
+				"msm-dai-cdc-dma-dev.45057",
+				"msm-dai-cdc-dma-dev.45058",
+				"msm-dai-cdc-dma-dev.45059",
+				"msm-dai-cdc-dma-dev.45061",
+				"msm-dai-cdc-dma-dev.45089",
+				"msm-dai-cdc-dma-dev.45091",
+				"msm-dai-cdc-dma-dev.45120",
+				"msm-dai-cdc-dma-dev.45121",
+				"msm-dai-cdc-dma-dev.45122",
+				"msm-dai-cdc-dma-dev.45123",
+				"msm-dai-cdc-dma-dev.45124",
+				"msm-dai-cdc-dma-dev.45125",
+				"msm-dai-cdc-dma-dev.45126",
+				"msm-dai-cdc-dma-dev.45127",
+				"msm-dai-cdc-dma-dev.45128",
+				"msm-dai-cdc-dma-dev.45129",
+				"msm-dai-cdc-dma-dev.45130",
+				"msm-dai-cdc-dma-dev.45131",
+				"msm-dai-cdc-dma-dev.45133",
+				"msm-dai-cdc-dma-dev.45135";
+		qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>;
+		qcom,msm-mbhc-hphl-swh = <1>;
+		qcom,msm-mbhc-gnd-swh = <1>;
+		qcom,cdc-dmic-gpios = <&cdc_dmic12_gpios>, <&cdc_dmic34_gpios>;
+		asoc-codec  = <&stub_codec>, <&bolero>,
+			      <&ext_disp_audio_codec>;
+		asoc-codec-names = "msm-stub-codec.1", "bolero-codec",
+				   "msm-ext-disp-audio-codec-rx";
+		qcom,wsa-max-devs = <2>;
+		qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
+				<&wsa881x_0213>, <&wsa881x_0214>;
+		qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+					  "SpkrLeft", "SpkrRight";
+		qcom,codec-aux-devs = <&wcd937x_codec>;
+		qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>;
+	};
+};
+
+* MSMSTUB ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,sm6150-asoc-snd-stub" for SM6150 target.
+- qcom,model : The user-visible name of this sound card.
+- asoc-platform: This is phandle list containing the references to platform device
+		 nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+		       the platform names should match to that of the phandle order
+		       given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+	    that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+		  cpu dai names should match to that of the phandle order given
+		  in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+		  where the id (%d) field represents the back-end AFE port id that
+		  this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+	      nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+		    codec dai names should match to that of the phandle order given
+		    in "asoc-codec".
+Optional properties:
+- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
+
+Example:
+
+	sound_stub {
+		compatible = "qcom,sm6150-asoc-snd-stub";
+		qcom,model = "sm6150-stub-snd-card";
+
+		asoc-platform = <&pcm0>;
+		asoc-platform-names = "msm-pcm-dsp.0";
+		asoc-cpu = <&sb_0_rx>, <&sb_0_tx>;
+		asoc-cpu-names = "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385";
+		asoc-codec = <&stub_codec>;
+		asoc-codec-names = "msm-stub-codec.1";
+		qcom,wsa-max-devs = <0>;
+	};
+
+* SA8155 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,sa8155-asoc-snd-auto" for auto adp codec and
+               "qcom,sa8155-asoc-snd-auto-custom" for auto custom codec.
+- qcom,model : The user-visible name of this sound card.
+- asoc-platform: This is phandle list containing the references to platform device
+		 nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+		       the platform names should match to that of the phandle order
+		       given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+	    that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+		  cpu dai names should match to that of the phandle order given
+		  in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+		  where the id (%d) field represents the back-end AFE port id that
+		  this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+	      nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+		    codec dai names should match to that of the phandle order given
+		    in "asoc-codec".
+Optional properties:
+- qcom,mi2s-audio-intf : Property to specify if MI2S interface is used for the target
+- qcom,auxpcm-audio-intf : Property to specify if AUX PCM interface is used for the target
+- qcom,msm-mi2s-master : List of master/slave configuration for MI2S interfaces
+
+Example:
+
+	sound-adp-star {
+		compatible = "qcom,sa8155-asoc-snd-adp-star";
+		qcom,model = "sa8155-adp-star-snd-card";
+		qcom,mi2s-audio-intf;
+		qcom,auxpcm-audio-intf;
+		qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>;
+
+		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+				<&loopback>, <&compress>, <&hostless>,
+				<&afe>, <&lsm>, <&routing>, <&compr>,
+				<&pcm_noirq>, <&loopback1>, <&pcm_dtmf>;
+		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-dsp-noirq", "msm-pcm-loopback.1",
+				"msm-pcm-dtmf";
+		asoc-cpu = <&dai_hdmi>, <&dai_dp>,
+				<&dai_mi2s0>, <&dai_mi2s1>,
+				<&dai_mi2s2>, <&dai_mi2s3>,
+				<&dai_mi2s4>, <&dai_pri_auxpcm>,
+				<&dai_sec_auxpcm>, <&dai_tert_auxpcm>,
+				<&dai_quat_auxpcm>, <&dai_quin_auxpcm>,
+				<&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+				<&afe_proxy_tx>, <&incall_record_rx>,
+				<&incall_record_tx>, <&incall_music_rx>,
+				<&incall_music_2_rx>,
+				<&usb_audio_rx>, <&usb_audio_tx>,
+				<&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>,
+				<&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>,
+				<&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>,
+				<&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>,
+				<&dai_sec_tdm_rx_0>, <&dai_sec_tdm_rx_1>,
+				<&dai_sec_tdm_rx_2>, <&dai_sec_tdm_rx_3>,
+				<&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>,
+				<&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>,
+				<&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>,
+				<&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>,
+				<&dai_tert_tdm_rx_4>, <&dai_tert_tdm_tx_0>,
+				<&dai_tert_tdm_tx_1>, <&dai_tert_tdm_tx_2>,
+				<&dai_tert_tdm_tx_3>, <&dai_quat_tdm_rx_0>,
+				<&dai_quat_tdm_rx_1>, <&dai_quat_tdm_rx_2>,
+				<&dai_quat_tdm_rx_3>, <&dai_quat_tdm_tx_0>,
+				<&dai_quat_tdm_tx_1>, <&dai_quat_tdm_tx_2>,
+				<&dai_quat_tdm_tx_3>, <&dai_quin_tdm_rx_0>,
+				<&dai_quin_tdm_rx_1>, <&dai_quin_tdm_rx_2>,
+				<&dai_quin_tdm_rx_3>, <&dai_quin_tdm_tx_0>,
+				<&dai_quin_tdm_tx_1>, <&dai_quin_tdm_tx_2>,
+				<&dai_quin_tdm_tx_3>;
+		asoc-cpu-names = "msm-dai-q6-hdmi.8",  "msm-dai-q6-dp.24608",
+				"msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+				"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+				"msm-dai-q6-mi2s.4", "msm-dai-q6-auxpcm.1",
+				"msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3",
+				"msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5",
+				"msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+				"msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+				"msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+				"msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770",
+				"msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673",
+				"msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866",
+				"msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870",
+				"msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867",
+				"msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871",
+				"msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36882",
+				"msm-dai-q6-tdm.36884", "msm-dai-q6-tdm.36886",
+				"msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883",
+				"msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887",
+				"msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898",
+				"msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902",
+				"msm-dai-q6-tdm.36904", "msm-dai-q6-tdm.36897",
+				"msm-dai-q6-tdm.36899", "msm-dai-q6-tdm.36901",
+				"msm-dai-q6-tdm.36903", "msm-dai-q6-tdm.36912",
+				"msm-dai-q6-tdm.36914", "msm-dai-q6-tdm.36916",
+				"msm-dai-q6-tdm.36918", "msm-dai-q6-tdm.36913",
+				"msm-dai-q6-tdm.36915", "msm-dai-q6-tdm.36917",
+				"msm-dai-q6-tdm.36919", "msm-dai-q6-tdm.36928",
+				"msm-dai-q6-tdm.36930", "msm-dai-q6-tdm.36932",
+				"msm-dai-q6-tdm.36934", "msm-dai-q6-tdm.36929",
+				"msm-dai-q6-tdm.36931", "msm-dai-q6-tdm.36933",
+				"msm-dai-q6-tdm.36935";
+		asoc-codec = <&stub_codec>;
+		asoc-codec-names = "msm-stub-codec.1";
+	};
diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt
new file mode 100644
index 0000000..51c748e
--- /dev/null
+++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt
@@ -0,0 +1,63 @@
+Qualcomm Technologies, Inc. SPMI Debug Controller (PMIC Arbiter)
+
+The SPMI PMIC Arbiter is found on various QTI chips.  It is an SPMI controller
+with wrapping arbitration logic to allow for multiple on-chip devices to control
+a single SPMI master.
+
+The PMIC Arbiter debug bus is present starting at arbiter version 5.  It has
+read and write access to all PMIC peripherals regardless of ownership
+configurations.  It cannot be used on production devices because it is disabled
+by an eFuse.
+
+See spmi.txt for the generic SPMI controller binding requirements for child
+nodes.
+
+Supported Properties:
+
+- compatible
+	Usage:      required
+	Value type: <string>
+	Definition: Must be "qcom,spmi-pmic-arb-debug".
+
+- reg
+	Usage:      required
+	Value type: <prop-encoded-array>
+	Definition: List of address and size pairs.  The address of the PMIC
+		    arbiter module is required.  The address of the debug bus
+		    disabling fuse is optional.
+
+- reg-names
+	Usage:      required
+	Value type: <stringlist>
+	Definition: Address names. Must include "core" for the PMIC arbiter
+		    module and may include "fuse" for the debug bus disabling
+		    fuse.  The strings must be specified in the same order as
+		    the corresponding addresses are specified in the reg
+		    property.
+
+- #address-cells
+	Usage:      required
+	Value type: <u32>
+	Definition: Must be 2.
+
+- #size-cells
+	Usage:      required
+	Value type: <u32>
+	Definition: Must be 0.
+
+- qcom,fuse-disable-bit
+	Usage:      required if "fuse" is listed in reg-names property
+	Value type: <u32>
+	Definition: The bit within the fuse register which is set when the debug
+		    bus is not available.  Supported values are 0 to 31.
+
+Example:
+
+qcom,spmi-debug@6b22000 {
+	compatible = "qcom,spmi-pmic-arb-debug";
+	reg = <0x6b22000 0x60>, <0x7820a8 4>;
+	reg-names = "core", "fuse";
+	qcom,fuse-disable-bit = <12>;
+	#address-cells = <2>;
+	#size-cells = <0>;
+};
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index a48baf2..8c8d2bb 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -51,6 +51,7 @@
 - nr_trim_pages         (only if CONFIG_MMU=n)
 - numa_zonelist_order
 - oom_dump_tasks
+- reap_mem_on_sigkill
 - oom_kill_allocating_task
 - overcommit_kbytes
 - overcommit_memory
@@ -654,6 +655,24 @@
 
 ==============================================================
 
+reap_mem_on_sigkill
+
+This enables or disables the memory reaping for a SIGKILL received
+process and that the sending process must have the CAP_KILL capabilities.
+
+If this is set to 1, when a process receives SIGKILL from a process
+that has the capability, CAP_KILL, the process is added into the oom_reaper
+queue which can be picked up by the oom_reaper thread to reap the memory of
+that process. This reaps for the process which received SIGKILL through
+either sys_kill from user or kill_pid from kernel.
+
+If this is set to 0, we are not reaping memory of a SIGKILL, sent through
+either sys_kill from user or kill_pid from kernel, received process.
+
+The default value is 0 (disabled).
+
+==============================================================
+
 oom_kill_allocating_task
 
 This enables or disables killing the OOM-triggering task in
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 95571b8..334d136 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -7,11 +7,24 @@
 dtb-$(CONFIG_ARCH_QCOM)	+= msm8994-angler-rev-101.dtb
 dtb-$(CONFIG_ARCH_QCOM)	+= msm8996-mtp.dtb
 dtb-$(CONFIG_ARCH_QCOM)	+= sdm845-mtp.dtb
+ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
+	dtbo-$(CONFIG_ARCH_KONA) += \
+		kona-cdp-overlay.dtbo \
+		kona-mtp-overlay.dtbo \
+		kona-rumi-overlay.dtbo \
+		kona-qrd-overlay.dtbo
+
+kona-cdp-overlay.dtbo-base := kona.dtb
+kona-mtp-overlay.dtbo-base := kona.dtb
+kona-rumi-overlay.dtbo-base := kona.dtb
+kona-qrd-overlay.dtbo-base := kona.dtb
+else
 dtb-$(CONFIG_ARCH_KONA)	+= kona-rumi.dtb \
 	kona-mtp.dtb \
 	kona-cdp.dtb \
 	kona-qrd.dtb
+endif
 
 always		:= $(dtb-y)
 subdir-y	:= $(dts-dirs)
-clean-files	:= *.dtb
+clean-files    := *.dtb
diff --git a/arch/arm64/boot/dts/qcom/kona-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/kona-cdp-overlay.dts
new file mode 100644
index 0000000..6f46ce5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/kona-cdp-overlay.dts
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-kona.h>
+#include <dt-bindings/clock/qcom,camcc-kona.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "kona-cdp.dtsi"
+
+/ {
+	model = "CDP";
+	compatible = "qcom,kona-cdp", "qcom,kona", "qcom,cdp";
+	qcom,board-id = <1 0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/kona-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/kona-mtp-overlay.dts
new file mode 100644
index 0000000..7f40af2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/kona-mtp-overlay.dts
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-kona.h>
+#include <dt-bindings/clock/qcom,camcc-kona.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "kona-mtp.dtsi"
+
+/ {
+	model = "MTP";
+	compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp";
+	qcom,board-id = <8 0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/kona-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/kona-qrd-overlay.dts
new file mode 100644
index 0000000..231e5ef
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/kona-qrd-overlay.dts
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-kona.h>
+#include <dt-bindings/clock/qcom,camcc-kona.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "kona-qrd.dtsi"
+
+/ {
+	model = "QRD";
+	compatible = "qcom,kona-qrd", "qcom,kona", "qcom,qrd";
+	qcom,board-id = <11 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/kona-rumi-overlay.dts b/arch/arm64/boot/dts/qcom/kona-rumi-overlay.dts
new file mode 100644
index 0000000..51e012b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/kona-rumi-overlay.dts
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-kona.h>
+#include <dt-bindings/clock/qcom,camcc-kona.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "kona-rumi.dtsi"
+
+/ {
+	model = "RUMI";
+	compatible = "qcom,kona-rumi", "qcom,kona", "qcom,rumi";
+	qcom,board-id = <15 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/kona-usb.dtsi b/arch/arm64/boot/dts/qcom/kona-usb.dtsi
index 81089fe..0cf2e09 100644
--- a/arch/arm64/boot/dts/qcom/kona-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/kona-usb.dtsi
@@ -13,6 +13,7 @@
 		reg-names = "core_base";
 
 		iommus = <&apps_smmu 0x0 0x0>;
+		qcom,iommu-dma = "disabled";
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
diff --git a/arch/arm64/boot/dts/qcom/kona.dts b/arch/arm64/boot/dts/qcom/kona.dts
new file mode 100644
index 0000000..2a02297
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/kona.dts
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+/dts-v1/;
+
+#include "kona.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. kona v1 SoC";
+	compatible = "qcom,kona";
+	qcom,board-id = <0 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/kona.dtsi b/arch/arm64/boot/dts/qcom/kona.dtsi
index 9c5df6b..d839397 100644
--- a/arch/arm64/boot/dts/qcom/kona.dtsi
+++ b/arch/arm64/boot/dts/qcom/kona.dtsi
@@ -268,7 +268,7 @@
 
 		xbl_aop_mem: xbl_aop_region@80700000 {
 			no-map;
-			reg = <0x0 0x80700000 0x0 0x140000>;
+			reg = <0x0 0x80700000 0x0 0x120000>;
 		};
 
 		cmd_db: reserved-memory@80820000 {
@@ -322,46 +322,46 @@
 			reg = <0x0 0x86615000 0x0 0x2000>;
 		};
 
-		pil_npu_mem: pil_npu_region@86680000 {
-			compatible = "removed-dma-pool";
-			no-map;
-			reg = <0x0 0x86680000 0x0 0x80000>;
-		};
-
-		pil_video_mem: pil_video_region@86700000 {
+		pil_npu_mem: pil_npu_region@86700000 {
 			compatible = "removed-dma-pool";
 			no-map;
 			reg = <0x0 0x86700000 0x0 0x500000>;
 		};
 
-		pil_cvp_mem: pil_cvp_region@86c00000 {
+		pil_video_mem: pil_video_region@86c00000 {
 			compatible = "removed-dma-pool";
 			no-map;
 			reg = <0x0 0x86c00000 0x0 0x500000>;
 		};
 
-		pil_cdsp_mem: pil_cdsp_region@87100000 {
+		pil_cvp_mem: pil_cvp_region@87100000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0x0 0x87100000 0x0 0x800000>;
+			reg = <0x0 0x87100000 0x0 0x500000>;
 		};
 
-		pil_slpi_mem: pil_slpi_region@87900000 {
+		pil_cdsp_mem: pil_cdsp_region@87600000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0x0 0x87900000 0x0 0x1400000>;
+			reg = <0x0 0x87600000 0x0 0x800000>;
 		};
 
-		pil_adsp_mem: pil_adsp_region@88d00000 {
+		pil_slpi_mem: pil_slpi_region@87e00000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0x0 0x88d00000 0x0 0x1a00000>;
+			reg = <0x0 0x87e00000 0x0 0x1500000>;
 		};
 
-		pil_spss_mem: pil_spss_region@8a700000 {
+		pil_adsp_mem: pil_adsp_region@89300000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0x0 0x8a700000 0x0 0x100000>;
+			reg = <0x0 0x89300000 0x0 0x1900000>;
+		};
+
+		pil_spss_mem: pil_spss_region@8ac00000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0x0 0x8ac00000 0x0 0x100000>;
 		};
 
 		/* global autoconfigured region for contiguous allocations */
diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
new file mode 100644
index 0000000..6b29c10
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
@@ -0,0 +1,628 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+&soc {
+	pcm0: qcom,msm-pcm {
+		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <0>;
+	};
+
+	routing: qcom,msm-pcm-routing {
+		compatible = "qcom,msm-pcm-routing";
+	};
+
+	compr: qcom,msm-compr-dsp {
+		compatible = "qcom,msm-compr-dsp";
+	};
+
+	pcm1: qcom,msm-pcm-low-latency {
+		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <1>;
+		qcom,msm-pcm-low-latency;
+		qcom,latency-level = "regular";
+	};
+
+	pcm2: qcom,msm-ultra-low-latency {
+		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <2>;
+		qcom,msm-pcm-low-latency;
+		qcom,latency-level = "ultra";
+	};
+
+	pcm_noirq: qcom,msm-pcm-dsp-noirq {
+		compatible = "qcom,msm-pcm-dsp-noirq";
+		qcom,msm-pcm-low-latency;
+		qcom,latency-level = "ultra";
+	};
+
+	trans_loopback: qcom,msm-transcode-loopback {
+		compatible = "qcom,msm-transcode-loopback";
+	};
+
+	compress: qcom,msm-compress-dsp {
+		compatible = "qcom,msm-compress-dsp";
+	};
+
+	voip: qcom,msm-voip-dsp {
+		compatible = "qcom,msm-voip-dsp";
+	};
+
+	voice: qcom,msm-pcm-voice {
+		compatible = "qcom,msm-pcm-voice";
+		qcom,destroy-cvd;
+	};
+
+	stub_codec: qcom,msm-stub-codec {
+		compatible = "qcom,msm-stub-codec";
+	};
+
+	qcom,msm-dai-fe {
+		compatible = "qcom,msm-dai-fe";
+	};
+
+	afe: qcom,msm-pcm-afe {
+		compatible = "qcom,msm-pcm-afe";
+	};
+
+	dai_hdmi: qcom,msm-dai-q6-hdmi {
+		compatible = "qcom,msm-dai-q6-hdmi";
+		qcom,msm-dai-q6-dev-id = <8>;
+	};
+
+	dai_dp: qcom,msm-dai-q6-dp {
+		compatible = "qcom,msm-dai-q6-hdmi";
+		qcom,msm-dai-q6-dev-id = <24608>;
+	};
+
+	loopback: qcom,msm-pcm-loopback {
+		compatible = "qcom,msm-pcm-loopback";
+	};
+
+	loopback1: qcom,msm-pcm-loopback-low-latency {
+		compatible = "qcom,msm-pcm-loopback";
+		qcom,msm-pcm-loopback-low-latency;
+	};
+
+	pcm_dtmf: qcom,msm-pcm-dtmf {
+		compatible = "qcom,msm-pcm-dtmf";
+	};
+
+	msm_dai_mi2s: qcom,msm-dai-mi2s {
+		compatible = "qcom,msm-dai-mi2s";
+		dai_mi2s0: qcom,msm-dai-q6-mi2s-prim {
+			compatible = "qcom,msm-dai-q6-mi2s";
+			qcom,msm-dai-q6-mi2s-dev-id = <0>;
+			qcom,msm-mi2s-rx-lines = <3>;
+			qcom,msm-mi2s-tx-lines = <0>;
+		};
+
+		dai_mi2s1: qcom,msm-dai-q6-mi2s-sec {
+			compatible = "qcom,msm-dai-q6-mi2s";
+			qcom,msm-dai-q6-mi2s-dev-id = <1>;
+			qcom,msm-mi2s-rx-lines = <1>;
+			qcom,msm-mi2s-tx-lines = <0>;
+		};
+
+		dai_mi2s2: qcom,msm-dai-q6-mi2s-tert {
+			compatible = "qcom,msm-dai-q6-mi2s";
+			qcom,msm-dai-q6-mi2s-dev-id = <2>;
+			qcom,msm-mi2s-rx-lines = <0>;
+			qcom,msm-mi2s-tx-lines = <3>;
+		};
+
+		dai_mi2s3: qcom,msm-dai-q6-mi2s-quat {
+			compatible = "qcom,msm-dai-q6-mi2s";
+			qcom,msm-dai-q6-mi2s-dev-id = <3>;
+			qcom,msm-mi2s-rx-lines = <1>;
+			qcom,msm-mi2s-tx-lines = <2>;
+		};
+
+		dai_mi2s4: qcom,msm-dai-q6-mi2s-quin {
+			compatible = "qcom,msm-dai-q6-mi2s";
+			qcom,msm-dai-q6-mi2s-dev-id = <4>;
+			qcom,msm-mi2s-rx-lines = <1>;
+			qcom,msm-mi2s-tx-lines = <2>;
+		};
+
+		dai_mi2s5: qcom,msm-dai-q6-mi2s-senary {
+			compatible = "qcom,msm-dai-q6-mi2s";
+			qcom,msm-dai-q6-mi2s-dev-id = <6>;
+			qcom,msm-mi2s-rx-lines = <0>;
+			qcom,msm-mi2s-tx-lines = <3>;
+		};
+	};
+
+	msm_dai_cdc_dma: qcom,msm-dai-cdc-dma {
+		compatible = "qcom,msm-dai-cdc-dma";
+		wsa_cdc_dma_0_rx: qcom,msm-dai-wsa-cdc-dma-0-rx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45056>;
+		};
+
+		wsa_cdc_dma_0_tx: qcom,msm-dai-wsa-cdc-dma-0-tx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45057>;
+		};
+
+		wsa_cdc_dma_1_rx: qcom,msm-dai-wsa-cdc-dma-1-rx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45058>;
+		};
+
+		wsa_cdc_dma_1_tx: qcom,msm-dai-wsa-cdc-dma-1-tx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45059>;
+		};
+
+		wsa_cdc_dma_2_tx: qcom,msm-dai-wsa-cdc-dma-2-tx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45061>;
+		};
+
+		va_cdc_dma_0_tx: qcom,msm-dai-va-cdc-dma-0-tx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45089>;
+		};
+
+		va_cdc_dma_1_tx: qcom,msm-dai-va-cdc-dma-1-tx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45091>;
+		};
+
+		rx_cdc_dma_0_rx: qcom,msm-dai-rx-cdc-dma-0-rx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45104>;
+		};
+
+		rx_cdc_dma_1_rx: qcom,msm-dai-rx-cdc-dma-1-rx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45106>;
+		};
+
+		rx_cdc_dma_2_rx: qcom,msm-dai-rx-cdc-dma-2-rx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45108>;
+		};
+
+		rx_cdc_dma_3_rx: qcom,msm-dai-rx-cdc-dma-3-rx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45110>;
+		};
+
+		rx_cdc_dma_4_rx: qcom,msm-dai-rx-cdc-dma-4-rx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45112>;
+		};
+
+		rx_cdc_dma_5_rx: qcom,msm-dai-rx-cdc-dma-5-rx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45114>;
+		};
+
+		rx_cdc_dma_6_rx: qcom,msm-dai-rx-cdc-dma-6-rx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45116>;
+		};
+
+		rx_cdc_dma_7_rx: qcom,msm-dai-rx-cdc-dma-7-rx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45118>;
+		};
+
+		tx_cdc_dma_0_tx: qcom,msm-dai-tx-cdc-dma-0-tx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45105>;
+		};
+
+		tx_cdc_dma_1_tx: qcom,msm-dai-tx-cdc-dma-1-tx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45107>;
+		};
+
+		tx_cdc_dma_2_tx: qcom,msm-dai-tx-cdc-dma-2-tx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45109>;
+		};
+
+		tx_cdc_dma_3_tx: qcom,msm-dai-tx-cdc-dma-3-tx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45111>;
+		};
+
+		tx_cdc_dma_4_tx: qcom,msm-dai-tx-cdc-dma-4-tx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45113>;
+		};
+
+		tx_cdc_dma_5_tx: qcom,msm-dai-tx-cdc-dma-5-tx {
+			compatible = "qcom,msm-dai-cdc-dma-dev";
+			qcom,msm-dai-cdc-dma-dev-id = <45115>;
+		};
+	};
+
+	lsm: qcom,msm-lsm-client {
+		compatible = "qcom,msm-lsm-client";
+	};
+
+	qcom,msm-dai-q6 {
+		compatible = "qcom,msm-dai-q6";
+		bt_sco_rx: qcom,msm-dai-q6-bt-sco-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12288>;
+		};
+
+		bt_sco_tx: qcom,msm-dai-q6-bt-sco-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12289>;
+		};
+
+		int_fm_rx: qcom,msm-dai-q6-int-fm-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12292>;
+		};
+
+		int_fm_tx: qcom,msm-dai-q6-int-fm-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12293>;
+		};
+
+		afe_pcm_rx: qcom,msm-dai-q6-be-afe-pcm-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <224>;
+		};
+
+		afe_pcm_tx: qcom,msm-dai-q6-be-afe-pcm-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <225>;
+		};
+
+		afe_proxy_rx: qcom,msm-dai-q6-afe-proxy-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <241>;
+		};
+
+		afe_proxy_tx: qcom,msm-dai-q6-afe-proxy-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <240>;
+		};
+
+		incall_record_rx: qcom,msm-dai-q6-incall-record-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32771>;
+		};
+
+		incall_record_tx: qcom,msm-dai-q6-incall-record-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32772>;
+		};
+
+		incall_music_rx: qcom,msm-dai-q6-incall-music-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32773>;
+		};
+
+		incall_music_2_rx: qcom,msm-dai-q6-incall-music-2-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32770>;
+		};
+
+		usb_audio_rx: qcom,msm-dai-q6-usb-audio-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <28672>;
+		};
+
+		usb_audio_tx: qcom,msm-dai-q6-usb-audio-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <28673>;
+		};
+	};
+
+	hostless: qcom,msm-pcm-hostless {
+		compatible = "qcom,msm-pcm-hostless";
+	};
+
+	audio_apr: qcom,msm-audio-apr {
+		compatible = "qcom,msm-audio-apr";
+		qcom,subsys-name = "apr_adsp";
+
+		msm_audio_ion: qcom,msm-audio-ion {
+			compatible = "qcom,msm-audio-ion";
+			qcom,smmu-version = <2>;
+			qcom,smmu-enabled;
+			iommus = <&apps_smmu 0x1801 0x0>;
+		};
+	};
+
+	dai_pri_auxpcm: qcom,msm-pri-auxpcm {
+		compatible = "qcom,msm-auxpcm-dev";
+		qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+		qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+		qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+		qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+		qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+		qcom,msm-auxpcm-interface = "primary";
+		qcom,msm-cpudai-afe-clk-ver = <2>;
+	};
+
+	dai_sec_auxpcm: qcom,msm-sec-auxpcm {
+		compatible = "qcom,msm-auxpcm-dev";
+		qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+		qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+		qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+		qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+		qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+		qcom,msm-auxpcm-interface = "secondary";
+		qcom,msm-cpudai-afe-clk-ver = <2>;
+	};
+
+	dai_tert_auxpcm: qcom,msm-tert-auxpcm {
+		compatible = "qcom,msm-auxpcm-dev";
+		qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+		qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+		qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+		qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+		qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+		qcom,msm-auxpcm-interface = "tertiary";
+		qcom,msm-cpudai-afe-clk-ver = <2>;
+	};
+
+	dai_quat_auxpcm: qcom,msm-quat-auxpcm {
+		compatible = "qcom,msm-auxpcm-dev";
+		qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+		qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+		qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+		qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+		qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+		qcom,msm-auxpcm-interface = "quaternary";
+		qcom,msm-cpudai-afe-clk-ver = <2>;
+	};
+
+	dai_quin_auxpcm: qcom,msm-quin-auxpcm {
+		compatible = "qcom,msm-auxpcm-dev";
+		qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+		qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+		qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+		qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+		qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+		qcom,msm-auxpcm-interface = "quinary";
+		qcom,msm-cpudai-afe-clk-ver = <2>;
+	};
+
+	hdmi_dba: qcom,msm-hdmi-dba-codec-rx {
+		compatible = "qcom,msm-hdmi-dba-codec-rx";
+		qcom,dba-bridge-chip = "adv7533";
+	};
+
+	qcom,msm-adsp-loader {
+		status = "ok";
+		compatible = "qcom,adsp-loader";
+		qcom,adsp-state = <0>;
+	};
+
+	tdm_pri_rx: qcom,msm-dai-tdm-pri-rx {
+		compatible = "qcom,msm-dai-tdm";
+		qcom,msm-cpudai-tdm-group-id = <37120>;
+		qcom,msm-cpudai-tdm-group-num-ports = <1>;
+		qcom,msm-cpudai-tdm-group-port-id = <36864>;
+		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
+		dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36864>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+
+	tdm_pri_tx: qcom,msm-dai-tdm-pri-tx {
+		compatible = "qcom,msm-dai-tdm";
+		qcom,msm-cpudai-tdm-group-id = <37121>;
+		qcom,msm-cpudai-tdm-group-num-ports = <1>;
+		qcom,msm-cpudai-tdm-group-port-id = <36865>;
+		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
+		dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36865>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+
+	tdm_sec_rx: qcom,msm-dai-tdm-sec-rx {
+		compatible = "qcom,msm-dai-tdm";
+		qcom,msm-cpudai-tdm-group-id = <37136>;
+		qcom,msm-cpudai-tdm-group-num-ports = <1>;
+		qcom,msm-cpudai-tdm-group-port-id = <36880>;
+		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
+		dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36880>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+
+	tdm_sec_tx: qcom,msm-dai-tdm-sec-tx {
+		compatible = "qcom,msm-dai-tdm";
+		qcom,msm-cpudai-tdm-group-id = <37137>;
+		qcom,msm-cpudai-tdm-group-num-ports = <1>;
+		qcom,msm-cpudai-tdm-group-port-id = <36881>;
+		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
+		dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36881>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+
+	tdm_tert_rx: qcom,msm-dai-tdm-tert-rx {
+		compatible = "qcom,msm-dai-tdm";
+		qcom,msm-cpudai-tdm-group-id = <37152>;
+		qcom,msm-cpudai-tdm-group-num-ports = <1>;
+		qcom,msm-cpudai-tdm-group-port-id = <36896>;
+		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
+		dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36896>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+
+	tdm_tert_tx: qcom,msm-dai-tdm-tert-tx {
+		compatible = "qcom,msm-dai-tdm";
+		qcom,msm-cpudai-tdm-group-id = <37153>;
+		qcom,msm-cpudai-tdm-group-num-ports = <1>;
+		qcom,msm-cpudai-tdm-group-port-id = <36897 >;
+		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
+		dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36897 >;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+
+	tdm_quat_rx: qcom,msm-dai-tdm-quat-rx {
+		compatible = "qcom,msm-dai-tdm";
+		qcom,msm-cpudai-tdm-group-id = <37168>;
+		qcom,msm-cpudai-tdm-group-num-ports = <1>;
+		qcom,msm-cpudai-tdm-group-port-id = <36912>;
+		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
+		dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36912>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+
+	tdm_quat_tx: qcom,msm-dai-tdm-quat-tx {
+		compatible = "qcom,msm-dai-tdm";
+		qcom,msm-cpudai-tdm-group-id = <37169>;
+		qcom,msm-cpudai-tdm-group-num-ports = <1>;
+		qcom,msm-cpudai-tdm-group-port-id = <36913 >;
+		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
+		dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36913 >;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+
+	tdm_quin_rx: qcom,msm-dai-tdm-quin-rx {
+		compatible = "qcom,msm-dai-tdm";
+		qcom,msm-cpudai-tdm-group-id = <37184>;
+		qcom,msm-cpudai-tdm-group-num-ports = <1>;
+		qcom,msm-cpudai-tdm-group-port-id = <36928>;
+		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
+		dai_quin_tdm_rx_0: qcom,msm-dai-q6-tdm-quin-rx-0 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36928>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+
+	tdm_quin_tx: qcom,msm-dai-tdm-quin-tx {
+		compatible = "qcom,msm-dai-tdm";
+		qcom,msm-cpudai-tdm-group-id = <37185>;
+		qcom,msm-cpudai-tdm-group-num-ports = <1>;
+		qcom,msm-cpudai-tdm-group-port-id = <36929>;
+		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
+		dai_quin_tdm_tx_0: qcom,msm-dai-q6-tdm-quin-tx-0 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36929>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+
+	dai_pri_spdif_rx: qcom,msm-dai-q6-spdif-pri-rx {
+		compatible = "qcom,msm-dai-q6-spdif";
+		qcom,msm-dai-q6-dev-id = <20480>;
+	};
+
+	dai_pri_spdif_tx: qcom,msm-dai-q6-spdif-pri-tx {
+		compatible = "qcom,msm-dai-q6-spdif";
+		qcom,msm-dai-q6-dev-id = <20481>;
+	};
+
+	dai_sec_spdif_rx: qcom,msm-dai-q6-spdif-sec-rx {
+		compatible = "qcom,msm-dai-q6-spdif";
+		qcom,msm-dai-q6-dev-id = <20482>;
+	};
+
+	dai_sec_spdif_tx: qcom,msm-dai-q6-spdif-sec-tx {
+		compatible = "qcom,msm-dai-q6-spdif";
+		qcom,msm-dai-q6-dev-id = <20483>;
+	};
+};
diff --git a/arch/arm64/configs/vendor/kona-perf_defconfig b/arch/arm64/configs/vendor/kona-perf_defconfig
index e18cfd6..64da0f1 100644
--- a/arch/arm64/configs/vendor/kona-perf_defconfig
+++ b/arch/arm64/configs/vendor/kona-perf_defconfig
@@ -358,6 +358,8 @@
 CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000
 CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y
 CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_MSM_SERVICE_NOTIFIER=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_PIL=y
 CONFIG_MSM_PIL_SSR_GENERIC=y
diff --git a/arch/arm64/configs/vendor/kona_defconfig b/arch/arm64/configs/vendor/kona_defconfig
index f799b6e..46084bde 100644
--- a/arch/arm64/configs/vendor/kona_defconfig
+++ b/arch/arm64/configs/vendor/kona_defconfig
@@ -370,6 +370,8 @@
 CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000
 CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y
 CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_MSM_SERVICE_NOTIFIER=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_PIL=y
 CONFIG_MSM_PIL_SSR_GENERIC=y
diff --git a/arch/arm64/include/asm/dma-iommu.h b/arch/arm64/include/asm/dma-iommu.h
index 59f2bd8..d922cd7 100644
--- a/arch/arm64/include/asm/dma-iommu.h
+++ b/arch/arm64/include/asm/dma-iommu.h
@@ -32,34 +32,37 @@
 #ifdef CONFIG_ARM64_DMA_USE_IOMMU
 
 struct dma_iommu_mapping *
-arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size);
+__depr_arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base,
+				size_t size);
 
-void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
+void __depr_arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
 
-int arm_iommu_attach_device(struct device *dev,
+int __depr_arm_iommu_attach_device(struct device *dev,
 					struct dma_iommu_mapping *mapping);
-void arm_iommu_detach_device(struct device *dev);
+void __depr_arm_iommu_detach_device(struct device *dev);
 
 void arm_iommu_put_dma_cookie(struct iommu_domain *domain);
 #else  /* !CONFIG_ARM64_DMA_USE_IOMMU */
 
 static inline struct dma_iommu_mapping *
-arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size)
+__depr_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 void
+__depr_arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
 {
 }
 
-static inline int arm_iommu_attach_device(struct device *dev,
+static inline int __depr_arm_iommu_attach_device(struct device *dev,
 			struct dma_iommu_mapping *mapping)
 {
 	return -ENODEV;
 }
 
-static inline void arm_iommu_detach_device(struct device *dev)
+static inline void __depr_arm_iommu_detach_device(struct device *dev)
 {
 }
 
diff --git a/arch/arm64/include/asm/string.h b/arch/arm64/include/asm/string.h
index dd95d33..03a6c256 100644
--- a/arch/arm64/include/asm/string.h
+++ b/arch/arm64/include/asm/string.h
@@ -16,6 +16,7 @@
 #ifndef __ASM_STRING_H
 #define __ASM_STRING_H
 
+#ifndef CONFIG_KASAN
 #define __HAVE_ARCH_STRRCHR
 extern char *strrchr(const char *, int c);
 
@@ -34,6 +35,13 @@
 #define __HAVE_ARCH_STRNLEN
 extern __kernel_size_t strnlen(const char *, __kernel_size_t);
 
+#define __HAVE_ARCH_MEMCMP
+extern int memcmp(const void *, const void *, size_t);
+
+#define __HAVE_ARCH_MEMCHR
+extern void *memchr(const void *, int, __kernel_size_t);
+#endif
+
 #define __HAVE_ARCH_MEMCPY
 extern void *memcpy(void *, const void *, __kernel_size_t);
 extern void *__memcpy(void *, const void *, __kernel_size_t);
@@ -42,16 +50,10 @@
 extern void *memmove(void *, const void *, __kernel_size_t);
 extern void *__memmove(void *, const void *, __kernel_size_t);
 
-#define __HAVE_ARCH_MEMCHR
-extern void *memchr(const void *, int, __kernel_size_t);
-
 #define __HAVE_ARCH_MEMSET
 extern void *memset(void *, int, __kernel_size_t);
 extern void *__memset(void *, int, __kernel_size_t);
 
-#define __HAVE_ARCH_MEMCMP
-extern int memcmp(const void *, const void *, size_t);
-
 #ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE
 #define __HAVE_ARCH_MEMCPY_FLUSHCACHE
 void memcpy_flushcache(void *dst, const void *src, size_t cnt);
diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c
index 4d37e51..71f776d 100644
--- a/arch/arm64/kernel/arm64ksyms.c
+++ b/arch/arm64/kernel/arm64ksyms.c
@@ -45,20 +45,23 @@
 EXPORT_SYMBOL(memstart_addr);
 
 	/* string / mem functions */
+#ifndef CONFIG_KASAN
 EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strcmp);
 EXPORT_SYMBOL(strncmp);
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memchr);
+#endif
+
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(__memset);
 EXPORT_SYMBOL(__memcpy);
 EXPORT_SYMBOL(__memmove);
-EXPORT_SYMBOL(memchr);
-EXPORT_SYMBOL(memcmp);
 
 	/* atomic bitops */
 EXPORT_SYMBOL(set_bit);
diff --git a/arch/arm64/lib/memchr.S b/arch/arm64/lib/memchr.S
index 4444c1d..0f164a4 100644
--- a/arch/arm64/lib/memchr.S
+++ b/arch/arm64/lib/memchr.S
@@ -30,7 +30,7 @@
  * Returns:
  *	x0 - address of first occurrence of 'c' or 0
  */
-ENTRY(memchr)
+WEAK(memchr)
 	and	w1, w1, #0xff
 1:	subs	x2, x2, #1
 	b.mi	2f
diff --git a/arch/arm64/lib/memcmp.S b/arch/arm64/lib/memcmp.S
index 2a4e239..fb295f5 100644
--- a/arch/arm64/lib/memcmp.S
+++ b/arch/arm64/lib/memcmp.S
@@ -58,7 +58,7 @@
 limit_wd	.req	x12
 mask		.req	x13
 
-ENTRY(memcmp)
+WEAK(memcmp)
 	cbz	limit, .Lret0
 	eor	tmp1, src1, src2
 	tst	tmp1, #7
diff --git a/arch/arm64/lib/strchr.S b/arch/arm64/lib/strchr.S
index dae0cf5..7c83091 100644
--- a/arch/arm64/lib/strchr.S
+++ b/arch/arm64/lib/strchr.S
@@ -29,7 +29,7 @@
  * Returns:
  *	x0 - address of first occurrence of 'c' or 0
  */
-ENTRY(strchr)
+WEAK(strchr)
 	and	w1, w1, #0xff
 1:	ldrb	w2, [x0], #1
 	cmp	w2, w1
diff --git a/arch/arm64/lib/strcmp.S b/arch/arm64/lib/strcmp.S
index 471fe61..7d5d153 100644
--- a/arch/arm64/lib/strcmp.S
+++ b/arch/arm64/lib/strcmp.S
@@ -60,7 +60,7 @@
 zeroones	.req	x10
 pos		.req	x11
 
-ENTRY(strcmp)
+WEAK(strcmp)
 	eor	tmp1, src1, src2
 	mov	zeroones, #REP8_01
 	tst	tmp1, #7
diff --git a/arch/arm64/lib/strlen.S b/arch/arm64/lib/strlen.S
index 55ccc8e..8e0b142 100644
--- a/arch/arm64/lib/strlen.S
+++ b/arch/arm64/lib/strlen.S
@@ -56,7 +56,7 @@
 #define REP8_7f 0x7f7f7f7f7f7f7f7f
 #define REP8_80 0x8080808080808080
 
-ENTRY(strlen)
+WEAK(strlen)
 	mov	zeroones, #REP8_01
 	bic	src, srcin, #15
 	ands	tmp1, srcin, #15
diff --git a/arch/arm64/lib/strncmp.S b/arch/arm64/lib/strncmp.S
index e267044..66bd1459 100644
--- a/arch/arm64/lib/strncmp.S
+++ b/arch/arm64/lib/strncmp.S
@@ -64,7 +64,7 @@
 mask		.req	x14
 endloop		.req	x15
 
-ENTRY(strncmp)
+WEAK(strncmp)
 	cbz	limit, .Lret0
 	eor	tmp1, src1, src2
 	mov	zeroones, #REP8_01
diff --git a/arch/arm64/lib/strnlen.S b/arch/arm64/lib/strnlen.S
index eae38da..355be04 100644
--- a/arch/arm64/lib/strnlen.S
+++ b/arch/arm64/lib/strnlen.S
@@ -59,7 +59,7 @@
 #define REP8_7f 0x7f7f7f7f7f7f7f7f
 #define REP8_80 0x8080808080808080
 
-ENTRY(strnlen)
+WEAK(strnlen)
 	cbz	limit, .Lhit_limit
 	mov	zeroones, #REP8_01
 	bic	src, srcin, #15
diff --git a/arch/arm64/lib/strrchr.S b/arch/arm64/lib/strrchr.S
index f8e2784..ea84924 100644
--- a/arch/arm64/lib/strrchr.S
+++ b/arch/arm64/lib/strrchr.S
@@ -29,7 +29,7 @@
  * Returns:
  *	x0 - address of last occurrence of 'c' or 0
  */
-ENTRY(strrchr)
+WEAK(strrchr)
 	mov	x3, #0
 	and	w1, w1, #0xff
 1:	ldrb	w2, [x0], #1
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index ce6528b..beb4a2e 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -1057,7 +1057,7 @@
 	iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast);
 
 	if (s1_bypass)
-		mapping->ops = &swiotlb_dma_ops;
+		mapping->ops = &arm64_swiotlb_dma_ops;
 	else if (is_fast)
 		err = fast_smmu_init_mapping(dev, mapping);
 	else
@@ -1158,7 +1158,8 @@
  * to calling arm_iommu_attach_device() to complete initialization.
  */
 struct dma_iommu_mapping *
-arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size)
+__depr_arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base,
+				size_t size)
 {
 	unsigned int bits = size >> PAGE_SHIFT;
 	struct dma_iommu_mapping *mapping;
@@ -1184,7 +1185,7 @@
 	kfree(mapping);
 	return ERR_PTR(-ENOMEM);
 }
-EXPORT_SYMBOL(arm_iommu_create_mapping);
+EXPORT_SYMBOL(__depr_arm_iommu_create_mapping);
 
 /*
  * DEPRECATED
@@ -1194,7 +1195,7 @@
  * Frees all resources associated with the iommu mapping.
  * The device associated with this mapping must be in the 'detached' state
  */
-void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
+void __depr_arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
 {
 	if (!mapping)
 		return;
@@ -1204,7 +1205,7 @@
 
 	kfree(mapping);
 }
-EXPORT_SYMBOL(arm_iommu_release_mapping);
+EXPORT_SYMBOL(__depr_arm_iommu_release_mapping);
 
 /**
  * DEPRECATED
@@ -1219,7 +1220,7 @@
  *
  * Only configures dma_ops for a single device in the iommu_group.
  */
-int arm_iommu_attach_device(struct device *dev,
+int __depr_arm_iommu_attach_device(struct device *dev,
 			    struct dma_iommu_mapping *mapping)
 {
 	int err;
@@ -1265,7 +1266,7 @@
 	pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev));
 	return 0;
 }
-EXPORT_SYMBOL(arm_iommu_attach_device);
+EXPORT_SYMBOL(__depr_arm_iommu_attach_device);
 
 /**
  * DEPRECATED
@@ -1275,7 +1276,7 @@
  * Detaches the provided device from a previously attached map.
  * This voids the dma operations (dma_map_ops pointer)
  */
-void arm_iommu_detach_device(struct device *dev)
+void __depr_arm_iommu_detach_device(struct device *dev)
 {
 	struct iommu_domain *domain;
 	int s1_bypass = 0;
@@ -1307,7 +1308,7 @@
 
 	pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev));
 }
-EXPORT_SYMBOL(arm_iommu_detach_device);
+EXPORT_SYMBOL(__depr_arm_iommu_detach_device);
 
 #else /*!CONFIG_ARM64_DMA_USE_IOMMU */
 
diff --git a/crypto/ahash.c b/crypto/ahash.c
index a64c143..78aaf21 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -550,8 +550,8 @@
 {
 	struct crypto_alg *base = &alg->halg.base;
 
-	if (alg->halg.digestsize > PAGE_SIZE / 8 ||
-	    alg->halg.statesize > PAGE_SIZE / 8 ||
+	if (alg->halg.digestsize > HASH_MAX_DIGESTSIZE ||
+	    alg->halg.statesize > HASH_MAX_STATESIZE ||
 	    alg->halg.statesize == 0)
 		return -EINVAL;
 
diff --git a/crypto/algapi.c b/crypto/algapi.c
index c0755cf..496fc51 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -57,9 +57,14 @@
 	if (alg->cra_alignmask & (alg->cra_alignmask + 1))
 		return -EINVAL;
 
-	if (alg->cra_blocksize > PAGE_SIZE / 8)
+	/* General maximums for all algs. */
+	if (alg->cra_alignmask > MAX_ALGAPI_ALIGNMASK)
 		return -EINVAL;
 
+	if (alg->cra_blocksize > MAX_ALGAPI_BLOCKSIZE)
+		return -EINVAL;
+
+	/* Lower maximums for specific alg types. */
 	if (!alg->cra_type && (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
 			       CRYPTO_ALG_TYPE_CIPHER) {
 		if (alg->cra_alignmask > MAX_CIPHER_ALIGNMASK)
diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
index c40a8c7..eb100a0 100644
--- a/crypto/algif_aead.c
+++ b/crypto/algif_aead.c
@@ -42,7 +42,7 @@
 
 struct aead_tfm {
 	struct crypto_aead *aead;
-	struct crypto_skcipher *null_tfm;
+	struct crypto_sync_skcipher *null_tfm;
 };
 
 static inline bool aead_sufficient_data(struct sock *sk)
@@ -75,13 +75,13 @@
 	return af_alg_sendmsg(sock, msg, size, ivsize);
 }
 
-static int crypto_aead_copy_sgl(struct crypto_skcipher *null_tfm,
+static int crypto_aead_copy_sgl(struct crypto_sync_skcipher *null_tfm,
 				struct scatterlist *src,
 				struct scatterlist *dst, unsigned int len)
 {
-	SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm);
+	SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm);
 
-	skcipher_request_set_tfm(skreq, null_tfm);
+	skcipher_request_set_sync_tfm(skreq, null_tfm);
 	skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_BACKLOG,
 				      NULL, NULL);
 	skcipher_request_set_crypt(skreq, src, dst, len, NULL);
@@ -99,7 +99,7 @@
 	struct af_alg_ctx *ctx = ask->private;
 	struct aead_tfm *aeadc = pask->private;
 	struct crypto_aead *tfm = aeadc->aead;
-	struct crypto_skcipher *null_tfm = aeadc->null_tfm;
+	struct crypto_sync_skcipher *null_tfm = aeadc->null_tfm;
 	unsigned int i, as = crypto_aead_authsize(tfm);
 	struct af_alg_async_req *areq;
 	struct af_alg_tsgl *tsgl, *tmp;
@@ -478,7 +478,7 @@
 {
 	struct aead_tfm *tfm;
 	struct crypto_aead *aead;
-	struct crypto_skcipher *null_tfm;
+	struct crypto_sync_skcipher *null_tfm;
 
 	tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
 	if (!tfm)
diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
index bfcf595..d0cde54 100644
--- a/crypto/algif_hash.c
+++ b/crypto/algif_hash.c
@@ -239,7 +239,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)) ? : 1];
+	char state[HASH_MAX_STATESIZE];
 	struct sock *sk2;
 	struct alg_sock *ask2;
 	struct hash_ctx *ctx2;
diff --git a/crypto/authenc.c b/crypto/authenc.c
index 4fa8d40..37f54d1 100644
--- a/crypto/authenc.c
+++ b/crypto/authenc.c
@@ -33,7 +33,7 @@
 struct crypto_authenc_ctx {
 	struct crypto_ahash *auth;
 	struct crypto_skcipher *enc;
-	struct crypto_skcipher *null;
+	struct crypto_sync_skcipher *null;
 };
 
 struct authenc_request_ctx {
@@ -185,9 +185,9 @@
 {
 	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
-	SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
+	SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
 
-	skcipher_request_set_tfm(skreq, ctx->null);
+	skcipher_request_set_sync_tfm(skreq, ctx->null);
 	skcipher_request_set_callback(skreq, aead_request_flags(req),
 				      NULL, NULL);
 	skcipher_request_set_crypt(skreq, req->src, req->dst, req->assoclen,
@@ -318,7 +318,7 @@
 	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(tfm);
 	struct crypto_ahash *auth;
 	struct crypto_skcipher *enc;
-	struct crypto_skcipher *null;
+	struct crypto_sync_skcipher *null;
 	int err;
 
 	auth = crypto_spawn_ahash(&ictx->auth);
diff --git a/crypto/authencesn.c b/crypto/authencesn.c
index 50b8047..80a25cc 100644
--- a/crypto/authencesn.c
+++ b/crypto/authencesn.c
@@ -36,7 +36,7 @@
 	unsigned int reqoff;
 	struct crypto_ahash *auth;
 	struct crypto_skcipher *enc;
-	struct crypto_skcipher *null;
+	struct crypto_sync_skcipher *null;
 };
 
 struct authenc_esn_request_ctx {
@@ -183,9 +183,9 @@
 {
 	struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
 	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
-	SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
+	SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
 
-	skcipher_request_set_tfm(skreq, ctx->null);
+	skcipher_request_set_sync_tfm(skreq, ctx->null);
 	skcipher_request_set_callback(skreq, aead_request_flags(req),
 				      NULL, NULL);
 	skcipher_request_set_crypt(skreq, req->src, req->dst, len, NULL);
@@ -341,7 +341,7 @@
 	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm);
 	struct crypto_ahash *auth;
 	struct crypto_skcipher *enc;
-	struct crypto_skcipher *null;
+	struct crypto_sync_skcipher *null;
 	int err;
 
 	auth = crypto_spawn_ahash(&ictx->auth);
diff --git a/crypto/ccm.c b/crypto/ccm.c
index 0a08334..b242fd0 100644
--- a/crypto/ccm.c
+++ b/crypto/ccm.c
@@ -50,7 +50,10 @@
 	u32 flags;
 	struct scatterlist src[3];
 	struct scatterlist dst[3];
-	struct skcipher_request skreq;
+	union {
+		struct ahash_request ahreq;
+		struct skcipher_request skreq;
+	};
 };
 
 struct cbcmac_tfm_ctx {
@@ -181,7 +184,7 @@
 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
 	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
-	AHASH_REQUEST_ON_STACK(ahreq, ctx->mac);
+	struct ahash_request *ahreq = &pctx->ahreq;
 	unsigned int assoclen = req->assoclen;
 	struct scatterlist sg[3];
 	u8 *odata = pctx->odata;
@@ -427,7 +430,7 @@
 	crypto_aead_set_reqsize(
 		tfm,
 		align + sizeof(struct crypto_ccm_req_priv_ctx) +
-		crypto_skcipher_reqsize(ctr));
+		max(crypto_ahash_reqsize(mac), crypto_skcipher_reqsize(ctr)));
 
 	return 0;
 
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index addca7b..7118fb5e 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -76,7 +76,7 @@
 
 struct cryptd_skcipher_ctx {
 	atomic_t refcnt;
-	struct crypto_skcipher *child;
+	struct crypto_sync_skcipher *child;
 };
 
 struct cryptd_skcipher_request_ctx {
@@ -449,14 +449,16 @@
 				  const u8 *key, unsigned int keylen)
 {
 	struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(parent);
-	struct crypto_skcipher *child = ctx->child;
+	struct crypto_sync_skcipher *child = ctx->child;
 	int err;
 
-	crypto_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
-	crypto_skcipher_set_flags(child, crypto_skcipher_get_flags(parent) &
+	crypto_sync_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+	crypto_sync_skcipher_set_flags(child,
+				       crypto_skcipher_get_flags(parent) &
 					 CRYPTO_TFM_REQ_MASK);
-	err = crypto_skcipher_setkey(child, key, keylen);
-	crypto_skcipher_set_flags(parent, crypto_skcipher_get_flags(child) &
+	err = crypto_sync_skcipher_setkey(child, key, keylen);
+	crypto_skcipher_set_flags(parent,
+				  crypto_sync_skcipher_get_flags(child) &
 					  CRYPTO_TFM_RES_MASK);
 	return err;
 }
@@ -483,13 +485,13 @@
 	struct cryptd_skcipher_request_ctx *rctx = skcipher_request_ctx(req);
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm);
-	struct crypto_skcipher *child = ctx->child;
-	SKCIPHER_REQUEST_ON_STACK(subreq, child);
+	struct crypto_sync_skcipher *child = ctx->child;
+	SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, child);
 
 	if (unlikely(err == -EINPROGRESS))
 		goto out;
 
-	skcipher_request_set_tfm(subreq, child);
+	skcipher_request_set_sync_tfm(subreq, child);
 	skcipher_request_set_callback(subreq, CRYPTO_TFM_REQ_MAY_SLEEP,
 				      NULL, NULL);
 	skcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen,
@@ -511,13 +513,13 @@
 	struct cryptd_skcipher_request_ctx *rctx = skcipher_request_ctx(req);
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm);
-	struct crypto_skcipher *child = ctx->child;
-	SKCIPHER_REQUEST_ON_STACK(subreq, child);
+	struct crypto_sync_skcipher *child = ctx->child;
+	SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, child);
 
 	if (unlikely(err == -EINPROGRESS))
 		goto out;
 
-	skcipher_request_set_tfm(subreq, child);
+	skcipher_request_set_sync_tfm(subreq, child);
 	skcipher_request_set_callback(subreq, CRYPTO_TFM_REQ_MAY_SLEEP,
 				      NULL, NULL);
 	skcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen,
@@ -568,7 +570,7 @@
 	if (IS_ERR(cipher))
 		return PTR_ERR(cipher);
 
-	ctx->child = cipher;
+	ctx->child = (struct crypto_sync_skcipher *)cipher;
 	crypto_skcipher_set_reqsize(
 		tfm, sizeof(struct cryptd_skcipher_request_ctx));
 	return 0;
@@ -578,7 +580,7 @@
 {
 	struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm);
 
-	crypto_free_skcipher(ctx->child);
+	crypto_free_sync_skcipher(ctx->child);
 }
 
 static void cryptd_skcipher_free(struct skcipher_instance *inst)
@@ -1243,7 +1245,7 @@
 {
 	struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(&tfm->base);
 
-	return ctx->child;
+	return &ctx->child->base;
 }
 EXPORT_SYMBOL_GPL(cryptd_skcipher_child);
 
diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c
index 0959b26..0bae599 100644
--- a/crypto/crypto_null.c
+++ b/crypto/crypto_null.c
@@ -26,7 +26,7 @@
 #include <linux/string.h>
 
 static DEFINE_MUTEX(crypto_default_null_skcipher_lock);
-static struct crypto_skcipher *crypto_default_null_skcipher;
+static struct crypto_sync_skcipher *crypto_default_null_skcipher;
 static int crypto_default_null_skcipher_refcnt;
 
 static int null_compress(struct crypto_tfm *tfm, const u8 *src,
@@ -152,16 +152,15 @@
 MODULE_ALIAS_CRYPTO("digest_null");
 MODULE_ALIAS_CRYPTO("cipher_null");
 
-struct crypto_skcipher *crypto_get_default_null_skcipher(void)
+struct crypto_sync_skcipher *crypto_get_default_null_skcipher(void)
 {
-	struct crypto_skcipher *tfm;
+	struct crypto_sync_skcipher *tfm;
 
 	mutex_lock(&crypto_default_null_skcipher_lock);
 	tfm = crypto_default_null_skcipher;
 
 	if (!tfm) {
-		tfm = crypto_alloc_skcipher("ecb(cipher_null)",
-					    0, CRYPTO_ALG_ASYNC);
+		tfm = crypto_alloc_sync_skcipher("ecb(cipher_null)", 0, 0);
 		if (IS_ERR(tfm))
 			goto unlock;
 
@@ -181,7 +180,7 @@
 {
 	mutex_lock(&crypto_default_null_skcipher_lock);
 	if (!--crypto_default_null_skcipher_refcnt) {
-		crypto_free_skcipher(crypto_default_null_skcipher);
+		crypto_free_sync_skcipher(crypto_default_null_skcipher);
 		crypto_default_null_skcipher = NULL;
 	}
 	mutex_unlock(&crypto_default_null_skcipher_lock);
diff --git a/crypto/echainiv.c b/crypto/echainiv.c
index 45819e6..77e607f 100644
--- a/crypto/echainiv.c
+++ b/crypto/echainiv.c
@@ -47,9 +47,9 @@
 	info = req->iv;
 
 	if (req->src != req->dst) {
-		SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull);
+		SYNC_SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull);
 
-		skcipher_request_set_tfm(nreq, ctx->sknull);
+		skcipher_request_set_sync_tfm(nreq, ctx->sknull);
 		skcipher_request_set_callback(nreq, req->base.flags,
 					      NULL, NULL);
 		skcipher_request_set_crypt(nreq, req->src, req->dst,
diff --git a/crypto/gcm.c b/crypto/gcm.c
index 0ad879e..e438492 100644
--- a/crypto/gcm.c
+++ b/crypto/gcm.c
@@ -50,7 +50,7 @@
 
 struct crypto_rfc4543_ctx {
 	struct crypto_aead *child;
-	struct crypto_skcipher *null;
+	struct crypto_sync_skcipher *null;
 	u8 nonce[4];
 };
 
@@ -1067,9 +1067,9 @@
 	unsigned int authsize = crypto_aead_authsize(aead);
 	unsigned int nbytes = req->assoclen + req->cryptlen -
 			      (enc ? 0 : authsize);
-	SKCIPHER_REQUEST_ON_STACK(nreq, ctx->null);
+	SYNC_SKCIPHER_REQUEST_ON_STACK(nreq, ctx->null);
 
-	skcipher_request_set_tfm(nreq, ctx->null);
+	skcipher_request_set_sync_tfm(nreq, ctx->null);
 	skcipher_request_set_callback(nreq, req->base.flags, NULL, NULL);
 	skcipher_request_set_crypt(nreq, req->src, req->dst, nbytes, NULL);
 
@@ -1093,7 +1093,7 @@
 	struct crypto_aead_spawn *spawn = &ictx->aead;
 	struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(tfm);
 	struct crypto_aead *aead;
-	struct crypto_skcipher *null;
+	struct crypto_sync_skcipher *null;
 	unsigned long align;
 	int err = 0;
 
diff --git a/crypto/seqiv.c b/crypto/seqiv.c
index 39dbf2f..64a412b 100644
--- a/crypto/seqiv.c
+++ b/crypto/seqiv.c
@@ -73,9 +73,9 @@
 	info = req->iv;
 
 	if (req->src != req->dst) {
-		SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull);
+		SYNC_SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull);
 
-		skcipher_request_set_tfm(nreq, ctx->sknull);
+		skcipher_request_set_sync_tfm(nreq, ctx->sknull);
 		skcipher_request_set_callback(nreq, req->base.flags,
 					      NULL, NULL);
 		skcipher_request_set_crypt(nreq, req->src, req->dst,
diff --git a/crypto/shash.c b/crypto/shash.c
index 5d732c6..d21f04d 100644
--- a/crypto/shash.c
+++ b/crypto/shash.c
@@ -73,13 +73,6 @@
 }
 EXPORT_SYMBOL_GPL(crypto_shash_setkey);
 
-static inline unsigned int shash_align_buffer_size(unsigned len,
-						   unsigned long mask)
-{
-	typedef u8 __aligned_largest u8_aligned;
-	return len + (mask & ~(__alignof__(u8_aligned) - 1));
-}
-
 static int shash_update_unaligned(struct shash_desc *desc, const u8 *data,
 				  unsigned int len)
 {
@@ -88,11 +81,17 @@
 	unsigned long alignmask = crypto_shash_alignmask(tfm);
 	unsigned int unaligned_len = alignmask + 1 -
 				     ((unsigned long)data & alignmask);
-	u8 ubuf[shash_align_buffer_size(unaligned_len, alignmask)]
-		__aligned_largest;
+	/*
+	 * We cannot count on __aligned() working for large values:
+	 * https://patchwork.kernel.org/patch/9507697/
+	 */
+	u8 ubuf[MAX_ALGAPI_ALIGNMASK * 2];
 	u8 *buf = PTR_ALIGN(&ubuf[0], alignmask + 1);
 	int err;
 
+	if (WARN_ON(buf + unaligned_len > ubuf + sizeof(ubuf)))
+		return -EINVAL;
+
 	if (unaligned_len > len)
 		unaligned_len = len;
 
@@ -124,11 +123,17 @@
 	unsigned long alignmask = crypto_shash_alignmask(tfm);
 	struct shash_alg *shash = crypto_shash_alg(tfm);
 	unsigned int ds = crypto_shash_digestsize(tfm);
-	u8 ubuf[shash_align_buffer_size(ds, alignmask)]
-		__aligned_largest;
+	/*
+	 * We cannot count on __aligned() working for large values:
+	 * https://patchwork.kernel.org/patch/9507697/
+	 */
+	u8 ubuf[MAX_ALGAPI_ALIGNMASK + HASH_MAX_DIGESTSIZE];
 	u8 *buf = PTR_ALIGN(&ubuf[0], alignmask + 1);
 	int err;
 
+	if (WARN_ON(buf + ds > ubuf + sizeof(ubuf)))
+		return -EINVAL;
+
 	err = shash->final(desc, buf);
 	if (err)
 		goto out;
@@ -458,9 +463,9 @@
 {
 	struct crypto_alg *base = &alg->base;
 
-	if (alg->digestsize > PAGE_SIZE / 8 ||
-	    alg->descsize > PAGE_SIZE / 8 ||
-	    alg->statesize > PAGE_SIZE / 8)
+	if (alg->digestsize > HASH_MAX_DIGESTSIZE ||
+	    alg->descsize > HASH_MAX_DESCSIZE ||
+	    alg->statesize > HASH_MAX_STATESIZE)
 		return -EINVAL;
 
 	base->cra_type = &crypto_shash_type;
diff --git a/crypto/skcipher.c b/crypto/skcipher.c
index 0bd8c6c..4caab81 100644
--- a/crypto/skcipher.c
+++ b/crypto/skcipher.c
@@ -949,6 +949,30 @@
 }
 EXPORT_SYMBOL_GPL(crypto_alloc_skcipher);
 
+struct crypto_sync_skcipher *crypto_alloc_sync_skcipher(
+				const char *alg_name, u32 type, u32 mask)
+{
+	struct crypto_skcipher *tfm;
+
+	/* Only sync algorithms allowed. */
+	mask |= CRYPTO_ALG_ASYNC;
+
+	tfm = crypto_alloc_tfm(alg_name, &crypto_skcipher_type2, type, mask);
+
+	/*
+	 * Make sure we do not allocate something that might get used with
+	 * an on-stack request: check the request size.
+	 */
+	if (!IS_ERR(tfm) && WARN_ON(crypto_skcipher_reqsize(tfm) >
+				    MAX_SYNC_SKCIPHER_REQSIZE)) {
+		crypto_free_skcipher(tfm);
+		return ERR_PTR(-EINVAL);
+	}
+
+	return (struct crypto_sync_skcipher *)tfm;
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_sync_skcipher);
+
 int crypto_has_skcipher2(const char *alg_name, u32 type, u32 mask)
 {
 	return crypto_type_has_alg(alg_name, &crypto_skcipher_type2,
diff --git a/crypto/xcbc.c b/crypto/xcbc.c
index 25c75af..c055f57f 100644
--- a/crypto/xcbc.c
+++ b/crypto/xcbc.c
@@ -57,15 +57,17 @@
 	u8 ctx[];
 };
 
+#define XCBC_BLOCKSIZE	16
+
 static int crypto_xcbc_digest_setkey(struct crypto_shash *parent,
 				     const u8 *inkey, unsigned int keylen)
 {
 	unsigned long alignmask = crypto_shash_alignmask(parent);
 	struct xcbc_tfm_ctx *ctx = crypto_shash_ctx(parent);
-	int bs = crypto_shash_blocksize(parent);
 	u8 *consts = PTR_ALIGN(&ctx->ctx[0], alignmask + 1);
 	int err = 0;
-	u8 key1[bs];
+	u8 key1[XCBC_BLOCKSIZE];
+	int bs = sizeof(key1);
 
 	if ((err = crypto_cipher_setkey(ctx->child, inkey, keylen)))
 		return err;
@@ -212,7 +214,7 @@
 		return PTR_ERR(alg);
 
 	switch(alg->cra_blocksize) {
-	case 16:
+	case XCBC_BLOCKSIZE:
 		break;
 	default:
 		goto out_put_alg;
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 2dedbc2..15cb8e6 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -52,6 +52,8 @@
 #define CNTFRQ		0x10
 #define CNTP_TVAL	0x28
 #define CNTP_CTL	0x2c
+#define CNTCVAL_LO	0x30
+#define CNTCVAL_HI	0x34
 #define CNTV_TVAL	0x38
 #define CNTV_CTL	0x3c
 
@@ -902,6 +904,23 @@
 	return cpumask_test_cpu(raw_smp_processor_id(), &evtstrm_available);
 }
 
+void arch_timer_mem_get_cval(u32 *lo, u32 *hi)
+{
+	u32 ctrl;
+
+	*lo = *hi = ~0U;
+
+	if (!arch_counter_base)
+		return;
+
+	ctrl = readl_relaxed_no_log(arch_counter_base + CNTV_CTL);
+
+	if (ctrl & ARCH_TIMER_CTRL_ENABLE) {
+		*lo = readl_relaxed_no_log(arch_counter_base + CNTCVAL_LO);
+		*hi = readl_relaxed_no_log(arch_counter_base + CNTCVAL_HI);
+	}
+}
+
 static u64 arch_counter_get_cntvct_mem(void)
 {
 	u32 vct_lo, vct_hi, tmp_hi;
diff --git a/drivers/crypto/qce/ablkcipher.c b/drivers/crypto/qce/ablkcipher.c
index ea4d96b..585e1ca 100644
--- a/drivers/crypto/qce/ablkcipher.c
+++ b/drivers/crypto/qce/ablkcipher.c
@@ -189,7 +189,7 @@
 	memcpy(ctx->enc_key, key, keylen);
 	return 0;
 fallback:
-	ret = crypto_skcipher_setkey(ctx->fallback, key, keylen);
+	ret = crypto_sync_skcipher_setkey(ctx->fallback, key, keylen);
 	if (!ret)
 		ctx->enc_keylen = keylen;
 	return ret;
@@ -212,9 +212,9 @@
 
 	if (IS_AES(rctx->flags) && ctx->enc_keylen != AES_KEYSIZE_128 &&
 	    ctx->enc_keylen != AES_KEYSIZE_256) {
-		SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
+		SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
 
-		skcipher_request_set_tfm(subreq, ctx->fallback);
+		skcipher_request_set_sync_tfm(subreq, ctx->fallback);
 		skcipher_request_set_callback(subreq, req->base.flags,
 					      NULL, NULL);
 		skcipher_request_set_crypt(subreq, req->src, req->dst,
@@ -245,9 +245,8 @@
 	memset(ctx, 0, sizeof(*ctx));
 	tfm->crt_ablkcipher.reqsize = sizeof(struct qce_cipher_reqctx);
 
-	ctx->fallback = crypto_alloc_skcipher(crypto_tfm_alg_name(tfm), 0,
-					      CRYPTO_ALG_ASYNC |
-					      CRYPTO_ALG_NEED_FALLBACK);
+	ctx->fallback = crypto_alloc_sync_skcipher(crypto_tfm_alg_name(tfm),
+						   0, CRYPTO_ALG_NEED_FALLBACK);
 	return PTR_ERR_OR_ZERO(ctx->fallback);
 }
 
@@ -255,7 +254,7 @@
 {
 	struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
 
-	crypto_free_skcipher(ctx->fallback);
+	crypto_free_sync_skcipher(ctx->fallback);
 }
 
 struct qce_ablkcipher_def {
diff --git a/drivers/crypto/qce/cipher.h b/drivers/crypto/qce/cipher.h
index 2b0278b..ee055bf 100644
--- a/drivers/crypto/qce/cipher.h
+++ b/drivers/crypto/qce/cipher.h
@@ -22,7 +22,7 @@
 struct qce_cipher_ctx {
 	u8 enc_key[QCE_MAX_KEY_SIZE];
 	unsigned int enc_keylen;
-	struct crypto_skcipher *fallback;
+	struct crypto_sync_skcipher *fallback;
 };
 
 /**
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index c80ec1d..0863996 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -397,29 +397,26 @@
 	return ret;
 }
 
-static int psci_suspend_finisher(unsigned long index)
+static int psci_suspend_finisher(unsigned long state_id)
 {
-	u32 *state = __this_cpu_read(psci_power_state);
-
-	return psci_ops.cpu_suspend(state[index - 1],
+	return psci_ops.cpu_suspend(state_id,
 				    __pa_symbol(cpu_resume));
 }
-
-int psci_cpu_suspend_enter(unsigned long index)
+int psci_cpu_suspend_enter(unsigned long state_id)
 {
 	int ret;
-	u32 *state = __this_cpu_read(psci_power_state);
+
 	/*
 	 * idle state index 0 corresponds to wfi, should never be called
 	 * from the cpu_suspend operations
 	 */
-	if (WARN_ON_ONCE(!index))
+	if (WARN_ON_ONCE(!state_id))
 		return -EINVAL;
 
-	if (!psci_power_state_loses_context(state[index - 1]))
-		ret = psci_ops.cpu_suspend(state[index - 1], 0);
+	if (!psci_power_state_loses_context(state_id))
+		ret = psci_ops.cpu_suspend(state_id, 0);
 	else
-		ret = cpu_suspend(index, psci_suspend_finisher);
+		ret = cpu_suspend(state_id, psci_suspend_finisher);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index 70ea28f..9bc9757 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -1787,7 +1787,9 @@
 			set_bit(SDE_INTF_INPUT_CTRL, &intf->features);
 
 		if (IS_SDE_MAJOR_SAME((sde_cfg->hwversion),
-				SDE_HW_VER_500))
+				SDE_HW_VER_500) ||
+				IS_SDE_MAJOR_SAME((sde_cfg->hwversion),
+				SDE_HW_VER_600))
 			set_bit(SDE_INTF_TE, &intf->features);
 	}
 
@@ -3633,6 +3635,8 @@
 		sde_cfg->sui_misr_supported = true;
 		sde_cfg->sui_block_xin_mask = 0x3F71;
 		sde_cfg->has_3d_merge_reset = true;
+		clear_bit(MDSS_INTR_AD4_0_INTR, sde_cfg->mdss_irqs);
+		clear_bit(MDSS_INTR_AD4_1_INTR, sde_cfg->mdss_irqs);
 	} else {
 		SDE_ERROR("unsupported chipset id:%X\n", hw_rev);
 		sde_cfg->perf.min_prefill_lines = 0xffff;
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 89622b7..c278777 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -2251,7 +2251,7 @@
 	dev = sde_kms->dev;
 
 	/* iterate state object for active secure/non-secure crtc */
-	for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
+	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
 		if (!crtc_state->active)
 			continue;
 
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 344e1fd..a093237 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -457,7 +457,7 @@
 	if (!of_property_read_bool(node, "iommus"))
 		return 0;
 
-	drvdata->iommu_mapping = arm_iommu_create_mapping(&amba_bustype,
+	drvdata->iommu_mapping = __depr_arm_iommu_create_mapping(&amba_bustype,
 							0, (SZ_1G * 4ULL));
 	if (IS_ERR_OR_NULL(drvdata->iommu_mapping)) {
 		dev_err(drvdata->dev, "Create mapping failed, err = %d\n", ret);
@@ -474,7 +474,8 @@
 		goto iommu_attach_fail;
 	}
 
-	ret = arm_iommu_attach_device(drvdata->dev, drvdata->iommu_mapping);
+	ret = __depr_arm_iommu_attach_device(drvdata->dev,
+					     drvdata->iommu_mapping);
 	if (ret) {
 		dev_err(drvdata->dev, "Attach device failed, err = %d\n", ret);
 		goto iommu_attach_fail;
@@ -483,7 +484,7 @@
 	return ret;
 
 iommu_attach_fail:
-	arm_iommu_release_mapping(drvdata->iommu_mapping);
+	__depr_arm_iommu_release_mapping(drvdata->iommu_mapping);
 iommu_map_err:
 	drvdata->iommu_mapping = NULL;
 	return ret;
@@ -494,8 +495,8 @@
 	if (!drvdata->iommu_mapping)
 		return;
 
-	arm_iommu_detach_device(drvdata->dev);
-	arm_iommu_release_mapping(drvdata->iommu_mapping);
+	__depr_arm_iommu_detach_device(drvdata->dev);
+	__depr_arm_iommu_release_mapping(drvdata->iommu_mapping);
 
 	drvdata->iommu_mapping = NULL;
 }
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 40bb47a..bf151f6 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -243,7 +243,6 @@
 #define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0)
 #define ARM_SMMU_OPT_FATAL_ASF		(1 << 1)
 #define ARM_SMMU_OPT_SKIP_INIT		(1 << 2)
-#define ARM_SMMU_OPT_DYNAMIC		(1 << 3)
 #define ARM_SMMU_OPT_3LVL_TABLES	(1 << 4)
 #define ARM_SMMU_OPT_NO_ASID_RETENTION	(1 << 5)
 #define ARM_SMMU_OPT_STATIC_CB		(1 << 6)
@@ -383,7 +382,6 @@
 	{ ARM_SMMU_OPT_SECURE_CFG_ACCESS, "calxeda,smmu-secure-config-access" },
 	{ ARM_SMMU_OPT_FATAL_ASF, "qcom,fatal-asf" },
 	{ ARM_SMMU_OPT_SKIP_INIT, "qcom,skip-init" },
-	{ ARM_SMMU_OPT_DYNAMIC, "qcom,dynamic" },
 	{ ARM_SMMU_OPT_3LVL_TABLES, "qcom,use-3-lvl-tables" },
 	{ ARM_SMMU_OPT_NO_ASID_RETENTION, "qcom,no-asid-retention" },
 	{ ARM_SMMU_OPT_STATIC_CB, "qcom,enable-static-cb"},
@@ -425,6 +423,10 @@
 				     unsigned long iova,
 				     struct scatterlist *sg,
 				     unsigned int nents, int prot);
+static int arm_smmu_setup_default_domain(struct device *dev,
+				struct iommu_domain *domain);
+static int __arm_smmu_domain_set_attr(struct iommu_domain *domain,
+				    enum iommu_attr attr, void *data);
 
 static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
 {
@@ -1703,6 +1705,15 @@
 	if (smmu_domain->smmu)
 		goto out_unlock;
 
+	if (domain->type == IOMMU_DOMAIN_DMA) {
+		ret = arm_smmu_setup_default_domain(dev, domain);
+		if (ret) {
+			dev_err(dev, "%s: default domain setup failed\n",
+				__func__);
+			goto out_unlock;
+		}
+	}
+
 	if (domain->type == IOMMU_DOMAIN_IDENTITY) {
 		smmu_domain->stage = ARM_SMMU_DOMAIN_BYPASS;
 		smmu_domain->smmu = smmu;
@@ -1711,13 +1722,6 @@
 	}
 
 	dynamic = is_dynamic_domain(domain);
-	if (dynamic && !(smmu->options & ARM_SMMU_OPT_DYNAMIC)) {
-		dev_err(smmu->dev, "dynamic domains not supported\n");
-		ret = -EPERM;
-
-		goto out_unlock;
-	}
-
 	/*
 	 * Mapping the requested stage onto what we support is surprisingly
 	 * complicated, mainly because the spec allows S1+S2 SMMUs without
@@ -2015,9 +2019,9 @@
 {
 	struct arm_smmu_domain *smmu_domain;
 
-	/* Do not support DOMAIN_DMA for now */
 	if (type != IOMMU_DOMAIN_UNMANAGED &&
-	    type != IOMMU_DOMAIN_IDENTITY)
+	    type != IOMMU_DOMAIN_IDENTITY &&
+	    type != IOMMU_DOMAIN_DMA)
 		return NULL;
 	/*
 	 * Allocate the domain and initialise some of its data structures.
@@ -2028,12 +2032,6 @@
 	if (!smmu_domain)
 		return NULL;
 
-	if (type == IOMMU_DOMAIN_DMA && (using_legacy_binding ||
-	    iommu_get_dma_cookie(&smmu_domain->domain))) {
-		kfree(smmu_domain);
-		return NULL;
-	}
-
 	mutex_init(&smmu_domain->init_mutex);
 	spin_lock_init(&smmu_domain->cb_lock);
 	spin_lock_init(&smmu_domain->sync_lock);
@@ -2520,6 +2518,157 @@
 	}
 }
 
+static struct device_node *arm_iommu_get_of_node(struct device *dev)
+{
+	struct device_node *np;
+
+	if (!dev->of_node)
+		return NULL;
+
+	np = of_parse_phandle(dev->of_node, "qcom,iommu-group", 0);
+	return np ? np : dev->of_node;
+}
+
+static int arm_smmu_setup_default_domain(struct device *dev,
+					 struct iommu_domain *domain)
+{
+	struct device_node *np;
+	int ret;
+	const char *str;
+	int attr = 1;
+	u32 val;
+
+	np = arm_iommu_get_of_node(dev);
+	if (!np)
+		return 0;
+
+	ret = of_property_read_string(np, "qcom,iommu-dma", &str);
+	if (ret)
+		str = "default";
+
+	if (!strcmp(str, "bypass"))
+		__arm_smmu_domain_set_attr(
+			domain, DOMAIN_ATTR_S1_BYPASS, &attr);
+	else if (!strcmp(str, "fastmap"))
+		__arm_smmu_domain_set_attr(
+			domain, DOMAIN_ATTR_FAST, &attr);
+	else if (!strcmp(str, "atomic"))
+		__arm_smmu_domain_set_attr(
+			domain, DOMAIN_ATTR_ATOMIC, &attr);
+	else if (!strcmp(str, "disabled")) {
+		/*
+		 * Don't touch hw, and don't allocate irqs or other resources.
+		 * Ensure the context bank is set to a valid value per dynamic
+		 * attr requirement.
+		 */
+		__arm_smmu_domain_set_attr(
+			domain, DOMAIN_ATTR_DYNAMIC, &attr);
+		val = 0;
+		__arm_smmu_domain_set_attr(
+			domain, DOMAIN_ATTR_CONTEXT_BANK, &val);
+	}
+
+	/*
+	 * default value:
+	 * Stall-on-fault
+	 * faults trigger kernel panic
+	 * return abort
+	 */
+	if (of_property_match_string(np, "qcom,iommu-faults",
+				     "stall-disable") >= 0)
+		__arm_smmu_domain_set_attr(domain,
+			DOMAIN_ATTR_CB_STALL_DISABLE, &attr);
+
+	if (of_property_match_string(np, "qcom,iommu-faults", "non-fatal") >= 0)
+		__arm_smmu_domain_set_attr(domain,
+			DOMAIN_ATTR_NON_FATAL_FAULTS, &attr);
+
+	if (of_property_match_string(np, "qcom,iommu-faults", "no-CFRE") >= 0)
+		__arm_smmu_domain_set_attr(
+			domain, DOMAIN_ATTR_NO_CFRE, &attr);
+
+	/* Default value: disabled */
+	ret = of_property_read_u32(np, "qcom,iommu-vmid", &val);
+	if (!ret) {
+		__arm_smmu_domain_set_attr(
+			domain, DOMAIN_ATTR_SECURE_VMID, &val);
+	}
+
+	/* Default value: disabled */
+	ret = of_property_read_string(np, "qcom,iommu-pagetable", &str);
+	if (ret)
+		str = "disabled";
+	if (!strcmp(str, "coherent"))
+		__arm_smmu_domain_set_attr(domain,
+			DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT, &attr);
+	else if (!strcmp(str, "LLC"))
+		__arm_smmu_domain_set_attr(domain,
+			DOMAIN_ATTR_USE_UPSTREAM_HINT, &attr);
+	else if (!strcmp(str, "LLC_NWA"))
+		__arm_smmu_domain_set_attr(domain,
+			DOMAIN_ATTR_USE_LLC_NWA, &attr);
+
+
+	/* Default value: disabled */
+	if (of_property_read_bool(np, "qcom,iommu-earlymap"))
+		__arm_smmu_domain_set_attr(domain,
+			DOMAIN_ATTR_EARLY_MAP, &attr);
+	return 0;
+}
+
+struct lookup_iommu_group_data {
+	struct device_node *np;
+	struct iommu_group *group;
+};
+
+/* This isn't a "fast lookup" since its N^2, but probably good enough */
+static int __bus_lookup_iommu_group(struct device *dev, void *priv)
+{
+	struct lookup_iommu_group_data *data = priv;
+	struct device_node *np;
+	struct iommu_group *group;
+
+	group = iommu_group_get(dev);
+	if (!group)
+		return 0;
+
+	np = of_parse_phandle(dev->of_node, "qcom,iommu-group", 0);
+	if (np != data->np) {
+		iommu_group_put(group);
+		return 0;
+	}
+
+	data->group = group;
+	iommu_group_put(group);
+	return 1;
+}
+
+static struct iommu_group *of_get_device_group(struct device *dev)
+{
+	struct lookup_iommu_group_data data = {0};
+	struct iommu_group *group;
+	int ret;
+
+	data.np = of_parse_phandle(dev->of_node, "qcom,iommu-group", 0);
+	if (!data.np)
+		return NULL;
+
+	ret = bus_for_each_dev(&platform_bus_type, NULL, &data,
+				__bus_lookup_iommu_group);
+	if (ret > 0)
+		return data.group;
+
+	ret = bus_for_each_dev(&pci_bus_type, NULL, &data,
+				__bus_lookup_iommu_group);
+	if (ret > 0)
+		return data.group;
+
+	group = generic_device_group(dev);
+	if (IS_ERR(group))
+		return NULL;
+	return group;
+}
+
 static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 {
 	int ret;
@@ -3040,12 +3189,17 @@
 	struct iommu_group *group = NULL;
 	int i, idx;
 
+	group = of_get_device_group(dev);
 	for_each_cfg_sme(fwspec, i, idx) {
 		if (group && smmu->s2crs[idx].group &&
-		    group != smmu->s2crs[idx].group)
+		    group != smmu->s2crs[idx].group) {
+			dev_err(dev, "ID:%x IDX:%x is already in a group!\n",
+				fwspec->ids[i], idx);
 			return ERR_PTR(-EINVAL);
+		}
 
-		group = smmu->s2crs[idx].group;
+		if (!group)
+			group = smmu->s2crs[idx].group;
 	}
 
 	if (group)
@@ -3074,9 +3228,6 @@
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
 	int ret = 0;
 
-	if (domain->type != IOMMU_DOMAIN_UNMANAGED)
-		return -EINVAL;
-
 	mutex_lock(&smmu_domain->init_mutex);
 	switch (attr) {
 	case DOMAIN_ATTR_NESTING:
@@ -3216,22 +3367,19 @@
 	return ret;
 }
 
-static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
+static int __arm_smmu_domain_set_attr2(struct iommu_domain *domain,
+				    enum iommu_attr attr, void *data);
+static int __arm_smmu_domain_set_attr(struct iommu_domain *domain,
 				    enum iommu_attr attr, void *data)
 {
 	int ret = 0;
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
 
-	if (domain->type != IOMMU_DOMAIN_UNMANAGED)
-		return -EINVAL;
-
-	mutex_lock(&smmu_domain->init_mutex);
-
 	switch (attr) {
 	case DOMAIN_ATTR_NESTING:
 		if (smmu_domain->smmu) {
 			ret = -EPERM;
-			goto out_unlock;
+			goto out;
 		}
 
 		if (*(int *)data)
@@ -3347,6 +3495,21 @@
 		}
 		ret = 0;
 		break;
+	default:
+		ret = __arm_smmu_domain_set_attr2(domain, attr, data);
+	}
+out:
+	return ret;
+}
+
+/* yeee-haw */
+static int __arm_smmu_domain_set_attr2(struct iommu_domain *domain,
+				    enum iommu_attr attr, void *data)
+{
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+	int ret = 0;
+
+	switch (attr) {
 	case DOMAIN_ATTR_USE_UPSTREAM_HINT:
 	case DOMAIN_ATTR_USE_LLC_NWA:
 		/* can't be changed while attached */
@@ -3409,11 +3572,21 @@
 		ret = -ENODEV;
 	}
 
-out_unlock:
-	mutex_unlock(&smmu_domain->init_mutex);
 	return ret;
 }
 
+static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
+				    enum iommu_attr attr, void *data)
+{
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+	int ret;
+
+	mutex_lock(&smmu_domain->init_mutex);
+	ret = __arm_smmu_domain_set_attr(domain, attr, data);
+	mutex_unlock(&smmu_domain->init_mutex);
+
+	return ret;
+}
 static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
 {
 	u32 mask, fwid = 0;
diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c
index 62759e2..b4d1936 100644
--- a/drivers/iommu/iommu-debug.c
+++ b/drivers/iommu/iommu-debug.c
@@ -18,6 +18,8 @@
 #include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/iommu.h>
+#include <linux/of_iommu.h>
+#include <linux/of_address.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
@@ -173,6 +175,8 @@
 	struct list_head list;
 	struct mutex clk_lock;
 	unsigned int clk_count;
+	/* Protects domain */
+	struct mutex state_lock;
 };
 
 static int iommu_debug_build_phoney_sg_table(struct device *dev,
@@ -219,6 +223,163 @@
 	sg_free_table(table);
 }
 
+struct iommu_debug_attr {
+	unsigned long dma_type;
+	int vmid;
+};
+
+static struct iommu_debug_attr std_attr = {
+	.dma_type = 0,
+	.vmid = 0,
+};
+
+static struct iommu_debug_attr fastmap_attr = {
+	.dma_type = DOMAIN_ATTR_FAST,
+	.vmid = 0,
+};
+
+static struct iommu_debug_attr secure_attr = {
+	.dma_type = 0,
+	.vmid = VMID_CP_CAMERA,
+};
+
+static int iommu_debug_set_attrs(struct iommu_debug_device *ddev,
+				 struct iommu_domain *domain,
+				 struct iommu_debug_attr *attrs)
+{
+	int val = 1;
+
+	/* Always set this to avoid clk latency during measurements */
+	iommu_domain_set_attr(domain, DOMAIN_ATTR_ATOMIC, &val);
+
+	if (attrs->dma_type == DOMAIN_ATTR_FAST)
+		iommu_domain_set_attr(domain, DOMAIN_ATTR_FAST, &val);
+
+	if (attrs->vmid != 0)
+		iommu_domain_set_attr(domain,
+			DOMAIN_ATTR_SECURE_VMID, &attrs->vmid);
+
+	return 0;
+}
+
+static void iommu_debug_print_attrs(struct seq_file *s,
+				    struct iommu_debug_attr *attrs)
+{
+	seq_puts(s, "Attributes:\n");
+	if (attrs->dma_type == DOMAIN_ATTR_FAST)
+		seq_printf(s, "%s\n",
+			   iommu_debug_attr_to_string(attrs->dma_type));
+
+	if (attrs->vmid != 0)
+		seq_printf(s, "SECURE_VMID=%d\n", attrs->vmid);
+}
+
+/*
+ * Set up a new dma allocator for dev
+ * Caller should hold state_lock
+ */
+static int iommu_debug_dma_reconfigure(struct iommu_debug_device *ddev,
+					struct iommu_debug_attr *attrs,
+					u64 dma_base, u64 size)
+{
+
+	const struct iommu_ops *iommu;
+	struct iommu_domain *domain;
+	struct device *dev = ddev->dev;
+	bool coherent;
+
+	if (ddev->domain) {
+		dev_err(dev, "Already attached.\n");
+		return -EBUSY;
+	}
+
+	iommu = of_iommu_configure(dev, dev->of_node);
+	if (!iommu) {
+		dev_err(dev, "Is not associated with an iommu\n");
+		return -EINVAL;
+	}
+
+	coherent = of_dma_is_coherent(dev->of_node);
+
+	if (!dev->iommu_group) {
+		dev_err(dev, "Does not have an iommu group\n");
+		return -EINVAL;
+	}
+
+	/* Detach from the default domain */
+	domain = iommu_get_domain_for_dev(dev);
+	if (domain) {
+		if (domain->type != IOMMU_DOMAIN_DMA) {
+			dev_err(dev, "Attached, but its not a default domain?\n");
+			return -EINVAL;
+		}
+		iommu_detach_group(domain, dev->iommu_group);
+	}
+
+	domain = iommu_domain_alloc(dev->bus);
+	if (!domain) {
+		dev_err(dev, "Allocating iommu domain failed\n");
+		return -EINVAL;
+	}
+
+	domain->is_debug_domain = true;
+
+	if (iommu_debug_set_attrs(ddev, domain, attrs)) {
+		dev_err(dev, "Setting attrs failed\n");
+		goto out_free_domain;
+	}
+
+	if (iommu_attach_group(domain, dev->iommu_group)) {
+		dev_err(dev, "attach group failed\n");
+		goto out_free_domain;
+	}
+
+	/*
+	 * Since arch_setup_dma_ops is void, interpret non-null dma-ops
+	 * as success.
+	 */
+	set_dma_ops(dev, NULL);
+	arch_setup_dma_ops(dev, dma_base, size, iommu, coherent);
+	if (!get_dma_ops(dev)) {
+		dev_err(dev, "arch_setup_dma_ops failed, dma ops are null.\n");
+		goto out_detach_group;
+	}
+
+	ddev->domain = domain;
+	return 0;
+
+out_detach_group:
+	iommu_detach_group(domain, dev->iommu_group);
+out_free_domain:
+	iommu_domain_free(domain);
+	return -EINVAL;
+}
+
+/* Caller should hold state_lock */
+static void iommu_debug_dma_deconfigure(struct iommu_debug_device *ddev)
+{
+	struct iommu_domain *domain;
+	struct device *dev = ddev->dev;
+
+	if (!dev->iommu_group) {
+		dev_err(dev, "Does not have an iommu group\n");
+		return;
+	}
+
+	domain = ddev->domain;
+	if (!domain) {
+		dev_err(dev, "Is not attached\n");
+		return;
+	}
+
+
+	arch_teardown_dma_ops(dev);
+	iommu_detach_group(domain, dev->iommu_group);
+	iommu_domain_free(domain);
+
+	ddev->domain = NULL;
+}
+
 static const char * const _size_to_string(unsigned long size)
 {
 	switch (size) {
@@ -265,44 +426,22 @@
 DEFINE_SIMPLE_ATTRIBUTE(iommu_debug_nr_iters_ops,
 			nr_iters_get, nr_iters_set, "%llu\n");
 
-static void iommu_debug_device_profiling(struct seq_file *s, struct device *dev,
-					 enum iommu_attr attrs[],
-					 void *attr_values[], int nattrs,
-					 const size_t sizes[])
+static void iommu_debug_device_profiling(struct seq_file *s,
+					struct iommu_debug_device *ddev,
+					struct iommu_debug_attr *attrs,
+					const size_t sizes[])
 {
-	int i;
 	const size_t *sz;
 	struct iommu_domain *domain;
+	struct device *dev = ddev->dev;
 	unsigned long iova = 0x10000;
 	phys_addr_t paddr = 0xa000;
 
-	domain = iommu_domain_alloc(&platform_bus_type);
-	if (!domain) {
-		seq_puts(s, "Couldn't allocate domain\n");
+	if (iommu_debug_dma_reconfigure(ddev, attrs, 0, SZ_1G * 4ULL))
 		return;
-	}
+	domain = ddev->domain;
 
-	seq_puts(s, "Domain attributes: [ ");
-	for (i = 0; i < nattrs; ++i) {
-		/* not all attrs are ints, but this will get us by for now */
-		seq_printf(s, "%s=%d%s", iommu_debug_attr_to_string(attrs[i]),
-			   *((int *)attr_values[i]),
-			   i < nattrs ? " " : "");
-	}
-	seq_puts(s, "]\n");
-	for (i = 0; i < nattrs; ++i) {
-		if (iommu_domain_set_attr(domain, attrs[i], attr_values[i])) {
-			seq_printf(s, "Couldn't set %d to the value at %p\n",
-				 attrs[i], attr_values[i]);
-			goto out_domain_free;
-		}
-	}
-
-	if (iommu_attach_group(domain, dev->iommu_group)) {
-		seq_puts(s,
-			 "Couldn't attach new domain to device. Is it already attached?\n");
-		goto out_domain_free;
-	}
+	iommu_debug_print_attrs(s, attrs);
 
 	seq_printf(s, "(average over %d iterations)\n", iters_per_op);
 	seq_printf(s, "%8s %19s %16s\n", "size", "iommu_map", "iommu_unmap");
@@ -419,9 +558,7 @@
 	}
 
 out_detach:
-	iommu_detach_group(domain, dev->iommu_group);
-out_domain_free:
-	iommu_domain_free(domain);
+	iommu_debug_dma_deconfigure(ddev);
 }
 
 static int iommu_debug_profiling_show(struct seq_file *s, void *ignored)
@@ -429,14 +566,10 @@
 	struct iommu_debug_device *ddev = s->private;
 	const size_t sizes[] = { SZ_4K, SZ_64K, SZ_1M, SZ_2M, SZ_1M * 12,
 					SZ_1M * 24, SZ_1M * 32, 0 };
-	enum iommu_attr attrs[] = {
-		DOMAIN_ATTR_ATOMIC,
-	};
-	int htw_disable = 1, atomic = 1;
-	void *attr_values[] = { &htw_disable, &atomic };
 
-	iommu_debug_device_profiling(s, ddev->dev, attrs, attr_values,
-				     ARRAY_SIZE(attrs), sizes);
+	mutex_lock(&ddev->state_lock);
+	iommu_debug_device_profiling(s, ddev, &std_attr, sizes);
+	mutex_unlock(&ddev->state_lock);
 
 	return 0;
 }
@@ -459,15 +592,9 @@
 	const size_t sizes[] = { SZ_4K, SZ_64K, SZ_1M, SZ_2M, SZ_1M * 12,
 					SZ_1M * 24, SZ_1M * 32, 0 };
 
-	enum iommu_attr attrs[] = {
-		DOMAIN_ATTR_ATOMIC,
-		DOMAIN_ATTR_SECURE_VMID,
-	};
-	int one = 1, secure_vmid = VMID_CP_PIXEL;
-	void *attr_values[] = { &one, &secure_vmid };
-
-	iommu_debug_device_profiling(s, ddev->dev, attrs, attr_values,
-				     ARRAY_SIZE(attrs), sizes);
+	mutex_lock(&ddev->state_lock);
+	iommu_debug_device_profiling(s, ddev, &secure_attr, sizes);
+	mutex_unlock(&ddev->state_lock);
 
 	return 0;
 }
@@ -490,15 +617,10 @@
 {
 	struct iommu_debug_device *ddev = s->private;
 	size_t sizes[] = {SZ_4K, SZ_8K, SZ_16K, SZ_64K, 0};
-	enum iommu_attr attrs[] = {
-		DOMAIN_ATTR_FAST,
-		DOMAIN_ATTR_ATOMIC,
-	};
-	int one = 1;
-	void *attr_values[] = { &one, &one };
 
-	iommu_debug_device_profiling(s, ddev->dev, attrs, attr_values,
-				     ARRAY_SIZE(attrs), sizes);
+	mutex_lock(&ddev->state_lock);
+	iommu_debug_device_profiling(s, ddev, &fastmap_attr, sizes);
+	mutex_unlock(&ddev->state_lock);
 
 	return 0;
 }
@@ -524,10 +646,9 @@
 	struct iommu_debug_device *ddev = s->private;
 	struct device *dev = ddev->dev;
 	u64 map_elapsed_ns[10], unmap_elapsed_ns[10];
-	struct dma_iommu_mapping *mapping;
+	struct iommu_domain *domain;
 	dma_addr_t dma_addr;
 	void *virt;
-	int fast = 1;
 	const char * const extra_labels[] = {
 		"not coherent",
 		"coherent",
@@ -537,27 +658,19 @@
 		DMA_ATTR_SKIP_CPU_SYNC,
 	};
 
+	mutex_lock(&ddev->state_lock);
+
 	virt = kmalloc(1518, GFP_KERNEL);
 	if (!virt)
 		goto out;
 
-	mapping = arm_iommu_create_mapping(&platform_bus_type, 0, SZ_1G * 4ULL);
-	if (!mapping) {
-		seq_puts(s, "fast_smmu_create_mapping failed\n");
+	if (iommu_debug_dma_reconfigure(ddev, &fastmap_attr, 0, SZ_1G * 4ULL)) {
+		seq_puts(s, "setup failed\n");
 		goto out_kfree;
 	}
+	domain = ddev->domain;
 
-	if (iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_FAST, &fast)) {
-		seq_puts(s, "iommu_domain_set_attr failed\n");
-		goto out_release_mapping;
-	}
-
-	if (arm_iommu_attach_device(dev, mapping)) {
-		seq_puts(s, "fast_smmu_attach_device failed\n");
-		goto out_release_mapping;
-	}
-
-	if (iommu_enable_config_clocks(mapping->domain)) {
+	if (iommu_enable_config_clocks(domain)) {
 		seq_puts(s, "Couldn't enable clocks\n");
 		goto out_detach;
 	}
@@ -613,14 +726,13 @@
 	}
 
 out_disable_config_clocks:
-	iommu_disable_config_clocks(mapping->domain);
+	iommu_disable_config_clocks(domain);
 out_detach:
-	arm_iommu_detach_device(dev);
-out_release_mapping:
-	arm_iommu_release_mapping(mapping);
+	iommu_debug_dma_deconfigure(ddev);
 out_kfree:
 	kfree(virt);
 out:
+	mutex_unlock(&ddev->state_lock);
 	return 0;
 }
 
@@ -1158,43 +1270,37 @@
 					      void *priv),
 				    void *priv)
 {
-	struct dma_iommu_mapping *mapping;
+	struct iommu_domain *domain;
 	struct iommu_debug_device *ddev = s->private;
 	struct device *dev = ddev->dev;
-	int ret = -EINVAL, fast = 1;
+	int ret = -EINVAL;
 	phys_addr_t pt_phys;
 
-	mapping = arm_iommu_create_mapping(&platform_bus_type, 0,
-						(SZ_1G * 4ULL));
-	if (!mapping)
+	mutex_lock(&ddev->state_lock);
+	if (iommu_debug_dma_reconfigure(ddev, &fastmap_attr, 0, SZ_1G * 4ULL)) {
+		seq_puts(s, "setup failed\n");
 		goto out;
-
-	if (iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_FAST, &fast)) {
-		seq_puts(s, "iommu_domain_set_attr failed\n");
-		goto out_release_mapping;
 	}
+	domain = ddev->domain;
 
-	if (arm_iommu_attach_device(dev, mapping))
-		goto out_release_mapping;
-
-	if (iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_PT_BASE_ADDR,
+	if (iommu_domain_get_attr(domain, DOMAIN_ATTR_PT_BASE_ADDR,
 				  &pt_phys)) {
 		ds_printf(dev, s, "Couldn't get page table base address\n");
 		goto out_release_mapping;
 	}
 
 	dev_err(dev, "testing with pgtables at %pa\n", &pt_phys);
-	if (iommu_enable_config_clocks(mapping->domain)) {
+	if (iommu_enable_config_clocks(domain)) {
 		ds_printf(dev, s, "Couldn't enable clocks\n");
 		goto out_release_mapping;
 	}
-	ret = fn(dev, s, mapping->domain, priv);
-	iommu_disable_config_clocks(mapping->domain);
+	ret = fn(dev, s, domain, priv);
+	iommu_disable_config_clocks(domain);
 
-	arm_iommu_detach_device(dev);
 out_release_mapping:
-	arm_iommu_release_mapping(mapping);
+	iommu_debug_dma_deconfigure(ddev);
 out:
+	mutex_unlock(&ddev->state_lock);
 	seq_printf(s, "%s\n", ret ? "FAIL" : "SUCCESS");
 	return 0;
 }
@@ -1228,29 +1334,22 @@
 static int iommu_debug_functional_arm_dma_api_show(struct seq_file *s,
 						   void *ignored)
 {
-	struct dma_iommu_mapping *mapping;
 	struct iommu_debug_device *ddev = s->private;
 	struct device *dev = ddev->dev;
 	size_t sizes[] = {SZ_4K, SZ_64K, SZ_2M, SZ_1M * 12, 0};
 	int ret = -EINVAL;
 
-	/* Make the size equal to MAX_ULONG */
-	mapping = arm_iommu_create_mapping(&platform_bus_type, 0,
-						(SZ_1G * 4ULL - 1));
-	if (!mapping)
+	mutex_lock(&ddev->state_lock);
+	if (iommu_debug_dma_reconfigure(ddev, &fastmap_attr, 0, SZ_1G * 4ULL))
 		goto out;
 
-	if (arm_iommu_attach_device(dev, mapping))
-		goto out_release_mapping;
+	ret = __functional_dma_api_alloc_test(dev, s, ddev->domain, sizes);
+	ret |= __functional_dma_api_basic_test(dev, s, ddev->domain, sizes);
+	ret |= __functional_dma_api_map_sg_test(dev, s, ddev->domain, sizes);
 
-	ret = __functional_dma_api_alloc_test(dev, s, mapping->domain, sizes);
-	ret |= __functional_dma_api_basic_test(dev, s, mapping->domain, sizes);
-	ret |= __functional_dma_api_map_sg_test(dev, s, mapping->domain, sizes);
-
-	arm_iommu_detach_device(dev);
-out_release_mapping:
-	arm_iommu_release_mapping(mapping);
+	iommu_debug_dma_deconfigure(ddev);
 out:
+	mutex_unlock(&ddev->state_lock);
 	seq_printf(s, "%s\n", ret ? "FAIL" : "SUCCESS");
 	return 0;
 }
@@ -1269,181 +1368,60 @@
 	.release = single_release,
 };
 
-static int iommu_debug_attach_do_attach(struct iommu_debug_device *ddev,
-					int val, bool is_secure)
-{
-	struct iommu_group *group = ddev->dev->iommu_group;
-
-	ddev->domain = iommu_domain_alloc(&platform_bus_type);
-	if (!ddev->domain) {
-		pr_err("Couldn't allocate domain\n");
-		return -ENOMEM;
-	}
-
-	ddev->domain->is_debug_domain = true;
-	val = VMID_CP_CAMERA;
-	if (is_secure && iommu_domain_set_attr(ddev->domain,
-					       DOMAIN_ATTR_SECURE_VMID,
-					       &val)) {
-		pr_err("Couldn't set secure vmid to %d\n", val);
-		goto out_domain_free;
-	}
-
-	if (iommu_attach_group(ddev->domain, group)) {
-		dev_err(ddev->dev, "Couldn't attach new domain to device\n");
-		goto out_domain_free;
-	}
-
-	return 0;
-
-out_domain_free:
-	iommu_domain_free(ddev->domain);
-	ddev->domain = NULL;
-	return -EIO;
-}
-
-static ssize_t __iommu_debug_dma_attach_write(struct file *file,
-					  const char __user *ubuf,
-					  size_t count, loff_t *offset)
-{
-	struct iommu_debug_device *ddev = file->private_data;
-	struct device *dev = ddev->dev;
-	struct dma_iommu_mapping *dma_mapping;
-	ssize_t retval = -EINVAL;
-	int val;
-
-	if (kstrtoint_from_user(ubuf, count, 0, &val)) {
-		pr_err("Invalid format. Expected a hex or decimal integer");
-		retval = -EFAULT;
-		goto out;
-	}
-
-	if (val) {
-		if (dev->archdata.mapping)
-			if (dev->archdata.mapping->domain) {
-				pr_err("Already attached.\n");
-				retval = -EINVAL;
-				goto out;
-			}
-		if (WARN(dev->archdata.iommu,
-			"Attachment tracking out of sync with device\n")) {
-			retval = -EINVAL;
-			goto out;
-		}
-
-		dma_mapping = arm_iommu_create_mapping(&platform_bus_type, 0,
-				(SZ_1G * 4ULL));
-
-		if (!dma_mapping)
-			goto out;
-
-		dma_mapping->domain->is_debug_domain = true;
-
-		if (arm_iommu_attach_device(dev, dma_mapping))
-			goto out_release_mapping;
-
-		ddev->mapping = dma_mapping;
-		pr_err("Attached\n");
-	} else {
-		if (!dev->archdata.mapping) {
-			pr_err("No mapping. Did you already attach?\n");
-			retval = -EINVAL;
-			goto out;
-		}
-		if (!dev->archdata.mapping->domain) {
-			pr_err("No domain. Did you already attach?\n");
-			retval = -EINVAL;
-			goto out;
-		}
-		arm_iommu_detach_device(dev);
-		arm_iommu_release_mapping(ddev->mapping);
-		pr_err("Detached\n");
-	}
-	retval = count;
-	return retval;
-
-out_release_mapping:
-	arm_iommu_release_mapping(dma_mapping);
-out:
-	return retval;
-}
-
 static ssize_t __iommu_debug_attach_write(struct file *file,
 					  const char __user *ubuf,
 					  size_t count, loff_t *offset,
-					  bool is_secure)
+					struct iommu_debug_attr *attrs)
 {
 	struct iommu_debug_device *ddev = file->private_data;
-	struct device *dev = ddev->dev;
-	struct iommu_domain *domain;
-	ssize_t retval;
-	int val;
+	ssize_t retval = -EINVAL;
+	int val, ret;
 
 	if (kstrtoint_from_user(ubuf, count, 0, &val)) {
 		pr_err("Invalid format. Expected a hex or decimal integer");
-		retval = -EFAULT;
-		goto out;
+		return -EFAULT;
 	}
 
+	mutex_lock(&ddev->state_lock);
 	if (val) {
-		if (ddev->domain) {
-			pr_err("Iommu-Debug is already attached?\n");
-			retval = -EINVAL;
-			goto out;
-		}
-
-		domain = iommu_get_domain_for_dev(dev);
-		if (domain) {
-			pr_err("Another driver is using this device's iommu\n"
-				"Iommu-Debug cannot be used concurrently\n");
-			retval = -EINVAL;
-			goto out;
-		}
-		if (iommu_debug_attach_do_attach(ddev, val, is_secure)) {
-			retval = -EIO;
-			goto out;
-		}
-		pr_err("Attached\n");
+		ret = iommu_debug_dma_reconfigure(ddev, attrs, 0, SZ_1G * 4ULL);
+		if (!ret)
+			pr_err("Attached\n");
 	} else {
-		if (!ddev->domain) {
-			pr_err("Iommu-Debug is not attached?\n");
-			retval = -EINVAL;
-			goto out;
-		}
-		iommu_detach_group(ddev->domain, dev->iommu_group);
-		iommu_domain_free(ddev->domain);
-		ddev->domain = NULL;
+		iommu_debug_dma_deconfigure(ddev);
 		pr_err("Detached\n");
 	}
-
+	mutex_unlock(&ddev->state_lock);
 	retval = count;
-out:
 	return retval;
 }
 
-static ssize_t iommu_debug_dma_attach_write(struct file *file,
+static ssize_t iommu_debug_secure_attach_write(struct file *file,
 					  const char __user *ubuf,
 					  size_t count, loff_t *offset)
 {
-	return __iommu_debug_dma_attach_write(file, ubuf, count, offset);
+	return __iommu_debug_attach_write(file, ubuf, count, offset,
+						&secure_attr);
+}
+
+static ssize_t iommu_debug_attach_write(struct file *file,
+					  const char __user *ubuf,
+					  size_t count, loff_t *offset)
+{
+	return __iommu_debug_attach_write(file, ubuf, count, offset, &std_attr);
 
 }
 
-static ssize_t iommu_debug_dma_attach_read(struct file *file, char __user *ubuf,
+static ssize_t iommu_debug_attach_read(struct file *file, char __user *ubuf,
 				       size_t count, loff_t *offset)
 {
 	struct iommu_debug_device *ddev = file->private_data;
-	struct device *dev = ddev->dev;
 	char c[2];
 
 	if (*offset)
 		return 0;
 
-	if (!dev->archdata.mapping)
-		c[0] = '0';
-	else
-		c[0] = dev->archdata.mapping->domain ? '1' : '0';
-
+	c[0] = ddev->domain ? '1' : '0';
 	c[1] = '\n';
 	if (copy_to_user(ubuf, &c, 2)) {
 		pr_err("copy_to_user failed\n");
@@ -1456,8 +1434,8 @@
 
 static const struct file_operations iommu_debug_dma_attach_fops = {
 	.open	= simple_open,
-	.write	= iommu_debug_dma_attach_write,
-	.read	= iommu_debug_dma_attach_read,
+	.write	= iommu_debug_attach_write,
+	.read	= iommu_debug_attach_read,
 };
 
 static ssize_t iommu_debug_test_virt_addr_read(struct file *file,
@@ -1496,52 +1474,15 @@
 	.read	= iommu_debug_test_virt_addr_read,
 };
 
-static ssize_t iommu_debug_attach_write(struct file *file,
-					  const char __user *ubuf,
-					  size_t count, loff_t *offset)
-{
-	return __iommu_debug_attach_write(file, ubuf, count, offset,
-					  false);
-
-}
-
-static ssize_t iommu_debug_attach_read(struct file *file, char __user *ubuf,
-				       size_t count, loff_t *offset)
-{
-	struct iommu_debug_device *ddev = file->private_data;
-	char c[2];
-
-	if (*offset)
-		return 0;
-
-	c[0] = ddev->domain ? '1' : '0';
-	c[1] = '\n';
-	if (copy_to_user(ubuf, &c, 2)) {
-		pr_err("copy_to_user failed\n");
-		return -EFAULT;
-	}
-	*offset = 1;		/* non-zero means we're done */
-
-	return 2;
-}
-
 static const struct file_operations iommu_debug_attach_fops = {
 	.open	= simple_open,
 	.write	= iommu_debug_attach_write,
 	.read	= iommu_debug_attach_read,
 };
 
-static ssize_t iommu_debug_attach_write_secure(struct file *file,
-					       const char __user *ubuf,
-					       size_t count, loff_t *offset)
-{
-	return __iommu_debug_attach_write(file, ubuf, count, offset,
-					  true);
-}
-
 static const struct file_operations iommu_debug_secure_attach_fops = {
 	.open	= simple_open,
-	.write	= iommu_debug_attach_write_secure,
+	.write	= iommu_debug_secure_attach_write,
 	.read	= iommu_debug_attach_read,
 };
 
@@ -1568,7 +1509,6 @@
 				     size_t count, loff_t *offset)
 {
 	struct iommu_debug_device *ddev = file->private_data;
-	struct device *dev = ddev->dev;
 	uint64_t pte;
 	char buf[100];
 	ssize_t retval;
@@ -1578,22 +1518,20 @@
 		pr_err("kptr_restrict needs to be disabled.\n");
 		return -EPERM;
 	}
-	if (!dev->archdata.mapping) {
-		pr_err("No mapping. Did you already attach?\n");
-		return -EINVAL;
-	}
-	if (!dev->archdata.mapping->domain) {
-		pr_err("No domain. Did you already attach?\n");
-		return -EINVAL;
-	}
 
 	if (*offset)
 		return 0;
 
+	mutex_lock(&ddev->state_lock);
+	if (!ddev->domain) {
+		pr_err("No domain. Did you already attach?\n");
+		mutex_unlock(&ddev->state_lock);
+		return -EINVAL;
+	}
+
 	memset(buf, 0, sizeof(buf));
 
-	pte = iommu_iova_to_pte(dev->archdata.mapping->domain,
-			ddev->iova);
+	pte = iommu_iova_to_pte(ddev->domain, ddev->iova);
 
 	if (!pte)
 		strlcpy(buf, "FAIL\n", sizeof(buf));
@@ -1609,6 +1547,7 @@
 		retval = buflen;
 	}
 
+	mutex_unlock(&ddev->state_lock);
 	return retval;
 }
 
@@ -1649,14 +1588,17 @@
 		pr_err("kptr_restrict needs to be disabled.\n");
 		return -EPERM;
 	}
-	if (!ddev->domain) {
-		pr_err("No domain. Did you already attach?\n");
-		return -EINVAL;
-	}
 
 	if (*offset)
 		return 0;
 
+	mutex_lock(&ddev->state_lock);
+	if (!ddev->domain) {
+		pr_err("No domain. Did you already attach?\n");
+		mutex_unlock(&ddev->state_lock);
+		return -EINVAL;
+	}
+
 	memset(buf, 0, 100);
 
 	phys = iommu_iova_to_phys_hard(ddev->domain, ddev->iova);
@@ -1678,6 +1620,7 @@
 		retval = buflen;
 	}
 
+	mutex_unlock(&ddev->state_lock);
 	return retval;
 }
 
@@ -1691,7 +1634,6 @@
 				     size_t count, loff_t *offset)
 {
 	struct iommu_debug_device *ddev = file->private_data;
-	struct device *dev = ddev->dev;
 	phys_addr_t phys;
 	char buf[100];
 	ssize_t retval;
@@ -1701,21 +1643,19 @@
 		pr_err("kptr_restrict needs to be disabled.\n");
 		return -EPERM;
 	}
-	if (!dev->archdata.mapping) {
-		pr_err("No mapping. Did you already attach?\n");
-		return -EINVAL;
-	}
-	if (!dev->archdata.mapping->domain) {
-		pr_err("No domain. Did you already attach?\n");
-		return -EINVAL;
-	}
-
 	if (*offset)
 		return 0;
 
+	mutex_lock(&ddev->state_lock);
+	if (!ddev->domain) {
+		pr_err("No domain. Did you already attach?\n");
+		mutex_unlock(&ddev->state_lock);
+		return -EINVAL;
+	}
+
 	memset(buf, 0, sizeof(buf));
 
-	phys = iommu_iova_to_phys_hard(dev->archdata.mapping->domain,
+	phys = iommu_iova_to_phys_hard(ddev->domain,
 			ddev->iova);
 	if (!phys)
 		strlcpy(buf, "FAIL\n", sizeof(buf));
@@ -1731,6 +1671,7 @@
 		retval = buflen;
 	}
 
+	mutex_unlock(&ddev->state_lock);
 	return retval;
 }
 
@@ -1758,11 +1699,6 @@
 		return -EINVAL;
 	}
 
-	if (!ddev->domain) {
-		pr_err("No domain. Did you already attach?\n");
-		return -EINVAL;
-	}
-
 	memset(buf, 0, 100);
 
 	if (copy_from_user(buf, ubuf, count)) {
@@ -1797,6 +1733,13 @@
 	if (kstrtoint(comma3 + 1, 0, &prot))
 		goto invalid_format;
 
+	mutex_lock(&ddev->state_lock);
+	if (!ddev->domain) {
+		pr_err("No domain. Did you already attach?\n");
+		mutex_unlock(&ddev->state_lock);
+		return -EINVAL;
+	}
+
 	ret = iommu_map(ddev->domain, iova, phys, size, prot);
 	if (ret) {
 		pr_err("iommu_map failed with %d\n", ret);
@@ -1808,6 +1751,7 @@
 	pr_err("Mapped %pa to %pa (len=0x%zx, prot=0x%x)\n",
 	       &iova, &phys, size, prot);
 out:
+	mutex_unlock(&ddev->state_lock);
 	return retval;
 
 invalid_format:
@@ -1849,23 +1793,11 @@
 		return -EINVAL;
 	}
 
-	if (!dev->archdata.mapping) {
-		pr_err("No mapping. Did you already attach?\n");
-		retval = -EINVAL;
-		goto out;
-	}
-	if (!dev->archdata.mapping->domain) {
-		pr_err("No domain. Did you already attach?\n");
-		retval = -EINVAL;
-		goto out;
-	}
-
 	memset(buf, 0, sizeof(buf));
 
 	if (copy_from_user(buf, ubuf, count)) {
 		pr_err("Couldn't copy from user\n");
-		retval = -EFAULT;
-		goto out;
+		return -EFAULT;
 	}
 
 	comma1 = strnchr(buf, count, ',');
@@ -1902,6 +1834,13 @@
 	else
 		goto invalid_format;
 
+	mutex_lock(&ddev->state_lock);
+	if (!ddev->domain) {
+		pr_err("No domain. Did you already attach?\n");
+		mutex_unlock(&ddev->state_lock);
+		return -EINVAL;
+	}
+
 	iova = dma_map_single_attrs(dev, v_addr, size,
 					DMA_TO_DEVICE, dma_attrs);
 
@@ -1917,6 +1856,7 @@
 	ddev->iova = iova;
 		pr_err("Saved iova=%pa for future PTE commands\n", &iova);
 out:
+	mutex_unlock(&ddev->state_lock);
 	return retval;
 
 invalid_format:
@@ -1932,21 +1872,11 @@
 	     size_t count, loff_t *offset)
 {
 	struct iommu_debug_device *ddev = file->private_data;
-	struct device *dev = ddev->dev;
 	char buf[100];
 	ssize_t retval;
 	size_t buflen;
 	dma_addr_t iova;
 
-	if (!dev->archdata.mapping) {
-		pr_err("No mapping. Did you already attach?\n");
-		return -EINVAL;
-	}
-	if (!dev->archdata.mapping->domain) {
-		pr_err("No domain. Did you already attach?\n");
-		return -EINVAL;
-	}
-
 	if (*offset)
 		return 0;
 
@@ -2016,16 +1946,25 @@
 	if (kstrtosize_t(comma1 + 1, 0, &size))
 		goto invalid_format;
 
+	mutex_lock(&ddev->state_lock);
+	if (!ddev->domain) {
+		pr_err("No domain. Did you already attach?\n");
+		mutex_unlock(&ddev->state_lock);
+		return -EINVAL;
+	}
+
 	unmapped = iommu_unmap(ddev->domain, iova, size);
 	if (unmapped != size) {
 		pr_err("iommu_unmap failed. Expected to unmap: 0x%zx, unmapped: 0x%zx",
 		       size, unmapped);
-		return -EIO;
+		retval = -EIO;
+		goto out;
 	}
 
 	retval = count;
 	pr_err("Unmapped %pa (len=0x%zx)\n", &iova, size);
 out:
+	mutex_unlock(&ddev->state_lock);
 	return retval;
 
 invalid_format:
@@ -2057,17 +1996,6 @@
 		return -EINVAL;
 	}
 
-	if (!dev->archdata.mapping) {
-		pr_err("No mapping. Did you already attach?\n");
-		retval = -EINVAL;
-		goto out;
-	}
-	if (!dev->archdata.mapping->domain) {
-		pr_err("No domain. Did you already attach?\n");
-		retval = -EINVAL;
-		goto out;
-	}
-
 	memset(buf, 0, sizeof(buf));
 
 	if (copy_from_user(buf, ubuf, count)) {
@@ -2106,11 +2034,18 @@
 	else
 		goto invalid_format;
 
+	mutex_lock(&ddev->state_lock);
+	if (!ddev->domain) {
+		pr_err("No domain. Did you already attach?\n");
+		mutex_unlock(&ddev->state_lock);
+		return -EINVAL;
+	}
 	dma_unmap_single_attrs(dev, iova, size, DMA_TO_DEVICE, dma_attrs);
 
 	retval = count;
 	pr_err("Unmapped %pa (len=0x%zx)\n", &iova, size);
 out:
+	mutex_unlock(&ddev->state_lock);
 	return retval;
 
 invalid_format:
@@ -2191,18 +2126,20 @@
 	struct iommu_debug_device *ddev = file->private_data;
 	unsigned long flags;
 
-	if (!ddev->domain) {
-		pr_err("No domain. Did you already attach?\n");
-		return -EINVAL;
-	}
-
 	if (kstrtoul_from_user(ubuf, count, 0, &flags)) {
 		pr_err("Invalid flags format\n");
 		return -EFAULT;
 	}
 
+	mutex_lock(&ddev->state_lock);
+	if (!ddev->domain) {
+		pr_err("No domain. Did you already attach?\n");
+		mutex_unlock(&ddev->state_lock);
+		return -EINVAL;
+	}
 	iommu_trigger_fault(ddev->domain, flags);
 
+	mutex_unlock(&ddev->state_lock);
 	return count;
 }
 
@@ -2236,6 +2173,7 @@
 		return -ENODEV;
 
 	mutex_init(&ddev->clk_lock);
+	mutex_init(&ddev->state_lock);
 	ddev->dev = dev;
 	dir = debugfs_create_dir(dev_name(dev), debugfs_tests_dir);
 	if (!dir) {
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 44097a3..81f93f2 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -756,6 +756,17 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called leds-nic78bx.
 
+config LEDS_QPNP_FLASH_V2
+        tristate "Support for QPNP V2 Flash LEDs"
+        depends on LEDS_CLASS && MFD_SPMI_PMIC
+	select LEDS_TRIGGERS
+        help
+          This driver supports the flash V2 LED functionality of Qualcomm
+          Technologies, Inc. QPNP PMICs.  This driver supports PMICs starting
+          from PMI8998, PM8150L and their derivatives.  It can configure the
+          flash LED target current for several independent channels.  It also
+          supports various over current and over temperature mitigation features.
+
 comment "LED Triggers"
 source "drivers/leds/trigger/Kconfig"
 
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 420b5d2..38b54a8 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -78,6 +78,7 @@
 obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
 obj-$(CONFIG_LEDS_SC27XX_BLTC)		+= leds-sc27xx-bltc.o
 obj-$(CONFIG_LEDS_LM3601X)		+= leds-lm3601x.o
+obj-$(CONFIG_LEDS_QPNP_FLASH_V2)        += leds-qpnp-flash-v2.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
new file mode 100644
index 0000000..eb73621f
--- /dev/null
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -0,0 +1,2670 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#define pr_fmt(fmt)	"flashv2: %s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
+#include <linux/leds-qpnp-flash.h>
+#include <linux/leds-qpnp-flash-v2.h>
+#include <linux/qpnp/qpnp-revid.h>
+#include <linux/log2.h>
+#include "leds.h"
+
+#define	FLASH_LED_REG_LED_STATUS1(base)		(base + 0x08)
+#define	FLASH_LED_REG_LED_STATUS2(base)		(base + 0x09)
+#define	FLASH_LED_REG_INT_RT_STS(base)		(base + 0x10)
+#define	FLASH_LED_REG_SAFETY_TMR(base)		(base + 0x40)
+#define	FLASH_LED_REG_TGR_CURRENT(base)		(base + 0x43)
+#define	FLASH_LED_REG_MOD_CTRL(base)		(base + 0x46)
+#define	FLASH_LED_REG_IRES(base)		(base + 0x47)
+#define	FLASH_LED_REG_STROBE_CFG(base)		(base + 0x48)
+#define	FLASH_LED_REG_STROBE_CTRL(base)		(base + 0x49)
+#define	FLASH_LED_EN_LED_CTRL(base)		(base + 0x4C)
+#define	FLASH_LED_REG_HDRM_PRGM(base)		(base + 0x4D)
+#define	FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(base)	(base + 0x50)
+#define	FLASH_LED_REG_WARMUP_DELAY(base)	(base + 0x51)
+#define	FLASH_LED_REG_ISC_DELAY(base)		(base + 0x52)
+#define	FLASH_LED_REG_THERMAL_RMP_DN_RATE(base)	(base + 0x55)
+#define	FLASH_LED_REG_THERMAL_THRSH1(base)	(base + 0x56)
+#define	FLASH_LED_REG_THERMAL_THRSH2(base)	(base + 0x57)
+#define	FLASH_LED_REG_THERMAL_THRSH3(base)	(base + 0x58)
+#define	FLASH_LED_REG_THERMAL_HYSTERESIS(base)	(base + 0x59)
+#define	FLASH_LED_REG_THERMAL_DEBOUNCE(base)	(base + 0x5A)
+#define	FLASH_LED_REG_VPH_DROOP_THRESHOLD(base)	(base + 0x61)
+#define	FLASH_LED_REG_VPH_DROOP_DEBOUNCE(base)	(base + 0x62)
+#define	FLASH_LED_REG_ILED_GRT_THRSH(base)	(base + 0x67)
+#define	FLASH_LED_REG_LED1N2_ICLAMP_LOW(base)	(base + 0x68)
+#define	FLASH_LED_REG_LED1N2_ICLAMP_MID(base)	(base + 0x69)
+#define	FLASH_LED_REG_LED3_ICLAMP_LOW(base)	(base + 0x6A)
+#define	FLASH_LED_REG_LED3_ICLAMP_MID(base)	(base + 0x6B)
+#define	FLASH_LED_REG_MITIGATION_SEL(base)	(base + 0x6E)
+#define	FLASH_LED_REG_MITIGATION_SW(base)	(base + 0x6F)
+#define	FLASH_LED_REG_LMH_LEVEL(base)		(base + 0x70)
+#define	FLASH_LED_REG_MULTI_STROBE_CTRL(base)	(base + 0x71)
+#define	FLASH_LED_REG_LPG_INPUT_CTRL(base)	(base + 0x72)
+#define	FLASH_LED_REG_CURRENT_DERATE_EN(base)	(base + 0x76)
+
+#define	FLASH_LED_HDRM_VOL_MASK			GENMASK(7, 4)
+#define	FLASH_LED_CURRENT_MASK			GENMASK(6, 0)
+#define	FLASH_LED_STROBE_MASK			GENMASK(1, 0)
+#define	FLASH_HW_STROBE_MASK			GENMASK(2, 0)
+#define	FLASH_LED_ISC_WARMUP_DELAY_MASK		GENMASK(1, 0)
+#define	FLASH_LED_CURRENT_DERATE_EN_MASK	GENMASK(2, 0)
+#define	FLASH_LED_VPH_DROOP_DEBOUNCE_MASK	GENMASK(1, 0)
+#define	FLASH_LED_CHGR_MITIGATION_SEL_MASK	GENMASK(5, 4)
+#define	FLASH_LED_LMH_MITIGATION_SEL_MASK	GENMASK(1, 0)
+#define	FLASH_LED_ILED_GRT_THRSH_MASK		GENMASK(5, 0)
+#define	FLASH_LED_LMH_LEVEL_MASK		GENMASK(1, 0)
+#define	FLASH_LED_VPH_DROOP_HYSTERESIS_MASK	GENMASK(5, 4)
+#define	FLASH_LED_VPH_DROOP_THRESHOLD_MASK	GENMASK(2, 0)
+#define	FLASH_LED_THERMAL_HYSTERESIS_MASK	GENMASK(1, 0)
+#define	FLASH_LED_THERMAL_DEBOUNCE_MASK		GENMASK(1, 0)
+#define	FLASH_LED_THERMAL_THRSH_MASK		GENMASK(2, 0)
+#define	FLASH_LED_MOD_CTRL_MASK			BIT(7)
+#define	FLASH_LED_HW_SW_STROBE_SEL_BIT		BIT(2)
+#define	FLASH_LED_VPH_DROOP_FAULT_MASK		BIT(4)
+#define	FLASH_LED_LMH_MITIGATION_EN_MASK	BIT(0)
+#define	FLASH_LED_CHGR_MITIGATION_EN_MASK	BIT(4)
+#define	THERMAL_OTST1_RAMP_CTRL_MASK		BIT(7)
+#define	THERMAL_OTST1_RAMP_CTRL_SHIFT		7
+#define	THERMAL_DERATE_SLOW_SHIFT		4
+#define	THERMAL_DERATE_SLOW_MASK		GENMASK(6, 4)
+#define	THERMAL_DERATE_FAST_MASK		GENMASK(2, 0)
+#define	LED1N2_FLASH_ONCE_ONLY_BIT		BIT(0)
+#define	LED3_FLASH_ONCE_ONLY_BIT		BIT(1)
+#define	LPG_INPUT_SEL_BIT			BIT(0)
+
+#define	VPH_DROOP_DEBOUNCE_US_TO_VAL(val_us)	(val_us / 8)
+#define	VPH_DROOP_HYST_MV_TO_VAL(val_mv)	(val_mv / 25)
+#define	VPH_DROOP_THRESH_VAL_TO_UV(val)		((val + 25) * 100000)
+#define	MITIGATION_THRSH_MA_TO_VAL(val_ma)	(val_ma / 100)
+#define	THERMAL_HYST_TEMP_TO_VAL(val, divisor)	(val / divisor)
+
+#define	FLASH_LED_ISC_WARMUP_DELAY_SHIFT	6
+#define	FLASH_LED_WARMUP_DELAY_DEFAULT		2
+#define	FLASH_LED_ISC_DELAY_DEFAULT		3
+#define	FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT	2
+#define	FLASH_LED_VPH_DROOP_HYST_SHIFT		4
+#define	FLASH_LED_VPH_DROOP_HYST_DEFAULT	2
+#define	FLASH_LED_VPH_DROOP_THRESH_DEFAULT	5
+#define	FLASH_LED_DEBOUNCE_MAX			3
+#define	FLASH_LED_HYSTERESIS_MAX		3
+#define	FLASH_LED_VPH_DROOP_THRESH_MAX		7
+#define	THERMAL_DERATE_SLOW_MAX			314592
+#define	THERMAL_DERATE_FAST_MAX			512
+#define	THERMAL_DEBOUNCE_TIME_MAX		64
+#define	THERMAL_DERATE_HYSTERESIS_MAX		3
+#define	FLASH_LED_THERMAL_THRSH_MIN		3
+#define	FLASH_LED_THERMAL_THRSH_MAX		7
+#define	FLASH_LED_THERMAL_OTST_LEVELS		3
+#define	FLASH_LED_VLED_MAX_DEFAULT_UV		3500000
+#define	FLASH_LED_IBATT_OCP_THRESH_DEFAULT_UA	4500000
+#define	FLASH_LED_RPARA_DEFAULT_UOHM		0
+#define	FLASH_LED_SAFETY_TMR_ENABLE		BIT(7)
+#define	FLASH_LED_LMH_LEVEL_DEFAULT		0
+#define	FLASH_LED_LMH_MITIGATION_ENABLE		1
+#define	FLASH_LED_LMH_MITIGATION_DISABLE	0
+#define	FLASH_LED_CHGR_MITIGATION_ENABLE	BIT(4)
+#define	FLASH_LED_CHGR_MITIGATION_DISABLE	0
+#define	FLASH_LED_LMH_MITIGATION_SEL_DEFAULT	2
+#define	FLASH_LED_MITIGATION_SEL_MAX		2
+#define	FLASH_LED_CHGR_MITIGATION_SEL_SHIFT	4
+#define	FLASH_LED_CHGR_MITIGATION_THRSH_DEFAULT	0xA
+#define	FLASH_LED_CHGR_MITIGATION_THRSH_MAX	0x1F
+#define	FLASH_LED_LMH_OCV_THRESH_DEFAULT_UV	3700000
+#define	FLASH_LED_LMH_RBATT_THRESH_DEFAULT_UOHM	400000
+#define	FLASH_LED_IRES_BASE			3
+#define	FLASH_LED_IRES_DIVISOR			2500
+#define	FLASH_LED_IRES_MIN_UA			5000
+#define	FLASH_LED_IRES_DEFAULT_UA		12500
+#define	FLASH_LED_IRES_DEFAULT_VAL		0x00
+#define	FLASH_LED_HDRM_VOL_SHIFT		4
+#define	FLASH_LED_HDRM_VOL_DEFAULT_MV		0x80
+#define	FLASH_LED_HDRM_VOL_HI_LO_WIN_DEFAULT_MV	0x04
+#define	FLASH_LED_HDRM_VOL_BASE_MV		125
+#define	FLASH_LED_HDRM_VOL_STEP_MV		25
+#define	FLASH_LED_STROBE_CFG_DEFAULT		0x00
+#define	FLASH_LED_HW_STROBE_OPTION_1		0x00
+#define	FLASH_LED_HW_STROBE_OPTION_2		0x01
+#define	FLASH_LED_HW_STROBE_OPTION_3		0x02
+#define	FLASH_LED_ENABLE			BIT(0)
+#define	FLASH_LED_MOD_ENABLE			BIT(7)
+#define	FLASH_LED_DISABLE			0x00
+#define	FLASH_LED_SAFETY_TMR_DISABLED		0x13
+#define	FLASH_LED_MAX_TOTAL_CURRENT_MA		3750
+#define	FLASH_LED_IRES5P0_MAX_CURR_MA		640
+#define	FLASH_LED_IRES7P5_MAX_CURR_MA		960
+#define	FLASH_LED_IRES10P0_MAX_CURR_MA		1280
+#define	FLASH_LED_IRES12P5_MAX_CURR_MA		1600
+#define	MAX_IRES_LEVELS				4
+
+/* notifier call chain for flash-led irqs */
+static ATOMIC_NOTIFIER_HEAD(irq_notifier_list);
+
+enum flash_charger_mitigation {
+	FLASH_DISABLE_CHARGER_MITIGATION,
+	FLASH_HW_CHARGER_MITIGATION_BY_ILED_THRSHLD,
+	FLASH_SW_CHARGER_MITIGATION,
+};
+
+enum flash_led_type {
+	FLASH_LED_TYPE_UNKNOWN,
+	FLASH_LED_TYPE_FLASH,
+	FLASH_LED_TYPE_TORCH,
+};
+
+enum {
+	LED1 = 0,
+	LED2,
+	LED3,
+};
+
+enum strobe_type {
+	SW_STROBE = 0,
+	HW_STROBE,
+	LPG_STROBE,
+};
+
+/*
+ * Configurations for each individual LED
+ */
+struct flash_node_data {
+	struct platform_device		*pdev;
+	struct led_classdev		cdev;
+	struct pinctrl			*strobe_pinctrl;
+	struct pinctrl_state		*hw_strobe_state_active;
+	struct pinctrl_state		*hw_strobe_state_suspend;
+	int				hw_strobe_gpio;
+	int				ires_ua;
+	int				default_ires_ua;
+	int				max_current;
+	int				current_ma;
+	int				prev_current_ma;
+	u8				duration;
+	u8				id;
+	u8				ires_idx;
+	u8				default_ires_idx;
+	u8				hdrm_val;
+	u8				current_reg_val;
+	u8				strobe_ctrl;
+	u8				strobe_sel;
+	enum flash_led_type		type;
+	bool				led_on;
+};
+
+
+struct flash_switch_data {
+	struct platform_device		*pdev;
+	struct regulator		*vreg;
+	struct pinctrl			*led_en_pinctrl;
+	struct pinctrl_state		*gpio_state_active;
+	struct pinctrl_state		*gpio_state_suspend;
+	struct led_classdev		cdev;
+	int				led_mask;
+	bool				regulator_on;
+	bool				enabled;
+	bool				symmetry_en;
+};
+
+/*
+ * Flash LED configuration read from device tree
+ */
+struct flash_led_platform_data {
+	struct pmic_revid_data	*pmic_rev_id;
+	int			*thermal_derate_current;
+	int			all_ramp_up_done_irq;
+	int			all_ramp_down_done_irq;
+	int			led_fault_irq;
+	int			ibatt_ocp_threshold_ua;
+	int			vled_max_uv;
+	int			rpara_uohm;
+	int			lmh_rbatt_threshold_uohm;
+	int			lmh_ocv_threshold_uv;
+	int			thermal_derate_slow;
+	int			thermal_derate_fast;
+	int			thermal_hysteresis;
+	int			thermal_debounce;
+	int			thermal_thrsh1;
+	int			thermal_thrsh2;
+	int			thermal_thrsh3;
+	int			hw_strobe_option;
+	u32			led1n2_iclamp_low_ma;
+	u32			led1n2_iclamp_mid_ma;
+	u32			led3_iclamp_low_ma;
+	u32			led3_iclamp_mid_ma;
+	u8			isc_delay;
+	u8			warmup_delay;
+	u8			current_derate_en_cfg;
+	u8			vph_droop_threshold;
+	u8			vph_droop_hysteresis;
+	u8			vph_droop_debounce;
+	u8			lmh_mitigation_sel;
+	u8			chgr_mitigation_sel;
+	u8			lmh_level;
+	u8			iled_thrsh_val;
+	bool			hdrm_auto_mode_en;
+	bool			thermal_derate_en;
+	bool			otst_ramp_bkup_en;
+};
+
+/*
+ * Flash LED data structure containing flash LED attributes
+ */
+struct qpnp_flash_led {
+	struct flash_led_platform_data	*pdata;
+	struct platform_device		*pdev;
+	struct regmap			*regmap;
+	struct flash_node_data		*fnode;
+	struct flash_switch_data	*snode;
+	struct power_supply		*bms_psy;
+	struct notifier_block		nb;
+	spinlock_t			lock;
+	int				num_fnodes;
+	int				num_snodes;
+	int				enable;
+	int				total_current_ma;
+	u16				base;
+	bool				trigger_lmh;
+	bool				trigger_chgr;
+};
+
+static int thermal_derate_slow_table[] = {
+	128, 256, 512, 1024, 2048, 4096, 8192, 314592,
+};
+
+static int thermal_derate_fast_table[] = {
+	32, 64, 96, 128, 256, 384, 512,
+};
+
+static int otst1_threshold_table[] = {
+	85, 79, 73, 67, 109, 103, 97, 91,
+};
+
+static int otst2_threshold_table[] = {
+	110, 104, 98, 92, 134, 128, 122, 116,
+};
+
+static int otst3_threshold_table[] = {
+	125, 119, 113, 107, 149, 143, 137, 131,
+};
+
+static int max_ires_curr_ma_table[MAX_IRES_LEVELS] = {
+	FLASH_LED_IRES12P5_MAX_CURR_MA, FLASH_LED_IRES10P0_MAX_CURR_MA,
+	FLASH_LED_IRES7P5_MAX_CURR_MA, FLASH_LED_IRES5P0_MAX_CURR_MA
+};
+
+static inline int get_current_reg_code(int target_curr_ma, int ires_ua)
+{
+	if (!ires_ua || !target_curr_ma || (target_curr_ma < (ires_ua / 1000)))
+		return 0;
+
+	return DIV_ROUND_CLOSEST(target_curr_ma * 1000, ires_ua) - 1;
+}
+
+static int qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data)
+{
+	int rc;
+	uint val;
+
+	rc = regmap_read(led->regmap, addr, &val);
+	if (rc < 0) {
+		pr_err("Unable to read from 0x%04X rc = %d\n", addr, rc);
+		return rc;
+	}
+
+	pr_debug("Read 0x%02X from addr 0x%04X\n", val, addr);
+	*data = (u8)val;
+	return 0;
+}
+
+static int qpnp_flash_led_write(struct qpnp_flash_led *led, u16 addr, u8 data)
+{
+	int rc;
+
+	rc = regmap_write(led->regmap, addr, data);
+	if (rc < 0) {
+		pr_err("Unable to write to 0x%04X rc = %d\n", addr, rc);
+		return rc;
+	}
+
+	pr_debug("Wrote 0x%02X to addr 0x%04X\n", data, addr);
+	return 0;
+}
+
+static int
+qpnp_flash_led_masked_read(struct qpnp_flash_led *led, u16 addr, u8 mask,
+								u8 *val)
+{
+	int rc;
+
+	rc = qpnp_flash_led_read(led, addr, val);
+	if (rc < 0)
+		return rc;
+
+	*val &= mask;
+	return rc;
+}
+
+static int
+qpnp_flash_led_masked_write(struct qpnp_flash_led *led, u16 addr, u8 mask,
+								u8 val)
+{
+	int rc;
+
+	rc = regmap_update_bits(led->regmap, addr, mask, val);
+	if (rc < 0)
+		pr_err("Unable to update bits from 0x%04X, rc = %d\n", addr,
+			rc);
+	else
+		pr_debug("Wrote 0x%02X to addr 0x%04X\n", val, addr);
+
+	return rc;
+}
+
+static enum
+led_brightness qpnp_flash_led_brightness_get(struct led_classdev *led_cdev)
+{
+	return led_cdev->brightness;
+}
+
+static int qpnp_flash_led_headroom_config(struct qpnp_flash_led *led)
+{
+	int rc, i, addr_offset;
+
+	for (i = 0; i < led->num_fnodes; i++) {
+		addr_offset = led->fnode[i].id;
+		rc = qpnp_flash_led_write(led,
+			FLASH_LED_REG_HDRM_PRGM(led->base + addr_offset),
+			led->fnode[i].hdrm_val);
+		if (rc < 0)
+			return rc;
+	}
+
+	return rc;
+}
+
+static int qpnp_flash_led_strobe_config(struct qpnp_flash_led *led)
+{
+	int i, rc, addr_offset;
+	u8 val = 0, mask, strobe_mask = 0, strobe_ctrl;
+
+	for (i = 0; i < led->num_fnodes; i++) {
+		val |= 0x1 << led->fnode[i].id;
+
+		if (led->fnode[i].strobe_sel == HW_STROBE) {
+			if (led->fnode[i].id == LED3)
+				strobe_mask |= LED3_FLASH_ONCE_ONLY_BIT;
+			else
+				strobe_mask |= LED1N2_FLASH_ONCE_ONLY_BIT;
+		}
+
+		if (led->fnode[i].id == LED3 &&
+				led->fnode[i].strobe_sel == LPG_STROBE)
+			strobe_mask |= LED3_FLASH_ONCE_ONLY_BIT;
+		/*
+		 * As per the hardware recommendation, to use LED2/LED3 in HW
+		 * strobe mode, LED1 should be set to HW strobe mode as well.
+		 */
+		if (led->fnode[i].strobe_sel == HW_STROBE &&
+		      (led->fnode[i].id == LED2 || led->fnode[i].id == LED3)) {
+			mask = FLASH_HW_STROBE_MASK;
+			addr_offset = led->fnode[LED1].id;
+			/*
+			 * HW_STROBE: enable, TRIGGER: level,
+			 * POLARITY: active high
+			 */
+			strobe_ctrl = BIT(2) | BIT(0);
+			rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_STROBE_CTRL(
+				led->base + addr_offset),
+				mask, strobe_ctrl);
+			if (rc < 0)
+				return rc;
+		}
+	}
+
+	rc = qpnp_flash_led_masked_write(led,
+		FLASH_LED_REG_MULTI_STROBE_CTRL(led->base),
+		strobe_mask, 0);
+	if (rc < 0)
+		return rc;
+
+	if (led->fnode[LED3].strobe_sel == LPG_STROBE) {
+		rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_LPG_INPUT_CTRL(led->base),
+			LPG_INPUT_SEL_BIT, LPG_INPUT_SEL_BIT);
+		if (rc < 0)
+			return rc;
+	}
+
+	return rc;
+}
+
+static qpnp_flash_led_thermal_config(struct qpnp_flash_led *led)
+{
+	int rc;
+	u8 val, mask;
+
+	val = (led->pdata->otst_ramp_bkup_en << THERMAL_OTST1_RAMP_CTRL_SHIFT);
+	mask = THERMAL_OTST1_RAMP_CTRL_MASK;
+	if (led->pdata->thermal_derate_slow >= 0) {
+		val |= (led->pdata->thermal_derate_slow <<
+				THERMAL_DERATE_SLOW_SHIFT);
+		mask |= THERMAL_DERATE_SLOW_MASK;
+	}
+
+	if (led->pdata->thermal_derate_fast >= 0) {
+		val |= led->pdata->thermal_derate_fast;
+		mask |= THERMAL_DERATE_FAST_MASK;
+	}
+
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_THERMAL_RMP_DN_RATE(led->base),
+			mask, val);
+	if (rc < 0)
+		return rc;
+
+	if (led->pdata->thermal_debounce >= 0) {
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_THERMAL_DEBOUNCE(led->base),
+				FLASH_LED_THERMAL_DEBOUNCE_MASK,
+				led->pdata->thermal_debounce);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (led->pdata->thermal_hysteresis >= 0) {
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_THERMAL_HYSTERESIS(led->base),
+				FLASH_LED_THERMAL_HYSTERESIS_MASK,
+				led->pdata->thermal_hysteresis);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (led->pdata->thermal_thrsh1 >= 0) {
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_THERMAL_THRSH1(led->base),
+				FLASH_LED_THERMAL_THRSH_MASK,
+				led->pdata->thermal_thrsh1);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (led->pdata->thermal_thrsh2 >= 0) {
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_THERMAL_THRSH2(led->base),
+				FLASH_LED_THERMAL_THRSH_MASK,
+				led->pdata->thermal_thrsh2);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (led->pdata->thermal_thrsh3 >= 0) {
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_THERMAL_THRSH3(led->base),
+				FLASH_LED_THERMAL_THRSH_MASK,
+				led->pdata->thermal_thrsh3);
+		if (rc < 0)
+			return rc;
+	}
+
+	return rc;
+}
+
+static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
+{
+	int rc;
+	u8 val = 0;
+
+	rc = qpnp_flash_led_headroom_config(led);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_strobe_config(led);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_write(led,
+				FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(led->base),
+				val);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_ISC_DELAY(led->base),
+			FLASH_LED_ISC_WARMUP_DELAY_MASK,
+			led->pdata->isc_delay);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_WARMUP_DELAY(led->base),
+			FLASH_LED_ISC_WARMUP_DELAY_MASK,
+			led->pdata->warmup_delay);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_CURRENT_DERATE_EN(led->base),
+			FLASH_LED_CURRENT_DERATE_EN_MASK,
+			led->pdata->current_derate_en_cfg);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_thermal_config(led);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_VPH_DROOP_DEBOUNCE(led->base),
+			FLASH_LED_VPH_DROOP_DEBOUNCE_MASK,
+			led->pdata->vph_droop_debounce);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_VPH_DROOP_THRESHOLD(led->base),
+			FLASH_LED_VPH_DROOP_THRESHOLD_MASK,
+			led->pdata->vph_droop_threshold);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_VPH_DROOP_THRESHOLD(led->base),
+			FLASH_LED_VPH_DROOP_HYSTERESIS_MASK,
+			led->pdata->vph_droop_hysteresis);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_MITIGATION_SEL(led->base),
+			FLASH_LED_LMH_MITIGATION_SEL_MASK,
+			led->pdata->lmh_mitigation_sel);
+	if (rc < 0)
+		return rc;
+
+	val = led->pdata->chgr_mitigation_sel
+				<< FLASH_LED_CHGR_MITIGATION_SEL_SHIFT;
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_MITIGATION_SEL(led->base),
+			FLASH_LED_CHGR_MITIGATION_SEL_MASK,
+			val);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_LMH_LEVEL(led->base),
+			FLASH_LED_LMH_LEVEL_MASK,
+			led->pdata->lmh_level);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_ILED_GRT_THRSH(led->base),
+			FLASH_LED_ILED_GRT_THRSH_MASK,
+			led->pdata->iled_thrsh_val);
+	if (rc < 0)
+		return rc;
+
+	if (led->pdata->led1n2_iclamp_low_ma) {
+		val = get_current_reg_code(led->pdata->led1n2_iclamp_low_ma,
+						led->fnode[LED1].ires_ua);
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_LED1N2_ICLAMP_LOW(led->base),
+				FLASH_LED_CURRENT_MASK, val);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (led->pdata->led1n2_iclamp_mid_ma) {
+		val = get_current_reg_code(led->pdata->led1n2_iclamp_mid_ma,
+						led->fnode[LED1].ires_ua);
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_LED1N2_ICLAMP_MID(led->base),
+				FLASH_LED_CURRENT_MASK, val);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (led->pdata->led3_iclamp_low_ma) {
+		val = get_current_reg_code(led->pdata->led3_iclamp_low_ma,
+						led->fnode[LED3].ires_ua);
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_LED3_ICLAMP_LOW(led->base),
+				FLASH_LED_CURRENT_MASK, val);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (led->pdata->led3_iclamp_mid_ma) {
+		val = get_current_reg_code(led->pdata->led3_iclamp_mid_ma,
+						led->fnode[LED3].ires_ua);
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_LED3_ICLAMP_MID(led->base),
+				FLASH_LED_CURRENT_MASK, val);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (led->pdata->hw_strobe_option > 0) {
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_STROBE_CFG(led->base),
+				FLASH_LED_STROBE_MASK,
+				led->pdata->hw_strobe_option);
+		if (rc < 0)
+			return rc;
+	}
+
+	return 0;
+}
+
+static int qpnp_flash_led_hw_strobe_enable(struct flash_node_data *fnode,
+						int hw_strobe_option, bool on)
+{
+	int rc = 0;
+
+	/*
+	 * If the LED controlled by this fnode is not GPIO controlled
+	 * for the given strobe_option, return.
+	 */
+	if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_1)
+		return 0;
+	else if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_2
+						&& fnode->id != LED3)
+		return 0;
+	else if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_3
+						&& fnode->id == LED1)
+		return 0;
+
+	if (gpio_is_valid(fnode->hw_strobe_gpio)) {
+		gpio_set_value(fnode->hw_strobe_gpio, on ? 1 : 0);
+	} else if (fnode->strobe_pinctrl && fnode->hw_strobe_state_active &&
+					fnode->hw_strobe_state_suspend) {
+		rc = pinctrl_select_state(fnode->strobe_pinctrl,
+			on ? fnode->hw_strobe_state_active :
+			fnode->hw_strobe_state_suspend);
+		if (rc < 0) {
+			pr_err("failed to change hw strobe pin state\n");
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static int qpnp_flash_led_regulator_enable(struct qpnp_flash_led *led,
+				struct flash_switch_data *snode, bool on)
+{
+	int rc = 0;
+
+	if (!snode || !snode->vreg)
+		return 0;
+
+	if (snode->regulator_on == on)
+		return 0;
+
+	if (on)
+		rc = regulator_enable(snode->vreg);
+	else
+		rc = regulator_disable(snode->vreg);
+
+	if (rc < 0) {
+		pr_err("regulator_%s failed, rc=%d\n",
+			on ? "enable" : "disable", rc);
+		return rc;
+	}
+
+	snode->regulator_on = on ? true : false;
+	return 0;
+}
+
+static int get_property_from_fg(struct qpnp_flash_led *led,
+		enum power_supply_property prop, int *val)
+{
+	int rc;
+	union power_supply_propval pval = {0, };
+
+	if (!led->bms_psy) {
+		pr_err("no bms psy found\n");
+		return -EINVAL;
+	}
+
+	rc = power_supply_get_property(led->bms_psy, prop, &pval);
+	if (rc) {
+		pr_err("bms psy doesn't support reading prop %d rc = %d\n",
+			prop, rc);
+		return rc;
+	}
+
+	*val = pval.intval;
+	return rc;
+}
+
+#define VOLTAGE_HDRM_DEFAULT_MV	350
+static int qpnp_flash_led_get_voltage_headroom(struct qpnp_flash_led *led)
+{
+	int i, voltage_hdrm_mv = 0, voltage_hdrm_max = 0;
+
+	for (i = 0; i < led->num_fnodes; i++) {
+		if (led->fnode[i].led_on) {
+			if (led->fnode[i].id < 2) {
+				if (led->fnode[i].current_ma < 750)
+					voltage_hdrm_mv = 125;
+				else if (led->fnode[i].current_ma < 1000)
+					voltage_hdrm_mv = 175;
+				else if (led->fnode[i].current_ma < 1250)
+					voltage_hdrm_mv = 250;
+				else
+					voltage_hdrm_mv = 350;
+			} else {
+				if (led->fnode[i].current_ma < 375)
+					voltage_hdrm_mv = 125;
+				else if (led->fnode[i].current_ma < 500)
+					voltage_hdrm_mv = 175;
+				else if (led->fnode[i].current_ma < 625)
+					voltage_hdrm_mv = 250;
+				else
+					voltage_hdrm_mv = 350;
+			}
+
+			voltage_hdrm_max = max(voltage_hdrm_max,
+						voltage_hdrm_mv);
+		}
+	}
+
+	if (!voltage_hdrm_max)
+		return VOLTAGE_HDRM_DEFAULT_MV;
+
+	return voltage_hdrm_max;
+}
+
+#define UCONV			1000000LL
+#define MCONV			1000LL
+#define FLASH_VDIP_MARGIN	50000
+#define BOB_EFFICIENCY		900LL
+#define VIN_FLASH_MIN_UV	3300000LL
+static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led,
+					int *max_current)
+{
+	int ocv_uv, ibat_now, voltage_hdrm_mv, rc;
+	int rbatt_uohm = 0;
+	int64_t ibat_flash_ua, avail_flash_ua, avail_flash_power_fw;
+	int64_t ibat_safe_ua, vin_flash_uv, vph_flash_uv, vph_flash_vdip;
+
+	/* RESISTANCE = esr_uohm + rslow_uohm */
+	rc = get_property_from_fg(led, POWER_SUPPLY_PROP_RESISTANCE,
+			&rbatt_uohm);
+	if (rc < 0) {
+		pr_err("bms psy does not support resistance, rc=%d\n", rc);
+		return rc;
+	}
+
+	/* If no battery is connected, return max possible flash current */
+	if (!rbatt_uohm) {
+		*max_current = FLASH_LED_MAX_TOTAL_CURRENT_MA;
+		return 0;
+	}
+
+	rc = get_property_from_fg(led, POWER_SUPPLY_PROP_VOLTAGE_OCV, &ocv_uv);
+	if (rc < 0) {
+		pr_err("bms psy does not support OCV, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = get_property_from_fg(led, POWER_SUPPLY_PROP_CURRENT_NOW,
+			&ibat_now);
+	if (rc < 0) {
+		pr_err("bms psy does not support current, rc=%d\n", rc);
+		return rc;
+	}
+
+	rbatt_uohm += led->pdata->rpara_uohm;
+	voltage_hdrm_mv = qpnp_flash_led_get_voltage_headroom(led);
+	vph_flash_vdip =
+		VPH_DROOP_THRESH_VAL_TO_UV(led->pdata->vph_droop_threshold)
+							+ FLASH_VDIP_MARGIN;
+
+	/* Check if LMH_MITIGATION needs to be triggered */
+	if (!led->trigger_lmh && (ocv_uv < led->pdata->lmh_ocv_threshold_uv ||
+			rbatt_uohm > led->pdata->lmh_rbatt_threshold_uohm)) {
+		led->trigger_lmh = true;
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_MITIGATION_SW(led->base),
+				FLASH_LED_LMH_MITIGATION_EN_MASK,
+				FLASH_LED_LMH_MITIGATION_ENABLE);
+		if (rc < 0) {
+			pr_err("trigger lmh mitigation failed, rc=%d\n", rc);
+			return rc;
+		}
+
+		/* Wait for LMH mitigation to take effect */
+		udelay(100);
+
+		return qpnp_flash_led_calc_max_current(led, max_current);
+	}
+
+	/*
+	 * Calculate the maximum current that can pulled out of the battery
+	 * before the battery voltage dips below a safe threshold.
+	 */
+	ibat_safe_ua = div_s64((ocv_uv - vph_flash_vdip) * UCONV,
+				rbatt_uohm);
+
+	if (ibat_safe_ua <= led->pdata->ibatt_ocp_threshold_ua) {
+		/*
+		 * If the calculated current is below the OCP threshold, then
+		 * use it as the possible flash current.
+		 */
+		ibat_flash_ua = ibat_safe_ua - ibat_now;
+		vph_flash_uv = vph_flash_vdip;
+	} else {
+		/*
+		 * If the calculated current is above the OCP threshold, then
+		 * use the ocp threshold instead.
+		 *
+		 * Any higher current will be tripping the battery OCP.
+		 */
+		ibat_flash_ua = led->pdata->ibatt_ocp_threshold_ua - ibat_now;
+		vph_flash_uv = ocv_uv - div64_s64((int64_t)rbatt_uohm
+				* led->pdata->ibatt_ocp_threshold_ua, UCONV);
+	}
+	/* Calculate the input voltage of the flash module. */
+	vin_flash_uv = max((led->pdata->vled_max_uv +
+				(voltage_hdrm_mv * MCONV)), VIN_FLASH_MIN_UV);
+	/* Calculate the available power for the flash module. */
+	avail_flash_power_fw = BOB_EFFICIENCY * vph_flash_uv * ibat_flash_ua;
+	/*
+	 * Calculate the available amount of current the flash module can draw
+	 * before collapsing the battery. (available power/ flash input voltage)
+	 */
+	avail_flash_ua = div64_s64(avail_flash_power_fw, vin_flash_uv * MCONV);
+	pr_debug("avail_iflash=%lld, ocv=%d, ibat=%d, rbatt=%d, trigger_lmh=%d\n",
+		avail_flash_ua, ocv_uv, ibat_now, rbatt_uohm, led->trigger_lmh);
+	*max_current = min(FLASH_LED_MAX_TOTAL_CURRENT_MA,
+			(int)(div64_s64(avail_flash_ua, MCONV)));
+	return 0;
+}
+
+static int qpnp_flash_led_calc_thermal_current_lim(struct qpnp_flash_led *led,
+						int *thermal_current_lim)
+{
+	int rc;
+	u8 thermal_thrsh1, thermal_thrsh2, thermal_thrsh3, otst_status;
+
+	/* Store THERMAL_THRSHx register values */
+	rc = qpnp_flash_led_masked_read(led,
+			FLASH_LED_REG_THERMAL_THRSH1(led->base),
+			FLASH_LED_THERMAL_THRSH_MASK,
+			&thermal_thrsh1);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_masked_read(led,
+			FLASH_LED_REG_THERMAL_THRSH2(led->base),
+			FLASH_LED_THERMAL_THRSH_MASK,
+			&thermal_thrsh2);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_masked_read(led,
+			FLASH_LED_REG_THERMAL_THRSH3(led->base),
+			FLASH_LED_THERMAL_THRSH_MASK,
+			&thermal_thrsh3);
+	if (rc < 0)
+		return rc;
+
+	/* Lower THERMAL_THRSHx thresholds to minimum */
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_THERMAL_THRSH1(led->base),
+			FLASH_LED_THERMAL_THRSH_MASK,
+			FLASH_LED_THERMAL_THRSH_MIN);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_THERMAL_THRSH2(led->base),
+			FLASH_LED_THERMAL_THRSH_MASK,
+			FLASH_LED_THERMAL_THRSH_MIN);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_THERMAL_THRSH3(led->base),
+			FLASH_LED_THERMAL_THRSH_MASK,
+			FLASH_LED_THERMAL_THRSH_MIN);
+	if (rc < 0)
+		return rc;
+
+	/* Check THERMAL_OTST status */
+	rc = qpnp_flash_led_read(led,
+			FLASH_LED_REG_LED_STATUS2(led->base),
+			&otst_status);
+	if (rc < 0)
+		return rc;
+
+	/* Look up current limit based on THERMAL_OTST status */
+	if (otst_status)
+		*thermal_current_lim =
+			led->pdata->thermal_derate_current[otst_status >> 1];
+
+	/* Restore THERMAL_THRESHx registers to original values */
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_THERMAL_THRSH1(led->base),
+			FLASH_LED_THERMAL_THRSH_MASK,
+			thermal_thrsh1);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_THERMAL_THRSH2(led->base),
+			FLASH_LED_THERMAL_THRSH_MASK,
+			thermal_thrsh2);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_THERMAL_THRSH3(led->base),
+			FLASH_LED_THERMAL_THRSH_MASK,
+			thermal_thrsh3);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+static int qpnp_flash_led_get_max_avail_current(struct qpnp_flash_led *led,
+						int *max_avail_current)
+{
+	int thermal_current_lim = 0, rc;
+
+	led->trigger_lmh = false;
+	rc = qpnp_flash_led_calc_max_current(led, max_avail_current);
+	if (rc < 0) {
+		pr_err("Couldn't calculate max_avail_current, rc=%d\n", rc);
+		return rc;
+	}
+
+	if (led->pdata->thermal_derate_en) {
+		rc = qpnp_flash_led_calc_thermal_current_lim(led,
+			&thermal_current_lim);
+		if (rc < 0) {
+			pr_err("Couldn't calculate thermal_current_lim, rc=%d\n",
+				rc);
+			return rc;
+		}
+	}
+
+	if (thermal_current_lim)
+		*max_avail_current = min(*max_avail_current,
+					thermal_current_lim);
+
+	return 0;
+}
+
+static void qpnp_flash_led_aggregate_max_current(struct flash_node_data *fnode)
+{
+	struct qpnp_flash_led *led = dev_get_drvdata(&fnode->pdev->dev);
+
+	if (fnode->current_ma)
+		led->total_current_ma += fnode->current_ma
+						- fnode->prev_current_ma;
+	else
+		led->total_current_ma -= fnode->prev_current_ma;
+
+	fnode->prev_current_ma = fnode->current_ma;
+}
+
+static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value)
+{
+	int i = 0;
+	int prgm_current_ma = value;
+	int min_ma = fnode->ires_ua / 1000;
+	struct qpnp_flash_led *led = dev_get_drvdata(&fnode->pdev->dev);
+
+	if (value <= 0)
+		prgm_current_ma = 0;
+	else if (value < min_ma)
+		prgm_current_ma = min_ma;
+
+	fnode->ires_idx = fnode->default_ires_idx;
+	fnode->ires_ua = fnode->default_ires_ua;
+
+	prgm_current_ma = min(prgm_current_ma, fnode->max_current);
+	if (prgm_current_ma > max_ires_curr_ma_table[fnode->ires_idx]) {
+		/* find the matching ires */
+		for (i = MAX_IRES_LEVELS - 1; i >= 0; i--) {
+			if (prgm_current_ma <= max_ires_curr_ma_table[i]) {
+				fnode->ires_idx = i;
+				fnode->ires_ua = FLASH_LED_IRES_MIN_UA +
+				      (FLASH_LED_IRES_BASE - fnode->ires_idx) *
+				      FLASH_LED_IRES_DIVISOR;
+				break;
+			}
+		}
+	}
+	fnode->current_ma = prgm_current_ma;
+	fnode->cdev.brightness = prgm_current_ma;
+	fnode->current_reg_val = get_current_reg_code(prgm_current_ma,
+					fnode->ires_ua);
+	if (prgm_current_ma)
+		fnode->led_on = true;
+
+	if (led->pdata->chgr_mitigation_sel == FLASH_SW_CHARGER_MITIGATION) {
+		qpnp_flash_led_aggregate_max_current(fnode);
+		led->trigger_chgr = false;
+		if (led->total_current_ma >= 1000)
+			led->trigger_chgr = true;
+	}
+}
+
+static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode)
+{
+	struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
+	int i, rc, addr_offset;
+
+	rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_EN_LED_CTRL(led->base),
+				snode->led_mask, FLASH_LED_DISABLE);
+	if (rc < 0)
+		return rc;
+
+	if (led->trigger_lmh) {
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_MITIGATION_SW(led->base),
+				FLASH_LED_LMH_MITIGATION_EN_MASK,
+				FLASH_LED_LMH_MITIGATION_DISABLE);
+		if (rc < 0) {
+			pr_err("disable lmh mitigation failed, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	if (!led->trigger_chgr) {
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_MITIGATION_SW(led->base),
+				FLASH_LED_CHGR_MITIGATION_EN_MASK,
+				FLASH_LED_CHGR_MITIGATION_DISABLE);
+		if (rc < 0) {
+			pr_err("disable chgr mitigation failed, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	led->enable--;
+	if (led->enable == 0) {
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_MOD_CTRL(led->base),
+				FLASH_LED_MOD_CTRL_MASK, FLASH_LED_DISABLE);
+		if (rc < 0)
+			return rc;
+	}
+
+	for (i = 0; i < led->num_fnodes; i++) {
+		if (!led->fnode[i].led_on ||
+				!(snode->led_mask & BIT(led->fnode[i].id)))
+			continue;
+
+		addr_offset = led->fnode[i].id;
+		rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_TGR_CURRENT(led->base + addr_offset),
+			FLASH_LED_CURRENT_MASK, 0);
+		if (rc < 0)
+			return rc;
+
+		led->fnode[i].led_on = false;
+
+		if (led->fnode[i].strobe_sel == HW_STROBE) {
+			rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
+					led->pdata->hw_strobe_option, false);
+			if (rc < 0) {
+				pr_err("Unable to disable hw strobe, rc=%d\n",
+					rc);
+				return rc;
+			}
+		}
+	}
+
+	if (snode->led_en_pinctrl) {
+		pr_debug("Selecting suspend state for %s\n", snode->cdev.name);
+		rc = pinctrl_select_state(snode->led_en_pinctrl,
+				snode->gpio_state_suspend);
+		if (rc < 0) {
+			pr_err("failed to select pinctrl suspend state rc=%d\n",
+				rc);
+			return rc;
+		}
+	}
+
+	snode->enabled = false;
+	return 0;
+}
+
+static int qpnp_flash_led_symmetry_config(struct flash_switch_data *snode)
+{
+	struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
+	int i, total_curr_ma = 0, num_leds = 0, prgm_current_ma;
+	enum flash_led_type type = FLASH_LED_TYPE_UNKNOWN;
+
+	for (i = 0; i < led->num_fnodes; i++) {
+		if (snode->led_mask & BIT(led->fnode[i].id)) {
+			if (led->fnode[i].type == FLASH_LED_TYPE_FLASH &&
+				led->fnode[i].led_on)
+				type = FLASH_LED_TYPE_FLASH;
+
+			if (led->fnode[i].type == FLASH_LED_TYPE_TORCH &&
+				led->fnode[i].led_on)
+				type = FLASH_LED_TYPE_TORCH;
+		}
+	}
+
+	if (type == FLASH_LED_TYPE_UNKNOWN) {
+		pr_err("Incorrect type possibly because of no active LEDs\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < led->num_fnodes; i++) {
+		if ((snode->led_mask & BIT(led->fnode[i].id)) &&
+			(led->fnode[i].type == type)) {
+			total_curr_ma += led->fnode[i].current_ma;
+			num_leds++;
+		}
+	}
+
+	if (num_leds > 0 && total_curr_ma > 0) {
+		prgm_current_ma = total_curr_ma / num_leds;
+	} else {
+		pr_err("Incorrect configuration, num_leds: %d total_curr_ma: %d\n",
+			num_leds, total_curr_ma);
+		return -EINVAL;
+	}
+
+	if (prgm_current_ma == 0) {
+		pr_warn("prgm_curr_ma cannot be 0\n");
+		return 0;
+	}
+
+	pr_debug("num_leds: %d total: %d prgm_curr_ma: %d\n", num_leds,
+		total_curr_ma, prgm_current_ma);
+
+	for (i = 0; i < led->num_fnodes; i++) {
+		if (snode->led_mask & BIT(led->fnode[i].id) &&
+			led->fnode[i].current_ma != prgm_current_ma &&
+			led->fnode[i].type == type) {
+			qpnp_flash_led_node_set(&led->fnode[i],
+				prgm_current_ma);
+			pr_debug("%s LED %d current: %d code: %d ires_ua: %d\n",
+				(type == FLASH_LED_TYPE_FLASH) ?
+					"flash" : "torch",
+				led->fnode[i].id, prgm_current_ma,
+				led->fnode[i].current_reg_val,
+				led->fnode[i].ires_ua);
+		}
+	}
+
+	return 0;
+}
+
+static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
+{
+	struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
+	int rc, i, addr_offset;
+	u8 val, mask;
+
+	if (snode->enabled == on) {
+		pr_debug("Switch node is already %s!\n",
+			on ? "enabled" : "disabled");
+		return 0;
+	}
+
+	if (!on) {
+		rc = qpnp_flash_led_switch_disable(snode);
+		return rc;
+	}
+
+	/* Iterate over all active leds for this switch node */
+	if (snode->symmetry_en) {
+		rc = qpnp_flash_led_symmetry_config(snode);
+		if (rc < 0) {
+			pr_err("Failed to configure current symmetrically, rc=%d\n",
+				rc);
+			return rc;
+		}
+	}
+
+	val = 0;
+	for (i = 0; i < led->num_fnodes; i++)
+		if (led->fnode[i].led_on &&
+				snode->led_mask & BIT(led->fnode[i].id))
+			val |= led->fnode[i].ires_idx << (led->fnode[i].id * 2);
+
+	rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_IRES(led->base),
+						FLASH_LED_CURRENT_MASK, val);
+	if (rc < 0)
+		return rc;
+
+	val = 0;
+	for (i = 0; i < led->num_fnodes; i++) {
+		if (!led->fnode[i].led_on ||
+				!(snode->led_mask & BIT(led->fnode[i].id)))
+			continue;
+
+		addr_offset = led->fnode[i].id;
+		if (led->fnode[i].strobe_sel == SW_STROBE)
+			mask = FLASH_LED_HW_SW_STROBE_SEL_BIT;
+		else
+			mask = FLASH_HW_STROBE_MASK;
+		rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_STROBE_CTRL(led->base + addr_offset),
+			mask, led->fnode[i].strobe_ctrl);
+		if (rc < 0)
+			return rc;
+
+		rc = qpnp_flash_led_masked_write(led,
+			FLASH_LED_REG_TGR_CURRENT(led->base + addr_offset),
+			FLASH_LED_CURRENT_MASK, led->fnode[i].current_reg_val);
+		if (rc < 0)
+			return rc;
+
+		rc = qpnp_flash_led_write(led,
+			FLASH_LED_REG_SAFETY_TMR(led->base + addr_offset),
+			led->fnode[i].duration);
+		if (rc < 0)
+			return rc;
+
+		val |= FLASH_LED_ENABLE << led->fnode[i].id;
+
+		if (led->fnode[i].strobe_sel == HW_STROBE) {
+			rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
+					led->pdata->hw_strobe_option, true);
+			if (rc < 0) {
+				pr_err("Unable to enable hw strobe rc=%d\n",
+					rc);
+				return rc;
+			}
+		}
+	}
+
+	if (snode->led_en_pinctrl) {
+		pr_debug("Selecting active state for %s\n", snode->cdev.name);
+		rc = pinctrl_select_state(snode->led_en_pinctrl,
+				snode->gpio_state_active);
+		if (rc < 0) {
+			pr_err("failed to select pinctrl active state rc=%d\n",
+				rc);
+			return rc;
+		}
+	}
+
+	if (led->enable == 0) {
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_MOD_CTRL(led->base),
+				FLASH_LED_MOD_CTRL_MASK, FLASH_LED_MOD_ENABLE);
+		if (rc < 0)
+			return rc;
+	}
+	led->enable++;
+
+	if (led->trigger_lmh) {
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_MITIGATION_SW(led->base),
+				FLASH_LED_LMH_MITIGATION_EN_MASK,
+				FLASH_LED_LMH_MITIGATION_ENABLE);
+		if (rc < 0) {
+			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) {
+		rc = qpnp_flash_led_masked_write(led,
+				FLASH_LED_REG_MITIGATION_SW(led->base),
+				FLASH_LED_CHGR_MITIGATION_EN_MASK,
+				FLASH_LED_CHGR_MITIGATION_ENABLE);
+		if (rc < 0) {
+			pr_err("trigger chgr mitigation failed, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	rc = qpnp_flash_led_masked_write(led,
+					FLASH_LED_EN_LED_CTRL(led->base),
+					snode->led_mask, val);
+	if (rc < 0)
+		return rc;
+
+	snode->enabled = true;
+	return 0;
+}
+
+int qpnp_flash_led_prepare(struct led_trigger *trig, int options,
+					int *max_current)
+{
+	struct led_classdev *led_cdev;
+	struct flash_switch_data *snode;
+	struct qpnp_flash_led *led;
+	int rc;
+
+	if (!trig) {
+		pr_err("Invalid led_trigger provided\n");
+		return -EINVAL;
+	}
+
+	led_cdev = trigger_to_lcdev(trig);
+	if (!led_cdev) {
+		pr_err("Invalid led_cdev in trigger %s\n", trig->name);
+		return -EINVAL;
+	}
+
+	snode = container_of(led_cdev, struct flash_switch_data, cdev);
+	led = dev_get_drvdata(&snode->pdev->dev);
+
+	if (!(options & FLASH_LED_PREPARE_OPTIONS_MASK)) {
+		pr_err("Invalid options %d\n", options);
+		return -EINVAL;
+	}
+
+	if (options & ENABLE_REGULATOR) {
+		rc = qpnp_flash_led_regulator_enable(led, snode, true);
+		if (rc < 0) {
+			pr_err("enable regulator failed, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	if (options & DISABLE_REGULATOR) {
+		rc = qpnp_flash_led_regulator_enable(led, snode, false);
+		if (rc < 0) {
+			pr_err("disable regulator failed, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	if (options & QUERY_MAX_AVAIL_CURRENT) {
+		rc = qpnp_flash_led_get_max_avail_current(led, max_current);
+		if (rc < 0) {
+			pr_err("query max current failed, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
+						enum led_brightness value)
+{
+	struct flash_node_data *fnode = NULL;
+	struct flash_switch_data *snode = NULL;
+	struct qpnp_flash_led *led = NULL;
+	int rc;
+
+	/*
+	 * strncmp() must be used here since a prefix comparison is required
+	 * in order to support names like led:switch_0 and led:flash_1.
+	 */
+	if (!strncmp(led_cdev->name, "led:switch", strlen("led:switch"))) {
+		snode = container_of(led_cdev, struct flash_switch_data, cdev);
+		led = dev_get_drvdata(&snode->pdev->dev);
+	} else if (!strncmp(led_cdev->name, "led:flash", strlen("led:flash")) ||
+			!strncmp(led_cdev->name, "led:torch",
+						strlen("led:torch"))) {
+		fnode = container_of(led_cdev, struct flash_node_data, cdev);
+		led = dev_get_drvdata(&fnode->pdev->dev);
+	}
+
+	if (!led) {
+		pr_err("Failed to get flash driver data\n");
+		return;
+	}
+
+	spin_lock(&led->lock);
+	if (snode) {
+		rc = qpnp_flash_led_switch_set(snode, value > 0);
+		if (rc < 0)
+			pr_err("Failed to set flash LED switch rc=%d\n", rc);
+	} else if (fnode) {
+		qpnp_flash_led_node_set(fnode, value);
+	}
+
+	spin_unlock(&led->lock);
+}
+
+/* sysfs show function for flash_max_current */
+static ssize_t qpnp_flash_led_max_current_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int rc, max_current = 0;
+	struct flash_switch_data *snode;
+	struct qpnp_flash_led *led;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+	snode = container_of(led_cdev, struct flash_switch_data, cdev);
+	led = dev_get_drvdata(&snode->pdev->dev);
+
+	rc = qpnp_flash_led_get_max_avail_current(led, &max_current);
+	if (rc < 0)
+		pr_err("query max current failed, rc=%d\n", rc);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", max_current);
+}
+
+/* sysfs attributes exported by flash_led */
+static struct device_attribute qpnp_flash_led_attrs[] = {
+	__ATTR(max_current, 0664, qpnp_flash_led_max_current_show, NULL),
+};
+
+static int flash_led_psy_notifier_call(struct notifier_block *nb,
+		unsigned long ev, void *v)
+{
+	struct power_supply *psy = v;
+	struct qpnp_flash_led *led =
+			container_of(nb, struct qpnp_flash_led, nb);
+
+	if (ev != PSY_EVENT_PROP_CHANGED)
+		return NOTIFY_OK;
+
+	if (!strcmp(psy->desc->name, "bms")) {
+		led->bms_psy = power_supply_get_by_name("bms");
+		if (!led->bms_psy)
+			pr_err("Failed to get bms power_supply\n");
+		else
+			power_supply_unreg_notifier(&led->nb);
+	}
+
+	return NOTIFY_OK;
+}
+
+static int flash_led_psy_register_notifier(struct qpnp_flash_led *led)
+{
+	int rc;
+
+	led->nb.notifier_call = flash_led_psy_notifier_call;
+	rc = power_supply_reg_notifier(&led->nb);
+	if (rc < 0) {
+		pr_err("Couldn't register psy notifier, rc = %d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+/* irq handler */
+static irqreturn_t qpnp_flash_led_irq_handler(int irq, void *_led)
+{
+	struct qpnp_flash_led *led = _led;
+	enum flash_led_irq_type irq_type = INVALID_IRQ;
+	int rc;
+	u8 irq_status, led_status1, led_status2;
+
+	pr_debug("irq received, irq=%d\n", irq);
+
+	rc = qpnp_flash_led_read(led,
+			FLASH_LED_REG_INT_RT_STS(led->base), &irq_status);
+	if (rc < 0) {
+		pr_err("Failed to read interrupt status reg, rc=%d\n", rc);
+		goto exit;
+	}
+
+	if (irq == led->pdata->all_ramp_up_done_irq)
+		irq_type = ALL_RAMP_UP_DONE_IRQ;
+	else if (irq == led->pdata->all_ramp_down_done_irq)
+		irq_type = ALL_RAMP_DOWN_DONE_IRQ;
+	else if (irq == led->pdata->led_fault_irq)
+		irq_type = LED_FAULT_IRQ;
+
+	if (irq_type == ALL_RAMP_UP_DONE_IRQ)
+		atomic_notifier_call_chain(&irq_notifier_list,
+						irq_type, NULL);
+
+	if (irq_type == LED_FAULT_IRQ) {
+		rc = qpnp_flash_led_read(led,
+			FLASH_LED_REG_LED_STATUS1(led->base), &led_status1);
+		if (rc < 0) {
+			pr_err("Failed to read led_status1 reg, rc=%d\n", rc);
+			goto exit;
+		}
+
+		rc = qpnp_flash_led_read(led,
+			FLASH_LED_REG_LED_STATUS2(led->base), &led_status2);
+		if (rc < 0) {
+			pr_err("Failed to read led_status2 reg, rc=%d\n", rc);
+			goto exit;
+		}
+
+		if (led_status1)
+			pr_emerg("led short/open fault detected! led_status1=%x\n",
+				led_status1);
+
+		if (led_status2 & FLASH_LED_VPH_DROOP_FAULT_MASK)
+			pr_emerg("led vph_droop fault detected!\n");
+	}
+
+	pr_debug("irq handled, irq_type=%x, irq_status=%x\n", irq_type,
+		irq_status);
+
+exit:
+	return IRQ_HANDLED;
+}
+
+int qpnp_flash_led_register_irq_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&irq_notifier_list, nb);
+}
+
+int qpnp_flash_led_unregister_irq_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&irq_notifier_list, nb);
+}
+
+static inline u8 get_safety_timer_code(u32 duration_ms)
+{
+	if (!duration_ms)
+		return 0;
+
+	return (duration_ms / 10) - 1;
+}
+
+static inline u8 get_vph_droop_thresh_code(u32 val_mv)
+{
+	if (!val_mv)
+		return 0;
+
+	return (val_mv / 100) - 25;
+}
+
+static int qpnp_flash_led_parse_hw_strobe_dt(struct flash_node_data *fnode)
+{
+	struct device_node *node = fnode->cdev.dev->of_node;
+
+	if (of_find_property(node, "qcom,hw-strobe-gpio", NULL)) {
+		fnode->hw_strobe_gpio = of_get_named_gpio(node,
+					"qcom,hw-strobe-gpio", 0);
+		if (fnode->hw_strobe_gpio < 0) {
+			pr_err("Invalid gpio specified\n");
+			return fnode->hw_strobe_gpio;
+		}
+
+		gpio_direction_output(fnode->hw_strobe_gpio, 0);
+	} else if (fnode->strobe_pinctrl) {
+		fnode->hw_strobe_gpio = -1;
+		fnode->hw_strobe_state_active =
+			pinctrl_lookup_state(fnode->strobe_pinctrl,
+						"strobe_enable");
+		if (IS_ERR_OR_NULL(fnode->hw_strobe_state_active)) {
+			pr_err("No active pin for hardware strobe, rc=%ld\n",
+				PTR_ERR(fnode->hw_strobe_state_active));
+			fnode->hw_strobe_state_active = NULL;
+		}
+
+		fnode->hw_strobe_state_suspend =
+			pinctrl_lookup_state(fnode->strobe_pinctrl,
+						"strobe_disable");
+		if (IS_ERR_OR_NULL(fnode->hw_strobe_state_suspend)) {
+			pr_err("No suspend pin for hardware strobe, rc=%ld\n",
+				PTR_ERR(fnode->hw_strobe_state_suspend));
+			fnode->hw_strobe_state_suspend = NULL;
+		}
+	}
+
+	return 0;
+}
+
+static int qpnp_flash_led_parse_strobe_sel_dt(struct qpnp_flash_led *led,
+						struct flash_node_data *fnode,
+						struct device_node *node)
+{
+	int rc;
+	u32 val;
+	u8 hw_strobe = 0, edge_trigger = 0, active_high = 0;
+
+	fnode->strobe_sel = SW_STROBE;
+	rc = of_property_read_u32(node, "qcom,strobe-sel", &val);
+	if (rc < 0) {
+		if (rc != -EINVAL) {
+			pr_err("Unable to read qcom,strobe-sel property\n");
+			return rc;
+		}
+	} else {
+		if (val < SW_STROBE || val > LPG_STROBE) {
+			pr_err("Incorrect strobe selection specified %d\n",
+				val);
+			return -EINVAL;
+		}
+		fnode->strobe_sel = (u8)val;
+	}
+
+	/*
+	 * LPG strobe is allowed only for LED3 and HW strobe option should be
+	 * option 2 or 3.
+	 */
+	if (fnode->strobe_sel == LPG_STROBE) {
+		if (led->pdata->hw_strobe_option ==
+				FLASH_LED_HW_STROBE_OPTION_1) {
+			pr_err("Incorrect strobe option for LPG strobe\n");
+			return -EINVAL;
+		}
+		if (fnode->id != LED3) {
+			pr_err("Incorrect LED chosen for LPG strobe\n");
+			return -EINVAL;
+		}
+	}
+
+	if (fnode->strobe_sel == HW_STROBE) {
+		edge_trigger = of_property_read_bool(node,
+						"qcom,hw-strobe-edge-trigger");
+		active_high = !of_property_read_bool(node,
+						"qcom,hw-strobe-active-low");
+		hw_strobe = 1;
+	} else if (fnode->strobe_sel == LPG_STROBE) {
+		/* LPG strobe requires level trigger and active high */
+		edge_trigger = 0;
+		active_high =  1;
+		hw_strobe = 1;
+	}
+
+	fnode->strobe_ctrl = (hw_strobe << 2) | (edge_trigger << 1) |
+				active_high;
+
+	return 0;
+}
+
+static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
+			struct flash_node_data *fnode, struct device_node *node)
+{
+	const char *temp_string;
+	int rc, min_ma;
+	u32 val;
+
+	fnode->pdev = led->pdev;
+	fnode->cdev.brightness_set = qpnp_flash_led_brightness_set;
+	fnode->cdev.brightness_get = qpnp_flash_led_brightness_get;
+
+	rc = of_property_read_string(node, "qcom,led-name", &fnode->cdev.name);
+	if (rc < 0) {
+		pr_err("Unable to read flash LED names\n");
+		return rc;
+	}
+
+	rc = of_property_read_string(node, "label", &temp_string);
+	if (!rc) {
+		if (!strcmp(temp_string, "flash")) {
+			fnode->type = FLASH_LED_TYPE_FLASH;
+		} else if (!strcmp(temp_string, "torch")) {
+			fnode->type = FLASH_LED_TYPE_TORCH;
+		} else {
+			pr_err("Wrong flash LED type\n");
+			return rc;
+		}
+	} else {
+		pr_err("Unable to read flash LED label\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(node, "qcom,id", &val);
+	if (!rc) {
+		fnode->id = (u8)val;
+	} else {
+		pr_err("Unable to read flash LED ID\n");
+		return rc;
+	}
+
+	rc = of_property_read_string(node, "qcom,default-led-trigger",
+						&fnode->cdev.default_trigger);
+	if (rc < 0) {
+		pr_err("Unable to read trigger name\n");
+		return rc;
+	}
+
+	fnode->default_ires_ua = fnode->ires_ua = FLASH_LED_IRES_DEFAULT_UA;
+	fnode->default_ires_idx = fnode->ires_idx = FLASH_LED_IRES_DEFAULT_VAL;
+	rc = of_property_read_u32(node, "qcom,ires-ua", &val);
+	if (!rc) {
+		fnode->default_ires_ua = fnode->ires_ua = val;
+		fnode->default_ires_idx = fnode->ires_idx =
+			FLASH_LED_IRES_BASE - (val - FLASH_LED_IRES_MIN_UA) /
+			FLASH_LED_IRES_DIVISOR;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read current resolution rc=%d\n", rc);
+		return rc;
+	}
+
+	min_ma = fnode->ires_ua / 1000;
+	rc = of_property_read_u32(node, "qcom,max-current", &val);
+	if (!rc) {
+		if (val < min_ma)
+			val = min_ma;
+		fnode->max_current = val;
+		fnode->cdev.max_brightness = val;
+	} else {
+		pr_err("Unable to read max current, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(node, "qcom,current-ma", &val);
+	if (!rc) {
+		if (val < min_ma || val > fnode->max_current)
+			pr_warn("Invalid operational current specified, capping it\n");
+		if (val < min_ma)
+			val = min_ma;
+		if (val > fnode->max_current)
+			val = fnode->max_current;
+		fnode->current_ma = val;
+		fnode->cdev.brightness = val;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read operational current, rc=%d\n", rc);
+		return rc;
+	}
+
+	fnode->duration = FLASH_LED_SAFETY_TMR_DISABLED;
+	rc = of_property_read_u32(node, "qcom,duration-ms", &val);
+	if (!rc) {
+		fnode->duration = get_safety_timer_code(val);
+		if (fnode->duration)
+			fnode->duration |= FLASH_LED_SAFETY_TMR_ENABLE;
+	} else if (rc == -EINVAL) {
+		if (fnode->type == FLASH_LED_TYPE_FLASH) {
+			pr_err("Timer duration is required for flash LED\n");
+			return rc;
+		}
+	} else {
+		pr_err("Unable to read timer duration\n");
+		return rc;
+	}
+
+	fnode->hdrm_val = FLASH_LED_HDRM_VOL_DEFAULT_MV;
+	rc = of_property_read_u32(node, "qcom,hdrm-voltage-mv", &val);
+	if (!rc) {
+		val = (val - FLASH_LED_HDRM_VOL_BASE_MV) /
+						FLASH_LED_HDRM_VOL_STEP_MV;
+		fnode->hdrm_val = (val << FLASH_LED_HDRM_VOL_SHIFT) &
+							FLASH_LED_HDRM_VOL_MASK;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read headroom voltage\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(node, "qcom,hdrm-vol-hi-lo-win-mv", &val);
+	if (!rc) {
+		fnode->hdrm_val |= (val / FLASH_LED_HDRM_VOL_STEP_MV) &
+						~FLASH_LED_HDRM_VOL_MASK;
+	} else if (rc == -EINVAL) {
+		fnode->hdrm_val |= FLASH_LED_HDRM_VOL_HI_LO_WIN_DEFAULT_MV;
+	} else {
+		pr_err("Unable to read hdrm hi-lo window voltage\n");
+		return rc;
+	}
+
+	rc = qpnp_flash_led_parse_strobe_sel_dt(led, fnode, node);
+	if (rc < 0)
+		return rc;
+
+	rc = led_classdev_register(&led->pdev->dev, &fnode->cdev);
+	if (rc < 0) {
+		pr_err("Unable to register led node %d\n", fnode->id);
+		return rc;
+	}
+
+	fnode->cdev.dev->of_node = node;
+	fnode->strobe_pinctrl = devm_pinctrl_get(fnode->cdev.dev);
+	if (IS_ERR_OR_NULL(fnode->strobe_pinctrl)) {
+		pr_debug("No pinctrl defined for %s, err=%ld\n",
+			fnode->cdev.name, PTR_ERR(fnode->strobe_pinctrl));
+		fnode->strobe_pinctrl = NULL;
+	}
+
+	if (fnode->strobe_sel == HW_STROBE)
+		return qpnp_flash_led_parse_hw_strobe_dt(fnode);
+
+	return 0;
+}
+
+static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led,
+						struct flash_switch_data *snode,
+						struct device_node *node)
+{
+	int rc = 0, num;
+	char reg_name[16], reg_sup_name[16];
+
+	rc = of_property_read_string(node, "qcom,led-name", &snode->cdev.name);
+	if (rc < 0) {
+		pr_err("Failed to read switch node name, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = sscanf(snode->cdev.name, "led:switch_%d", &num);
+	if (!rc) {
+		pr_err("No number for switch device?\n");
+		return -EINVAL;
+	}
+
+	rc = of_property_read_string(node, "qcom,default-led-trigger",
+					&snode->cdev.default_trigger);
+	if (rc < 0) {
+		pr_err("Unable to read trigger name, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(node, "qcom,led-mask", &snode->led_mask);
+	if (rc < 0) {
+		pr_err("Unable to read led mask rc=%d\n", rc);
+		return rc;
+	}
+
+	snode->symmetry_en = of_property_read_bool(node, "qcom,symmetry-en");
+
+	if (snode->led_mask < 1 || snode->led_mask > 7) {
+		pr_err("Invalid value for led-mask\n");
+		return -EINVAL;
+	}
+
+	scnprintf(reg_name, sizeof(reg_name), "switch%d-supply", num);
+	if (of_find_property(led->pdev->dev.of_node, reg_name, NULL)) {
+		scnprintf(reg_sup_name, sizeof(reg_sup_name), "switch%d", num);
+		snode->vreg = devm_regulator_get(&led->pdev->dev, reg_sup_name);
+		if (IS_ERR_OR_NULL(snode->vreg)) {
+			rc = PTR_ERR(snode->vreg);
+			if (rc != -EPROBE_DEFER)
+				pr_err("Failed to get regulator, rc=%d\n", rc);
+			snode->vreg = NULL;
+			return rc;
+		}
+	}
+
+	snode->pdev = led->pdev;
+	snode->cdev.brightness_set = qpnp_flash_led_brightness_set;
+	snode->cdev.brightness_get = qpnp_flash_led_brightness_get;
+	snode->cdev.flags |= LED_KEEP_TRIGGER;
+	rc = led_classdev_register(&led->pdev->dev, &snode->cdev);
+	if (rc < 0) {
+		pr_err("Unable to register led switch node\n");
+		return rc;
+	}
+
+	snode->cdev.dev->of_node = node;
+
+	snode->led_en_pinctrl = devm_pinctrl_get(snode->cdev.dev);
+	if (IS_ERR_OR_NULL(snode->led_en_pinctrl)) {
+		pr_debug("No pinctrl defined for %s, err=%ld\n",
+			snode->cdev.name, PTR_ERR(snode->led_en_pinctrl));
+		snode->led_en_pinctrl = NULL;
+	}
+
+	if (snode->led_en_pinctrl) {
+		snode->gpio_state_active =
+			pinctrl_lookup_state(snode->led_en_pinctrl,
+						"led_enable");
+		if (IS_ERR_OR_NULL(snode->gpio_state_active)) {
+			pr_err("Cannot lookup LED active state\n");
+			devm_pinctrl_put(snode->led_en_pinctrl);
+			snode->led_en_pinctrl = NULL;
+			return PTR_ERR(snode->gpio_state_active);
+		}
+
+		snode->gpio_state_suspend =
+			pinctrl_lookup_state(snode->led_en_pinctrl,
+						"led_disable");
+		if (IS_ERR_OR_NULL(snode->gpio_state_suspend)) {
+			pr_err("Cannot lookup LED disable state\n");
+			devm_pinctrl_put(snode->led_en_pinctrl);
+			snode->led_en_pinctrl = NULL;
+			return PTR_ERR(snode->gpio_state_suspend);
+		}
+	}
+
+	return 0;
+}
+
+static int get_code_from_table(int *table, int len, int value)
+{
+	int i;
+
+	for (i = 0; i < len; i++) {
+		if (value == table[i])
+			break;
+	}
+
+	if (i == len) {
+		pr_err("Couldn't find %d from table\n", value);
+		return -ENODATA;
+	}
+
+	return i;
+}
+
+static int qpnp_flash_led_parse_thermal_config_dt(struct qpnp_flash_led *led,
+						struct device_node *node)
+{
+	int rc;
+	u32 val;
+
+	led->pdata->thermal_derate_en =
+		of_property_read_bool(node, "qcom,thermal-derate-en");
+
+	if (led->pdata->thermal_derate_en) {
+		led->pdata->thermal_derate_current =
+			devm_kcalloc(&led->pdev->dev,
+					FLASH_LED_THERMAL_OTST_LEVELS,
+					sizeof(int), GFP_KERNEL);
+		if (!led->pdata->thermal_derate_current)
+			return -ENOMEM;
+
+		rc = of_property_read_u32_array(node,
+					"qcom,thermal-derate-current",
+					led->pdata->thermal_derate_current,
+					FLASH_LED_THERMAL_OTST_LEVELS);
+		if (rc < 0) {
+			pr_err("Unable to read thermal current limits, rc=%d\n",
+				rc);
+			return rc;
+		}
+	}
+
+	led->pdata->otst_ramp_bkup_en =
+		!of_property_read_bool(node, "qcom,otst-ramp-back-up-dis");
+
+	led->pdata->thermal_derate_slow = -EINVAL;
+	rc = of_property_read_u32(node, "qcom,thermal-derate-slow", &val);
+	if (!rc) {
+		if (val < 0 || val > THERMAL_DERATE_SLOW_MAX) {
+			pr_err("Invalid thermal_derate_slow %d\n", val);
+			return -EINVAL;
+		}
+
+		led->pdata->thermal_derate_slow =
+			get_code_from_table(thermal_derate_slow_table,
+				ARRAY_SIZE(thermal_derate_slow_table), val);
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read thermal derate slow, rc=%d\n", rc);
+		return rc;
+	}
+
+	led->pdata->thermal_derate_fast = -EINVAL;
+	rc = of_property_read_u32(node, "qcom,thermal-derate-fast", &val);
+	if (!rc) {
+		if (val < 0 || val > THERMAL_DERATE_FAST_MAX) {
+			pr_err("Invalid thermal_derate_fast %d\n", val);
+			return -EINVAL;
+		}
+
+		led->pdata->thermal_derate_fast =
+			get_code_from_table(thermal_derate_fast_table,
+				ARRAY_SIZE(thermal_derate_fast_table), val);
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read thermal derate fast, rc=%d\n", rc);
+		return rc;
+	}
+
+	led->pdata->thermal_debounce = -EINVAL;
+	rc = of_property_read_u32(node, "qcom,thermal-debounce", &val);
+	if (!rc) {
+		if (val < 0 || val > THERMAL_DEBOUNCE_TIME_MAX) {
+			pr_err("Invalid thermal_debounce %d\n", val);
+			return -EINVAL;
+		}
+
+		if (val >= 0 && val < 16)
+			led->pdata->thermal_debounce = 0;
+		else
+			led->pdata->thermal_debounce = ilog2(val) - 3;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read thermal debounce, rc=%d\n", rc);
+		return rc;
+	}
+
+	led->pdata->thermal_hysteresis = -EINVAL;
+	rc = of_property_read_u32(node, "qcom,thermal-hysteresis", &val);
+	if (!rc) {
+		if (led->pdata->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE)
+			val = THERMAL_HYST_TEMP_TO_VAL(val, 20);
+		else
+			val = THERMAL_HYST_TEMP_TO_VAL(val, 15);
+
+		if (val < 0 || val > THERMAL_DERATE_HYSTERESIS_MAX) {
+			pr_err("Invalid thermal_derate_hysteresis %d\n", val);
+			return -EINVAL;
+		}
+
+		led->pdata->thermal_hysteresis = val;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read thermal hysteresis, rc=%d\n", rc);
+		return rc;
+	}
+
+	led->pdata->thermal_thrsh1 = -EINVAL;
+	rc = of_property_read_u32(node, "qcom,thermal-thrsh1", &val);
+	if (!rc) {
+		led->pdata->thermal_thrsh1 =
+			get_code_from_table(otst1_threshold_table,
+				ARRAY_SIZE(otst1_threshold_table), val);
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read thermal thrsh1, rc=%d\n", rc);
+		return rc;
+	}
+
+	led->pdata->thermal_thrsh2 = -EINVAL;
+	rc = of_property_read_u32(node, "qcom,thermal-thrsh2", &val);
+	if (!rc) {
+		led->pdata->thermal_thrsh2 =
+			get_code_from_table(otst2_threshold_table,
+				ARRAY_SIZE(otst2_threshold_table), val);
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read thermal thrsh2, rc=%d\n", rc);
+		return rc;
+	}
+
+	led->pdata->thermal_thrsh3 = -EINVAL;
+	rc = of_property_read_u32(node, "qcom,thermal-thrsh3", &val);
+	if (!rc) {
+		led->pdata->thermal_thrsh3 =
+			get_code_from_table(otst3_threshold_table,
+				ARRAY_SIZE(otst3_threshold_table), val);
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read thermal thrsh3, rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int qpnp_flash_led_parse_vph_droop_config_dt(struct qpnp_flash_led *led,
+						struct device_node *node)
+{
+	int rc;
+	u32 val;
+
+	led->pdata->vph_droop_debounce = FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,vph-droop-debounce-us", &val);
+	if (!rc) {
+		led->pdata->vph_droop_debounce =
+			VPH_DROOP_DEBOUNCE_US_TO_VAL(val);
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read VPH droop debounce, rc=%d\n", rc);
+		return rc;
+	}
+
+	if (led->pdata->vph_droop_debounce > FLASH_LED_DEBOUNCE_MAX) {
+		pr_err("Invalid VPH droop debounce specified\n");
+		return -EINVAL;
+	}
+
+	led->pdata->vph_droop_threshold = FLASH_LED_VPH_DROOP_THRESH_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,vph-droop-threshold-mv", &val);
+	if (!rc) {
+		led->pdata->vph_droop_threshold =
+			get_vph_droop_thresh_code(val);
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read VPH droop threshold, rc=%d\n", rc);
+		return rc;
+	}
+
+	if (led->pdata->vph_droop_threshold > FLASH_LED_VPH_DROOP_THRESH_MAX) {
+		pr_err("Invalid VPH droop threshold specified\n");
+		return -EINVAL;
+	}
+
+	led->pdata->vph_droop_hysteresis =
+			FLASH_LED_VPH_DROOP_HYST_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,vph-droop-hysteresis-mv", &val);
+	if (!rc) {
+		led->pdata->vph_droop_hysteresis =
+			VPH_DROOP_HYST_MV_TO_VAL(val);
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read VPH droop hysteresis, rc=%d\n", rc);
+		return rc;
+	}
+
+	if (led->pdata->vph_droop_hysteresis > FLASH_LED_HYSTERESIS_MAX) {
+		pr_err("Invalid VPH droop hysteresis specified\n");
+		return -EINVAL;
+	}
+
+	led->pdata->vph_droop_hysteresis <<= FLASH_LED_VPH_DROOP_HYST_SHIFT;
+	return rc;
+}
+
+static int qpnp_flash_led_parse_iclamp_config_dt(struct qpnp_flash_led *led,
+						struct device_node *node)
+{
+	int rc;
+	u32 val;
+
+	rc = of_property_read_u32(node, "qcom,led1n2-iclamp-low-ma", &val);
+	if (!rc) {
+		led->pdata->led1n2_iclamp_low_ma = val;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read led1n2_iclamp_low current, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(node, "qcom,led1n2-iclamp-mid-ma", &val);
+	if (!rc) {
+		led->pdata->led1n2_iclamp_mid_ma = val;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read led1n2_iclamp_mid current, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(node, "qcom,led3-iclamp-low-ma", &val);
+	if (!rc) {
+		led->pdata->led3_iclamp_low_ma = val;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read led3_iclamp_low current, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(node, "qcom,led3-iclamp-mid-ma", &val);
+	if (!rc) {
+		led->pdata->led3_iclamp_mid_ma = val;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read led3_iclamp_mid current, rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int qpnp_flash_led_parse_lmh_config_dt(struct qpnp_flash_led *led,
+						struct device_node *node)
+{
+	int rc;
+	u32 val;
+
+	led->pdata->lmh_ocv_threshold_uv =
+		FLASH_LED_LMH_OCV_THRESH_DEFAULT_UV;
+	rc = of_property_read_u32(node, "qcom,lmh-ocv-threshold-uv", &val);
+	if (!rc) {
+		led->pdata->lmh_ocv_threshold_uv = val;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to parse lmh ocv threshold, rc=%d\n", rc);
+		return rc;
+	}
+
+	led->pdata->lmh_rbatt_threshold_uohm =
+		FLASH_LED_LMH_RBATT_THRESH_DEFAULT_UOHM;
+	rc = of_property_read_u32(node, "qcom,lmh-rbatt-threshold-uohm", &val);
+	if (!rc) {
+		led->pdata->lmh_rbatt_threshold_uohm = val;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to parse lmh rbatt threshold, rc=%d\n", rc);
+		return rc;
+	}
+
+	led->pdata->lmh_level = FLASH_LED_LMH_LEVEL_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,lmh-level", &val);
+	if (!rc) {
+		led->pdata->lmh_level = val;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to parse lmh_level, rc=%d\n", rc);
+		return rc;
+	}
+
+	led->pdata->lmh_mitigation_sel = FLASH_LED_LMH_MITIGATION_SEL_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,lmh-mitigation-sel", &val);
+	if (!rc) {
+		led->pdata->lmh_mitigation_sel = val;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to parse lmh_mitigation_sel, rc=%d\n", rc);
+		return rc;
+	}
+
+	if (led->pdata->lmh_mitigation_sel > FLASH_LED_MITIGATION_SEL_MAX) {
+		pr_err("Invalid lmh_mitigation_sel specified\n");
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,
+						struct device_node *node)
+{
+	struct device_node *revid_node;
+	int rc;
+	u32 val;
+	bool short_circuit_det, open_circuit_det, vph_droop_det;
+
+	rc = of_property_read_u32(node, "reg", &val);
+	if (rc < 0) {
+		pr_err("Couldn't find reg in node %s, rc = %d\n",
+			node->full_name, rc);
+		return rc;
+	}
+
+	led->base = val;
+	revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
+	if (!revid_node) {
+		pr_err("Missing qcom,pmic-revid property - driver failed\n");
+		return -EINVAL;
+	}
+
+	led->pdata->pmic_rev_id = get_revid_data(revid_node);
+	if (IS_ERR_OR_NULL(led->pdata->pmic_rev_id)) {
+		pr_err("Unable to get pmic_revid rc=%ld\n",
+			PTR_ERR(led->pdata->pmic_rev_id));
+		/*
+		 * the revid peripheral must be registered, any failure
+		 * here only indicates that the rev-id module has not
+		 * probed yet.
+		 */
+		return -EPROBE_DEFER;
+	}
+	of_node_put(revid_node);
+
+	pr_debug("PMIC subtype %d Digital major %d\n",
+		led->pdata->pmic_rev_id->pmic_subtype,
+		led->pdata->pmic_rev_id->rev4);
+
+	led->pdata->hdrm_auto_mode_en = of_property_read_bool(node,
+							"qcom,hdrm-auto-mode");
+
+	led->pdata->isc_delay = FLASH_LED_ISC_DELAY_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,isc-delay-us", &val);
+	if (!rc) {
+		led->pdata->isc_delay =
+				val >> FLASH_LED_ISC_WARMUP_DELAY_SHIFT;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read ISC delay, rc=%d\n", rc);
+		return rc;
+	}
+
+	led->pdata->warmup_delay = FLASH_LED_WARMUP_DELAY_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,warmup-delay-us", &val);
+	if (!rc) {
+		led->pdata->warmup_delay =
+				val >> FLASH_LED_ISC_WARMUP_DELAY_SHIFT;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read WARMUP delay, rc=%d\n", rc);
+		return rc;
+	}
+
+	short_circuit_det =
+		of_property_read_bool(node, "qcom,short-circuit-det");
+	open_circuit_det = of_property_read_bool(node, "qcom,open-circuit-det");
+	vph_droop_det = of_property_read_bool(node, "qcom,vph-droop-det");
+	led->pdata->current_derate_en_cfg = (vph_droop_det << 2) |
+				(open_circuit_det << 1) | short_circuit_det;
+
+	rc = qpnp_flash_led_parse_thermal_config_dt(led, node);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_parse_vph_droop_config_dt(led, node);
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_flash_led_parse_iclamp_config_dt(led, node);
+	if (rc < 0)
+		return rc;
+
+	led->pdata->hw_strobe_option = -EINVAL;
+	rc = of_property_read_u32(node, "qcom,hw-strobe-option", &val);
+	if (!rc) {
+		led->pdata->hw_strobe_option = val;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to parse hw strobe option, rc=%d\n", rc);
+		return rc;
+	}
+
+	led->pdata->vled_max_uv = FLASH_LED_VLED_MAX_DEFAULT_UV;
+	rc = of_property_read_u32(node, "qcom,vled-max-uv", &val);
+	if (!rc) {
+		led->pdata->vled_max_uv = val;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to parse vled_max voltage, rc=%d\n", rc);
+		return rc;
+	}
+
+	led->pdata->ibatt_ocp_threshold_ua =
+		FLASH_LED_IBATT_OCP_THRESH_DEFAULT_UA;
+	rc = of_property_read_u32(node, "qcom,ibatt-ocp-threshold-ua", &val);
+	if (!rc) {
+		led->pdata->ibatt_ocp_threshold_ua = val;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to parse ibatt_ocp threshold, rc=%d\n", rc);
+		return rc;
+	}
+
+	led->pdata->rpara_uohm = FLASH_LED_RPARA_DEFAULT_UOHM;
+	rc = of_property_read_u32(node, "qcom,rparasitic-uohm", &val);
+	if (!rc) {
+		led->pdata->rpara_uohm = val;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to parse rparasitic, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_flash_led_parse_lmh_config_dt(led, node);
+	if (rc < 0)
+		return rc;
+
+	led->pdata->chgr_mitigation_sel = FLASH_SW_CHARGER_MITIGATION;
+	rc = of_property_read_u32(node, "qcom,chgr-mitigation-sel", &val);
+	if (!rc) {
+		led->pdata->chgr_mitigation_sel = val;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to parse chgr_mitigation_sel, rc=%d\n", rc);
+		return rc;
+	}
+
+	if (led->pdata->chgr_mitigation_sel > FLASH_LED_MITIGATION_SEL_MAX) {
+		pr_err("Invalid chgr_mitigation_sel specified\n");
+		return -EINVAL;
+	}
+
+	led->pdata->iled_thrsh_val = FLASH_LED_CHGR_MITIGATION_THRSH_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,iled-thrsh-ma", &val);
+	if (!rc) {
+		led->pdata->iled_thrsh_val = MITIGATION_THRSH_MA_TO_VAL(val);
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to parse iled_thrsh_val, rc=%d\n", rc);
+		return rc;
+	}
+
+	if (led->pdata->iled_thrsh_val > FLASH_LED_CHGR_MITIGATION_THRSH_MAX) {
+		pr_err("Invalid iled_thrsh_val specified\n");
+		return -EINVAL;
+	}
+
+	led->pdata->all_ramp_up_done_irq =
+		of_irq_get_byname(node, "all-ramp-up-done-irq");
+	if (led->pdata->all_ramp_up_done_irq < 0)
+		pr_debug("all-ramp-up-done-irq not used\n");
+
+	led->pdata->all_ramp_down_done_irq =
+		of_irq_get_byname(node, "all-ramp-down-done-irq");
+	if (led->pdata->all_ramp_down_done_irq < 0)
+		pr_debug("all-ramp-down-done-irq not used\n");
+
+	led->pdata->led_fault_irq =
+		of_irq_get_byname(node, "led-fault-irq");
+	if (led->pdata->led_fault_irq < 0)
+		pr_debug("led-fault-irq not used\n");
+
+	return 0;
+}
+
+static int qpnp_flash_led_register_interrupts(struct qpnp_flash_led *led)
+{
+	int rc;
+
+	/* setup irqs */
+	if (led->pdata->all_ramp_up_done_irq >= 0) {
+		rc = devm_request_threaded_irq(&led->pdev->dev,
+			led->pdata->all_ramp_up_done_irq,
+			NULL, qpnp_flash_led_irq_handler,
+			IRQF_ONESHOT,
+			"qpnp_flash_led_all_ramp_up_done_irq", led);
+		if (rc < 0) {
+			pr_err("Unable to request all_ramp_up_done(%d) IRQ(err:%d)\n",
+				led->pdata->all_ramp_up_done_irq, rc);
+			return rc;
+		}
+	}
+
+	if (led->pdata->all_ramp_down_done_irq >= 0) {
+		rc = devm_request_threaded_irq(&led->pdev->dev,
+			led->pdata->all_ramp_down_done_irq,
+			NULL, qpnp_flash_led_irq_handler,
+			IRQF_ONESHOT,
+			"qpnp_flash_led_all_ramp_down_done_irq", led);
+		if (rc < 0) {
+			pr_err("Unable to request all_ramp_down_done(%d) IRQ(err:%d)\n",
+				led->pdata->all_ramp_down_done_irq, rc);
+			return rc;
+		}
+	}
+
+	if (led->pdata->led_fault_irq >= 0) {
+		rc = devm_request_threaded_irq(&led->pdev->dev,
+			led->pdata->led_fault_irq,
+			NULL, qpnp_flash_led_irq_handler,
+			IRQF_ONESHOT,
+			"qpnp_flash_led_fault_irq", led);
+		if (rc < 0) {
+			pr_err("Unable to request led_fault(%d) IRQ(err:%d)\n",
+				led->pdata->led_fault_irq, rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int qpnp_flash_led_probe(struct platform_device *pdev)
+{
+	struct qpnp_flash_led *led;
+	struct device_node *node, *temp;
+	const char *temp_string;
+	int rc, i = 0, j = 0;
+
+	node = pdev->dev.of_node;
+	if (!node) {
+		pr_err("No flash LED nodes defined\n");
+		return -ENODEV;
+	}
+
+	led = devm_kzalloc(&pdev->dev, sizeof(struct qpnp_flash_led),
+								GFP_KERNEL);
+	if (!led)
+		return -ENOMEM;
+
+	led->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!led->regmap) {
+		pr_err("Couldn't get parent's regmap\n");
+		return -EINVAL;
+	}
+
+	led->pdev = pdev;
+	led->pdata = devm_kzalloc(&pdev->dev,
+			sizeof(struct flash_led_platform_data), GFP_KERNEL);
+	if (!led->pdata)
+		return -ENOMEM;
+
+	spin_lock_init(&led->lock);
+
+	rc = qpnp_flash_led_parse_common_dt(led, node);
+	if (rc < 0) {
+		pr_err("Failed to parse common flash LED device tree\n");
+		return rc;
+	}
+
+	for_each_available_child_of_node(node, temp) {
+		rc = of_property_read_string(temp, "label", &temp_string);
+		if (rc < 0) {
+			pr_err("Failed to parse label, rc=%d\n", rc);
+			return rc;
+		}
+
+		if (!strcmp("switch", temp_string)) {
+			led->num_snodes++;
+		} else if (!strcmp("flash", temp_string) ||
+				!strcmp("torch", temp_string)) {
+			led->num_fnodes++;
+		} else {
+			pr_err("Invalid label for led node\n");
+			return -EINVAL;
+		}
+	}
+
+	if (!led->num_fnodes) {
+		pr_err("No LED nodes defined\n");
+		return -ECHILD;
+	}
+
+	led->fnode = devm_kcalloc(&pdev->dev, led->num_fnodes,
+				sizeof(*led->fnode), GFP_KERNEL);
+	if (!led->fnode)
+		return -ENOMEM;
+
+	led->snode = devm_kcalloc(&pdev->dev, led->num_snodes,
+				sizeof(*led->snode), GFP_KERNEL);
+	if (!led->snode)
+		return -ENOMEM;
+
+	temp = NULL;
+	i = 0;
+	j = 0;
+	for_each_available_child_of_node(node, temp) {
+		rc = of_property_read_string(temp, "label", &temp_string);
+		if (rc < 0) {
+			pr_err("Failed to parse label, rc=%d\n", rc);
+			return rc;
+		}
+
+		if (!strcmp("flash", temp_string) ||
+				!strcmp("torch", temp_string)) {
+			rc = qpnp_flash_led_parse_each_led_dt(led,
+					&led->fnode[i], temp);
+			if (rc < 0) {
+				pr_err("Unable to parse flash node %d rc=%d\n",
+					i, rc);
+				goto error_led_register;
+			}
+			i++;
+		}
+
+		if (!strcmp("switch", temp_string)) {
+			rc = qpnp_flash_led_parse_and_register_switch(led,
+					&led->snode[j], temp);
+			if (rc < 0) {
+				pr_err("Unable to parse and register switch node, rc=%d\n",
+					rc);
+				goto error_switch_register;
+			}
+			j++;
+		}
+	}
+
+	rc = qpnp_flash_led_register_interrupts(led);
+	if (rc < 0)
+		goto error_switch_register;
+
+	led->bms_psy = power_supply_get_by_name("bms");
+	if (!led->bms_psy) {
+		rc = flash_led_psy_register_notifier(led);
+		if (rc < 0) {
+			pr_err("Couldn't register psy notifier, rc = %d\n", rc);
+			goto error_switch_register;
+		}
+	}
+
+	rc = qpnp_flash_led_init_settings(led);
+	if (rc < 0) {
+		pr_err("Failed to initialize flash LED, rc=%d\n", rc);
+		goto unreg_notifier;
+	}
+
+	for (i = 0; i < led->num_snodes; i++) {
+		for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++) {
+			rc = sysfs_create_file(&led->snode[i].cdev.dev->kobj,
+					&qpnp_flash_led_attrs[j].attr);
+			if (rc < 0) {
+				pr_err("sysfs creation failed, rc=%d\n", rc);
+				goto sysfs_fail;
+			}
+		}
+	}
+
+	dev_set_drvdata(&pdev->dev, led);
+
+	return 0;
+
+sysfs_fail:
+	for (--j; j >= 0; j--)
+		sysfs_remove_file(&led->snode[i].cdev.dev->kobj,
+				&qpnp_flash_led_attrs[j].attr);
+
+	for (--i; i >= 0; i--) {
+		for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++)
+			sysfs_remove_file(&led->snode[i].cdev.dev->kobj,
+					&qpnp_flash_led_attrs[j].attr);
+	}
+
+	i = led->num_snodes;
+unreg_notifier:
+	power_supply_unreg_notifier(&led->nb);
+error_switch_register:
+	while (i > 0)
+		led_classdev_unregister(&led->snode[--i].cdev);
+	i = led->num_fnodes;
+error_led_register:
+	while (i > 0)
+		led_classdev_unregister(&led->fnode[--i].cdev);
+
+	return rc;
+}
+
+static int qpnp_flash_led_remove(struct platform_device *pdev)
+{
+	struct qpnp_flash_led *led = dev_get_drvdata(&pdev->dev);
+	int i, j;
+
+	for (i = 0; i < led->num_snodes; i++) {
+		for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++)
+			sysfs_remove_file(&led->snode[i].cdev.dev->kobj,
+					&qpnp_flash_led_attrs[j].attr);
+
+		if (led->snode[i].regulator_on)
+			qpnp_flash_led_regulator_enable(led,
+					&led->snode[i], false);
+	}
+
+	while (i > 0)
+		led_classdev_unregister(&led->snode[--i].cdev);
+
+	i = led->num_fnodes;
+	while (i > 0)
+		led_classdev_unregister(&led->fnode[--i].cdev);
+
+	power_supply_unreg_notifier(&led->nb);
+	return 0;
+}
+
+const struct of_device_id qpnp_flash_led_match_table[] = {
+	{ .compatible = "qcom,qpnp-flash-led-v2",},
+	{ },
+};
+
+static struct platform_driver qpnp_flash_led_driver = {
+	.driver		= {
+		.name = "qcom,qpnp-flash-led-v2",
+		.of_match_table = qpnp_flash_led_match_table,
+	},
+	.probe		= qpnp_flash_led_probe,
+	.remove		= qpnp_flash_led_remove,
+};
+
+static int __init qpnp_flash_led_init(void)
+{
+	return platform_driver_register(&qpnp_flash_led_driver);
+}
+late_initcall(qpnp_flash_led_init);
+
+static void __exit qpnp_flash_led_exit(void)
+{
+	platform_driver_unregister(&qpnp_flash_led_driver);
+}
+module_exit(qpnp_flash_led_exit);
+
+MODULE_DESCRIPTION("QPNP Flash LED driver v2");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("leds:leds-qpnp-flash-v2");
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index 7d38e6b..dbb9a36 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -21,6 +21,22 @@
 	return led_cdev->brightness;
 }
 
+static inline struct led_classdev *trigger_to_lcdev(struct led_trigger *trig)
+{
+	struct led_classdev *led_cdev;
+
+	read_lock(&trig->leddev_list_lock);
+	list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
+		if (!strcmp(led_cdev->default_trigger, trig->name)) {
+			read_unlock(&trig->leddev_list_lock);
+			return led_cdev;
+		}
+	}
+
+	read_unlock(&trig->leddev_list_lock);
+	return NULL;
+}
+
 void led_init_core(struct led_classdev *led_cdev);
 void led_stop_software_blink(struct led_classdev *led_cdev);
 void led_set_brightness_nopm(struct led_classdev *led_cdev,
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index e1fa6ba..bb3096b 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -559,7 +559,12 @@
 		}
 		memset(result + size, 0, JOURNAL_MAC_SIZE - size);
 	} else {
-		__u8 digest[size];
+		__u8 digest[HASH_MAX_DIGESTSIZE];
+
+		if (WARN_ON(size > sizeof(digest))) {
+			dm_integrity_io_error(ic, "digest_size", -EINVAL);
+			goto err;
+		}
 		r = crypto_shash_final(desc, digest);
 		if (unlikely(r)) {
 			dm_integrity_io_error(ic, "crypto_shash_final", r);
@@ -1324,7 +1329,7 @@
 		struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io));
 		char *checksums;
 		unsigned extra_space = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0;
-		char checksums_onstack[ic->tag_size + extra_space];
+		char checksums_onstack[HASH_MAX_DIGESTSIZE];
 		unsigned sectors_to_process = dio->range.n_sectors;
 		sector_t sector = dio->range.logical_sector;
 
@@ -1333,8 +1338,14 @@
 
 		checksums = kmalloc((PAGE_SIZE >> SECTOR_SHIFT >> ic->sb->log2_sectors_per_block) * ic->tag_size + extra_space,
 				    GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN);
-		if (!checksums)
+		if (!checksums) {
 			checksums = checksums_onstack;
+			if (WARN_ON(extra_space &&
+				    digest_size > sizeof(checksums_onstack))) {
+				r = -EINVAL;
+				goto error;
+			}
+		}
 
 		__bio_for_each_segment(bv, bio, iter, dio->orig_bi_iter) {
 			unsigned pos;
@@ -1546,7 +1557,7 @@
 				} while (++s < ic->sectors_per_block);
 #ifdef INTERNAL_VERIFY
 				if (ic->internal_hash) {
-					char checksums_onstack[max(crypto_shash_digestsize(ic->internal_hash), ic->tag_size)];
+					char checksums_onstack[max(HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
 
 					integrity_sector_checksum(ic, logical_sector, mem + bv.bv_offset, checksums_onstack);
 					if (unlikely(memcmp(checksums_onstack, journal_entry_tag(ic, je), ic->tag_size))) {
@@ -1596,7 +1607,7 @@
 				if (ic->internal_hash) {
 					unsigned digest_size = crypto_shash_digestsize(ic->internal_hash);
 					if (unlikely(digest_size > ic->tag_size)) {
-						char checksums_onstack[digest_size];
+						char checksums_onstack[HASH_MAX_DIGESTSIZE];
 						integrity_sector_checksum(ic, logical_sector, (char *)js, checksums_onstack);
 						memcpy(journal_entry_tag(ic, je), checksums_onstack, ic->tag_size);
 					} else
@@ -2023,7 +2034,7 @@
 				    unlikely(from_replay) &&
 #endif
 				    ic->internal_hash) {
-					char test_tag[max(crypto_shash_digestsize(ic->internal_hash), ic->tag_size)];
+					char test_tag[max_t(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
 
 					integrity_sector_checksum(ic, sec + ((l - j) << ic->sb->log2_sectors_per_block),
 								  (char *)access_journal_data(ic, i, l), test_tag);
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
index 8306ee0..1c9b878 100644
--- a/drivers/md/dm-verity-fec.c
+++ b/drivers/md/dm-verity-fec.c
@@ -215,12 +215,15 @@
 	struct dm_verity_fec_io *fio = fec_io(io);
 	u64 block, ileaved;
 	u8 *bbuf, *rs_block;
-	u8 want_digest[v->digest_size];
+	u8 want_digest[HASH_MAX_DIGESTSIZE];
 	unsigned n, k;
 
 	if (neras)
 		*neras = 0;
 
+	if (WARN_ON(v->digest_size > sizeof(want_digest)))
+		return -EINVAL;
+
 	/*
 	 * read each of the rsn data blocks that are part of the RS block, and
 	 * interleave contents to available bufs
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
index eb7aef6..32b3e97 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
@@ -394,7 +394,7 @@
 	strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN);
 	client->usecase_ndx = VOTE_INDEX_DISABLE;
 	client->id = id;
-	SDEROT_DBG("bus vote client %s created:%p id :%d\n", client_name,
+	SDEROT_DBG("bus vote client %s created:%pK id :%d\n", client_name,
 		client, id);
 	id++;
 	list_add(&client->list, &sde_res->reg_bus_clist);
@@ -410,7 +410,7 @@
 	if (!client) {
 		SDEROT_ERR("reg bus vote: invalid client handle\n");
 	} else {
-		SDEROT_DBG("bus vote client %s destroyed:%p id:%u\n",
+		SDEROT_DBG("bus vote client %s destroyed:%pK id:%u\n",
 			client->name, client, client->id);
 		mutex_lock(&sde_res->reg_bus_lock);
 		list_del_init(&client->list);
@@ -837,7 +837,7 @@
 		SDEROT_ERR("unable to map SDE ROT VBIF base\n");
 		goto probe_done;
 	}
-	SDEROT_DBG("SDE ROT VBIF HW Base addr=%p len=0x%x\n",
+	SDEROT_DBG("SDE ROT VBIF HW Base addr=%pK len=0x%x\n",
 			mdata->vbif_nrt_io.base, mdata->vbif_nrt_io.len);
 
 	rc = sde_mdp_parse_dt_misc(pdev, mdata);
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 0c43fa4..a9e358c 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -496,7 +496,7 @@
 {
 	if (entry->input_fence) {
 		SDEROT_EVTLOG(entry->input_fence, 1111);
-		SDEROT_DBG("sys_fence_put i:%p\n", entry->input_fence);
+		SDEROT_DBG("sys_fence_put i:%pK\n", entry->input_fence);
 		sde_rotator_put_sync_fence(entry->input_fence);
 		entry->input_fence = NULL;
 	}
@@ -507,7 +507,7 @@
 			sde_rotator_resync_timeline(entry->fenceq->timeline);
 
 		SDEROT_EVTLOG(entry->output_fence, 2222);
-		SDEROT_DBG("sys_fence_put o:%p\n", entry->output_fence);
+		SDEROT_DBG("sys_fence_put o:%pK\n", entry->output_fence);
 		sde_rotator_put_sync_fence(entry->output_fence);
 		entry->output_fence = NULL;
 	}
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 82e9648..dd30cbd 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
@@ -353,7 +353,7 @@
 
 		if (*dump_mem) {
 			dump_addr = *dump_mem;
-			pr_info("%s: start_addr:0x%p end_addr:0x%p reg_addr=0x%X\n",
+			pr_info("%s: start_addr:0x%pK end_addr:0x%pK reg_addr=0x%X\n",
 				dump_name, dump_addr, dump_addr + (u32)len * 16,
 				addr);
 		} else {
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 a5176d9..fe9113f 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -2356,7 +2356,7 @@
 		ctx->vbinfo_cap[idx].qbuf_ts = ktime_get();
 		ctx->vbinfo_cap[idx].dqbuf_ts = NULL;
 		SDEDEV_DBG(ctx->rot_dev->dev,
-				"create buffer fence s:%d.%u i:%d f:%p\n",
+				"create buffer fence s:%d.%u i:%d f:%pK\n",
 				ctx->session_id,
 				ctx->vbinfo_cap[idx].fence_ts,
 				idx,
@@ -3045,7 +3045,7 @@
 
 		if (!src_buf || !dst_buf) {
 			SDEDEV_ERR(rot_dev->dev,
-				"null buffer in retire s:%d sb:%p db:%p\n",
+				"null buffer in retire s:%d sb:%pK db:%pK\n",
 				ctx->session_id,
 				src_buf, dst_buf);
 		}
@@ -3334,7 +3334,7 @@
 			dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
 			if (!src_buf || !dst_buf) {
 				SDEDEV_ERR(rot_dev->dev,
-					"null buffer in device run s:%d sb:%p db:%p\n",
+					"null buffer in device run s:%d sb:%pK db:%pK\n",
 					ctx->session_id,
 					src_buf, dst_buf);
 				goto error_process_buffers;
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 e45d010..8148a30 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -972,7 +972,7 @@
 		if (ctx && (ctx->session_id == session_id) &&
 				(ctx->sequence_id == sequence_id)) {
 			SDEROT_DBG(
-				"rotCtx sloti[%d][%d] ==> ctx:%p | session-id:%d | sequence-id:%d\n",
+				"rotCtx sloti[%d][%d] ==> ctx:%pK | session-id:%d | sequence-id:%d\n",
 				q_id, i, ctx, ctx->session_id,
 				ctx->sequence_id);
 			return ctx;
@@ -1001,7 +1001,7 @@
 	if (dbgbuf->dmabuf && (dbgbuf->buflen > 0)) {
 		dma_buf_begin_cpu_access(dbgbuf->dmabuf, DMA_FROM_DEVICE);
 		dbgbuf->vaddr = dma_buf_kmap(dbgbuf->dmabuf, 0);
-		SDEROT_DBG("vaddr mapping: 0x%p/%ld w:%d/h:%d\n",
+		SDEROT_DBG("vaddr mapping: 0x%pK/%ld w:%d/h:%d\n",
 				dbgbuf->vaddr, dbgbuf->buflen,
 				dbgbuf->width, dbgbuf->height);
 	}
@@ -2046,7 +2046,7 @@
 	unsigned long flags;
 
 	if (rot->irq_num >= 0) {
-		SDEROT_DBG("Wait for REGDMA completion, ctx:%p, ts:%X\n",
+		SDEROT_DBG("Wait for REGDMA completion, ctx:%pK, ts:%X\n",
 				ctx, ctx->timestamp);
 		rc = wait_event_timeout(ctx->regdma_waitq,
 				!rot->ops.get_pending_ts(rot, ctx, &swts),
@@ -2230,7 +2230,7 @@
 	}
 
 	data->mapped = true;
-	SDEROT_DBG("swts buffer mapped: %pad/%lx va:%p\n", &data->addr,
+	SDEROT_DBG("swts buffer mapped: %pad/%lx va:%pK\n", &data->addr,
 			data->len, rot->swts_buffer);
 
 	sde_smmu_ctrl(0);
@@ -2450,7 +2450,7 @@
 	if (resinfo->rot->irq_num >= 0)
 		sde_hw_rotator_enable_irq(resinfo->rot);
 
-	SDEROT_DBG("New rotator resource:%p, priority:%d\n",
+	SDEROT_DBG("New rotator resource:%pK, priority:%d\n",
 			resinfo, wb_id);
 
 	return &resinfo->hw;
@@ -2472,7 +2472,7 @@
 	resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw);
 
 	SDEROT_DBG(
-		"Free rotator resource:%p, priority:%d, active:%d, pending:%d\n",
+		"Free rotator resource:%pK, priority:%d, active:%d, pending:%d\n",
 		resinfo, hw->wb_id, atomic_read(&hw->num_active),
 		hw->pending_count);
 
@@ -2535,7 +2535,7 @@
 	sde_hw_rotator_put_ctx(ctx);
 
 	SDEROT_DBG(
-		"New rot CTX:%p, ctxidx:%d, session-id:%d, prio:%d, timestamp:%X, active:%d sbuf:%d\n",
+		"New rot CTX:%pK, ctxidx:%d, session-id:%d, prio:%d, timestamp:%X, active:%d sbuf:%d\n",
 		ctx, sde_hw_rotator_get_regdma_ctxidx(ctx), ctx->session_id,
 		ctx->q_id, ctx->timestamp,
 		atomic_read(&ctx->hwres->num_active),
@@ -2556,7 +2556,7 @@
 		return;
 
 	SDEROT_DBG(
-		"Free rot CTX:%p, ctxidx:%d, session-id:%d, prio:%d, timestamp:%X, active:%d sbuf:%d\n",
+		"Free rot CTX:%pK, ctxidx:%d, session-id:%d, prio:%d, timestamp:%X, active:%d sbuf:%d\n",
 		ctx, sde_hw_rotator_get_regdma_ctxidx(ctx), ctx->session_id,
 		ctx->q_id, ctx->timestamp,
 		atomic_read(&ctx->hwres->num_active),
@@ -3284,7 +3284,7 @@
 			ctx->last_regdma_isr_status = isr;
 			ctx->last_regdma_timestamp  = ts;
 			SDEROT_DBG(
-				"regdma complete: ctx:%p, ts:%X\n", ctx, ts);
+				"regdma complete: ctx:%pK, ts:%X\n", ctx, ts);
 			wake_up_all(&ctx->regdma_waitq);
 
 			ts  = (ts - 1) & SDE_REGDMA_SWTS_MASK;
@@ -3317,8 +3317,9 @@
 					ctx->last_regdma_isr_status = isr;
 					ctx->last_regdma_timestamp  = ts;
 					wake_up_all(&ctx->regdma_waitq);
-					SDEROT_DBG("Wakeup rotctx[%d][%d]:%p\n",
-							i, j, ctx);
+					SDEROT_DBG(
+						"Wakeup rotctx[%d][%d]:%pK\n",
+						i, j, ctx);
 				}
 			}
 		}
@@ -3541,7 +3542,7 @@
 
 					if (ctx) {
 						SPRINT(
-							"rotCtx[%d][%d]:%p\n",
+							"rotCtx[%d][%d]:%pK\n",
 							i, j, ctx);
 						++num_active;
 					}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
index b1cd754c..70316f4 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
@@ -370,7 +370,7 @@
 static inline char __iomem *sde_hw_rotator_get_regdma_segment_base(
 		struct sde_hw_rotator_context *ctx)
 {
-	SDEROT_DBG("regdma base @slot[%d]: %p\n",
+	SDEROT_DBG("regdma base @slot[%d]: %pK\n",
 			sde_hw_rotator_get_regdma_ctxidx(ctx),
 			ctx->regdma_base);
 
@@ -389,7 +389,7 @@
 	u32 idx = sde_hw_rotator_get_regdma_ctxidx(ctx);
 	char __iomem *addr = ctx->regdma_wrptr;
 
-	SDEROT_DBG("regdma slot[%d] ==> %p\n", idx, addr);
+	SDEROT_DBG("regdma slot[%d] ==> %pK\n", idx, addr);
 	return addr;
 }
 
@@ -406,7 +406,7 @@
 	u32 idx = sde_hw_rotator_get_regdma_ctxidx(ctx);
 
 	ctx->regdma_wrptr = wrptr;
-	SDEROT_DBG("regdma slot[%d] <== %p\n", idx, wrptr);
+	SDEROT_DBG("regdma slot[%d] <== %pK\n", idx, wrptr);
 }
 
 /**
@@ -425,7 +425,7 @@
 		list_add_tail(&ctx->list, &rot->sbuf_ctx[ctx->q_id]);
 	spin_unlock_irqrestore(&rot->rotisr_lock, flags);
 
-	SDEROT_DBG("rotCtx[%d][%d] <== ctx:%p | session-id:%d\n",
+	SDEROT_DBG("rotCtx[%d][%d] <== ctx:%pK | session-id:%d\n",
 			 ctx->q_id, idx, ctx, ctx->session_id);
 }
 
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c
index 812f2dd..c25b8dc 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c
@@ -785,7 +785,7 @@
 	}
 
 	if (!IS_ERR_OR_NULL(data->srcp_dma_buf)) {
-		SDEROT_DBG("ion hdl=%p buf=0x%pa\n", data->srcp_dma_buf,
+		SDEROT_DBG("ion hdl=%pK buf=0x%pa\n", data->srcp_dma_buf,
 							&data->addr);
 		if (sde_mdp_is_map_needed(data) && data->mapped) {
 			domain = sde_smmu_get_domain_type(data->flags,
@@ -840,7 +840,7 @@
 	if (sde_mdp_is_map_needed(data)) {
 		domain = sde_smmu_get_domain_type(data->flags, rotator);
 
-		SDEROT_DBG("%d domain=%d ihndl=%p\n",
+		SDEROT_DBG("%d domain=%d ihndl=%pK\n",
 				__LINE__, domain, data->srcp_dma_buf);
 		data->srcp_attachment =
 			sde_smmu_dma_buf_attach(data->srcp_dma_buf, dev,
@@ -973,7 +973,7 @@
 		data->addr += data->offset;
 		data->len -= data->offset;
 
-		SDEROT_DBG("ihdl=%p buf=0x%pa len=0x%lx\n",
+		SDEROT_DBG("ihdl=%pK buf=0x%pa len=0x%lx\n",
 			 data->srcp_dma_buf, &data->addr, data->len);
 	} else {
 		sde_mdp_put_img(data, rotator, dir);
diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c
index e2e95de..234e62b 100644
--- a/drivers/mfd/qcom-spmi-pmic.c
+++ b/drivers/mfd/qcom-spmi-pmic.c
@@ -1,15 +1,5 @@
-/*
- * Copyright (c) 2014, 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2014, 2017-2018, The Linux Foundation. All rights reserved. */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -124,11 +114,23 @@
 	.fast_io	= true,
 };
 
+static const struct regmap_config spmi_regmap_can_sleep_config = {
+	.reg_bits	= 16,
+	.val_bits	= 8,
+	.max_register	= 0xffff,
+	.fast_io	= false,
+};
+
 static int pmic_spmi_probe(struct spmi_device *sdev)
 {
+	struct device_node *root = sdev->dev.of_node;
 	struct regmap *regmap;
 
-	regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config);
+	if (of_property_read_bool(root, "qcom,can-sleep"))
+		regmap = devm_regmap_init_spmi_ext(sdev,
+						&spmi_regmap_can_sleep_config);
+	else
+		regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config);
 	if (IS_ERR(regmap))
 		return PTR_ERR(regmap);
 
diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c
index a205750..7ccdc62 100644
--- a/drivers/net/ppp/ppp_mppe.c
+++ b/drivers/net/ppp/ppp_mppe.c
@@ -95,7 +95,7 @@
  * State for an MPPE (de)compressor.
  */
 struct ppp_mppe_state {
-	struct crypto_skcipher *arc4;
+	struct crypto_sync_skcipher *arc4;
 	struct shash_desc *sha1;
 	unsigned char *sha1_digest;
 	unsigned char master_key[MPPE_MAX_KEY_LEN];
@@ -155,15 +155,15 @@
 static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
 {
 	struct scatterlist sg_in[1], sg_out[1];
-	SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
+	SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
 
-	skcipher_request_set_tfm(req, state->arc4);
+	skcipher_request_set_sync_tfm(req, state->arc4);
 	skcipher_request_set_callback(req, 0, NULL, NULL);
 
 	get_new_key_from_sha(state);
 	if (!initial_key) {
-		crypto_skcipher_setkey(state->arc4, state->sha1_digest,
-				       state->keylen);
+		crypto_sync_skcipher_setkey(state->arc4, state->sha1_digest,
+					    state->keylen);
 		sg_init_table(sg_in, 1);
 		sg_init_table(sg_out, 1);
 		setup_sg(sg_in, state->sha1_digest, state->keylen);
@@ -181,7 +181,8 @@
 		state->session_key[1] = 0x26;
 		state->session_key[2] = 0x9e;
 	}
-	crypto_skcipher_setkey(state->arc4, state->session_key, state->keylen);
+	crypto_sync_skcipher_setkey(state->arc4, state->session_key,
+				    state->keylen);
 	skcipher_request_zero(req);
 }
 
@@ -203,7 +204,7 @@
 		goto out;
 
 
-	state->arc4 = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
+	state->arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
 	if (IS_ERR(state->arc4)) {
 		state->arc4 = NULL;
 		goto out_free;
@@ -250,7 +251,7 @@
 		crypto_free_shash(state->sha1->tfm);
 		kzfree(state->sha1);
 	}
-	crypto_free_skcipher(state->arc4);
+	crypto_free_sync_skcipher(state->arc4);
 	kfree(state);
 out:
 	return NULL;
@@ -266,7 +267,7 @@
 		kfree(state->sha1_digest);
 		crypto_free_shash(state->sha1->tfm);
 		kzfree(state->sha1);
-		crypto_free_skcipher(state->arc4);
+		crypto_free_sync_skcipher(state->arc4);
 		kfree(state);
 	}
 }
@@ -366,7 +367,7 @@
 	      int isize, int osize)
 {
 	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
-	SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
+	SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
 	int proto;
 	int err;
 	struct scatterlist sg_in[1], sg_out[1];
@@ -426,7 +427,7 @@
 	setup_sg(sg_in, ibuf, isize);
 	setup_sg(sg_out, obuf, osize);
 
-	skcipher_request_set_tfm(req, state->arc4);
+	skcipher_request_set_sync_tfm(req, state->arc4);
 	skcipher_request_set_callback(req, 0, NULL, NULL);
 	skcipher_request_set_crypt(req, sg_in, sg_out, isize, NULL);
 	err = crypto_skcipher_encrypt(req);
@@ -480,7 +481,7 @@
 		int osize)
 {
 	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
-	SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
+	SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
 	unsigned ccount;
 	int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED;
 	struct scatterlist sg_in[1], sg_out[1];
@@ -615,7 +616,7 @@
 	setup_sg(sg_in, ibuf, 1);
 	setup_sg(sg_out, obuf, 1);
 
-	skcipher_request_set_tfm(req, state->arc4);
+	skcipher_request_set_sync_tfm(req, state->arc4);
 	skcipher_request_set_callback(req, 0, NULL, NULL);
 	skcipher_request_set_crypt(req, sg_in, sg_out, 1, NULL);
 	if (crypto_skcipher_decrypt(req)) {
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 29032ca..22c6f8f8 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -12,4 +12,13 @@
 	  This should be enabled to support audio & video over HDMI or
 	  DP for hot pluggable sink devices.
 
+config QPNP_REVID
+	tristate "QPNP Revision ID Peripheral"
+	depends on SPMI
+	help
+	  Say 'y' here to include support for the Qualcomm Technologies, Inc.
+	  QPNP REVID peripheral. REVID prints out the PMIC type and revision
+	  numbers in the kernel log along with the PMIC option status. The PMIC
+	  type is mapped to a QTI chip part number and logged as well.
+
 endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index 6da4b4b..4c286fa 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -3,4 +3,6 @@
 #
 # Makefile for the MSM specific device drivers.
 #
+
 obj-$(CONFIG_MSM_EXT_DISPLAY) += msm_ext_display.o
+obj-$(CONFIG_QPNP_REVID) += qpnp-revid.o
diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c
new file mode 100644
index 0000000..f4010aa
--- /dev/null
+++ b/drivers/platform/msm/qpnp-revid.c
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ */
+
+#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/qpnp/qpnp-revid.h>
+#include <linux/of.h>
+
+#define REVID_REVISION1	0x0
+#define REVID_REVISION2	0x1
+#define REVID_REVISION3	0x2
+#define REVID_REVISION4	0x3
+#define REVID_TYPE	0x4
+#define REVID_SUBTYPE	0x5
+#define REVID_STATUS1	0x8
+#define REVID_SPARE_0	0x60
+#define REVID_TP_REV	0xf1
+#define REVID_FAB_ID	0xf2
+
+#define QPNP_REVID_DEV_NAME "qcom,qpnp-revid"
+
+static const char *const pmic_names[] = {
+	[0] =	"Unknown PMIC",
+	[PM8941_SUBTYPE] = "PM8941",
+	[PM8841_SUBTYPE] = "PM8841",
+	[PM8019_SUBTYPE] = "PM8019",
+	[PM8226_SUBTYPE] = "PM8226",
+	[PM8110_SUBTYPE] = "PM8110",
+	[PMA8084_SUBTYPE] = "PMA8084",
+	[PMI8962_SUBTYPE] = "PMI8962",
+	[PMD9635_SUBTYPE] = "PMD9635",
+	[PM8994_SUBTYPE] = "PM8994",
+	[PMI8994_SUBTYPE] = "PMI8994",
+	[PM8916_SUBTYPE] = "PM8916",
+	[PM8004_SUBTYPE] = "PM8004",
+	[PM8909_SUBTYPE] = "PM8909",
+	[PM2433_SUBTYPE] = "PM2433",
+	[PMD9655_SUBTYPE] = "PMD9655",
+	[PM8950_SUBTYPE] = "PM8950",
+	[PMI8950_SUBTYPE] = "PMI8950",
+	[PMK8001_SUBTYPE] = "PMK8001",
+	[PMI8996_SUBTYPE] = "PMI8996",
+	[PM8998_SUBTYPE] = "PM8998",
+	[PMI8998_SUBTYPE] = "PMI8998",
+	[PM8005_SUBTYPE] = "PM8005",
+	[PM8937_SUBTYPE] = "PM8937",
+	[PM660L_SUBTYPE] = "PM660L",
+	[PM660_SUBTYPE] = "PM660",
+	[PMI632_SUBTYPE] = "PMI632",
+	[PMI8937_SUBTYPE] = "PMI8937",
+	[PM8150_SUBTYPE] = "PM8150",
+	[PM8150B_SUBTYPE] = "PM8150B",
+	[PM8150L_SUBTYPE] = "PM8150L",
+	[PM6150_SUBTYPE] = "PM6150",
+};
+
+struct revid_chip {
+	struct list_head	link;
+	struct device_node	*dev_node;
+	struct pmic_revid_data	data;
+};
+
+static LIST_HEAD(revid_chips);
+static DEFINE_MUTEX(revid_chips_lock);
+
+static const struct of_device_id qpnp_revid_match_table[] = {
+	{ .compatible = QPNP_REVID_DEV_NAME },
+	{}
+};
+
+static u8 qpnp_read_byte(struct regmap *regmap, u16 addr)
+{
+	int rc;
+	int val;
+
+	rc = regmap_read(regmap, addr, &val);
+	if (rc) {
+		pr_err("read failed rc=%d\n", rc);
+		return 0;
+	}
+	return (u8)val;
+}
+
+/**
+ * get_revid_data - Return the revision information of PMIC
+ * @dev_node: Pointer to the revid peripheral of the PMIC for which
+ *		revision information is seeked
+ *
+ * CONTEXT: Should be called in non atomic context
+ *
+ * RETURNS: pointer to struct pmic_revid_data filled with the information
+ *		about the PMIC revision
+ */
+struct pmic_revid_data *get_revid_data(struct device_node *dev_node)
+{
+	struct revid_chip *revid_chip;
+
+	if (!dev_node)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&revid_chips_lock);
+	list_for_each_entry(revid_chip, &revid_chips, link) {
+		if (dev_node == revid_chip->dev_node) {
+			mutex_unlock(&revid_chips_lock);
+			return &revid_chip->data;
+		}
+	}
+	mutex_unlock(&revid_chips_lock);
+	return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL(get_revid_data);
+
+#define PM8941_PERIPHERAL_SUBTYPE	0x01
+#define PM8226_PERIPHERAL_SUBTYPE	0x04
+#define PMD9655_PERIPHERAL_SUBTYPE	0x0F
+#define PMI8950_PERIPHERAL_SUBTYPE	0x11
+#define PMI8937_PERIPHERAL_SUBTYPE	0x37
+static size_t build_pmic_string(char *buf, size_t n, int sid,
+		u8 subtype, u8 rev1, u8 rev2, u8 rev3, u8 rev4)
+{
+	size_t pos = 0;
+	/*
+	 * In early versions of PM8941 and PM8226, the major revision number
+	 * started incrementing from 0 (eg 0 = v1.0, 1 = v2.0).
+	 * Increment the major revision number here if the chip is an early
+	 * version of PM8941 or PM8226.
+	 */
+	if (((int)subtype == PM8941_PERIPHERAL_SUBTYPE
+			|| (int)subtype == PM8226_PERIPHERAL_SUBTYPE)
+			&& rev4 < 0x02)
+		rev4++;
+
+	pos += snprintf(buf + pos, n - pos, "PMIC@SID%d", sid);
+	if (subtype >= ARRAY_SIZE(pmic_names) || subtype == 0)
+		pos += snprintf(buf + pos, n - pos, ": %s (subtype: 0x%02X)",
+				pmic_names[0], subtype);
+	else
+		pos += snprintf(buf + pos, n - pos, ": %s",
+				pmic_names[subtype]);
+	pos += snprintf(buf + pos, n - pos, " v%d.%d", rev4, rev3);
+	if (rev2 || rev1)
+		pos += snprintf(buf + pos, n - pos, ".%d", rev2);
+	if (rev1)
+		pos += snprintf(buf + pos, n - pos, ".%d", rev1);
+	return pos;
+}
+
+#define PMIC_PERIPHERAL_TYPE		0x51
+#define PMIC_STRING_MAXLENGTH		80
+static int qpnp_revid_probe(struct platform_device *pdev)
+{
+	u8 rev1, rev2, rev3, rev4, pmic_type, pmic_subtype, pmic_status;
+	u8 option1, option2, option3, option4, spare0;
+	unsigned int base;
+	int rc, fab_id, tp_rev;
+	char pmic_string[PMIC_STRING_MAXLENGTH] = {'\0'};
+	struct revid_chip *revid_chip;
+	struct regmap *regmap;
+
+	regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!regmap) {
+		dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node, "reg", &base);
+	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;
+	}
+	pmic_type = qpnp_read_byte(regmap, base + REVID_TYPE);
+	if (pmic_type != PMIC_PERIPHERAL_TYPE) {
+		pr_err("Invalid REVID peripheral type: %02X\n", pmic_type);
+		return -EINVAL;
+	}
+
+	rev1 = qpnp_read_byte(regmap, base + REVID_REVISION1);
+	rev2 = qpnp_read_byte(regmap, base + REVID_REVISION2);
+	rev3 = qpnp_read_byte(regmap, base + REVID_REVISION3);
+	rev4 = qpnp_read_byte(regmap, base + REVID_REVISION4);
+
+	pmic_subtype = qpnp_read_byte(regmap, base + REVID_SUBTYPE);
+	if (pmic_subtype != PMD9655_PERIPHERAL_SUBTYPE)
+		pmic_status = qpnp_read_byte(regmap, base + REVID_STATUS1);
+	else
+		pmic_status = 0;
+
+	/* special case for PMI8937 */
+	if (pmic_subtype == PMI8950_PERIPHERAL_SUBTYPE) {
+		/* read spare register */
+		spare0 = qpnp_read_byte(regmap, base + REVID_SPARE_0);
+		if (spare0)
+			pmic_subtype = PMI8937_PERIPHERAL_SUBTYPE;
+	}
+
+	if (of_property_read_bool(pdev->dev.of_node, "qcom,fab-id-valid"))
+		fab_id = qpnp_read_byte(regmap, base + REVID_FAB_ID);
+	else
+		fab_id = -EINVAL;
+
+	if (of_property_read_bool(pdev->dev.of_node, "qcom,tp-rev-valid"))
+		tp_rev = qpnp_read_byte(regmap, base + REVID_TP_REV);
+	else
+		tp_rev = -EINVAL;
+
+	revid_chip = devm_kzalloc(&pdev->dev, sizeof(struct revid_chip),
+						GFP_KERNEL);
+	if (!revid_chip)
+		return -ENOMEM;
+
+	revid_chip->dev_node = pdev->dev.of_node;
+	revid_chip->data.rev1 = rev1;
+	revid_chip->data.rev2 = rev2;
+	revid_chip->data.rev3 = rev3;
+	revid_chip->data.rev4 = rev4;
+	revid_chip->data.pmic_subtype = pmic_subtype;
+	revid_chip->data.pmic_type = pmic_type;
+	revid_chip->data.fab_id = fab_id;
+	revid_chip->data.tp_rev = tp_rev;
+
+	if (pmic_subtype < ARRAY_SIZE(pmic_names))
+		revid_chip->data.pmic_name = pmic_names[pmic_subtype];
+	else
+		revid_chip->data.pmic_name = pmic_names[0];
+
+	mutex_lock(&revid_chips_lock);
+	list_add(&revid_chip->link, &revid_chips);
+	mutex_unlock(&revid_chips_lock);
+
+	option1 = pmic_status & 0x3;
+	option2 = (pmic_status >> 2) & 0x3;
+	option3 = (pmic_status >> 4) & 0x3;
+	option4 = (pmic_status >> 6) & 0x3;
+
+	build_pmic_string(pmic_string, PMIC_STRING_MAXLENGTH,
+			  to_spmi_device(pdev->dev.parent)->usid,
+			pmic_subtype, rev1, rev2, rev3, rev4);
+	pr_info("%s options: %d, %d, %d, %d\n",
+			pmic_string, option1, option2, option3, option4);
+	return 0;
+}
+
+static struct platform_driver qpnp_revid_driver = {
+	.probe	= qpnp_revid_probe,
+	.driver	= {
+		.name		= QPNP_REVID_DEV_NAME,
+		.of_match_table	= qpnp_revid_match_table,
+	},
+};
+
+static int __init qpnp_revid_init(void)
+{
+	return platform_driver_register(&qpnp_revid_driver);
+}
+
+static void __exit qpnp_revid_exit(void)
+{
+	return platform_driver_unregister(&qpnp_revid_driver);
+}
+
+subsys_initcall(qpnp_revid_init);
+module_exit(qpnp_revid_exit);
+
+MODULE_DESCRIPTION("QPNP REVID DRIVER");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" QPNP_REVID_DEV_NAME);
diff --git a/drivers/soc/qcom/service-locator-private.h b/drivers/soc/qcom/service-locator-private.h
index dcec83b..3142740 100644
--- a/drivers/soc/qcom/service-locator-private.h
+++ b/drivers/soc/qcom/service-locator-private.h
@@ -89,7 +89,7 @@
 	.data_type = QMI_EOTI,	\
 	.elem_len  = 0,		\
 	.elem_size = 0,		\
-	.is_array  = NO_ARRAY,	\
+	.array_type  = NO_ARRAY,	\
 	.tlv_type  = 0x00,	\
 	.offset    = 0,		\
 	.ei_array  = NULL,	\
@@ -100,7 +100,7 @@
 		.data_type      = QMI_STRING,
 		.elem_len       = QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1,
 		.elem_size      = sizeof(char),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0,
 		.offset         = offsetof(struct servreg_loc_entry_v01,
 					   name),
@@ -109,7 +109,7 @@
 		.data_type      = QMI_UNSIGNED_4_BYTE,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint32_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0,
 		.offset         = offsetof(struct servreg_loc_entry_v01,
 					   instance_id),
@@ -118,7 +118,7 @@
 		.data_type      = QMI_UNSIGNED_1_BYTE,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint8_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0,
 		.offset         = offsetof(struct servreg_loc_entry_v01,
 					   service_data_valid),
@@ -127,7 +127,7 @@
 		.data_type      = QMI_UNSIGNED_4_BYTE,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint32_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0,
 		.offset         = offsetof(struct servreg_loc_entry_v01,
 					   service_data),
@@ -140,7 +140,7 @@
 		.data_type      = QMI_OPT_FLAG,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint8_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x10,
 		.offset         = offsetof(struct
 				qmi_servreg_loc_indication_register_req_msg_v01,
@@ -150,7 +150,7 @@
 		.data_type      = QMI_UNSIGNED_1_BYTE,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint8_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x10,
 		.offset         = offsetof(struct
 				qmi_servreg_loc_indication_register_req_msg_v01,
@@ -164,7 +164,7 @@
 		.data_type      = QMI_STRUCT,
 		.elem_len       = 1,
 		.elem_size      = sizeof(struct qmi_response_type_v01),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x02,
 		.offset         = offsetof(struct
 			qmi_servreg_loc_indication_register_resp_msg_v01,
@@ -179,7 +179,7 @@
 		.data_type      = QMI_STRING,
 		.elem_len       = QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1,
 		.elem_size      = sizeof(char),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x01,
 		.offset         = offsetof(struct
 				qmi_servreg_loc_get_domain_list_req_msg_v01,
@@ -189,7 +189,7 @@
 		.data_type      = QMI_OPT_FLAG,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint8_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x10,
 		.offset         = offsetof(struct
 				qmi_servreg_loc_get_domain_list_req_msg_v01,
@@ -199,7 +199,7 @@
 		.data_type      = QMI_UNSIGNED_4_BYTE,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint32_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x10,
 		.offset         = offsetof(struct
 				qmi_servreg_loc_get_domain_list_req_msg_v01,
@@ -213,7 +213,7 @@
 		.data_type      = QMI_STRUCT,
 		.elem_len       = 1,
 		.elem_size      = sizeof(struct qmi_response_type_v01),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x02,
 		.offset         = offsetof(struct
 				qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -224,7 +224,7 @@
 		.data_type      = QMI_OPT_FLAG,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint8_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x10,
 		.offset         = offsetof(struct
 				qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -234,7 +234,7 @@
 		.data_type      = QMI_UNSIGNED_2_BYTE,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint16_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x10,
 		.offset         = offsetof(struct
 				qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -244,7 +244,7 @@
 		.data_type      = QMI_OPT_FLAG,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint8_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x11,
 		.offset         = offsetof(struct
 				qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -254,7 +254,7 @@
 		.data_type      = QMI_UNSIGNED_2_BYTE,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint16_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x11,
 		.offset         = offsetof(struct
 				qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -264,7 +264,7 @@
 		.data_type      = QMI_OPT_FLAG,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint8_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x12,
 		.offset         = offsetof(struct
 				qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -274,7 +274,7 @@
 		.data_type      = QMI_DATA_LEN,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint8_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x12,
 		.offset         = offsetof(struct
 				qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -284,7 +284,7 @@
 		.data_type      = QMI_STRUCT,
 		.elem_len       = QMI_SERVREG_LOC_LIST_LENGTH_V01,
 		.elem_size      = sizeof(struct servreg_loc_entry_v01),
-		.is_array       = VAR_LEN_ARRAY,
+		.array_type       = VAR_LEN_ARRAY,
 		.tlv_type       = 0x12,
 		.offset         = offsetof(struct
 				qmi_servreg_loc_get_domain_list_resp_msg_v01,
@@ -299,7 +299,7 @@
 		.data_type      = QMI_STRING,
 		.elem_len       = QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1,
 		.elem_size      = sizeof(char),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x01,
 		.offset         = offsetof(struct
 			qmi_servreg_loc_register_service_list_req_msg_v01,
@@ -309,7 +309,7 @@
 		.data_type      = QMI_DATA_LEN,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint8_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x02,
 		.offset         = offsetof(struct
 			qmi_servreg_loc_register_service_list_req_msg_v01,
@@ -319,7 +319,7 @@
 		.data_type      = QMI_STRUCT,
 		.elem_len       = QMI_SERVREG_LOC_LIST_LENGTH_V01,
 		.elem_size      = sizeof(struct servreg_loc_entry_v01),
-		.is_array       = VAR_LEN_ARRAY,
+		.array_type       = VAR_LEN_ARRAY,
 		.tlv_type       = 0x02,
 		.offset         = offsetof(struct
 			qmi_servreg_loc_register_service_list_req_msg_v01,
@@ -334,7 +334,7 @@
 		.data_type      = QMI_STRUCT,
 		.elem_len       = 1,
 		.elem_size      = sizeof(struct qmi_response_type_v01),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x02,
 		.offset         = offsetof(struct
 			qmi_servreg_loc_register_service_list_resp_msg_v01,
diff --git a/drivers/soc/qcom/service-notifier-private.h b/drivers/soc/qcom/service-notifier-private.h
index 26070f7..fb3d75b 100644
--- a/drivers/soc/qcom/service-notifier-private.h
+++ b/drivers/soc/qcom/service-notifier-private.h
@@ -89,7 +89,7 @@
 		.data_type      = QMI_UNSIGNED_1_BYTE,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint8_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x01,
 		.offset         = offsetof(struct
 				qmi_servreg_notif_register_listener_req_msg_v01,
@@ -99,7 +99,7 @@
 		.data_type      = QMI_STRING,
 		.elem_len       = QMI_SERVREG_NOTIF_NAME_LENGTH_V01 + 1,
 		.elem_size      = sizeof(char),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x02,
 		.offset         = offsetof(struct
 				qmi_servreg_notif_register_listener_req_msg_v01,
@@ -107,8 +107,8 @@
 	},
 	{
 		.data_type      = QMI_EOTI,
-		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.array_type       = NO_ARRAY,
+		.array_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -117,7 +117,7 @@
 		.data_type      = QMI_STRUCT,
 		.elem_len       = 1,
 		.elem_size      = sizeof(struct qmi_response_type_v01),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x02,
 		.offset         = offsetof(struct
 			qmi_servreg_notif_register_listener_resp_msg_v01,
@@ -128,7 +128,7 @@
 		.data_type      = QMI_OPT_FLAG,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint8_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x10,
 		.offset         = offsetof(struct
 			qmi_servreg_notif_register_listener_resp_msg_v01,
@@ -139,7 +139,7 @@
 		.elem_len       = 1,
 		.elem_size      = sizeof(
 			enum qmi_servreg_notif_service_state_enum_type_v01),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x10,
 		.offset         = offsetof(struct
 			qmi_servreg_notif_register_listener_resp_msg_v01,
@@ -147,8 +147,8 @@
 	},
 	{
 		.data_type      = QMI_EOTI,
-		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.array_type       = NO_ARRAY,
+		.array_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -157,7 +157,7 @@
 		.data_type      = QMI_STRING,
 		.elem_len       = QMI_SERVREG_NOTIF_NAME_LENGTH_V01 + 1,
 		.elem_size      = sizeof(char),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x01,
 		.offset         = offsetof(struct
 				qmi_servreg_notif_query_state_req_msg_v01,
@@ -165,8 +165,8 @@
 	},
 	{
 		.data_type      = QMI_EOTI,
-		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.array_type       = NO_ARRAY,
+		.array_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -175,7 +175,7 @@
 		.data_type      = QMI_STRUCT,
 		.elem_len       = 1,
 		.elem_size      = sizeof(struct qmi_response_type_v01),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x02,
 		.offset         = offsetof(struct
 				qmi_servreg_notif_query_state_resp_msg_v01,
@@ -186,7 +186,7 @@
 		.data_type      = QMI_OPT_FLAG,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint8_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x10,
 		.offset         = offsetof(struct
 				qmi_servreg_notif_query_state_resp_msg_v01,
@@ -197,7 +197,7 @@
 		.elem_len       = 1,
 		.elem_size      = sizeof(enum
 				qmi_servreg_notif_service_state_enum_type_v01),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x10,
 		.offset         = offsetof(struct
 				qmi_servreg_notif_query_state_resp_msg_v01,
@@ -205,8 +205,8 @@
 	},
 	{
 		.data_type      = QMI_EOTI,
-		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.array_type       = NO_ARRAY,
+		.array_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -216,7 +216,7 @@
 		.elem_len       = 1,
 		.elem_size      = sizeof(enum
 				qmi_servreg_notif_service_state_enum_type_v01),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x01,
 		.offset         = offsetof(struct
 				qmi_servreg_notif_state_updated_ind_msg_v01,
@@ -226,7 +226,7 @@
 		.data_type      = QMI_STRING,
 		.elem_len       = QMI_SERVREG_NOTIF_NAME_LENGTH_V01 + 1,
 		.elem_size      = sizeof(char),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x02,
 		.offset         = offsetof(struct
 				qmi_servreg_notif_state_updated_ind_msg_v01,
@@ -236,7 +236,7 @@
 		.data_type      = QMI_UNSIGNED_2_BYTE,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint16_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x03,
 		.offset         = offsetof(struct
 				qmi_servreg_notif_state_updated_ind_msg_v01,
@@ -244,8 +244,8 @@
 	},
 	{
 		.data_type      = QMI_EOTI,
-		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.array_type       = NO_ARRAY,
+		.array_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -254,7 +254,7 @@
 		.data_type      = QMI_STRING,
 		.elem_len       = QMI_SERVREG_NOTIF_NAME_LENGTH_V01 + 1,
 		.elem_size      = sizeof(char),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x01,
 		.offset         = offsetof(struct
 				qmi_servreg_notif_set_ack_req_msg_v01,
@@ -264,7 +264,7 @@
 		.data_type      = QMI_UNSIGNED_2_BYTE,
 		.elem_len       = 1,
 		.elem_size      = sizeof(uint16_t),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x02,
 		.offset         = offsetof(struct
 				qmi_servreg_notif_set_ack_req_msg_v01,
@@ -272,8 +272,8 @@
 	},
 	{
 		.data_type      = QMI_EOTI,
-		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.array_type       = NO_ARRAY,
+		.array_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -282,7 +282,7 @@
 		.data_type      = QMI_STRUCT,
 		.elem_len       = 1,
 		.elem_size      = sizeof(struct qmi_response_type_v01),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x02,
 		.offset         = offsetof(struct
 				qmi_servreg_notif_set_ack_resp_msg_v01,
@@ -291,8 +291,8 @@
 	},
 	{
 		.data_type      = QMI_EOTI,
-		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.array_type       = NO_ARRAY,
+		.array_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -301,7 +301,7 @@
 		.data_type      = QMI_STRING,
 		.elem_len       = QMI_SERVREG_NOTIF_NAME_LENGTH_V01 + 1,
 		.elem_size      = sizeof(char),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x01,
 		.offset         = offsetof(struct
 				qmi_servreg_notif_restart_pd_req_msg_v01,
@@ -309,8 +309,8 @@
 	},
 	{
 		.data_type      = QMI_EOTI,
-		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.array_type       = NO_ARRAY,
+		.array_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -319,7 +319,7 @@
 		.data_type      = QMI_STRUCT,
 		.elem_len       = 1,
 		.elem_size      = sizeof(struct qmi_response_type_v01),
-		.is_array       = NO_ARRAY,
+		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x02,
 		.offset         = offsetof(struct
 				qmi_servreg_notif_restart_pd_resp_msg_v01,
@@ -328,8 +328,8 @@
 	},
 	{
 		.data_type      = QMI_EOTI,
-		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.array_type       = NO_ARRAY,
+		.array_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 #endif
diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
index 0d3b70b..633632a 100644
--- a/drivers/spmi/Kconfig
+++ b/drivers/spmi/Kconfig
@@ -24,4 +24,14 @@
 	  This is required for communicating with Qualcomm PMICs and
 	  other devices that have the SPMI interface.
 
+config SPMI_MSM_PMIC_ARB_DEBUG
+	tristate "QTI SPMI Debug Controller (PMIC Arbiter)"
+	depends on ARCH_QCOM || COMPILE_TEST
+	depends on HAS_IOMEM
+	help
+	  If you say yes to this option, support will be included for the
+	  built-in SPMI PMIC Arbiter debug interface on Qualcomm Technologies,
+	  Inc. (QTI) MSM family processors.  This feature is available on chips
+	  with PMIC arbiter version 5 and above.
+
 endif
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
index fc75104..4f20815 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -4,3 +4,4 @@
 obj-$(CONFIG_SPMI)	+= spmi.o
 
 obj-$(CONFIG_SPMI_MSM_PMIC_ARB)	+= spmi-pmic-arb.o
+obj-$(CONFIG_SPMI_MSM_PMIC_ARB_DEBUG)	+= spmi-pmic-arb-debug.o
diff --git a/drivers/spmi/spmi-pmic-arb-debug.c b/drivers/spmi/spmi-pmic-arb-debug.c
new file mode 100644
index 0000000..ce34687
--- /dev/null
+++ b/drivers/spmi/spmi-pmic-arb-debug.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+
+/* PMIC Arbiter debug register offsets */
+#define PMIC_ARB_DEBUG_CMD0		0x00
+#define PMIC_ARB_DEBUG_CMD1		0x04
+#define PMIC_ARB_DEBUG_CMD2		0x08
+#define PMIC_ARB_DEBUG_CMD3		0x0C
+#define PMIC_ARB_DEBUG_STATUS		0x14
+#define PMIC_ARB_DEBUG_WDATA(n)		(0x18 + 4 * (n))
+#define PMIC_ARB_DEBUG_RDATA(n)		(0x38 + 4 * (n))
+
+/* Transaction status flag bits */
+enum pmic_arb_chnl_status {
+	PMIC_ARB_STATUS_DONE		= BIT(0),
+	PMIC_ARB_STATUS_FAILURE		= BIT(1),
+	PMIC_ARB_STATUS_DENIED		= BIT(2),
+	PMIC_ARB_STATUS_DROPPED		= BIT(3),
+};
+
+/* Command Opcodes */
+enum pmic_arb_cmd_op_code {
+	PMIC_ARB_OP_EXT_WRITEL		= 0,
+	PMIC_ARB_OP_EXT_READL		= 1,
+	PMIC_ARB_OP_EXT_WRITE		= 2,
+	PMIC_ARB_OP_RESET		= 3,
+	PMIC_ARB_OP_SLEEP		= 4,
+	PMIC_ARB_OP_SHUTDOWN		= 5,
+	PMIC_ARB_OP_WAKEUP		= 6,
+	PMIC_ARB_OP_AUTHENTICATE	= 7,
+	PMIC_ARB_OP_MSTR_READ		= 8,
+	PMIC_ARB_OP_MSTR_WRITE		= 9,
+	PMIC_ARB_OP_EXT_READ		= 13,
+	PMIC_ARB_OP_WRITE		= 14,
+	PMIC_ARB_OP_READ		= 15,
+	PMIC_ARB_OP_ZERO_WRITE		= 16,
+};
+
+#define PMIC_ARB_TIMEOUT_US		100
+#define PMIC_ARB_MAX_TRANS_BYTES	8
+#define PMIC_ARB_MAX_SID		0xF
+
+/**
+ * spmi_pmic_arb_debug - SPMI PMIC Arbiter debug object
+ *
+ * @addr:		base address of SPMI PMIC arbiter debug module
+ * @lock:		lock to synchronize accesses.
+ */
+struct spmi_pmic_arb_debug {
+	void __iomem		*addr;
+	raw_spinlock_t		lock;
+};
+
+static inline void pmic_arb_debug_write(struct spmi_pmic_arb_debug *pa,
+				u32 offset, u32 val)
+{
+	writel_relaxed(val, pa->addr + offset);
+}
+
+static inline u32 pmic_arb_debug_read(struct spmi_pmic_arb_debug *pa,
+				u32 offset)
+{
+	return readl_relaxed(pa->addr + offset);
+}
+
+/* pa->lock must be held by the caller. */
+static int pmic_arb_debug_wait_for_done(struct spmi_controller *ctrl)
+{
+	struct spmi_pmic_arb_debug *pa = spmi_controller_get_drvdata(ctrl);
+	u32 status = 0;
+	u32 timeout = PMIC_ARB_TIMEOUT_US;
+
+	while (timeout--) {
+		status = pmic_arb_debug_read(pa, PMIC_ARB_DEBUG_STATUS);
+
+		if (status & PMIC_ARB_STATUS_DONE) {
+			if (status & PMIC_ARB_STATUS_DENIED) {
+				dev_err(&ctrl->dev, "%s: transaction denied (0x%x)\n",
+					__func__, status);
+				return -EPERM;
+			}
+
+			if (status & PMIC_ARB_STATUS_FAILURE) {
+				dev_err(&ctrl->dev, "%s: transaction failed (0x%x)\n",
+					__func__, status);
+				return -EIO;
+			}
+
+			if (status & PMIC_ARB_STATUS_DROPPED) {
+				dev_err(&ctrl->dev, "%s: transaction dropped (0x%x)\n",
+					__func__, status);
+				return -EIO;
+			}
+
+			return 0;
+		}
+		udelay(1);
+	}
+
+	dev_err(&ctrl->dev, "%s: timeout, status 0x%x\n", __func__, status);
+	return -ETIMEDOUT;
+}
+
+/* pa->lock must be held by the caller. */
+static int pmic_arb_debug_issue_command(struct spmi_controller *ctrl, u8 opc,
+				u8 sid, u16 addr, size_t len)
+{
+	struct spmi_pmic_arb_debug *pa = spmi_controller_get_drvdata(ctrl);
+	u16 pid       = (addr >> 8) & 0xFF;
+	u16 offset    = addr & 0xFF;
+	u8 byte_count = len - 1;
+
+	if (byte_count >= PMIC_ARB_MAX_TRANS_BYTES) {
+		dev_err(&ctrl->dev, "pmic-arb supports 1 to %d bytes per transaction, but %zu requested\n",
+			PMIC_ARB_MAX_TRANS_BYTES, len);
+		return  -EINVAL;
+	}
+
+	if (sid > PMIC_ARB_MAX_SID) {
+		dev_err(&ctrl->dev, "pmic-arb supports sid 0 to %u, but %u requested\n",
+			PMIC_ARB_MAX_SID, sid);
+		return  -EINVAL;
+	}
+
+	pmic_arb_debug_write(pa, PMIC_ARB_DEBUG_CMD3, offset);
+	pmic_arb_debug_write(pa, PMIC_ARB_DEBUG_CMD2, pid);
+	pmic_arb_debug_write(pa, PMIC_ARB_DEBUG_CMD1, (byte_count << 4) | sid);
+
+	/* Start the transaction */
+	pmic_arb_debug_write(pa, PMIC_ARB_DEBUG_CMD0, opc << 1);
+
+	return pmic_arb_debug_wait_for_done(ctrl);
+}
+
+/* Non-data command */
+static int pmic_arb_debug_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
+{
+	dev_dbg(&ctrl->dev, "cmd op:0x%x sid:%d\n", opc, sid);
+
+	/* Check for valid non-data command */
+	if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP)
+		return -EINVAL;
+
+	return -EOPNOTSUPP;
+}
+
+static int pmic_arb_debug_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
+				u16 addr, u8 *buf, size_t len)
+{
+	struct spmi_pmic_arb_debug *pa = spmi_controller_get_drvdata(ctrl);
+	unsigned long flags;
+	int i, rc;
+
+	/* Check the opcode */
+	if (opc >= 0x60 && opc <= 0x7F)
+		opc = PMIC_ARB_OP_READ;
+	else if (opc >= 0x20 && opc <= 0x2F)
+		opc = PMIC_ARB_OP_EXT_READ;
+	else if (opc >= 0x38 && opc <= 0x3F)
+		opc = PMIC_ARB_OP_EXT_READL;
+	else
+		return -EINVAL;
+
+	raw_spin_lock_irqsave(&pa->lock, flags);
+
+	rc = pmic_arb_debug_issue_command(ctrl, opc, sid, addr, len);
+	if (rc)
+		goto done;
+
+	/* Read data from FIFO */
+	for (i = 0; i < len; i++)
+		buf[i] = pmic_arb_debug_read(pa, PMIC_ARB_DEBUG_RDATA(i));
+done:
+	raw_spin_unlock_irqrestore(&pa->lock, flags);
+
+	return rc;
+}
+
+static int pmic_arb_debug_write_cmd(struct spmi_controller *ctrl, u8 opc,
+				u8 sid, u16 addr, const u8 *buf, size_t len)
+{
+	struct spmi_pmic_arb_debug *pa = spmi_controller_get_drvdata(ctrl);
+	unsigned long flags;
+	int i, rc;
+
+	if (len > PMIC_ARB_MAX_TRANS_BYTES) {
+		dev_err(&ctrl->dev, "pmic-arb supports 1 to %d bytes per transaction, but %zu requested\n",
+			PMIC_ARB_MAX_TRANS_BYTES, len);
+		return  -EINVAL;
+	}
+
+	/* Check the opcode */
+	if (opc >= 0x40 && opc <= 0x5F)
+		opc = PMIC_ARB_OP_WRITE;
+	else if (opc >= 0x00 && opc <= 0x0F)
+		opc = PMIC_ARB_OP_EXT_WRITE;
+	else if (opc >= 0x30 && opc <= 0x37)
+		opc = PMIC_ARB_OP_EXT_WRITEL;
+	else if (opc >= 0x80)
+		opc = PMIC_ARB_OP_ZERO_WRITE;
+	else
+		return -EINVAL;
+
+	raw_spin_lock_irqsave(&pa->lock, flags);
+
+	/* Write data to FIFO */
+	for (i = 0; i < len; i++)
+		pmic_arb_debug_write(pa, PMIC_ARB_DEBUG_WDATA(i), buf[i]);
+
+	rc = pmic_arb_debug_issue_command(ctrl, opc, sid, addr, len);
+
+	raw_spin_unlock_irqrestore(&pa->lock, flags);
+
+	return rc;
+}
+
+static int spmi_pmic_arb_debug_probe(struct platform_device *pdev)
+{
+	struct spmi_pmic_arb_debug *pa;
+	struct spmi_controller *ctrl;
+	struct resource *res;
+	int rc;
+	u32 fuse_val, fuse_bit;
+	void __iomem *fuse_addr;
+
+	/* Check if the debug bus is disabled by a fuse. */
+	rc = of_property_read_u32(pdev->dev.of_node, "qcom,fuse-disable-bit",
+				  &fuse_bit);
+	if (!rc) {
+		if (fuse_bit > 31) {
+			dev_err(&pdev->dev, "qcom,fuse-disable-bit supports values 0 to 31, but %u specified\n",
+				fuse_bit);
+			return -EINVAL;
+		}
+
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						   "fuse");
+		if (!res) {
+			dev_err(&pdev->dev, "fuse address not specified\n");
+			return -EINVAL;
+		}
+
+		fuse_addr = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(fuse_addr))
+			return PTR_ERR(fuse_addr);
+
+		fuse_val = readl_relaxed(fuse_addr);
+		devm_iounmap(&pdev->dev, fuse_addr);
+
+		if (fuse_val & BIT(fuse_bit)) {
+			dev_err(&pdev->dev, "SPMI PMIC arbiter debug bus disabled by fuse\n");
+			return -ENODEV;
+		}
+	}
+
+
+	ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa));
+	if (!ctrl)
+		return -ENOMEM;
+
+	pa = spmi_controller_get_drvdata(ctrl);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
+	if (!res) {
+		dev_err(&pdev->dev, "core address not specified\n");
+		rc = -EINVAL;
+		goto err_put_ctrl;
+	}
+
+	pa->addr = devm_ioremap_resource(&ctrl->dev, res);
+	if (IS_ERR(pa->addr)) {
+		rc = PTR_ERR(pa->addr);
+		goto err_put_ctrl;
+	}
+
+	platform_set_drvdata(pdev, ctrl);
+	raw_spin_lock_init(&pa->lock);
+
+	ctrl->cmd = pmic_arb_debug_cmd;
+	ctrl->read_cmd = pmic_arb_debug_read_cmd;
+	ctrl->write_cmd = pmic_arb_debug_write_cmd;
+
+	rc = spmi_controller_add(ctrl);
+	if (rc)
+		goto err_put_ctrl;
+
+	dev_info(&ctrl->dev, "SPMI PMIC arbiter debug bus controller added\n");
+
+	return 0;
+
+err_put_ctrl:
+	spmi_controller_put(ctrl);
+	return rc;
+}
+
+static int spmi_pmic_arb_debug_remove(struct platform_device *pdev)
+{
+	struct spmi_controller *ctrl = platform_get_drvdata(pdev);
+
+	spmi_controller_remove(ctrl);
+	spmi_controller_put(ctrl);
+
+	return 0;
+}
+
+static const struct of_device_id spmi_pmic_arb_debug_match_table[] = {
+	{ .compatible = "qcom,spmi-pmic-arb-debug", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, spmi_pmic_arb_debug_match_table);
+
+static struct platform_driver spmi_pmic_arb_debug_driver = {
+	.probe		= spmi_pmic_arb_debug_probe,
+	.remove		= spmi_pmic_arb_debug_remove,
+	.driver		= {
+		.name	= "spmi_pmic_arb_debug",
+		.of_match_table = spmi_pmic_arb_debug_match_table,
+	},
+};
+
+int __init spmi_pmic_arb_debug_init(void)
+{
+	return platform_driver_register(&spmi_pmic_arb_debug_driver);
+}
+arch_initcall(spmi_pmic_arb_debug_init);
+
+static void __exit spmi_pmic_arb_debug_exit(void)
+{
+	platform_driver_unregister(&spmi_pmic_arb_debug_driver);
+}
+module_exit(spmi_pmic_arb_debug_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:spmi_pmic_arb_debug");
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index f066681..22cc80f 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -90,7 +90,7 @@
 
 /* Maximum number of support PMIC peripherals */
 #define PMIC_ARB_MAX_PERIPHS		512
-#define PMIC_ARB_TIMEOUT_US		100
+#define PMIC_ARB_TIMEOUT_US		1000
 #define PMIC_ARB_MAX_TRANS_BYTES	(8)
 
 #define PMIC_ARB_APID_MASK		0xFF
@@ -491,16 +491,6 @@
 	dev_err_ratelimited(&pmic_arb->spmic->dev, "%s apid=%d sid=0x%x per=0x%x irq=%d\n",
 			__func__, apid, sid, per, id);
 	writel_relaxed(irq_mask, pmic_arb->ver_ops->irq_clear(pmic_arb, apid));
-
-	if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid,
-			(per << 8) + QPNPINT_REG_LATCHED_CLR, &irq_mask, 1))
-		dev_err_ratelimited(&pmic_arb->spmic->dev, "failed to ack irq_mask = 0x%x for ppid = %x\n",
-				irq_mask, ppid);
-
-	if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid,
-			       (per << 8) + QPNPINT_REG_EN_CLR, &irq_mask, 1))
-		dev_err_ratelimited(&pmic_arb->spmic->dev, "failed to ack irq_mask = 0x%x for ppid = %x\n",
-				irq_mask, ppid);
 }
 
 static void periph_interrupt(struct spmi_pmic_arb *pmic_arb, u16 apid)
@@ -535,16 +525,28 @@
 	u8 ee = pmic_arb->ee;
 	u32 status, enable;
 	int i, id, apid;
+	/* status based dispatch */
+	bool acc_valid = false;
+	u32 irq_status = 0;
 
 	chained_irq_enter(chip, desc);
 
 	for (i = first; i <= last; ++i) {
 		status = readl_relaxed(
 				ver_ops->owner_acc_status(pmic_arb, ee, i));
+		if (status)
+			acc_valid = true;
+
 		while (status) {
 			id = ffs(status) - 1;
 			status &= ~BIT(id);
 			apid = id + i * 32;
+			if (apid < pmic_arb->min_apid
+			    || apid > pmic_arb->max_apid) {
+				WARN_ONCE(true, "spurious spmi irq received for apid=%d\n",
+					apid);
+				continue;
+			}
 			enable = readl_relaxed(
 					ver_ops->acc_enable(pmic_arb, apid));
 			if (enable & SPMI_PIC_ACC_ENABLE_BIT)
@@ -552,6 +554,28 @@
 		}
 	}
 
+	/* ACC_STATUS is empty but IRQ fired check IRQ_STATUS */
+	if (!acc_valid) {
+		for (i = pmic_arb->min_apid; i <= pmic_arb->max_apid; i++) {
+			/* skip if APPS is not irq owner */
+			if (pmic_arb->apid_data[i].irq_ee != pmic_arb->ee)
+				continue;
+
+			irq_status = readl_relaxed(
+					     ver_ops->irq_status(pmic_arb, i));
+			if (irq_status) {
+				enable = readl_relaxed(
+					     ver_ops->acc_enable(pmic_arb, i));
+				if (enable & SPMI_PIC_ACC_ENABLE_BIT) {
+					dev_dbg(&pmic_arb->spmic->dev,
+						"Dispatching IRQ for apid=%d status=%x\n",
+						i, irq_status);
+					periph_interrupt(pmic_arb, i);
+				}
+			}
+		}
+	}
+
 	chained_irq_exit(chip, desc);
 }
 
@@ -689,6 +713,19 @@
 	.flags		= IRQCHIP_MASK_ON_SUSPEND,
 };
 
+static int qpnpint_irq_domain_activate(struct irq_domain *domain,
+					struct irq_data *d, bool reserve)
+{
+	u8 irq = hwirq_to_irq(d->hwirq);
+	u8 buf;
+
+	buf = BIT(irq);
+	qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &buf, 1);
+	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &buf, 1);
+
+	return 0;
+}
+
 static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 					   struct device_node *controller,
 					   const u32 *intspec,
@@ -860,7 +897,8 @@
 	 * version 5, there is more than one APID mapped to each PPID.
 	 * The owner field for each of these mappings specifies the EE which is
 	 * allowed to write to the APID.  The owner of the last (highest) APID
-	 * for a given PPID will receive interrupts from the PPID.
+	 * which has the IRQ owner bit set for a given PPID will receive
+	 * interrupts from the PPID.
 	 */
 	for (i = 0; ; i++, apidd++) {
 		offset = pmic_arb->ver_ops->apid_map_offset(i);
@@ -883,16 +921,16 @@
 		apid = pmic_arb->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID;
 		prev_apidd = &pmic_arb->apid_data[apid];
 
-		if (valid && is_irq_ee &&
-				prev_apidd->write_ee == pmic_arb->ee) {
+		if (!valid || apidd->write_ee == pmic_arb->ee) {
+			/* First PPID mapping or one for this EE */
+			pmic_arb->ppid_to_apid[ppid] = i | PMIC_ARB_APID_VALID;
+		} else if (valid && is_irq_ee &&
+			   prev_apidd->write_ee == pmic_arb->ee) {
 			/*
 			 * Duplicate PPID mapping after the one for this EE;
 			 * override the irq owner
 			 */
 			prev_apidd->irq_ee = apidd->irq_ee;
-		} else if (!valid || is_irq_ee) {
-			/* First PPID mapping or duplicate for another EE */
-			pmic_arb->ppid_to_apid[ppid] = i | PMIC_ARB_APID_VALID;
 		}
 
 		apidd->ppid = ppid;
@@ -961,6 +999,11 @@
 		offset = 0x10000 * pmic_arb->ee + 0x80 * apid;
 		break;
 	case PMIC_ARB_CHANNEL_RW:
+		if (pmic_arb->apid_data[apid].write_ee != pmic_arb->ee) {
+			dev_err(&pmic_arb->spmic->dev, "disallowed SPMI write to sid=%u, addr=0x%04X\n",
+				sid, addr);
+			return -EPERM;
+		}
 		offset = 0x10000 * apid;
 		break;
 	}
@@ -1121,6 +1164,7 @@
 static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
 	.map	= qpnpint_irq_domain_map,
 	.xlate	= qpnpint_irq_domain_dt_translate,
+	.activate	= qpnpint_irq_domain_activate,
 };
 
 static int spmi_pmic_arb_probe(struct platform_device *pdev)
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index c82ea12..efa917a 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -2372,7 +2372,7 @@
 		clk_disable_unprepare(mdwc->sleep_clk);
 
 		if (mdwc->iommu_map) {
-			arm_iommu_detach_device(mdwc->dev);
+			__depr_arm_iommu_detach_device(mdwc->dev);
 			dev_dbg(mdwc->dev, "IOMMU detached\n");
 		}
 	}
@@ -2518,7 +2518,7 @@
 		u32 tmp;
 
 		if (mdwc->iommu_map) {
-			ret = arm_iommu_attach_device(mdwc->dev,
+			ret = __depr_arm_iommu_attach_device(mdwc->dev,
 					mdwc->iommu_map);
 			if (ret)
 				dev_err(mdwc->dev, "IOMMU attach failed (%d)\n",
@@ -3091,7 +3091,7 @@
 	if (!of_property_read_bool(node, "iommus"))
 		return 0;
 
-	mdwc->iommu_map = arm_iommu_create_mapping(&platform_bus_type,
+	mdwc->iommu_map = __depr_arm_iommu_create_mapping(&platform_bus_type,
 			SMMU_BASE, SMMU_SIZE);
 	if (IS_ERR_OR_NULL(mdwc->iommu_map)) {
 		ret = PTR_ERR(mdwc->iommu_map) ?: -ENODEV;
@@ -3118,7 +3118,7 @@
 		goto release_mapping;
 	}
 
-	ret = arm_iommu_attach_device(mdwc->dev, mdwc->iommu_map);
+	ret = __depr_arm_iommu_attach_device(mdwc->dev, mdwc->iommu_map);
 	if (ret) {
 		dev_err(mdwc->dev, "IOMMU attach failed (%d)\n", ret);
 		goto release_mapping;
@@ -3128,7 +3128,7 @@
 	return 0;
 
 release_mapping:
-	arm_iommu_release_mapping(mdwc->iommu_map);
+	__depr_arm_iommu_release_mapping(mdwc->iommu_map);
 	mdwc->iommu_map = NULL;
 	return ret;
 }
@@ -3555,7 +3555,7 @@
 
 	/* IOMMU will be reattached upon each resume/connect */
 	if (mdwc->iommu_map)
-		arm_iommu_detach_device(mdwc->dev);
+		__depr_arm_iommu_detach_device(mdwc->dev);
 
 	/*
 	 * Clocks and regulators will not be turned on until the first time
@@ -3606,8 +3606,8 @@
 
 uninit_iommu:
 	if (mdwc->iommu_map) {
-		arm_iommu_detach_device(mdwc->dev);
-		arm_iommu_release_mapping(mdwc->iommu_map);
+		__depr_arm_iommu_detach_device(mdwc->dev);
+		__depr_arm_iommu_release_mapping(mdwc->iommu_map);
 	}
 	of_platform_depopulate(&pdev->dev);
 err:
@@ -3687,8 +3687,8 @@
 
 	if (mdwc->iommu_map) {
 		if (!atomic_read(&dwc->in_lpm))
-			arm_iommu_detach_device(mdwc->dev);
-		arm_iommu_release_mapping(mdwc->iommu_map);
+			__depr_arm_iommu_detach_device(mdwc->dev);
+		__depr_arm_iommu_release_mapping(mdwc->iommu_map);
 	}
 
 	return 0;
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index 349e595..99ccc84f 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -96,6 +96,7 @@
 extern u64 (*arch_timer_read_counter)(void);
 extern struct arch_timer_kvm_info *arch_timer_get_kvm_info(void);
 extern bool arch_timer_evtstrm_available(void);
+extern void arch_timer_mem_get_cval(u32 *lo, u32 *hi);
 
 #else
 
@@ -114,6 +115,10 @@
 	return false;
 }
 
+static void arch_timer_mem_get_cval(u32 *lo, u32 *hi)
+{
+	*lo = *hi = ~0U;
+}
 #endif
 
 #endif
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index bd5e8cc..21371ac 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -20,8 +20,10 @@
 /*
  * Maximum values for blocksize and alignmask, used to allocate
  * static buffers that are big enough for any combination of
- * ciphers and architectures.
+ * algs and architectures. Ciphers have a lower maximum size.
  */
+#define MAX_ALGAPI_BLOCKSIZE		160
+#define MAX_ALGAPI_ALIGNMASK		63
 #define MAX_CIPHER_BLOCKSIZE		16
 #define MAX_CIPHER_ALIGNMASK		15
 
diff --git a/include/crypto/cbc.h b/include/crypto/cbc.h
index f5b8bfc..3bf28bee 100644
--- a/include/crypto/cbc.h
+++ b/include/crypto/cbc.h
@@ -113,7 +113,7 @@
 	unsigned int bsize = crypto_skcipher_blocksize(tfm);
 	unsigned int nbytes = walk->nbytes;
 	u8 *src = walk->src.virt.addr;
-	u8 last_iv[bsize];
+	u8 last_iv[MAX_CIPHER_BLOCKSIZE];
 
 	/* Start of the last block. */
 	src += nbytes - (nbytes & (bsize - 1)) - bsize;
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
index 76e432c..2158701 100644
--- a/include/crypto/hash.h
+++ b/include/crypto/hash.h
@@ -151,9 +151,13 @@
 	void *__ctx[] CRYPTO_MINALIGN_ATTR;
 };
 
+#define HASH_MAX_DIGESTSIZE	 64
+#define HASH_MAX_DESCSIZE	360
+#define HASH_MAX_STATESIZE	512
+
 #define SHASH_DESC_ON_STACK(shash, ctx)				  \
 	char __##shash##_desc[sizeof(struct shash_desc) +	  \
-		crypto_shash_descsize(ctx)] CRYPTO_MINALIGN_ATTR; \
+		HASH_MAX_DESCSIZE] CRYPTO_MINALIGN_ATTR; \
 	struct shash_desc *shash = (struct shash_desc *)__##shash##_desc
 
 /**
diff --git a/include/crypto/internal/geniv.h b/include/crypto/internal/geniv.h
index 2bcfb93..71be24c 100644
--- a/include/crypto/internal/geniv.h
+++ b/include/crypto/internal/geniv.h
@@ -20,7 +20,7 @@
 struct aead_geniv_ctx {
 	spinlock_t lock;
 	struct crypto_aead *child;
-	struct crypto_skcipher *sknull;
+	struct crypto_sync_skcipher *sknull;
 	u8 salt[] __attribute__ ((aligned(__alignof__(u32))));
 };
 
diff --git a/include/crypto/null.h b/include/crypto/null.h
index 15aeef6..0ef577c 100644
--- a/include/crypto/null.h
+++ b/include/crypto/null.h
@@ -9,7 +9,7 @@
 #define NULL_DIGEST_SIZE	0
 #define NULL_IV_SIZE		0
 
-struct crypto_skcipher *crypto_get_default_null_skcipher(void);
+struct crypto_sync_skcipher *crypto_get_default_null_skcipher(void);
 void crypto_put_default_null_skcipher(void);
 
 #endif
diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h
index 2f327f0..45ae894 100644
--- a/include/crypto/skcipher.h
+++ b/include/crypto/skcipher.h
@@ -65,6 +65,10 @@
 	struct crypto_tfm base;
 };
 
+struct crypto_sync_skcipher {
+	struct crypto_skcipher base;
+};
+
 /**
  * struct skcipher_alg - symmetric key cipher definition
  * @min_keysize: Minimum key size supported by the transformation. This is the
@@ -139,9 +143,17 @@
 	struct crypto_alg base;
 };
 
-#define SKCIPHER_REQUEST_ON_STACK(name, tfm) \
+#define MAX_SYNC_SKCIPHER_REQSIZE      384
+/*
+ * This performs a type-check against the "tfm" argument to make sure
+ * all users have the correct skcipher tfm for doing on-stack requests.
+ */
+#define SYNC_SKCIPHER_REQUEST_ON_STACK(name, tfm) \
 	char __##name##_desc[sizeof(struct skcipher_request) + \
-		crypto_skcipher_reqsize(tfm)] CRYPTO_MINALIGN_ATTR; \
+			     MAX_SYNC_SKCIPHER_REQSIZE + \
+			     (!(sizeof((struct crypto_sync_skcipher *)1 == \
+				       (typeof(tfm))1))) \
+			    ] CRYPTO_MINALIGN_ATTR; \
 	struct skcipher_request *name = (void *)__##name##_desc
 
 /**
@@ -197,6 +209,9 @@
 struct crypto_skcipher *crypto_alloc_skcipher(const char *alg_name,
 					      u32 type, u32 mask);
 
+struct crypto_sync_skcipher *crypto_alloc_sync_skcipher(const char *alg_name,
+					      u32 type, u32 mask);
+
 static inline struct crypto_tfm *crypto_skcipher_tfm(
 	struct crypto_skcipher *tfm)
 {
@@ -212,6 +227,11 @@
 	crypto_destroy_tfm(tfm, crypto_skcipher_tfm(tfm));
 }
 
+static inline void crypto_free_sync_skcipher(struct crypto_sync_skcipher *tfm)
+{
+	crypto_free_skcipher(&tfm->base);
+}
+
 /**
  * crypto_has_skcipher() - Search for the availability of an skcipher.
  * @alg_name: is the cra_name / name or cra_driver_name / driver name of the
@@ -280,6 +300,12 @@
 	return tfm->ivsize;
 }
 
+static inline unsigned int crypto_sync_skcipher_ivsize(
+	struct crypto_sync_skcipher *tfm)
+{
+	return crypto_skcipher_ivsize(&tfm->base);
+}
+
 static inline unsigned int crypto_skcipher_alg_chunksize(
 	struct skcipher_alg *alg)
 {
@@ -356,6 +382,12 @@
 	return crypto_tfm_alg_blocksize(crypto_skcipher_tfm(tfm));
 }
 
+static inline unsigned int crypto_sync_skcipher_blocksize(
+	struct crypto_sync_skcipher *tfm)
+{
+	return crypto_skcipher_blocksize(&tfm->base);
+}
+
 static inline unsigned int crypto_skcipher_alignmask(
 	struct crypto_skcipher *tfm)
 {
@@ -379,6 +411,24 @@
 	crypto_tfm_clear_flags(crypto_skcipher_tfm(tfm), flags);
 }
 
+static inline u32 crypto_sync_skcipher_get_flags(
+	struct crypto_sync_skcipher *tfm)
+{
+	return crypto_skcipher_get_flags(&tfm->base);
+}
+
+static inline void crypto_sync_skcipher_set_flags(
+	struct crypto_sync_skcipher *tfm, u32 flags)
+{
+	crypto_skcipher_set_flags(&tfm->base, flags);
+}
+
+static inline void crypto_sync_skcipher_clear_flags(
+	struct crypto_sync_skcipher *tfm, u32 flags)
+{
+	crypto_skcipher_clear_flags(&tfm->base, flags);
+}
+
 /**
  * crypto_skcipher_setkey() - set key for cipher
  * @tfm: cipher handle
@@ -401,6 +451,12 @@
 	return tfm->setkey(tfm, key, keylen);
 }
 
+static inline int crypto_sync_skcipher_setkey(struct crypto_sync_skcipher *tfm,
+					 const u8 *key, unsigned int keylen)
+{
+	return crypto_skcipher_setkey(&tfm->base, key, keylen);
+}
+
 static inline unsigned int crypto_skcipher_default_keysize(
 	struct crypto_skcipher *tfm)
 {
@@ -422,6 +478,14 @@
 	return __crypto_skcipher_cast(req->base.tfm);
 }
 
+static inline struct crypto_sync_skcipher *crypto_sync_skcipher_reqtfm(
+	struct skcipher_request *req)
+{
+	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+
+	return container_of(tfm, struct crypto_sync_skcipher, base);
+}
+
 /**
  * crypto_skcipher_encrypt() - encrypt plaintext
  * @req: reference to the skcipher_request handle that holds all information
@@ -500,6 +564,12 @@
 	req->base.tfm = crypto_skcipher_tfm(tfm);
 }
 
+static inline void skcipher_request_set_sync_tfm(struct skcipher_request *req,
+					    struct crypto_sync_skcipher *tfm)
+{
+	skcipher_request_set_tfm(req, &tfm->base);
+}
+
 static inline struct skcipher_request *skcipher_request_cast(
 	struct crypto_async_request *req)
 {
diff --git a/include/dt-bindings/msm/pm.h b/include/dt-bindings/msm/pm.h
new file mode 100644
index 0000000..f7bb19d
--- /dev/null
+++ b/include/dt-bindings/msm/pm.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __DT_MSM_PM_H__
+#define __DT_MSM_PM_H__
+
+#define LPM_RESET_LVL_NONE	0
+#define LPM_RESET_LVL_RET	1
+#define LPM_RESET_LVL_GDHS	2
+#define LPM_RESET_LVL_PC	3
+
+#define LPM_AFF_LVL_CPU		0
+#define LPM_AFF_LVL_L2		1
+#define LPM_AFF_LVL_CCI		2
+
+#endif
diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
index ecb53be..5e0aaa5 100644
--- a/include/linux/compiler_types.h
+++ b/include/linux/compiler_types.h
@@ -202,7 +202,6 @@
  */
 #define __pure			__attribute__((pure))
 #define __aligned(x)		__attribute__((aligned(x)))
-#define __aligned_largest	__attribute__((aligned))
 #define __printf(a, b)		__attribute__((format(printf, a, b)))
 #define __scanf(a, b)		__attribute__((format(scanf, a, b)))
 #define __maybe_unused		__attribute__((unused))
diff --git a/include/linux/leds-qpnp-flash-v2.h b/include/linux/leds-qpnp-flash-v2.h
new file mode 100644
index 0000000..b961ab1
--- /dev/null
+++ b/include/linux/leds-qpnp-flash-v2.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __LEDS_QPNP_FLASH_V2_H
+#define __LEDS_QPNP_FLASH_V2_H
+
+#include <linux/leds.h>
+#include <linux/notifier.h>
+
+enum flash_led_irq_type {
+	LED_FAULT_IRQ = BIT(0),
+	MITIGATION_IRQ = BIT(1),
+	FLASH_TIMER_EXP_IRQ = BIT(2),
+	ALL_RAMP_DOWN_DONE_IRQ = BIT(3),
+	ALL_RAMP_UP_DONE_IRQ = BIT(4),
+	LED3_RAMP_UP_DONE_IRQ = BIT(5),
+	LED2_RAMP_UP_DONE_IRQ = BIT(6),
+	LED1_RAMP_UP_DONE_IRQ = BIT(7),
+	INVALID_IRQ = BIT(8),
+};
+
+int qpnp_flash_led_register_irq_notifier(struct notifier_block *nb);
+int qpnp_flash_led_unregister_irq_notifier(struct notifier_block *nb);
+
+#endif
diff --git a/include/linux/leds-qpnp-flash.h b/include/linux/leds-qpnp-flash.h
new file mode 100644
index 0000000..d820d2c
--- /dev/null
+++ b/include/linux/leds-qpnp-flash.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __LEDS_QPNP_FLASH_H
+#define __LEDS_QPNP_FLASH_H
+
+#include <linux/leds.h>
+
+#define ENABLE_REGULATOR		BIT(0)
+#define DISABLE_REGULATOR		BIT(1)
+#define QUERY_MAX_AVAIL_CURRENT		BIT(2)
+#define QUERY_MAX_CURRENT		BIT(3)
+
+#define FLASH_LED_PREPARE_OPTIONS_MASK	GENMASK(3, 0)
+
+int qpnp_flash_led_prepare(struct led_trigger *trig, int options,
+					int *max_current);
+#ifdef CONFIG_BACKLIGHT_QCOM_SPMI_WLED
+int wled_flash_led_prepare(struct led_trigger *trig, int options,
+					int *max_current);
+#else
+static inline int wled_flash_led_prepare(struct led_trigger *trig, int options,
+					int *max_current)
+{
+	return -EINVAL;
+}
+#endif
+
+#endif
diff --git a/include/linux/oom.h b/include/linux/oom.h
index 816372f..9af7e19 100644
--- a/include/linux/oom.h
+++ b/include/linux/oom.h
@@ -119,4 +119,8 @@
 extern int sysctl_oom_dump_tasks;
 extern int sysctl_oom_kill_allocating_task;
 extern int sysctl_panic_on_oom;
+extern int sysctl_reap_mem_on_sigkill;
+
+/* calls for LMK reaper */
+extern void add_to_oom_reaper(struct task_struct *p);
 #endif /* _INCLUDE_LINUX_OOM_H */
diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h
new file mode 100644
index 0000000..7bd1e8e
--- /dev/null
+++ b/include/linux/qpnp/qpnp-revid.h
@@ -0,0 +1,319 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __QPNP_REVID
+#define __QPNP_REVID
+
+/* Common TYPE for all PMICs */
+#define PMIC_TYPE		0x51
+
+/* PM8994 */
+#define PM8941_SUBTYPE		0x01
+
+#define PM8941_V1P0_REV1	0x00
+#define PM8941_V1P0_REV2	0x00
+#define PM8941_V1P0_REV3	0x00
+#define PM8941_V1P0_REV4	0x01
+
+#define PM8941_V2P0_REV1	0x00
+#define PM8941_V2P0_REV2	0x00
+#define PM8941_V2P0_REV3	0x00
+#define PM8941_V2P0_REV4	0x01
+
+#define PM8941_V3P0_REV1	0x00
+#define PM8941_V3P0_REV2	0x00
+#define PM8941_V3P0_REV3	0x00
+#define PM8941_V3P0_REV4	0x03
+
+#define PM8941_V3P1_REV1	0x00
+#define PM8941_V3P1_REV2	0x00
+#define PM8941_V3P1_REV3	0x01
+#define PM8941_V3P1_REV4	0x03
+
+/* PM8841 */
+#define PM8841_SUBTYPE		0x02
+
+/* PM8019 */
+#define PM8019_SUBTYPE		0x03
+
+/* PM8226 */
+#define PM8226_SUBTYPE		0x04
+
+#define PM8226_V2P2_REV1	0x00
+#define PM8226_V2P2_REV2	0x00
+#define PM8226_V2P2_REV3	0x02
+#define PM8226_V2P2_REV4	0x02
+
+#define PM8226_V2P1_REV1	0x00
+#define PM8226_V2P1_REV2	0x00
+#define PM8226_V2P1_REV3	0x01
+#define PM8226_V2P1_REV4	0x02
+
+#define PM8226_V2P0_REV1	0x00
+#define PM8226_V2P0_REV2	0x00
+#define PM8226_V2P0_REV3	0x00
+#define PM8226_V2P0_REV4	0x02
+
+#define PM8226_V1P0_REV1	0x00
+#define PM8226_V1P0_REV2	0x00
+#define PM8226_V1P0_REV3	0x00
+#define PM8226_V1P0_REV4	0x00
+
+/* PM8110 */
+#define PM8110_SUBTYPE		0x05
+
+#define PM8110_V1P0_REV1	0x00
+#define PM8110_V1P0_REV2	0x00
+#define PM8110_V1P0_REV3	0x00
+#define PM8110_V1P0_REV4	0x01
+
+#define PM8110_V1P1_REV1	0x00
+#define PM8110_V1P1_REV2	0x01
+#define PM8110_V1P1_REV3	0x00
+#define PM8110_V1P1_REV4	0x01
+
+#define PM8110_V1P3_REV1	0x00
+#define PM8110_V1P3_REV2	0x03
+#define PM8110_V1P3_REV3	0x00
+#define PM8110_V1P3_REV4	0x01
+
+#define PM8110_V2P0_REV1	0x00
+#define PM8110_V2P0_REV2	0x00
+#define PM8110_V2P0_REV3	0x00
+#define PM8110_V2P0_REV4	0x02
+
+/* PMA8084 */
+#define PMA8084_SUBTYPE		0x06
+
+/* PMI8962 */
+#define PMI8962_SUBTYPE		0x07
+
+/* PMD9635 */
+#define PMD9635_SUBTYPE		0x08
+/* PM8994 */
+#define PM8994_SUBTYPE		0x09
+
+/* PMI8994 */
+#define PMI8994_TYPE		0x51
+#define PMI8994_SUBTYPE		0x0A
+
+#define PMI8994_V1P0_REV1	0x00
+#define PMI8994_V1P0_REV2	0x00
+#define PMI8994_V1P0_REV3	0x00
+#define PMI8994_V1P0_REV4	0x01
+
+#define PMI8994_V2P0_REV1	0x00
+#define PMI8994_V2P0_REV2	0x00
+#define PMI8994_V2P0_REV3	0x00
+#define PMI8994_V2P0_REV4	0x02
+
+/* PM8916 */
+#define PM8916_SUBTYPE		0x0B
+
+#define PM8916_V1P0_REV1	0x00
+#define PM8916_V1P0_REV2	0x00
+#define PM8916_V1P0_REV3	0x00
+#define PM8916_V1P0_REV4	0x01
+
+#define PM8916_V1P1_REV1	0x00
+#define PM8916_V1P1_REV2	0x00
+#define PM8916_V1P1_REV3	0x01
+#define PM8916_V1P1_REV4	0x01
+
+#define PM8916_V2P0_REV1	0x00
+#define PM8916_V2P0_REV2	0x00
+#define PM8916_V2P0_REV3	0x00
+#define PM8916_V2P0_REV4	0x02
+
+/* PM8004 */
+#define PM8004_SUBTYPE		0x0C
+
+/* PM8909 */
+#define PM8909_SUBTYPE		0x0D
+
+#define PM8909_V1P0_REV1	0x00
+#define PM8909_V1P0_REV2	0x00
+#define PM8909_V1P0_REV3	0x00
+#define PM8909_V1P0_REV4	0x01
+
+#define PM8909_V1P1_REV1	0x00
+#define PM8909_V1P1_REV2	0x00
+#define PM8909_V1P1_REV3	0x01
+#define PM8909_V1P1_REV4	0x01
+
+/* PM2433 */
+#define PM2433_SUBTYPE		0x0E
+
+/* PMD9655 */
+#define PMD9655_SUBTYPE		0x0F
+
+/* PM8950 */
+#define PM8950_SUBTYPE		0x10
+#define PM8950_V1P0_REV4	0x01
+
+#define PM8950_V2P0_REV4	0x02
+
+/* PMI8950 */
+#define PMI8950_SUBTYPE		0x11
+
+/* PMK8001 */
+#define PMK8001_SUBTYPE		0x12
+
+/* PMI8996 */
+#define PMI8996_SUBTYPE		0x13
+
+/* PM8998 */
+#define PM8998_SUBTYPE	0x14
+
+/* PMI8998 */
+#define PMI8998_SUBTYPE	0x15
+
+/* PM660 */
+#define PM660L_SUBTYPE	0x1A
+#define PM660_SUBTYPE	0x1B
+
+/* PM8150 */
+#define PM8150_SUBTYPE		0x1E
+#define PM8150L_SUBTYPE		0x1F
+#define PM8150B_SUBTYPE		0x20
+
+#define PM6150_SUBTYPE		0x28
+#define PM6150L_SUBTYPE		0x1F
+
+/* PMI632 */
+#define PMI632_SUBTYPE	0x25
+
+/* PMI8998 REV_ID */
+#define PMI8998_V1P0_REV1	0x00
+#define PMI8998_V1P0_REV2	0x00
+#define PMI8998_V1P0_REV3	0x00
+#define PMI8998_V1P0_REV4	0x01
+
+#define PMI8998_V1P1_REV1	0x00
+#define PMI8998_V1P1_REV2	0x00
+#define PMI8998_V1P1_REV3	0x01
+#define PMI8998_V1P1_REV4	0x01
+
+#define PMI8998_V2P0_REV1	0x00
+#define PMI8998_V2P0_REV2	0x00
+#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
+
+/* PM660L REV_ID */
+#define PM660L_V1P1_REV1	0x00
+#define PM660L_V1P1_REV2	0x00
+#define PM660L_V1P1_REV3	0x01
+#define PM660L_V1P1_REV4	0x01
+
+#define PM660L_V2P0_REV1	0x00
+#define PM660L_V2P0_REV2	0x00
+#define PM660L_V2P0_REV3	0x00
+#define PM660L_V2P0_REV4	0x02
+
+/* PMI632 REV_ID */
+#define PMI632_V1P0_REV1	0x00
+#define PMI632_V1P0_REV2	0x00
+#define PMI632_V1P0_REV3	0x00
+#define PMI632_V1P0_REV4	0x01
+
+/* PM8150B_REV_ID */
+#define PM8150B_V1P0_REV1	0x00
+#define PM8150B_V1P0_REV2	0x00
+#define PM8150B_V1P0_REV3	0x00
+#define PM8150B_V1P0_REV4	0x01
+
+#define PM8150B_V2P0_REV1	0x00
+#define PM8150B_V2P0_REV2	0x00
+#define PM8150B_V2P0_REV3	0x00
+#define PM8150B_V2P0_REV4	0x02
+
+/* PM8150L_REV_ID */
+#define PM8150L_V1P0_REV1	0x00
+#define PM8150L_V1P0_REV2	0x00
+#define PM8150L_V1P0_REV3	0x00
+#define PM8150L_V1P0_REV4	0x01
+
+#define PM8150L_V2P0_REV1	0x00
+#define PM8150L_V2P0_REV2	0x00
+#define PM8150L_V2P0_REV3	0x00
+#define PM8150L_V2P0_REV4	0x02
+
+#define PM8150L_V3P0_REV1	0x00
+#define PM8150L_V3P0_REV2	0x00
+#define PM8150L_V3P0_REV3	0x00
+#define PM8150L_V3P0_REV4	0x03
+
+#define PM6150_V1P0_REV1	0x00
+#define PM6150_V1P0_REV2	0x00
+#define PM6150_V1P0_REV3	0x00
+#define PM6150_V1P0_REV4	0x01
+
+#define PM6150_V1P1_REV1	0x00
+#define PM6150_V1P1_REV2	0x00
+#define PM6150_V1P1_REV3	0x01
+#define PM6150_V1P1_REV4	0x01
+
+#define PM6150_V2P0_REV1	0x00
+#define PM6150_V2P0_REV2	0x00
+#define PM6150_V2P0_REV3	0x00
+#define PM6150_V2P0_REV4	0x02
+
+/* 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
+
+/* PM8937 */
+#define PM8937_SUBTYPE		0x19
+
+/* PMI8937 */
+#define PMI8937_SUBTYPE		0x37
+
+/* SMB1381 */
+#define SMB1381_SUBTYPE		0x17
+
+/* SMB1355 */
+#define SMB1355_SUBTYPE		0x1C
+
+struct pmic_revid_data {
+	u8		rev1;
+	u8		rev2;
+	u8		rev3;
+	u8		rev4;
+	u8		pmic_type;
+	u8		pmic_subtype;
+	const char	*pmic_name;
+	int		fab_id;
+	int		tp_rev;
+};
+
+#ifdef CONFIG_QPNP_REVID
+struct pmic_revid_data *get_revid_data(struct device_node *dev_node);
+#else
+static inline
+struct pmic_revid_data *get_revid_data(struct device_node *dev_node)
+{
+	return NULL;
+}
+#endif
+#endif
diff --git a/include/linux/soc/qcom/qmi.h b/include/linux/soc/qcom/qmi.h
index bdf9047..2fb53c7 100644
--- a/include/linux/soc/qcom/qmi.h
+++ b/include/linux/soc/qcom/qmi.h
@@ -88,6 +88,7 @@
 #define QMI_ERR_CLIENT_IDS_EXHAUSTED_V01	5
 #define QMI_ERR_INVALID_ID_V01			41
 #define QMI_ERR_ENCODING_V01			58
+#define QMI_ERR_DISABLED_V01			69
 #define QMI_ERR_INCOMPATIBLE_STATE_V01		90
 #define QMI_ERR_NOT_SUPPORTED_V01		94
 
diff --git a/kernel/signal.c b/kernel/signal.c
index 5843c54..b6f24c8 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -41,6 +41,8 @@
 #include <linux/compiler.h>
 #include <linux/posix-timers.h>
 #include <linux/livepatch.h>
+#include <linux/oom.h>
+#include <linux/capability.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/signal.h>
@@ -1324,8 +1326,11 @@
 	ret = check_kill_permission(sig, info, p);
 	rcu_read_unlock();
 
-	if (!ret && sig)
+	if (!ret && sig) {
 		ret = do_send_sig_info(sig, info, p, type);
+		if (capable(CAP_KILL) && sig == SIGKILL)
+			add_to_oom_reaper(p);
+	}
 
 	return ret;
 }
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c23e0b0..bb60a0b 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1271,6 +1271,13 @@
 		.proc_handler	= proc_dointvec,
 	},
 	{
+		.procname       = "reap_mem_on_sigkill",
+		.data           = &sysctl_reap_mem_on_sigkill,
+		.maxlen         = sizeof(sysctl_reap_mem_on_sigkill),
+		.mode           = 0644,
+		.proc_handler   = proc_dointvec,
+	},
+	{
 		.procname	= "overcommit_ratio",
 		.data		= &sysctl_overcommit_ratio,
 		.maxlen		= sizeof(sysctl_overcommit_ratio),
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 1198b32..19aec79 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -52,6 +52,7 @@
 int sysctl_panic_on_oom;
 int sysctl_oom_kill_allocating_task;
 int sysctl_oom_dump_tasks = 1;
+int sysctl_reap_mem_on_sigkill;
 
 /*
  * Serializes oom killer invocations (out_of_memory()) from all contexts to
@@ -634,13 +635,21 @@
 
 static void wake_oom_reaper(struct task_struct *tsk)
 {
+	/*
+	 * Move the lock here to avoid scenario of queuing
+	 * the same task by both OOM killer and any other SIGKILL
+	 * path.
+	 */
+	spin_lock(&oom_reaper_lock);
+
 	/* tsk is already queued? */
-	if (tsk == oom_reaper_list || tsk->oom_reaper_list)
+	if (tsk == oom_reaper_list || tsk->oom_reaper_list) {
+		spin_unlock(&oom_reaper_lock);
 		return;
+	}
 
 	get_task_struct(tsk);
 
-	spin_lock(&oom_reaper_lock);
 	tsk->oom_reaper_list = oom_reaper_list;
 	oom_reaper_list = tsk;
 	spin_unlock(&oom_reaper_lock);
@@ -660,6 +669,16 @@
 }
 #endif /* CONFIG_MMU */
 
+static void __mark_oom_victim(struct task_struct *tsk)
+{
+	struct mm_struct *mm = tsk->mm;
+
+	if (!cmpxchg(&tsk->signal->oom_mm, NULL, mm)) {
+		mmgrab(tsk->signal->oom_mm);
+		set_bit(MMF_OOM_VICTIM, &mm->flags);
+	}
+}
+
 /**
  * mark_oom_victim - mark the given task as OOM victim
  * @tsk: task to mark
@@ -672,18 +691,13 @@
  */
 static void mark_oom_victim(struct task_struct *tsk)
 {
-	struct mm_struct *mm = tsk->mm;
-
 	WARN_ON(oom_killer_disabled);
 	/* OOM killer might race with memcg OOM */
 	if (test_and_set_tsk_thread_flag(tsk, TIF_MEMDIE))
 		return;
 
 	/* oom_mm is bound to the signal struct life time. */
-	if (!cmpxchg(&tsk->signal->oom_mm, NULL, mm)) {
-		mmgrab(tsk->signal->oom_mm);
-		set_bit(MMF_OOM_VICTIM, &mm->flags);
-	}
+	__mark_oom_victim(tsk);
 
 	/*
 	 * Make sure that the task is woken up from uninterruptible sleep
@@ -1145,3 +1159,21 @@
 	out_of_memory(&oc);
 	mutex_unlock(&oom_lock);
 }
+
+void add_to_oom_reaper(struct task_struct *p)
+{
+	if (!sysctl_reap_mem_on_sigkill)
+		return;
+
+	p = find_lock_task_mm(p);
+	if (!p)
+		return;
+
+	get_task_struct(p);
+	if (task_will_free_mem(p)) {
+		__mark_oom_victim(p);
+		wake_oom_reaper(p);
+	}
+	task_unlock(p);
+	put_task_struct(p);
+}
diff --git a/mm/swap_ratio.c b/mm/swap_ratio.c
index 577b8c1..19e459d 100644
--- a/mm/swap_ratio.c
+++ b/mm/swap_ratio.c
@@ -9,8 +9,9 @@
 
 #define SWAP_RATIO_GROUP_START (SWAP_FLAG_PRIO_MASK - 9) /* 32758 */
 #define SWAP_RATIO_GROUP_END (SWAP_FLAG_PRIO_MASK) /* 32767 */
-#define SWAP_FAST_WRITES (SWAPFILE_CLUSTER * (SWAP_CLUSTER_MAX / 8))
-#define SWAP_SLOW_WRITES SWAPFILE_CLUSTER
+#define SWAP_FAST_WRITES	\
+	((SWAPFILE_CLUSTER * (SWAP_CLUSTER_MAX / 8)) / SWAP_BATCH)
+#define SWAP_SLOW_WRITES (SWAPFILE_CLUSTER / SWAP_BATCH)
 
 /*
  * The fast/slow swap write ratio.
@@ -78,6 +79,12 @@
 	n = plist_next_entry(&(*si)->avail_lists[node],
 			struct swap_info_struct,
 			avail_lists[node]);
+	if (n == *si) {
+		/* No other swap device */
+		ret = -ENODEV;
+		goto skip;
+	}
+
 	spin_unlock(&swap_avail_lock);
 	spin_lock(&n->lock);
 	spin_lock(&swap_avail_lock);
@@ -175,6 +182,9 @@
 
 int swap_ratio(struct swap_info_struct **si, int node)
 {
+	if (!sysctl_swap_ratio_enable)
+		return -ENODEV;
+
 	if (is_swap_ratio_group((*si)->prio))
 		return swap_ratio_slow(si, node);
 	else
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 54da4b0..598b764 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -58,6 +58,11 @@
 include scripts/Makefile.host
 endif
 
+# Do not include host rules unless needed
+ifneq ($(dtbo-y),)
+include scripts/Makefile.dtbo
+endif
+
 ifndef obj
 $(warning kbuild: Makefile.build is included improperly)
 endif
diff --git a/scripts/Makefile.dtbo b/scripts/Makefile.dtbo
new file mode 100644
index 0000000..ce83b35
--- /dev/null
+++ b/scripts/Makefile.dtbo
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0
+__dtbo := $(sort $(dtbo-y))
+
+dtbo-base	:= $(sort $(foreach m,$(__dtbo),$($(m)-base)))
+dtbo := $(foreach m,$(__dtbo),$(if $($(m)-base),$(m)))
+
+__dtbo     := $(addprefix $(obj)/,$(__dtbo))
+dtbo-base	:= $(addprefix $(obj)/,$(dtbo-base))
+dtbo	:= $(addprefix $(obj)/,$(dtbo))
+
+ifneq ($(DTC_OVERLAY_TEST_EXT),)
+DTC_OVERLAY_TEST = $(DTC_OVERLAY_TEST_EXT)
+quiet_cmd_dtbo_verify	= VERIFY  $@
+cmd_dtbo_verify = $(DTC_OVERLAY_TEST) $(addprefix $(obj)/,$($(@F)-base)) $@ $(dot-target).dtb
+else
+cmd_dtbo_verify = true
+endif
+
+$(obj)/%.dtbo: $(src)/%.dts FORCE
+	$(call if_changed_dep,dtc)
+	$(call if_changed,dtbo_verify)
+
+$(call multi_depend, $(dtbo), , -base)
+
+always +=  $(dtbo)
diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py
index add49a1..8447951 100755
--- a/scripts/gcc-wrapper.py
+++ b/scripts/gcc-wrapper.py
@@ -17,33 +17,9 @@
 # force LANG to be set to en_US.UTF-8 to get consistent warnings.
 
 allowed_warnings = set([
-    "seqiv.c:76",
-    "echainiv.c:50",
-    "crypto.c:67",
-    "shash.c:91",
-    "shash.c:127",
-    "smp.c:176",
-    "xcbc.c:68",
-    "hmac.c:56",
-    "cbc.c:14",
-    "cbc.h:116",
-    "cryptd.c:487",
-    "cryptd.c:515",
-    "ablkcipher.c:215",
-    "authenc.c:188",
-    "authenc.c:186",
-    "authencesn.c:186",
-    "libcrc32c.c:45",
-    "ppp_mppe.c:158",
-    "ppp_mppe.c:369",
-    "ppp_mppe.c:483",
-    "dm-verity-fec.c:218",
     "umid.c:138",
     "umid.c:213",
     "umid.c:388",
-    "shash.c:92",
-    "shash.c:128",
-    "smp.c:177",
  ])
 
 # Capture the name of the object file, can find it.